Building Low-Latency Voice AI Agents with Workflow Orchestration Trade-offs

gradient_labs · Finance · 2026 · source Agentic: yes · promotional bias: low · source-backed · extracted with prompt 0.5.5 (schema v2)

Generated from extraction.json — do not edit by hand. Every claim cites verbatim source evidence; stated means the quote directly asserts the claim, implied means it supports it indirectly.

Problem

Domain: Regulated financial-services voice support agents

Gradient Labs had a durable Temporal-based text support agent for regulated financial-services customers, but moving the same agent into live voice exposed a latency mismatch: customers would hang up after a few seconds, while child workflows under the same parent workflow could take seconds just to start.

Constraints:

Architecture

Gradient Labs reused its Temporal-based text support-agent stack for voice, with LiveKit-style telephony, Deepgram speech-to-text, a text LLM agent, and Cartesia/ElevenLabs text-to-speech. The long-running conversation workflow still coordinates multi-day text conversations and high-level voice lifecycle work. Each voice turn invokes a short-lived turn workflow that composes classification, answer generation, guardrails, translation, LLM calls, API calls, and tools. To avoid child workflows starting sequentially under the parent workflow lock, the team built a fast exec library: the main turn workflow starts detached wrapper workflows from side effects/goroutines, those wrappers signal results back through high-cardinality signal names, and a custom future interface preserves code ergonomics while reducing scheduled-to-start latency.

Diagram confidence: explicit (topology described by the source).

flowchart LR
  customer[Customer] --> channel-integrations[Channel integrations]
  channel-integrations --> conversation-workflow[Conversation workflow]
  channel-integrations --> speech-to-text-layer[Speech-to-text layer]
  conversation-workflow --> turn-workflow[Turn workflow]
  speech-to-text-layer --> turn-workflow
  turn-workflow --> fast-exec-library[Fast exec library]
  turn-workflow --> agent-skills[Agent skills]
  turn-workflow --> text-to-speech-layer[Text-to-speech layer]
  text-to-speech-layer --> customer
  agent-skills --> activities-and-services[Activities and services]
  agent-skills --> fast-inference-providers[Fast inference providers]
  temporal-server-and-sdk[Temporal server and SDK] --> turn-workflow
  temporal-server-and-sdk --> fast-exec-library
  temporal-server-and-sdk --> temporal-ui[Temporal UI]
  fast-exec-library --> wrapper-workflows[Wrapper workflows]
  fast-exec-library --> temporal-server-and-sdk
  temporal-ui --> debug-workflow-skill[Debug workflow skill]
  post-call-workflows[Post-call workflows] --> conversation-workflow
Drag to pan · scroll or use +/− to zoom · reconstructed from the source's described component topology

Components

Component Role Interacts with
Customer Financial-services customer interacting through text or phone support. Channel integrations
Channel integrations Intercom, Salesforce, Zendesk, proprietary API, telephony, and voice room integrations that send and receive customer messages. Conversation workflow, Speech-to-text layer
Conversation workflow Long-running Temporal workflow that holds the conversation lifecycle and receives customer messages as signals. Turn workflow, Channel integrations, Post-call workflows
Speech-to-text layer Voice input layer using Deepgram low-latency speech-to-text before passing text into the existing agent path. Turn workflow
Turn workflow Short-lived workflow invoked many times to generate the next agent action: reply, tool call, escalation, closure, or finish. Fast exec library, Agent skills, Text-to-speech layer
Agent skills Composable AI skills such as classification, answer generation, guardrails, translation, LLM completions, API calls, and tool calls. Activities and services, Fast inference providers
Activities and services Temporal activities and backing services used by the agent for LLM completions, APIs, tools, and support-system actions. Agent skills
Fast inference providers Low-latency model providers and small constrained models such as Grok and Cerebras used with cached/compressed prompts and redundant requests. Agent skills
Temporal server and SDK Workflow runtime that provides durability, history, transfer tasks, locks, UI, side effects, signals, and futures. Turn workflow, Fast exec library, Temporal UI
Fast exec library Custom library that starts detached wrapper workflows and exposes a future-like interface backed by high-cardinality signals. Wrapper workflows, Temporal server and SDK, Turn workflow
Wrapper workflows Detached workflows that execute former child-workflow work and signal results back to the main turn workflow. Fast exec library
Temporal UI Workflow debugging surface enhanced with side-effect summaries, signal summaries, and links to wrapper workflows. Temporal server and SDK, Debug workflow skill
Debug workflow skill Automated debugging skill that traverses child workflows and source code to diagnose what went wrong. Temporal UI
Text-to-speech layer Voice output layer using Cartesia or ElevenLabs expressive voices, started early where possible to overlap Temporal latency. Turn workflow, Customer
Post-call workflows Higher-level Temporal workflows for pre-call, outbound call batches, per-call lifecycle, SMS heads-up, and after-call actions. Conversation workflow

