late-businessperson-58140
12/18/2025, 1:59 PMtall-airline-16756
12/18/2025, 1:59 PMtall-airline-16756
12/18/2025, 1:59 PMreduce_latency=true.
Speech pipeline optimizations
• Enable preemptive generation: start TTS synthesis as soon as the LLM begins producing text rather than waiting for the full response.
• Tune end-of-utterance detection (min_endpointing_delay, max_endpointing_delay) to reduce wait time without cutting users off.
Infrastructure & resources
• Avoid CPU-throttled instance types (AWS t3/t4). Use non-burstable instances (m5/c5) or ensure CPU credits are sufficient.
• Ensure sufficient network bandwidth and low packet loss between components.
Application-level improvements
• Cache or parallelize slow downstream API calls used during response generation.
• Shorten prompts and limit output length for faster TTFT (Time To First Token).
Measure to find the bottleneck
• Monitor TTFT (goal <500ms), TTFB (<300ms), and end‑to‑end latency (aim <1.5s).
• Collect LLMMetrics, TTSMetrics, and STTMetrics to see which stage is slowest.
If you want, tell me:
• Which providers/models you’re using for STT, LLM, and TTS,
• Where your agent is deployed (region / instance type),
and I’ll recommend the highest-impact changes specific to your setup.
Sources: Introducing LiveKit Inference: A unified model interface for voice AI | Introducing LiveKit Inference: A unified model interface for voice AI | examples/frontdesk | livekit/livekit_composite | DeepWiki | examples/voice_agents | livekit/livekit_composite | DeepWiki | Troubleshooting Latency and Timeout Errors with Turn Detection on AWSlate-businessperson-58140
12/18/2025, 2:02 PMtall-airline-16756
12/18/2025, 2:03 PMmin_endpointing_delay slightly (default 0.5s) and adjust max_endpointing_delay to avoid added wait while not chopping speech.
1. Provider & model choices
• For Gemini, prefer lower-latency variants (e.g., Gemini flash) or Realtime endpoints.
• If Sarvam’s streaming or low-latency TTS options aren’t available, test alternatives (Deepgram for STT, low-latency TTS models) to compare.
1. Infrastructure
• Avoid burstable CPU instances (AWS t3/t4); use m5/c5 or ensure CPU credits aren’t exhausted.
• Check network bandwidth and packet loss between components.
1. Measure bottlenecks
• Collect TTFT (LLM), TTFB (TTS), and STT latency via Agents Metrics API to see which stage adds most delay.
• Example targets: TTFT <500ms, TTFB <300ms, end-to-end <1.5s.
If you want, tell me:
• which Sarvam models and API mode (streaming vs non-streaming) you’re using,
• which Gemini endpoint/model (Realtime/flash),
• where your agent is deployed (cloud provider + region and instance type),
and I’ll give precise changes you can apply first.
Sources: Introducing LiveKit Inference: A unified model interface for voice AI | Google Gemini LLM | LiveKit Docs | Sarvam STT plugin guide | LiveKit Docs | Gemini Live API plugin | LiveKit docs | Observability data hooks | LiveKit docslate-businessperson-58140
12/18/2025, 2:04 PMtall-airline-16756
12/18/2025, 2:04 PMfrom livekit.plugins import sarvam
stt = sarvam.STT(language="hi-IN", model="saarika:v2.5")
tts = sarvam.TTS(target_language_code="hi-IN", speaker="anushka", model="bulbul:v2")
• Verify you are using Sarvam’s streaming endpoints (check your Sarvam client config) so partial transcripts and incremental audio are available.
2) Enable Gemini streaming
• Use Gemini via LiveKit Inference or Realtime endpoint so tokens stream as generated:
from livekit.agents import inference
llm = inference.LLM(model="google/gemini-2.5-flash") # streaming-enabled model
3) Turn on preemptive generation
• Start TTS while LLM is still producing tokens:
from livekit.agents import AgentSession
session = AgentSession(
stt=stt,
llm=llm,
tts=tts,
preemptive_generation=True
)
4) Tune endpointing / VAD
• Reduce wait after user stops speaking (adjust conservatively):
session.min_endpointing_delay = 0.3
session.max_endpointing_delay = 2.0
• Ensure a reliable VAD (preload if available) so shorter delays don’t cut users off.
5) Use LiveKit Inference when possible
• LiveKit Inference reduces network hops and can use provisioned capacity:
session.llm = "google/gemini-2.5-flash" # routes via Inference
session.stt = "auto:hi-IN"
session.tts = "sarvam/bulbul:v2"
session.preemptive_generation = True
• If you stay with direct Sarvam, confirm Sarvam supports low-latency streaming for both STT and TTS.
6) Infrastructure checks
• Deploy your agent in the same cloud region as Sarvam and Gemini.
• Avoid burstable CPU instances (AWS t3/t4); use m5/c5 or ensure CPU credits are fine.
7) Instrument metrics to find bottlenecks
• Capture TTFT (LLM), TTFB (TTS), and STT latency via the Agents Metrics API to see which stage is slowest. Aim for TTFT <500ms and TTFB <300ms.
If you want, tell me:
• exact Sarvam models and whether you’re using Sarvam streaming endpoints,
• which Gemini endpoint/model (Realtime or other),
• where the agent is deployed (cloud + region and instance type),
and I’ll give the precise code/config changes and the next quick tests to run.
Sources: Sarvam STT plugin guide | LiveKit Docs | Sarvam TTS plugin guide | LiveKit Docs | Agent speech and audio | LiveKit docs | Simple Call Answering Agent | LiveKit docs | examples/bank-ivr | livekit/livekit_composite | DeepWikilate-businessperson-58140
12/19/2025, 6:47 AMtall-airline-16756
12/19/2025, 6:48 AMimport config.settings as settings
import httpx
from livekit.plugins import google, sarvam
def get_http_client():
return httpx.AsyncClient(timeout=30.0)
def get_llm():
provider = "google"
model = "gemini-2.5-flash"
if provider == "google":
return google.LLM(
model=model,
api_key=settings.GOOGLE_API_KEY,
# streaming is used by default when LLM is used in AgentSession
)
raise ValueError(f"Unsupported AI provider: {provider}")
def get_stt():
return sarvam.STT(
api_key=settings.SARVAM_API_KEY,
language="hi-IN", # set real language to avoid detection delay
model="saarika:v2.5",
enable_preprocessing=False, # disable heavy preprocessing to save time
)
def get_tts(language: str = None, voice: str = None):
language = language or "hi-IN"
voice = voice or "anushka"
return sarvam.TTS(
api_key=settings.SARVAM_API_KEY,
model="bulbul:v2",
speaker=voice,
target_language_code=language,
enable_preprocessing=False, # reduce TTS overhead
# LiveKit Agents will stream generated audio when configured in AgentSession
)
2) AgentSession: enable preemptive generation, VAD, and endpoint tuning
from livekit.agents import AgentSession, inference
from livekit.plugins import silero
vad = silero.VAD.load()
session = AgentSession(
stt=get_stt(),
llm=get_llm(),
tts=get_tts(),
vad=vad,
preemptive_generation=True, # start LLM/TTS early from partial transcripts
min_endpointing_delay=0.3, # respond faster on clear silence
max_endpointing_delay=1.5, # avoid long wait times
turn_detection="vad",
)
3) Quick checklist to verify after deploying
• Confirm Sarvam STT/TTS endpoints are using streaming mode (client config or WebSocket).
• Confirm Gemini is reachable via the Realtime/flash endpoint and streams tokens.
• Host your agent in the same region as Sarvam/Gemini (reduce RTT).
• Avoid burstable CPU instances (use m5/c5) and monitor TTFT/TTFB via metrics.
If you want, share:
• exact Sarvam endpoint type you call (HTTP vs WebSocket),
• the Gemini endpoint you use (Realtime vs REST),
and I’ll give the exact config snippet or WebSocket client code to enable streaming.
Sources: How can I reduce latency in voice agents using STT, TTS and LLM? | examples/frontdesk | livekit/livekit_composite | DeepWiki | Gemini Live API plugin | LiveKit docs | Simple Call Answering Agent | LiveKit docslate-businessperson-58140
12/19/2025, 6:58 AMtall-airline-16756
12/19/2025, 6:58 AMgoogle.LLM(...) which uses the direct Google client.
• Inference approach: pass the model identifier string (e.g. "google/gemini-2.5-flash") to the session or to inference.LLM(...) so LiveKit uses its Inference layer.
Minimal examples
1) Use a model string (recommended — routes via LiveKit Inference)
# AgentSession will route LLM calls through LiveKit Inference
session = AgentSession(
stt=get_stt(),
llm="google/gemini-2.5-flash",
tts=get_tts(),
preemptive_generation=True,
...
)
2) Use the inference helper explicitly
from livekit.agents import inference
llm = inference.LLM(model="google/gemini-2.5-flash")
session = AgentSession(stt=get_stt(), llm=llm, tts=get_tts(), preemptive_generation=True)
Notes
• LiveKit Inference provides co-location, provisioned capacity, and optimized routing; using the model string or inference.LLM enables those benefits.
• You can still keep Sarvam for STT/TTS via the plugin; passing a Sarvam model string for `tts`/`stt` may also route through Inference if supported, otherwise continue using the sarvam plugin.
• Make sure your deployment and LiveKit config have credentials/API keys available so Inference can call Gemini.
If you want, I can convert your current get_llm() to return the inference.LLM(...) object or show the exact AgentSession file diff. Which do you prefer?late-businessperson-58140
12/19/2025, 7:00 AMtall-airline-16756
12/19/2025, 7:00 AMinference.LLM) for lower latency and reliability in production.
• Use direct provider clients (google.LLM(...)) for local testing, debugging, or if you need provider-specific features not exposed by Inference.
Why LiveKit Inference is better (recommended)
• Lower latency: co-location and optimized routing reduce network hops and queuing.
• Provisioned capacity: avoids public endpoint queuing during peak times.
• Simplicity at the session level: just pass "google/gemini-2.5-flash" or inference.LLM(...) and LiveKit handles routing.
• Observability: integrated metrics for TTFT/TTFB and request routing.
When to use direct provider clients
• You need a provider-specific feature or experimental flag not yet supported by Inference.
• You’re debugging provider-specific behavior locally and want direct control.
• Short-term prototype where you control auth and endpoint directly.
How to switch (two minimal options)
• Model string (recommended):
session = AgentSession(
stt=get_stt(),
llm="google/gemini-2.5-flash",
tts=get_tts(),
preemptive_generation=True,
)
• Explicit inference helper:
from livekit.agents import inference
llm = inference.LLM(model="google/gemini-2.5-flash")
session = AgentSession(stt=get_stt(), llm=llm, tts=get_tts(), preemptive_generation=True)
If you want, I can:
• Convert your get_llm() to return inference.LLM(...) (code diff), or
• Show the exact AgentSession file changes to switch to Inference.
Which would you prefer?late-businessperson-58140
12/19/2025, 7:05 AMtall-airline-16756
12/19/2025, 7:05 AMpreemptive_generation is not an argument of Agent.__init__() — it belongs on AgentSession. Move any preemptive_generation (and other session-level options like min_endpointing_delay, max_endpointing_delay, vad, turn_detection) into the AgentSession creation instead of the Agent constructor.
Example fix (minimal):
1) Agent init — do NOT pass preemptive_generation here:
class MyAgent(Agent):
def __init__(self, metadata, job_context):
super().__init__(
instructions=self.agent_prompt,
# other Agent args (role, memory, etc.)
)
2) Create AgentSession with preemptive_generation and start the session:
from livekit.agents import AgentSession
from livekit.plugins import silero
vad = silero.VAD.load()
session = AgentSession(
stt=get_stt(),
llm="google/gemini-2.5-flash", # or inference.LLM(...)
tts=get_tts(),
vad=vad,
preemptive_generation=True, # ← correct place
min_endpointing_delay=0.3,
max_endpointing_delay=1.5,
turn_detection="vad",
)
agent = MyAgent(metadata=metadata, job_context=ctx)
await session.start(agent=agent, room=ctx.room)
If you paste the current Agent init and the code where you build/start the session, I’ll point exactly where to move the options and give the exact diff.late-businessperson-58140
12/19/2025, 7:06 AMtall-airline-16756
12/19/2025, 7:06 AMclass MyAgent(Agent):
def __init__(self, metadata, job_context):
super().__init__(
instructions=self.agent_prompt,
# do NOT include stt/llm/tts/vad/preemptive_generation/etc. here
)
2) AgentSession (correct place for your options)
from livekit.agents import AgentSession
from livekit.plugins import silero
session = AgentSession(
stt=get_stt(),
llm=get_llm(), # or "google/gemini-2.5-flash" / inference.LLM(...)
tts=get_tts(),
vad=silero.VAD.load(),
preemptive_generation=True, # ← correct spot
min_endpointing_delay=0.3,
max_endpointing_delay=1.5,
turn_detection="vad",
)
agent = MyAgent(metadata=metadata, job_context=ctx)
await session.start(agent=agent, room=ctx.room)
If you paste your current Agent class and the code where you create/start the session, I’ll show the exact lines to remove and the precise diff.late-businessperson-58140
12/19/2025, 7:10 AMtall-airline-16756
12/19/2025, 7:10 AMfrom livekit.agents import inference
llm = inference.LLM(model="google/gemini-2.5-flash", api_key=settings.GOOGLE_API_KEY)
session = AgentSession(llm=llm, ...)
• If you pass the model string to AgentSession, make sure the runtime that runs AgentSession has GOOGLE_API_KEY available in its environment.
B — Use direct provider client (temporary test)
• Test direct authentication to confirm the key is valid:
from livekit.plugins import google
llm = google.LLM(model="gemini-2.5-flash", api_key=settings.GOOGLE_API_KEY)
# run a quick chat/test call to confirm success
• If this works but Inference fails, the problem is Inference credentials or IAM configuration.
3) Other checks
• No leading/trailing spaces/quotes in the key.
• Key has necessary permissions for the Gemini/Vertex AI endpoint you target.
• If using Vertex-specific flags, ensure they match (do not set vertexai=True unless using Vertex).
• No proxy/firewall blocking outbound calls from your host to Google/Inference service.
• If running in LiveKit Cloud / container, confirm the env var was injected into the container.
4) If you want me to patch your code
• Tell me whether you prefer:
◦ A: session.llm = "google/gemini-2.5-flash" (Inference via model string), or
◦ B: session.llm = inference.LLM(..., api_key=...)
and paste how you set env vars (local .env, Docker, or cloud). I’ll give the exact one-line change.
Would you like me to show the minimal test script to verify the Google key locally?late-businessperson-58140
12/19/2025, 8:07 AMtall-airline-16756
12/19/2025, 8:07 AMgoogle.LLM(..., api_key=...) works but LiveKit Inference fails with 401, the issue is Inference not receiving valid Google credentials. Quick checklist and exact fixes:
1) Ensure env var is available to the process that runs Inference
• Export the key where your agent process runs:
GOOGLE_API_KEY=your_gemini_api_key
• If using a .env, Docker, or cloud service, confirm the env var is injected into the running container/process.
2) Use inference.LLM or model string and pass api_key explicitly
• Option A — explicit inference object (safe for debugging):
from livekit.agents import inference
llm = inference.LLM(model="google/gemini-2.5-flash", api_key=settings.GOOGLE_API_KEY)
session = AgentSession(llm=llm, stt=get_stt(), tts=get_tts(), vad=vad, preemptive_generation=True)
• Option B — model string (requires env var visible to runtime):
session = AgentSession(llm="google/gemini-2.5-flash", ...)
3) Install & enable Inference extras and feature access
• Ensure your runtime has the inference extras installed (if required): livekit-agents[inference] or similar.
• Confirm Inference is enabled for your LiveKit deployment (console/config) so model routing is permitted.
4) Check permissions & key validity
• No extra spaces/quotes in the key.
• Key has permission to call Gemini/Vertex endpoints.
• If using project-scoped credentials, ensure the model name is accessible in that project/region.
5) Test minimal Inference call
• Use the explicit inference.LLM snippet above and run a simple chat/test to confirm. If explicit call fails but google.LLM works, capture the exact error and paste it.
If you want, tell me:
• how you inject env vars (local .env, Docker, or cloud), and
• whether you prefer I provide the minimal test script using inference.LLM
I’ll give the exact change/snippet for your deployment.