i'm doing my own dashboard with gantt chart showin...
# ask-ai
b
i'm doing my own dashboard with gantt chart showing which part of the pipeline is the bottleneck. my llm said this, what do you think?
Copy code
That is a fantastic question. The formula in the LiveKit docs is an idealized, theoretical minimum.

The docs say total_latency = eou.end_of_utterance_delay + llm.ttft + tts.ttfb.

This formula mathematically assumes a perfectly instantaneous, zero-latency pipeline where:

The LLM provider (like OpenAI) receives your prompt on the exact same millisecond that the LiveKit VAD finishes end_of_utterance_delay.
The TTS provider (like ElevenLabs) receives your text on the exact same millisecond that the LLM emits its very first token (ttft).
In a perfect world with zero network overhead, zero queueing, and perfect streaming (sending word-by-word instead of waiting for a full sentence), that formula is 100% correct.

But the raw UNIX timestamps prove reality is messier:
If that formula were perfectly true in reality, the tts_node starting time would equal the LLM First Token time.

But as your own data proved in Turn #3:

LLM First Token arrived at .286s
TTS didn't start until .548s
That is over 250ms of "hidden" latency that the LiveKit docs equation completely ignores! It ignores it because it assumes your server teleported the LLM token instantly to the TTS server. In reality, your server had to parse the token, realize it was the end of a sentence, construct an HTTP payload, and wait for the TLS handshake with the TTS provider.

Conclusion: The LiveKit docs formula is what they want the latency to be. It is useful for marketing and rough budgeting.

