Voice Agent Series · Part 1

Building a voice agent: Fixing the latency problem

In this multi-part post I will walk through how we build a voice agent, the key considerations, and why voice-agent architecture differs from typical AI architecture.

Ullas Sankhla Written by Ullas Sankhla LendEasy Engineering · July 2026
Caller STT speech → text streaming LLM calls decider + 3–4 agents + tool calls biggest bottleneck TTS text → speech chunked audio Response total budget: ~700–800 ms
Every caller utterance travels the full STT → LLM → TTS loop — and the whole round trip has under a second to finish.

The Problem

We define a voice agent as an LLM-driven workflow that sets out to accomplish a particular task for the caller or an organization. Let's take the case of a voice agent making a first-party collections call. Before it can discuss anything about the account, it needs to verify the caller's identity — asking for the ZIP code on file, and falling back to another identifier like date of birth if the caller doesn't have it — deliver the required disclosures, state the past-due balance, answer questions like the payoff amount, and then actually collect a payment or send a secure payment link.

This is a multi-part question and answer session with multiple failure points.

Hi, this is Jordan calling from Lenders Club on arecorded line. Am I speaking with Kaya? Yes, this is Kaya. Great — I'd like to talk about your home loan with LendersClub. Before we proceed, can you confirm your ZIP code? Sure — it's 92614. Perfect — thanks, Kaya. The loan is 11 days past due —that's $1,740.62. Did you want to take care of that today? Actually, what would it take to pay the whole loan off? The payoff as of today is $186,930.44 — or we can do justthe $1,740.62 that's past due, whichever works better. Let's do the past-due amount. Can you text me the link?
A single collections call spans right-party contact, identity verification, out-of-order questions, and negotiation — each turn is a potential failure point.

Challenges

There are several challenges here that are unique to an application that is handling a live collections call. Here are the most critical ones:

  1. Have a low latency response to any utterance. Typical voice applications need to respond within 1 second — ideally within 700–800 ms of the caller finishing speaking.
  2. Callers can ask questions out of order — just as they would with a human. Therefore we can try to fix the logic and workflow — but we cannot be too rigid.
  3. Handling barge-in — callers talk over the agent mid-sentence, just as they would with a human. The agent has to stop speaking, listen, and recover without losing its place in the conversation.
  4. Negotiating with the caller on how and when they can pay or giving them various options requires the agent to be robust, context aware.
  5. Making progress — perhaps the most difficult of them all: the agent must keep making progress towards its goal.
  6. No human in the loop — There is no human in the loop who can interrupt and stop the agent from making a wrong decision.

Each of these challenges on its own can derail the conversation and reduce the effectiveness of the call or make the human in the call frustrated enough to end the call.

Low Stakes vs High Stakes Situation

Contrast this with a servicing copilot that supports a loan officer working a case on the servicing plane — drafting messages, summarizing the account, suggesting the next action. That is a low-stakes scenario: the loan officer reviews every suggestion and can step in before anything reaches the borrower. On a live call, the voice agent is in a high-stakes scenario — if the voice agent cannot serve the client properly, the business may end up losing that customer. It can end up as a bad customer review on Google. Worst case, it could lead to a compliance violation for a business in the financial domain.

Low stakes

Servicing copilot

A loan officer reviews every suggestion. Mistakes are caught before they reach the borrower.

High stakes

Voice agent

Live customer, no reviewer: lost customers, bad reviews, compliance risk.

Sources of Latency

We will first and foremost focus on latency as that is table stakes to get the user interaction acceptable. There are three primary sources of latency here: the speech-to-text system (STT), LLM calls, and text-to-speech (TTS).

time → STT Decider LLM calls 3–4 calls per turn TTS majority of the time: LLM calls
The three latency sources stack up sequentially — and the LLM stage, with 3–4 calls per turn, dominates the budget.

The STT system detects the speech and converts it to text. This takes time, adding to the delay before we can even invoke the business logic. This system has to be robust enough to handle intermittent pauses.

A voice agent call can take up to 3-4 different LLM calls. In our setup we use a decider agent that is responsible for invoking one or more LLMs based on conversation history, available agents and a set of hard rules. This is followed by the various LLM calls to formulate a response and other intermediate calls to decide the next activity. While this may also include external tool calling — the majority of the time is spent in LLM calls.

The last step is the TTS system. The TTS system uses the LLM text and sends it to speech conversion and adds to that time taken.

Fixing the Latency problem

We trigger the STT system in streaming mode to reduce the latency of the utterance to text conversion. In this mode the STT streams back the tokens as the caller speaks. Each utterance also comes back with an end-of-turn confidence score, and we can specify an end-of-turn threshold. When the streaming packets come in we work with the embedded end-of-turn signal and use that as further evidence to decide when to end the turn — with a custom waiting period.

Caller audio Streamed text what is the payoff amount End-of-turn confidence threshold end of turn ✓ + custom waiting period tokens stream in while the caller is still speaking — the turn ends the moment confidence crosses the threshold
Streaming transcription with an embedded end-of-turn confidence score lets us end the turn dynamically instead of waiting on a fixed silence timer.

This makes sure that we can make a dynamic decision on when to end the turn as pauses are detected — this saves valuable time and also gives us more configurability.

Next is the LLM — the most critical latency bottleneck. We decided to use Cerebras to get the maximum throughput for our latency needs. Cerebras uses wafer scale chips and claims throughput to be in 1000s of tokens per second — much higher than 10s of tokens per second from typical LLM providers. This enables us to get a quick response for our needs. We achieve very low latencies by combining this with careful prompt design: a large static system prompt (which Cerebras caches automatically) and everything else in the user prompt. We use an instruct model with Cerebras, and we leave enough headroom for the prompt, any server-side thinking (which consumes additional tokens), and the specific JSON output we expect from the LLM. On any error, we fall back to a predefined, hardcoded plan to make sure that the user still receives a response and is not left hanging.

Typical provider 10s of tokens/sec Wafer-scale chips 1000s of tokens/sec cached static system prompt JSON output hardcoded fallback plan
Wafer-scale inference streams tokens orders of magnitude faster — combined with prompt caching, structured JSON output, and a fallback plan so the caller is never left hanging.

The last part is TTS — this is interesting because it leaves no room for streaming the response from the TTS provider. We developed a custom solution to stream the voice output chunk by chunk over our websocket connection. We had to fine tune here to make sure artifacts do not appear if the PCM audio chunks are too small — after a bit of fine-tuning we got latencies low and removed the chunking artifacts that made the audio sound undersampled.

Chunks too small artifacts, sounds undersampled Tuned chunk size low latency, no artifacts PCM audio streamed chunk by chunk over the websocket connection
Our custom TTS streaming pushes PCM audio chunk-by-chunk over the websocket — chunk size had to be tuned to kill audible artifacts.

Finally, we account for unforeseen delays when we are fetching data from external services — these can create an awkward silence for the caller. We introduced filler utterances the voice agent can use to keep the caller engaged and the connection alive.

time → caller asks external service fetch… (unforeseen delay) “Give me a second while I look that up…” filler utterance keeps the line alive agent answers
When an external fetch runs long, a filler utterance bridges the gap so the caller never sits in awkward silence.

Along the way we have learnt that building a voice agent requires many non-trivial engineering decisions beyond just calling an LLM. Follow our blog as we share the journey of building robust, multi-step voice agentic workflows that truly delight our clients and their customers by solving problems at scale!