Data flow

A customer message or voice utterance enters the conversation workflow. For voice, speech-to-text converts audio, then the turn workflow receives conversation state and kicks off work for classification, possible answers, guardrails, and related skills. Fast inference providers, cached/compressed prompts, constrained small models, and redundant concurrent LLM requests reduce LLM latency. Instead of Temporal child workflows being started sequentially through the parent workflow lock, fast exec starts detached wrapper workflows and listens for result signals. The fastest relevant answer returns to the turn workflow, text-to-speech can be started early to overlap latency, and the agent responds before the caller hangs up.

6 supporting quotes
“we have one conversation workflow. And this is a long-running workflow that can last up to a couple of weeks depending on how complex the customer's issue is and how long the customer takes to reply to our agent. So, if the customer takes a couple of days”transcript, stated
“the turn workflow is is one and done. This is short-lived, and we'd invoke many turns throughout the lifetime of a conversation.”transcript, stated
“classification, obviously generating answers, a number of guardrails given our our regulated industries, translation, and so on. Each of these are registered as child workflows.”transcript, stated
“we knew we were going to have this quite traditional setup of speech to text going in, uh a text-based LLM-based agent in the middle, and then text to speech”transcript, stated
“So, we can solve for both of these. The first thing we can do for that latency problem is we can start a a go routine or a thread [clears throat] and have it make the Temporal client call to start the child workflow. This lets the main turn workflow”transcript, stated
“we start each detached child workflow in its own wrapper workflow. And that wrapper executes the child workflow and then once it gets that it signals back”transcript, stated

Why this architecture

The architecture is a deliberate compromise. Temporal remained useful for conversation durability, shared text-agent code, debugging, testing environments, and high-level lifecycle orchestration. But the latency-sensitive turn workflow could not wait for parent-locked child workflows to start one by one. Fast exec trades Temporal's strong child-start guarantees for detached starts, wrapper workflows, and signals, preserving most developer ergonomics and UI debuggability while accepting a smaller window of failure because in voice a late response is equivalent to failure anyway.

6 supporting quotes
“added voice to their AI support agent using Temporal. Plus, the deliberate trade-off they made trading resilience for speed to meet the demands of real-time voice. All without AI engineering changing a single line of code. So, please join me in welcoming Elliot to the stage. >> [applause]”transcript, stated
“overhead of Temporal every time? So, we decided to use Temporal for for a few reasons. One was we wanted consistency and code sharing with our text agent. The team had already built out a number of skills and for our MVP of the voice agent, we wanted to use some of those straight”transcript, stated
“but still register them using the same kind of shared internal libraries and abstractions. Uh we find Temporal super useful for debugging. Our team spends a lot of time in that workflow view that I shared at the start um and it's really good to understand what”transcript, stated
“while one of these is doing work under that lock, all the others are waiting to acquire it. And this is why we're seeing that staggered pattern of only one child workflow being able to start at a time. So, we're right where we're scheduling all this work”transcript, stated
“Something not succeeding in time is basically the same as that thing failing completely anyway. There's no need to pick up where you left off. So, we have to solve for or tolerate these partial failure cases anyway. That being the case, is it really so”transcript, stated
“we called it fast exec, and our turn workflow local code has gone back basically to to how it looked before, which is great. The workflow is still kind of ugly. The signal IDs haven't helped here, so my colleague DJ contributed to the to the Go SDK to add”transcript, stated

Models used: Grok · Cerebras models · small open-source models · speech-to-speech real-time models · Deepgram · Cartesia · ElevenLabs · Claude

