← All practical guides
AI application performance13 min readUpdated Sep 26, 2026

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.

01

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.

MeasurementStart → endDecision it supports
Time to first visible answerUser submits → first answer content is displayedIs the application making the user wait before receiving useful content? Count a spinner or “searching” status separately.
Time to usable completionUser submits → final result is displayed and any required validation has finishedWhen can the user act on the result? For structured output, this may be later than the last generated token.
Model-call first-chunk timeApplication issues a streaming generation request → its model client receives the first chunkHow much delay occurs inside that outbound call before anything is streamed back?
Model-call durationStart of the outbound call → its defined completion or errorHow 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

02

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

Loading diagram…
Conceptual ordering, not measured durations or a universal architecture. A request crosses application waiting, retrieval, tools and final generation before answer display. The first protocol chunk may precede answer content. Model-service internals require server telemetry; later generation overlaps delivery and display. Earlier model calls that select tools must also be traced in applications that use them.
03

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 symptomInspect firstWhat it establishes—and what remains unknownNext measurement or comparison
Long blank wait; final model call starts lateApplication queue, retrieval stages, assembly and earlier model/tool roundsThe 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 timeQuery preparation, embedding, search, reranking and context assembly spansA 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 anotherStart/end times and which inputs each tool needsSerial 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 highSDK attempts, connection acquisition and matching server telemetry if availableThe 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 slowOutput length, later chunk gaps, additional tool rounds and final processingA 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 burstsApplication forwarding, intermediary buffering and client consumption/renderingThe 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 littleApplication queue wait, pool acquisition, concurrency, attempts and provider waiting metricsCorrelation 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 waitUser-visible timeline and the gateway metric's documented scopeA 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.

04

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 intervalSeconds after submissionElapsed time
Submit → application ingress0.00–0.080.08 s
Application queue0.08–0.280.20 s
Retrieve policy0.28–0.880.60 s
Tool A: order status0.88–1.580.70 s
Tool B: delivery estimate1.58–2.681.10 s
Assemble final model input2.68–2.780.10 s
Issue generation → application receives first answer chunk2.78–3.580.80 s
First chunk received → first answer displayed3.58–3.700.12 s
First → final chunk received by application3.58–5.982.40 s
Final chunk received → usable completion displayed5.98–6.100.12 s

Three conclusions follow from these assumptions:

  1. 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.
  2. 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.
  3. 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.

05

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.

06

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 availableCandidate actionWhat would validate the choice
Application queue wait dominates under a particular loadInvestigate admission, worker capacity or a shared resource limitQueue wait and the chosen user milestone improve for comparable load, without merely increasing rejection or timeout counts.
A retrieval substage consumes the required pathTarget that substage, such as avoiding repeated eligible work or adjusting an excessive candidate budgetIts 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 serializedOverlap those calls within downstream limitsTheir 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 inputsEvaluate a justified input-size change or ask the serving owner about that stageMatched server and application first-response measurements improve while preserving task quality.
Long output explains a slow completion tailTry a more concise response requirement if it fits the taskUsable completion improves with acceptable completeness; do not count truncated answers as successes.
Content is ready upstream but delayed before displayInspect buffering and forwarding at the first delayed boundaryAnswer-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.

  1. Generative AI metrics — Development conventions, revision 8ffdf568e1b4 ↗OpenTelemetry · Accessed 2026-09-26
  2. Traces: spans, events and context propagation ↗OpenTelemetry · Accessed 2026-09-26
  3. vLLM V1 metrics design, revision b78fbab4be55 ↗vLLM · Accessed 2026-09-26
  4. Text Generation Inference: Streaming ↗Hugging Face · Accessed 2026-09-26
  5. Histograms and summaries ↗Prometheus · Accessed 2026-09-26

Explore the individual tools

Suggest a correction · More practical guides

Why AI responses are slow: tracing retrieval, tools and model generation — Runeval