> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/aiperf/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/aiperf/_mcp/server.

# Interactive Chat Sanity Checks

`aiperf chat` lets you talk to an OpenAI-compatible endpoint one message at a
time and see per-turn speed stats — time to first token, throughput,
inter-token latency, and prompt-cache hit rate — after every reply. It is a
lightweight sanity-check companion to `aiperf profile`: handy for confirming an
endpoint is wired up correctly and getting a ballpark feel for performance
before committing to a full benchmark run, and for eyeballing
speculative-decoding or reasoning-model behavior where speedups are
prompt-dependent.

It is deliberately minimal. For real benchmarking — concurrency, request rates,
datasets, sampling knobs, artifacts, and statistical aggregation — use
`aiperf profile`. Every number `aiperf chat` prints is produced by the same
metric classes `profile` uses, so they stay consistent (including
reasoning-token accounting).

---

## Prerequisites

Before you begin, ensure you have:

- AIPerf installed
- An OpenAI-compatible inference server running (e.g. vLLM, SGLang) and
  reachable, exposing `/v1/chat/completions`

---

## Single-Shot Sanity Check

Send one message and exit with `--quick`:

```bash
aiperf chat \
    --model Qwen/Qwen3-0.6B \
    --url http://localhost:8000 \
    --quick "say hello in one short sentence"
```

**Sample Output:**

```
Using model: Qwen/Qwen3-0.6B
Hello! How can I help you today?
TTFT: 20.06 ms
TPS:  154.11 tokens/s (9 tokens in 0.06s)
ITL:  6.31 ms/token (decode 158.40 tokens/s)
Cache: 14/18 prompt tokens cached (77.8%)
```

Every reply is followed by the same per-turn stats block, explained next.

---

## Reading the per-turn stats

The block is the same in every mode (single-shot, multi-turn, or
`--no-history`). All four values come from the same metric classes `aiperf
profile` uses:

- **TTFT** — time to first token (client-observed).
- **TPS** — generated tokens divided by end-to-end latency. The vLLM-familiar
  rate; it *includes* TTFT, so it blends prefill and decode into one number.
- **ITL** (inter-token latency) / **decode** — a decode-focused rate that
  excludes prefill. Because it ignores TTFT, it stays comparable across turns
  even when a growing history inflates prefill (where TPS sags). Omitted for
  single-token replies, where it is undefined.
- **Cache** — prompt-cache hit rate (`cached / prompt tokens`). Prefix caches
  are **server-side and shared across requests and sessions**, so a hit does
  not require a prior turn in this conversation — a shared system prompt or any
  prefix the server already cached (from earlier requests, other sessions, or
  other clients) can hit, even on a first or single-shot message. It is read
  from the server's `usage`, so it appears only when the server reports prompt
  caching (see below), and reflects the same counts `aiperf profile` records.

> **Don't see the `Cache:` line?** The server has to *report* cached tokens in
> its `usage`, which is separate from merely *enabling* caching. Launch the
> server accordingly:
>
> - **vLLM:** `--enable-prefix-caching` **and** `--enable-prompt-tokens-details`.
>   The reporting flag is off by default and independent of prefix caching —
>   without it vLLM sends `prompt_tokens_details: null` and no `Cache:` line
>   appears.
> - **SGLang:** `--enable-cache-report` (off by default).
> - **TRT-LLM:** reports `cached_tokens` by default; no extra flag.
>
> A genuinely novel prefix is a cold miss (`Cache: 0/N … (0.0%)`); the rate
> rises as prefixes are reused — within this session or already resident in the
> server's cache. See
> [Vendor Usage Field Reference](/aiperf/dev/reference/vendor-usage-field-reference) for the
> full matrix.

---

## Interactive Multi-Turn Chat

Omit `--quick` to start an interactive session. History is retained and resent
each turn, so the model has full context (press `Ctrl-D` to exit). Watching the
same stats evolve turn over turn is the point: TTFT and the cache hit rate climb
as the resent prefix grows, while ITL — the decode-only rate — stays roughly
flat even as the headline TPS sags.