Scale

Alternatives considered (roads not taken)

Use speech-to-speech real-time models.

Rejected because: They were expressive and low-latency but unreliable for regulated financial services due to prompt injection and hallucination.

3 supporting quotes
“don't know if uh people here have tried them, but they can be really expressive, super low latency, and really quite fun to talk to in lots of cases. For the regulated industries that we serve, though, these just weren't reliable enough for our customers. Even the state-of-the-art ones we found”transcript, stated
“For the regulated industries that we serve, though, these just weren't reliable enough for our customers. Even the state-of-the-art ones we found quite liable to prompt injection, to hallucination. So, this wasn't going to work for us. We're keeping an eye”transcript, stated
“these just weren't reliable enough for our customers. Even the state-of-the-art ones we found quite liable to prompt injection, to hallucination. So, this wasn't going to work for us. We're keeping an eye on this. Uh new models coming out all the time, so so maybe we'll”transcript, stated

Use agent-builder voice products.

Rejected because: They provided good UX and speech layers, but not enough flexibility for the AI engineering team to customize the regulated agent behavior.

“there are lots of systems and products where you can choose your model, bring your prompt, and they'll layer on a lot of the speech to text and text to speech parts”transcript, stated
“these didn't give our AI engineering team the flexibility under the hood to uh to customize the agent in the way we needed.”transcript, stated

Remove Temporal from the turn workflow entirely.

Rejected because: This would reduce latency but was hard because activities were only accessible through Temporal workflows and the team wanted shared code, testing, and debugging.

3 supporting quotes
“Let's rip Temporal out of it straight up, and we'll just turn this into the turn activity." That uh that wouldn't let us pick off pick up where we left off in the same way, but for voice we've established that's not quite as important. This wasn't as easy to”transcript, stated
“This wasn't as easy to do as we hoped, and we tied ourselves in a bit of a knot here. So, I would encourage you to to try to avoid ending up in this situation. We had at the bottom of the stack our activities, and these were only easily accessible as”transcript, stated
“activities could only be invoked from workflows, everything else that already existed as as child workflows, they had to remain as workflows”transcript, stated

Use normal Temporal child workflows for all concurrent turn work.

Rejected because: Children of the same parent workflow started sequentially because each transfer task acquired the parent workflow lock.

3 supporting quotes
“we thought our workflow would would look like this diagram, all this work kicking off at once, all running, and then we can just take the fastest answer and and go from there. What we actually saw though was what I opened with. We saw this absolute mess. Uh”transcript, stated
“all child workflows of the agent's turn, and these are all taking seconds to start, let alone to finish. So, the first thing we thought was that this would just be worker scaling. Maybe our machines aren't powerful enough. We don't We don't have enough”transcript, stated
“is acquire a lock on the parent workflow. And this is going to be the smoking gun for us. This workflow lock is is going to be the problem. After it's done that, it creates the child workflow, goes ahead and writes that new run ID of the child workflow into the”transcript, stated

Run classification, answer generation, and guardrails sequentially.

Rejected because: For voice, the team reduced latency by running classification and possible answers concurrently, discarding irrelevant results after classification returned.

3 supporting quotes
“What we decided to do for voice though is shave off some latency by running all of these concurrently. So, at the same time as running the classification, instead of waiting for it to finish, we'll answer all the questions that the customer could have asked.”transcript, stated
“we'll answer all the questions that the customer could have asked. And then once the classification returns and we know which question we're actually supposed to be answering”transcript, stated
“classification returns and we know which question we're actually supposed to be answering, we'll throw the other results away. Now, like I said, this is trade-off, this isn't free, but we're using these cheap cached input tokens with these small models,”transcript, stated

Patterns

durable-execution (infrastructure)

Temporal coordinates long-running conversations and the original text-agent turn stack, giving durability and recoverability for multi-day interactions.

3 supporting quotes
“Temporal and one long-running workflow here is the ideal setup for for a long-running conversation.”transcript, stated
“Obviously, the durability thing is is important, but for me the mental model this gives you of having one place to go and see this thing that is the conversation.”transcript, stated
“And with Temporal, it's super super easy to just pick up where we left off.”transcript, stated

latency-optimization (operations)