But your Gantt chart is using absolute UNIX clocks. It is showing you what the latency actually is on the wire. If you want to optimize your user experience, the Gantt chart (and the 6.42s total time) is the truth you should optimize against, because that's exactly how long the caller was sitting in silence waiting for audio!
t
Thanks for reaching out, Jura. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — your LLM’s write-up is accurate and useful. I’ll summarize the key points it made, confirm what’s correct for LiveKit pipelines, and give a couple practical next steps you can add to your Gantt/dashboard to make it actionable. What your LLM got right • The LiveKit formula ◦ total_latency = eou.end_of_utterance_delay + llm.ttft + tts.ttfb ◦ This is a best-case, lower-bound sum of the core service latencies (end-of-utterance delay, LLM Time‑to‑First‑Token, TTS Time‑to‑First‑Byte). • Why reality differs ◦ That formula assumes perfect, instantaneous chaining between components. It does not include the extra time spent parsing tokens, deciding sentence boundaries, building/serializing requests, TLS/HTTP handshakes, or internal queuing. ◦ Your observed gap (LLM first token at 0.286s, TTS start at 0.548s → ≈262ms) is the kind of “hidden” latency that the formula ignores and that actually affects the caller’s experience. • What to optimize for ◦ For perceived/user-facing latency, use wall-clock end-to-end time (what your Gantt chart shows). The Gantt is the truth for how long the caller waited. Why the gap happens (concrete contributors) • Network hops and transport (agent ↔️ LLM ↔️ agent ↔️ TTS) • Agent-side processing: streaming token parsing, sentence boundary detection, guardrail/tool checks • Serialization and API overhead: building the TTS request, TLS handshake and HTTP latency • Queueing or scheduling inside your agent or third-party providers Practical improvements to add to your dashboard • Add explicit intermediate metrics/timings so you can attribute the hidden gap: ◦ agent_processing_delay: time from eou_metrics_collected → start of LLM request ◦ llm_stream_to_agent_delay: time from LLM first token received → agent finished parsing/deciding ◦ tts_initiation_delay: time from agent decision → HTTP request sent to TTS ◦ tts_network_handshake: TCP/TLS/first-byte time for TTS call (if available) • Correlate metrics with service logs/timestamps and ensure clocks are synced (NTP or server-provided timestamps) so your UNIX times are reliable. • Instrument the agent to emit these additional events so your Gantt can show each sub-stage as separate bars — that makes bottlenecks obvious. Short-term optimizations to try • Pipeline earlier: stream tokens and detect sentence boundaries earlier so TTS can begin sooner (if acceptable for quality). • Prewarm or keep-alive connections to TTS to reduce TLS/HTTP overhead. • Reduce agent-side serialization/processing overhead (simplify parsing path, asynchronous handoffs). • Consider colocating services or using lower-latency routes for providers if network latency is significant. Bottom line • The LiveKit formula is a useful theoretical lower bound. Your empirical Gantt-based measurements are the operational truth you should optimize against. • Your LLM’s reasoning is sound: use the formula for targets/design, use measured wall-clock timelines to prioritize and fix real bottlenecks. If you want, I can: • Suggest exact events/metric names to emit from your agent so your Gantt shows those sub-stages. • Review a sample trace or timestamps (e.g., Turn #3 lines) and point out which optimization would likely yield the biggest reduction. Which would you prefer? Sources: examples/frontdesk | livekit/livekit_composite | DeepWiki | LLM Metrics | LiveKit Documentation | Agents (Node.js) | livekit/livekit_composite | DeepWiki | examples/voice_agents | livekit/livekit_composite | DeepWiki | examples/bank-ivr | livekit/livekit_composite | DeepWiki
b
Does
EOUMetric.end_of_utterance_delay
included
EOUMetric.on_user_turn_completed_delay
?
t
Good question — thanks for checking the exact semantics. No —
EOUMetrics.end_of_utterance_delay
does not include
on_user_turn_completed
time (and there is no documented metric named
on_user_turn_completed_delay
). Quick breakdown: •
EOUMetrics.end_of_utterance_delay
measures the time from when the user stops speaking to when end‑of‑utterance (EOU) detection fires. It covers VAD silence timing and any turn‑detection model adjustments. •
on_user_turn_completed
is a pipeline lifecycle hook that runs after EOU detection. Any processing you do inside that hook (parsing tokens, creating requests, queuing work, etc.) happens after
end_of_utterance_delay
has already been recorded. • Because there is no
on_user_turn_completed_delay
metric built into LiveKit, that post‑EOU work is not included in
end_of_utterance_delay
. You’ll need to instrument and emit additional metrics/events if you want that interval captured in your Gantt/dashboard. If you want, I can suggest specific metric/event names and where to emit them so your dashboard shows: • time from EOU detection →
on_user_turn_completed
start •
on_user_turn_completed
processing duration • time from LLM first token → TTS initiation Which of those would you like to add first? Sources: STT Metrics | LiveKit Documentation | examples/voice_agents | livekit/livekit_composite | DeepWiki | Pipeline nodes and hooks | LiveKit Documentation
b
There is
EOUMetric.on_user_turn_completed_delay
. It sits in your doc https://docs.livekit.io/deploy/observability/data/#end-of-utterance-eou-
t
Thanks — good catch and thank you for the doc link. You’re right:
EOUMetric.on_user_turn_completed_delay
is listed in the LiveKit observability docs. To be clear: • They are separate metrics.
EOUMetric.end_of_utterance_delay
measures the time from when the user stops speaking until the EOU detection fires (VAD/turn detection).
EOUMetric.on_user_turn_completed_delay
measures the time associated with the
on_user_turn_completed
lifecycle step — i.e., the processing that happens after EOU detection completes. •
end_of_utterance_delay
does not include
on_user_turn_completed_delay
.
end_of_utterance_delay
ends when EOU is detected.
on_user_turn_completed_delay
captures the subsequent work (your agent’s post‑EOU processing). If you want full end‑to‑end attribution, you need to sum or correlate these metrics in your dashboard. What I recommend for your Gantt/dashboard • Show both metrics as separate segments so you can see: ◦ EOU detection latency (
end_of_utterance_delay
) ◦ Post‑EOU processing latency (
on_user_turn_completed_delay
) • Add explicit markers for when LLM first token arrives and when TTS is initiated so you can observe the gaps between these stages. • Correlate using synchronized timestamps (NTP or server timestamps) so the sums are accurate. If you’d like, share a sample trace (Turn #3 timestamps) and I’ll point out exactly which spans correspond to these metrics and which optimizations would reduce the biggest gaps. Which trace would you like me to look at? Sources: STT Metrics | LiveKit Documentation | Pipeline nodes and hooks | LiveKit Documentation
b
does
EOUMetric.on_user_turn_completed_delay
runs sync right before LLM node? Or it run async, parrallel with LLM node?
t
Thanks — helpful question. I’m responding to your asking whether
EOUMetric.on_user_turn_completed_delay
runs synchronously immediately before the LLM node or if it runs asynchronously/parallel with the LLM node. Short answer •
EOUMetric.on_user_turn_completed_delay
runs synchronously and represents pre-LLM processing. • It runs before the LLM node begins; it does not run in parallel with LLM inference. Why • End‑of‑utterance detection triggers the end of the user turn, then the
on_user_turn_completed
lifecycle hook is invoked. Any work done in that hook (context augmentation, RAG lookups, modifications to ChatContext, etc.) is executed before the agent proceeds to the LLM node. • Because those changes must be applied to the conversation state prior to calling the LLM, the pipeline waits for
on_user_turn_completed
to finish. That makes
on_user_turn_completed_delay
part of the pre‑inference latency (it blocks the pipeline until complete). What that means for your dashboard • Treat
on_user_turn_completed_delay
as a sequential span that precedes LLM TTFT. Sum it with other preprocessing delays when attributing end‑to‑end latency. • If you want to verify behavior in traces, instrument and display: ◦ EOU detection →
end_of_utterance_delay
◦
on_user_turn_completed
start →
on_user_turn_completed_delay
◦ LLM request start →
llm.ttft
(first token) ◦ TTS initiation →
tts.ttfb
This will make the scheduling and bottlenecks explicit. If you’d like, paste a short trace (timestamps for EOU detection, on_user_turn_completed start/end, LLM request start, first token) and I’ll map the spans and point out which stage to optimize first. Sources: How does end-of-utterance detection work in conversations? | Pipeline nodes and hooks | LiveKit Documentation | External data and RAG | LiveKit Documentation | LLM Metrics | LiveKit Documentation
b
So the formula
Copy code
total_latency = eou.end_of_utterance_delay + llm.ttft + tts.ttfb
is invalid. it should've been
Copy code
total_latency = eou.end_of_utterance_delay + eou.on_user_turn_completed_delay + llm.ttft + tts.ttfb
t
You’re correct — the original formula is incomplete for real-world end-to-end latency as you measure it, and your expanded formula is the right way to represent what callers actually experience. Concise confirmation • The LiveKit formula
Copy code
total_latency = eou.end_of_utterance_delay + llm.ttft + tts.ttfb
is a lower‑bound / best‑case estimate that captures core service latencies. • For observed, wall‑clock end‑to‑end latency you should include the post‑EOU processing:
Copy code
total_latency = eou.end_of_utterance_delay + eou.on_user_turn_completed_delay + llm.ttft + tts.ttfb
on_user_turn_completed_delay
is synchronous pre‑LLM work and therefore adds to the user‑facing wait time. Why this matters •
end_of_utterance_delay
finishes when EOU detection fires.
on_user_turn_completed_delay
covers the subsequent processing (context augmentation, RAG lookups, preparing the LLM prompt) that must complete before the LLM is invoked. • Those processing steps block the pipeline, so excluding them underestimates the true silence/latency the caller experiences. Practical tips for your dashboard • Display
end_of_utterance_delay
and
on_user_turn_completed_delay
as separate Gantt segments (so you can see if preprocessing or EOU detection is the bottleneck). • Correlate LLM and TTS events with those segments (LLM request start, LLM first token, TTS request start, TTS first byte). • Ensure clock sync across services so sums match observed wall‑clock times. • If you want finer attribution, add metrics for agent_processing_delay, tts_initiation_delay, and network/handshake times. If you’d like, paste one trace (timestamps for EOU detect, on_user_turn_completed start/end, LLM request start, first token, TTS start) and I’ll map the spans and show exactly where time is being spent and which optimizations will matter most.