```bash
aiperf chat --model Qwen/Qwen3-0.6B --url http://localhost:8000
```

```
Please enter a message for the chat model (Ctrl-D to exit):
> what's the capital of France?
The capital of France is Paris.
TTFT: 21.483 ms
TPS:  148.20 tokens/s (8 tokens in 0.05s)
ITL:  6.05 ms/token (decode 165.29 tokens/s)
Cache: 12/40 prompt tokens cached (30.0%)
> and its population?
As of recent estimates, the population of Paris is about 2.1 million.
TTFT: 34.92 ms
TPS:  121.66 tokens/s (15 tokens in 0.12s)
ITL:  6.11 ms/token (decode 163.67 tokens/s)
Cache: 56/72 prompt tokens cached (77.8%)
```

---

## Stateless Turns (`--no-history`)

By default each turn resends the full conversation. Pass `--no-history` to make
every message an independent, stateless request instead — the completion-style
flow, where the model has no memory of prior turns:

```bash
aiperf chat --model Qwen/Qwen3-0.6B --no-history
```

This is useful for measuring single-turn performance repeatedly without the
prefill cost of a growing history. The same stats block still prints; the cache
hit rate won't climb from *this* session's history (none is resent), but it can
still be non-zero when the server already holds a matching prefix — e.g. a
shared system prompt or a prefix cached from earlier requests. `--no-history` is
ignored with `--quick`, which is already a single request.

---

## Reasoning Models

When the endpoint serves a reasoning model, `aiperf chat` counts reasoning
tokens the same way `aiperf profile` does. Whether the server emits reasoning in
a dedicated `reasoning_content` field (via a reasoning parser) or inline as
`<think>...</think>` in the content, the generated reasoning tokens are included
in the token total, and a separate reasoning count is shown in the TPS line:

```
TTFT: 20.06 ms
TPS:  154.11 tokens/s (186 tokens, 142 reasoning in 1.20s)
ITL:  6.12 ms/token (decode 163.40 tokens/s)
```

---

## Options

| Option | Description |
|---|---|
| `--model`, `-m` | Model name served by the endpoint (required). |
| `--url`, `-u` | Base URL of the OpenAI-compatible server (default `http://localhost:8000`). |
| `--system-prompt` | Optional system prompt prepended to the conversation. |
| `--quick`, `-q` | Send a single message and exit instead of looping. |
| `--no-history` | Treat each interactive message as a stateless request (no history retained). Ignored with `--quick`. |
| `--api-key` | API key sent as a Bearer token (defaults to `OPENAI_API_KEY`). |
| `--tokenizer` | Tokenizer for client-side token counts (defaults to the model name). Pass `builtin` for a zero-network tokenizer. |

---

## Tuning request timeouts

`aiperf chat` fails fast on an unreachable endpoint but never caps overall
generation time, so long replies are not truncated. Both timeouts are tunable
via environment variables (no total timeout is applied):

- `AIPERF_CHAT_CONNECT_TIMEOUT` (default `10.0`) — seconds to establish a
  connection before a turn fails.
- `AIPERF_CHAT_READ_TIMEOUT` (default `300.0`) — seconds to wait for the next
  streamed chunk before a turn fails (only fires if the server stalls).

See [Environment Variables](/aiperf/dev/reference/environment-variables) for the full list.

## See Also

- [Multi-Turn Conversations](/aiperf/dev/tutorials/datasets-inputs/multi-turn-conversations) - Benchmark multi-turn sessions at scale
- [Using Local Tokenizers Without HuggingFace](/aiperf/dev/tutorials/configuration/using-local-tokenizers-without-hugging-face)
- [Metrics Reference](/aiperf/dev/reference/ai-perf-metrics-reference) - Definitions of TTFT, ITL, OSL, and more