The team reduced voice latency through faster providers, compression/caching, cached input tokens, constrained small models, redundant concurrent inference, eager workflow start, early TTS kickoff, and detached workflow starts.

4 supporting quotes
“We onboarded Grok and Cerebras for fast inference. These were able to serve us tokens much faster than the APIs we'd been using before.”transcript, stated
“We implemented compression and caching of conversations called code style, and restructured a lot of our prompts to take full use of cached input tokens.”transcript, stated
“we would send three requests to the LLMs for each question that the customer could have asked.”transcript, stated
“Uh in particular, eager workflow start saved us a bit of time. And then thinking all the time that we thought we were stuck on Temporal latency, that really lit a fire under the team to save time elsewhere.”transcript, stated

tool-use-orchestration (agent-architecture)

A short-lived turn workflow composes classification, answer generation, guardrails, translation, activities, LLM completions, APIs, and tools to decide the next support action.

3 supporting quotes
“This takes the full state of the conversation so far, and its job is to generate the next reply from the agent.”transcript, stated
“invoking tool calls, uh escalating, closing, finishing the conversation, and so on would would be the decision of this turn workflow”transcript, stated
“things like LLM completions, hitting APIs, tool calls, and and so on.”transcript, stated

model-routing (model-operations)

The voice path races multiple identical or provider/model-diverse LLM requests and uses whichever response arrives first.

3 supporting quotes
“we would uh send requests to a couple of different providers or models.”transcript, stated
“And we would just take the one that came back to us first. Uh that's a little bit hacky, but but this worked. This this saved us a bunch of time and brought our average latency for agent replies way down.”transcript, stated
“This this saved us a bunch of time and brought our average latency for agent replies way down. This created a new problem for us, though.”transcript, stated

guardrails-io-filtering (safety)

The agent runs multiple guardrail skills over candidate answers for quality and compliance in regulated financial services.

3 supporting quotes
“these are industries with strict regulations, so they have a really high bar on the quality of the response from our agent.”transcript, stated
“This is uh a lot of different skills, so classification, obviously generating answers, a number of guardrails given our our regulated industries, translation, and so on.”transcript, stated
“we'll run a number of guardrails over it for quality, compliance, and so on.”transcript, stated

observability-tracing (observability)

The team values Temporal UI and a debug workflow skill for inspecting what happened in each turn, why the agent responded that way, and which detached wrapper work produced results.

3 supporting quotes
“Our team spends a lot of time in that workflow view that I shared at the start”transcript, stated
“it's really good to understand what happened in a given turn and why the agent responded in the way it did.”transcript, stated
“if you drop a workflow ID, it can traverse continuous new child workflows and so on and if it has access to the source code as well”transcript, stated

fallback-degradation (reliability)

For live voice turns, the team accepts losing some child-start guarantees because any work that misses the latency window is effectively failed anyway.

3 supporting quotes
“Something not succeeding in time is basically the same as that thing failing completely anyway.”transcript, stated
“we have to solve for or tolerate these partial failure cases anyway.”transcript, stated
“If they have to wait two, three, four, five seconds for a response from the agent, they are going to hang up.”transcript, stated

Tradeoffs

Trade child-start guarantees for faster voice turns.

Chose detached wrapper workflows started from side effects/goroutines over normal child workflows with strong start guarantees.

Rationale: For live voice, a child workflow that fails to start is not meaningfully worse than one that starts too late; both miss the response window.

3 supporting quotes
“we get some strong guarantees from Temporal that all of these child workflows will start.”transcript, stated
“if we forego that guarantee, could we do anything to make things a bit faster?”transcript, stated
“Something not succeeding in time is basically the same as that thing failing completely anyway.”transcript, stated

Keep Temporal for high-level coordination.

Chose Temporal for conversation lifecycle, outbound batches, calls, pre-call SMS, and post-call actions over removing Temporal from the voice system entirely.

Rationale: Temporal remains valuable where latency sensitivity is lower and lifecycle coordination, retries, and state visibility matter.

3 supporting quotes
“For the high-level coordination of your agents across the life cycle of a conversation.”transcript, stated
“for all of this temporal is is a perfect fit. I I couldn't recommend it more at that high level of coordination.”transcript, stated
“Down in our turn workflow where this is happening, every time a customer needs a reply from our agent, it's a lot harder to justify that latency.”transcript, stated

