Why AI responses are slow: tracing retrieval, tools and model generation
Separate first-visible-answer delay from completion time, map the request's required work, and choose the next measurement for retrieval, tools, queueing or generation.
The direct answer
Measure the time to the first visible answer separately from the time to a complete, usable result. Follow one correlated request through application queues, retrieval, tools, model calls and display; optimize the work that delays the milestone you care about, and add measurements where the trace cannot yet distinguish causes.
Choose the wait you are trying to shorten
A user reporting “the AI is slow” might mean a blank screen before an answer, long pauses while text arrives, or a long wait for a finished result. Start by selecting that milestone and its clock boundaries.
| Measurement | Start → end | Decision it supports |
|---|---|---|
| Time to first visible answer | User submits → first answer content is displayed | Is the application making the user wait before receiving useful content? Count a spinner or “searching” status separately. |
| Time to usable completion | User submits → final result is displayed and any required validation has finished | When can the user act on the result? For structured output, this may be later than the last generated token. |
| Model-call first-chunk time | Application issues a streaming generation request → its model client receives the first chunk | How much delay occurs inside that outbound call before anything is streamed back? |
| Model-call duration | Start of the outbound call → its defined completion or error | How much of the request is spent in this call? Verify that the timer includes consuming the stream. |
The first two are application measurements proposed here. They are not standard GenAI metric names. The model client may run in your backend; “client” in a provider metric does not necessarily mean the browser.
OpenTelemetry's Development conventions define gen_ai.client.operation.time_to_first_chunk for streaming calls. They separately describe server gen_ai.server.time_to_first_token as covering the wait through queueing and prefill. Different start points and observation locations make these different measurements. GenAI metric definitions
Record the first protocol chunk and the first answer-bearing chunk separately if the protocol can send metadata or tool arguments before answer text. Neither receipt proves that the UI has displayed anything. Likewise, an HTTP first-byte timer may stop at headers or a status event.
Streaming can make partial output visible before generation finishes. It does not, by itself, establish less total generation work or a faster completed answer; Hugging Face's TGI documentation illustrates earlier visibility with unchanged completion time. Measure both milestones in your application. TGI streaming
Map the work that must finish before the answer
Create a trace for the application operation, with child spans for retrieval, each tool execution and each model call. OpenTelemetry spans represent work with timestamps, parentage and attributes; events can mark individual instants, and propagated context joins work across services. These primitives support a request timeline, but missing instrumentation still leaves missing evidence. OpenTelemetry traces
Use the conceptual timeline below to decide which boundaries you can observe. Prefill means processing the model input before producing the initial output; subsequent generation is commonly called decode. A provider's internal queue and computation need provider-side measurements. An application timer around its SDK cannot separate them from connection setup, transit or other handling.
The depicted route performs retrieval and tools before its final generation. A model-driven tool loop also has a model call that chooses the tool, followed by execution and another model call. Include every round; do not hide those calls inside a single “tools” label.
Measure the critical path: the sequence of dependencies that determines when the chosen milestone can happen. If two required lookups overlap, their elapsed contribution is their combined time coverage up to the join, not the sum of both durations. A parent span already includes its children. Adding the parent and children counts the same time twice.
For each large interval, ask whether the next step actually waits for it. Work continuing after the final result, such as an asynchronous export, should not be blamed for that result's latency unless it contends for resources in a way you can measure. Gaps in a trace are unresolved time; add instrumentation before calling them queueing or model computation.
For application queues, capture enqueue and work-start boundaries. For retrieval, split query preparation or embedding, search, reranking and context assembly when the aggregate span is large enough to investigate. For each tool, distinguish client wait from downstream execution if both sides are observable. These are proposed instrumentation boundaries, not fields every tracing integration supplies automatically.
Conceptual request timeline: observe both generation and display
Use the symptom to choose the next measurement
Compare requests from the same route and workload class before changing infrastructure. “High” in this table means worse than your relevant baseline or product objective, not a universal threshold. The table is a diagnostic procedure derived from the measurement boundaries above.
| Observed symptom | Inspect first | What it establishes—and what remains unknown | Next measurement or comparison |
|---|---|---|---|
| Long blank wait; final model call starts late | Application queue, retrieval stages, assembly and earlier model/tool rounds | The delay precedes final generation. It does not implicate that final model's decode speed. | Time the largest required stage and split its waiting from execution where possible. |
| Retrieval dominates pre-generation time | Query preparation, embedding, search, reranking and context assembly spans | A broad retrieval span identifies a region, not which component is slow. | Compare stage durations, input sizes and cache outcomes for the same query class; check answer evidence before reducing retrieval work. |
| Several tools run one after another | Start/end times and which inputs each tool needs | Serial execution consumes time, but timestamps alone do not prove the tools are independent. | Inspect data dependencies and shared limits; overlap only calls that can safely run together. |
| Model-call first-chunk time is high | SDK attempts, connection acquisition and matching server telemetry if available | The outbound call is slow before streaming starts. Client timing alone cannot split network, provider queue and prefill. | Correlate server queue/prefill measurements or request them from the provider; keep the interval unresolved if unavailable. |
| First answer arrives promptly; completion is slow | Output length, later chunk gaps, additional tool rounds and final processing | A long tail can reflect more output, stalled delivery, extra work or slower generation. | Compare similar output lengths and call sequences; inspect server decode timing alongside application chunk timing. |
| Backend receives output steadily; UI updates arrive in bursts | Application forwarding, intermediary buffering and client consumption/rendering | The display delay is downstream of observed receipt; it does not establish slow model execution. | Add forwarding and browser receipt/display markers; compare where the pauses first appear. |
| Tail latency rises under load while the median changes little | Application queue wait, pool acquisition, concurrency, attempts and provider waiting metrics | Correlation with load suggests contention, but does not identify the constrained resource. | Match slow traces to admission/start times and serving load; separate retries from single-attempt calls. |
| Gateway overhead is small; users still wait | User-visible timeline and the gateway metric's documented scope | A small gateway contribution says little about retrieval, provider work or display time. | Measure the request across all required stages instead of using an overhead benchmark as the application SLO. |
A concrete server-side example is vLLM's V1 metrics design, which documents queue, prefill and decode intervals as well as frontend timing. Its TTFT starts at frontend input processing, whereas some intervals come from engine events. Read the installed engine's definitions before combining them. The same design distinguishes a gap between output events from a per-request time-per-output-token calculation, because one event can contain multiple tokens. vLLM metrics design, pinned revision
Use that distinction with any backend: a chunk-gap measurement is not automatically a token-generation measurement. Without server telemetry, report what the application observed rather than deriving a GPU explanation from a streaming gap.
Work through one hypothetical slow response
Hypothetical trace; all timings are assumed. No application, benchmark or load test was run. Imagine a support assistant that retrieves a policy and then runs two read-only lookups: order status and delivery estimate. Application logic already knows both lookup inputs after retrieval; no model call chooses these tools in this example. It waits for both results before sending one final generation request.
Assume one successful attempt, no cache hits, no output validation delay, and a first protocol chunk that already contains answer text. The unified time axis below is an explanatory assumption; real measurements across machines require clock care and correlation.
| Event or interval | Seconds after submission | Elapsed time |
|---|---|---|
| Submit → application ingress | 0.00–0.08 | 0.08 s |
| Application queue | 0.08–0.28 | 0.20 s |
| Retrieve policy | 0.28–0.88 | 0.60 s |
| Tool A: order status | 0.88–1.58 | 0.70 s |
| Tool B: delivery estimate | 1.58–2.68 | 1.10 s |
| Assemble final model input | 2.68–2.78 | 0.10 s |
| Issue generation → application receives first answer chunk | 2.78–3.58 | 0.80 s |
| First chunk received → first answer displayed | 3.58–3.70 | 0.12 s |
| First → final chunk received by application | 3.58–5.98 | 2.40 s |
| Final chunk received → usable completion displayed | 5.98–6.10 | 0.12 s |
Three conclusions follow from these assumptions:
- First visible answer takes 3.70 s; completion takes 6.10 s. The model client's first-chunk time is only 0.80 s. Calling all three values “TTFT” would hide most of the user's wait.
- The model request starts after 2.78 s. Its 0.80 s first-chunk interval cannot explain that earlier delay. The application has 1.80 s of serial tool work worth investigating. The 0.80 s provider-call interval remains unsplit; this trace contains no provider queue or prefill measurements.
- The model-call duration is 3.20 s, from 2.78 to 5.98. The 0.12 s first-display interval overlaps the 2.40 s remaining stream interval, so adding every table row would overcount. A non-overlapping completion calculation is 2.78 + 0.80 + 2.40 + 0.12 = 6.10 s.
Now suppose inspection confirms the tools are independent, both inputs are ready at 0.88 s, and running together changes neither result nor duration. Their joined duration would be max(0.70, 1.10) = 1.10 s instead of 1.80 s. If every later duration also stayed unchanged, the first visible answer would move to 3.00 s and completion to 5.40 s: a conditional 0.70 s saving.
That is arithmetic under stated assumptions, not a promised improvement. Shared rate limits or resource contention can invalidate it. If delivery estimate actually needs the order-status result, the dependency prevents this overlap.
For comparison, halving the assumed retrieval interval saves only 0.30 s under the same unchanged-downstream assumptions. This comparison helps choose a focused experiment; it does not justify removing evidence the answer needs. Enabling streaming is not the next fix here because the assumed request already streams.
Instrument so the numbers answer the same question
Use this checklist to validate an existing trace before adding a dashboard or optimization.
- Define two user milestones. Record submission, first answer display and usable completion in the client. Document how the display timestamp is captured; a DOM update callback is a proxy unless actual rendering is measured. Track status-only updates separately.
- Correlate boundaries. Preserve a request/trace relationship across the application, retrieval service and tools; retain provider request IDs when available. If the provider does not participate in your trace, mark that visibility limit.
- Time local intervals locally. Use a monotonic clock for elapsed durations. Do not subtract unrelated process or browser clock origins. Treat cross-host absolute timestamps as subject to clock skew; use locally measured spans and explicit correlation when reconciling the timeline. vLLM interval calculations
- Cover waiting and every round. Record ingress, enqueue/start, connection acquisition where observable, retrieval stages, each model/tool attempt, retry backoff and final processing. Identify missing intervals rather than assigning them a guessed cause.
- Keep the stream inside the timer. Record first protocol chunk, first answer-bearing chunk, subsequent receipt events or a suitable gap distribution, end of consumption and terminal status. Check whether SDK instrumentation ends when the iterator is returned or when it is exhausted. For non-streaming calls, first-chunk telemetry is inapplicable; measure completion rather than inventing a zero. GenAI metric definitions
- Keep delivery observable. Record when the application forwards content and when the browser receives and displays it. Start with coarse boundary events; collecting every chunk can add overhead and volume. Verify the instrumentation under the workload it is meant to diagnose.
- Record comparison context. Include route, model identity/version where available, prompt/configuration revision, streaming mode, input/output token counts and their accounting source, tool-round count, cache outcome, concurrency and outcome. Keep request IDs on traces rather than making each one a metric label.
- Keep failures visible. Distinguish success, timeout, cancellation, retry and partial-stream failure. A response that emitted one chunk and then failed is not a completed answer. Track the count of requests that never reached each milestone, alongside durations for those that did.
- Use comparable distributions. Report count, time window and p50/p95 for first-visible and completion separately; add higher percentiles when the sample supports them. Separate streaming modes, workloads and outcomes before interpreting a change. Do not use only deliberately selected slow traces to estimate fleet latency.
- Aggregate before computing quantiles. Merge compatible histogram observations/buckets across instances and then estimate the percentile. Averaging instance p95s is not the overall p95; histogram resolution also limits precision. Prometheus histograms and summaries
Likewise, a request's completion p95 cannot be reconstructed by summing the p95 of each stage: the slowest observations may belong to different requests, and stages may overlap. Measure completion directly, then inspect representative traces from that distribution to explain it. This is a consequence of the boundaries and dependencies, not an additional telemetry metric.
Choose one change and state what would validate it
Turn the diagnosis into a small decision record: target milestone → observed delaying stage → proposed change → expected signal → correctness check. Keep an explicit “unknown” when the trace cannot yet attribute a delay.
| Evidence available | Candidate action | What would validate the choice |
|---|---|---|
| Application queue wait dominates under a particular load | Investigate admission, worker capacity or a shared resource limit | Queue wait and the chosen user milestone improve for comparable load, without merely increasing rejection or timeout counts. |
| A retrieval substage consumes the required path | Target that substage, such as avoiding repeated eligible work or adjusting an excessive candidate budget | Its interval shrinks and the answer still receives the required evidence; separately record cache freshness and hit/miss conditions if caching changes. |
| Required tools are independent but serialized | Overlap those calls within downstream limits | Their combined elapsed interval shrinks, results remain correct and rate-limit/retry behavior does not erase the saving. |
| Server evidence identifies long prefill for the relevant inputs | Evaluate a justified input-size change or ask the serving owner about that stage | Matched server and application first-response measurements improve while preserving task quality. |
| Long output explains a slow completion tail | Try a more concise response requirement if it fits the task | Usable completion improves with acceptable completeness; do not count truncated answers as successes. |
| Content is ready upstream but delayed before display | Inspect buffering and forwarding at the first delayed boundary | Answer-bearing chunks reach the UI earlier and required final validation still occurs. |
Treat these as investigations to run, not results reported by this guide. Hold the task, model configuration, cache conditions, output requirements and load comparable where possible; retain differences you cannot control. Repeat enough cases to distinguish a useful change from generation and traffic variability. Compare the user milestone, completion/error counts and answer usefulness, not just the one span you optimized.
Documentation context, checked 26 September 2026: the OpenTelemetry GenAI definitions cited here are pinned to document revision 8ffdf568e1b4 (22 September 2026) and marked Development. The illustrative vLLM V1 design is pinned to b78fbab4be55 (17 September 2026); it includes historical and proposed material, so this guide uses only its stated measurement boundaries and interval distinctions, not a promise that every release exports every metric. TGI's streaming page, OpenTelemetry's trace concepts and Prometheus guidance were fetched on the same date. Record your installed instrumentation and server versions before adopting metric names or comparing results. No SDK execution, measured latency result or deployment recommendation is claimed.
Sources & further reading
Documentation informs the product behavior described here. The worked scenarios and conceptual diagrams explain how those behaviors fit together.
- Generative AI metrics — Development conventions, revision 8ffdf568e1b4 ↗OpenTelemetry · Accessed 2026-09-26
- Traces: spans, events and context propagation ↗OpenTelemetry · Accessed 2026-09-26
- vLLM V1 metrics design, revision b78fbab4be55 ↗vLLM · Accessed 2026-09-26
- Text Generation Inference: Streaming ↗Hugging Face · Accessed 2026-09-26
- Histograms and summaries ↗Prometheus · Accessed 2026-09-26