Race redundant LLM work.

Chose three requests per possible customer question, sometimes across providers or models over one sequential classify-then-answer request path.

Rationale: The team spent extra compute to reduce variance and average reply latency while cheap cached tokens and pre-launch scale made the cost acceptable.

3 supporting quotes
“instead of answering every question once, we would send three requests to the LLMs for each question that the customer could have asked.”transcript, stated
“And we would just take the one that came back to us first. Uh that's a little bit hacky, but but this worked. This this saved us a bunch of time and brought our average latency for agent replies way down.”transcript, stated
“Uh that's a little bit hacky, but but this worked. This this saved us a bunch of time and brought our average latency for agent replies way down.”transcript, stated

Reuse the text agent for voice MVP.

Chose speech-to-text into existing text LLM agent, then text-to-speech out over building a new voice-native agent from scratch.

Rationale: Reusing the text system let the team keep existing skills, libraries, test environments, and debugging, but it later required latency-specific re-engineering.

3 supporting quotes
“that sounds uh kind of familiar, right? We already have this. This is already working really nicely for us for text.”transcript, stated
“It let us build on a lot of what we already have, but some of the the other options of not doing it that way. So for example, the the speech-to-speech real-time models for our regulated use cases just weren't reliable enough for for our customers.”transcript, stated
“we'd already built it before we realized we would have a big problem here.”transcript, stated

Constrain small models for holding responses.

Chose strict phatic and pragmatic tags for small, cheap, fast models over asking the model to freely generate natural holding responses.

Rationale: Constrained output made it possible to use fast small models without dropping the regulated quality bar.

3 supporting quotes
“we gave them very narrow tasks so that we could speed things up without compromising on our quality bar.”transcript, stated
“we break that down into very strict tags rather than just asking the agent to reply to the customer.”transcript, stated
“if you really constrain the models, you can use small, cheap, fast models”transcript, stated

Gotchas (what bit them)

The text-agent architecture hid a voice-specific latency trap.

Root cause: Temporal was acceptable for asynchronous text where a minutes-late recovery still mattered, but live voice callers leave before recovery is useful.

Resolution: Keep Temporal for high-level lifecycle work while treating latency-sensitive turn execution differently.

3 supporting quotes
“And for our text agent, we're not massively latency sensitive. We don't want that to be slow, but if something has gone wrong and we come back up a couple of minutes later, pick up where we left off, it's fine at that point to just send the reply to the customer.”transcript, stated
“if something has gone wrong and we come back up a couple of minutes later, pick up where we left off, it's fine”transcript, stated
“if we pick back up after a couple of minutes, the customer's going to have hung up.”transcript, stated

Temporal child workflows appeared concurrent but started sequentially.

Root cause: Transfer-task goroutines each acquired the parent workflow lock before creating a child workflow and writing the run ID to parent history.

Resolution: Start former child workflows as detached wrapper workflows and signal results back to the turn workflow.

3 supporting quotes
“we were starting the work sequentially and and that was our problem.”transcript, stated
“the first thing each of these does is acquire a lock on the parent workflow.”transcript, stated
“while one of these is doing work under that lock, all the others are waiting to acquire it.”transcript, stated

Activities being reachable only through Temporal created optimization lock-in.

Root cause: The architecture tied bottom-layer activities to workflows, so converting the turn workflow into a plain activity was not straightforward.

Resolution: Use detached wrapper workflows as an intermediate compromise, and treat the coupling as technical debt for possible future refactor.

3 supporting quotes
“our activities, and these were only easily accessible as activities. We couldn't just plug in and call these directly.”transcript, stated
“everything else that already existed as as child workflows, they had to remain as workflows so that they could invoke the activities.”transcript, stated
“So, we were we were a little bit stuck. So, we step back and we can have a quick look at what's actually happening under the hood here.”transcript, stated

Side effects and signals made the workflow hard to understand.

Root cause: Detached workflows solved latency but produced side-effect/signal-heavy histories and channel code that confused engineers and Claude.

Resolution: Wrap the pattern in fast exec futures, add side-effect and signal summaries, and link wrapper workflow URLs from the Temporal UI.

3 supporting quotes
“The code starts to look quite ugly. Even in this toy example, we're having to consume the results on this channel.”transcript, stated
“If you have side effect, side effect, side effect, signal, signal, signal, you don't really have any clue what's going on.”transcript, stated
“And even Claude didn't enjoy working with these. You point Claude to one of these and it's it has no no clue what's happening.”transcript, stated

Regulated support could not use the lowest-latency speech-to-speech models.

Root cause: The models were vulnerable to prompt injection and hallucination, even when tested with more sophisticated supervisor setups.

Resolution: Use a speech-to-text, text LLM, and text-to-speech cascade so existing guardrails and text-agent controls stay in the loop.

3 supporting quotes
“the speech-to-speech real-time models for our regulated use cases just weren't reliable enough for for our customers.”transcript, stated
“was able to prompt inject them in in various ways like observed a number of hallucinations.”transcript, stated
“we kind of settled in that speech-to-text text-to-speech way of doing things.”transcript, stated

Testing-environment latency symptoms were initially misattributed to weak workers.

Root cause: The problem first appeared in underpowered test environments, making worker scaling look like the likely cause.

Resolution: Reproduce in production and isolate the root cause by starting the same workflows from a standalone Temporal client outside the shared parent.

3 supporting quotes
“originally we saw this in one of these testing environments that I mentioned earlier. These tend to be kind of underpowered compared to production”transcript, stated
“So, we took it to production, and we saw the exact same thing. So, we started to suspect this wasn't just due to scaling issues.”transcript, stated
“when we kicked them off in that way, all of these started pretty much at the same time.”transcript, stated

Evaluation

The case describes operational validation through latency traces, Temporal UI inspection, testing and production comparison, standalone Temporal-client experiments, good-run/bad-run latency observation, and production voice-call outcomes. The team also relies on guardrails for quality/compliance and workflow debugging to understand why the agent responded a certain way.

Metrics: scheduled-to-start latency · customer wait time before hang-up · LLM response latency · latency variance across good and bad runs · Temporal nested workflow overhead · Temporal wrapper workflow overhead · text-to-speech latency · speech-to-text latency · production call success without hang-up · quality and compliance guardrail pass

6 supporting quotes
“For those of you who are less familiar with Temporal, specifically what we're looking at here is the light green bars are our scheduled to start latency. And that's the time between our code asking Temporal to kick off some work and that work actually starting.”transcript, stated
“On a good run, we'd be not much over 300 milliseconds. On a bad run, we could be double, triple, or even more than that.”transcript, stated
“So, we took it to production, and we saw the exact same thing. So, we started to suspect this wasn't just due to scaling issues.”transcript, stated
“when we kicked them off in that way, all of these started pretty much at the same time.”transcript, stated
“the agent will now come back to them in a reasonable amount of time, and they can have that conversation.”transcript, stated
“the text-to-speech side is anywhere from like 150 to 300 milliseconds-ish with 11 Labs.”transcript, stated

Outcomes

The source reports child workflow start delays of three to five seconds, callers hanging up after two to five seconds, text conversations lasting days or weeks, text-agent turns in the mid-tens of seconds before optimization, good voice runs just over 300ms, three LLM requests per possible question, about 30ms per nested Temporal level, 100-200ms final Temporal overhead, 150-300ms ElevenLabs TTS, and about 200ms self-hosted Deepgram STT.

6 supporting quotes
“This this saved us a bunch of time and brought our average latency for agent replies way down.”transcript, stated
“This workflow lock is is going to be the problem. After it's done that, it creates the child workflow, goes ahead and writes that new run ID of the child workflow into the parent workflow history, and only then does it release the lock on the parent workflow.”transcript, stated
“And we wrap this up in a little library, we called it fast exec, and our turn workflow local code has gone back basically to to how it looked before, which is great.”transcript, stated
“this is working for us. If the customer gets in touch, instead of waiting for a while and hanging up, the agent will now come back”transcript, stated
“You should rip this out, remove Temporal, save yourself a couple hundred milliseconds that you're leaving on the table.”transcript, stated
“So, there's a chance that refactor is in our future at Gradient Labs. That said, Temporal is launching new stuff just about every day.”transcript, stated