Data as of Sep 17, 2026 · Based on 50 AI responses from ChatGPT Search and Google AI Mode · See how Parse measures this
Your brand can be here too.
The best approach is to build a **synthetic-caller evaluation harness that runs real audio conversations against your deployed voice agent**, rather than generating thousands of text transcripts. The key is to test three things separately: **conversation behavior, voice behavior, and system/load behavior**. ##…
The best approach is to build a synthetic-caller evaluation harness that runs real audio conversations against your deployed voice agent, rather than generating thousands of text transcripts.
The key is to test three things separately: conversation behavior, voice behavior, and system/load behavior.
Scenario generator
│
▼
Synthetic caller ──► TTS ──► real voice transport ──► Your voice agent
▲ │
│ ▼
Persona + goal STT/LLM/TTS
│ │
└────────────── conversation state ◄─────────────┘
│
▼
Trace + audio + tool calls
│
┌───────────────┴──────────────┐
▼ ▼
Deterministic checks LLM judges
(did task happen?) (natural? concise? safe?)
This is increasingly the direction of serious voice-agent evaluation: bot-to-bot audio, with the simulator actually speaking and listening rather than simply feeding transcripts to the agent.
Instead of writing 10,000 scripts, create perhaps 100–500 scenario templates:
Then generate many variations from each scenario.
This gives you 10,000 different conversations without needing 10,000 hand-authored scripts. Microsoft's current simulation tooling similarly recommends scenario descriptions plus desired turn counts rather than manually authoring every conversation.
Don't use an LLM that simply says "the next thing a user might say."
Give it a private state:
{
"goal": "reschedule_appointment",
"known_facts": ["appointment_id=123"],
"constraints": ["morning_only"],
"personality": "impatient",
"hidden_intent": "will accept Tuesday if offered",
"behavior": [
"occasionally interrupt",
"ask unrelated question once",
"correct agent if misunderstood"
]
}
The simulator should decide what to say based on what the agent actually just said.
This matters because research is finding that synthetic users can be overly cooperative and miss the friction of real users.
For a voice agent, I'd run at least two tiers.
Tier A: cheap/high-volume
Run thousands of simulations with text or lightweight audio to catch:
Tier B: expensive/realistic
Run hundreds/thousands of actual audio calls through the production-equivalent voice stack to test:
Modern voice-agent evaluation frameworks explicitly use this bot-to-bot audio architecture because text replay misses these failure modes.
Don't have an LLM give the conversation one vague "7/10."
Use deterministic assertions wherever possible.
For example:
Task completed? YES/NO
Correct tool called? YES/NO
Correct arguments? YES/NO
Unauthorized disclosure? YES/NO
Required confirmation obtained? YES/NO
Correct final state? YES/NO
First-response latency 420 ms
p95 turn latency 1.8 s
Interruptions handled 4/5
Conversation length 11 turns
Then use an LLM judge for subjective dimensions:
The emerging EVA benchmark, for example, separates task accuracy from conversation experience, including progression, conciseness, and turn-taking.
Your distribution shouldn't be 10,000 polite users.
I'd roughly create buckets like:
And vary things like:
EVA's open-source benchmark takes a similar approach by perturbing conversations with noise, accents, connection degradation, and other conditions.
This is a separate problem from conversation quality.
For example:
10 concurrent calls → baseline
100 concurrent calls → normal load
1,000 concurrent calls → expected peak
2,000 concurrent calls → stress
5,000 concurrent calls → spike
Measure:
A conventional HTTP load test isn't sufficient because voice calls are long-lived, stateful, streaming sessions.
Give every scenario a stable seed:
scenario_id = appointment_reschedule_0472
seed = 918273
agent = v1.8.2
Then you can run:
v1.8.2 → 10,000 calls
v1.8.3 → same 10,000 calls
and compare them directly.
That's much more useful than simply generating another 10,000 random conversations after every release. Conversation-simulation systems such as MLflow explicitly support reproducible scenario-based evaluation for this reason.
If you're building this yourself, my stack would look roughly like:
Scenario engine → synthetic caller → real-time audio transport → voice agent → trace collector → deterministic assertions + LLM judge → results database/dashboard
And I'd store the audio, transcript, tool calls, timing events, scenario state, and scores for every call.
For a starting point rather than building everything yourself, there are now several useful references/projects: ServiceNow's EVA is open source and specifically designed around bot-to-bot voice evaluation, while DeepEval provides conversation simulation and voice-mode evaluation.
If I had to pick one principle: don't optimize for "10,000 conversations." Optimize for 10,000 independently generated attempts to break the agent, with enough evidence to explain exactly why each failure happened. That's what turns synthetic testing from a demo into an actual QA system.
Simulating thousands of conversations to stress-test a voice agent requires a **bot-to-bot architecture**—`pairing a programmatic "Simulated User" against your voice agent, orchestrating it via parallel execution scripts, and passing the resulting transcripts through an LLM…
Simulating thousands of conversations to stress-test a voice agent requires a bot-to-bot architecture—pairing a programmatic "Simulated User" against your voice agent, orchestrating it via parallel execution scripts, and passing the resulting transcripts through an LLM judge.
The industry-standard blueprint to pull this off efficiently relies on a structured, 5-stage process:
Don't just use a generic LLM prompt for your caller. Create a parameterized simulated user framework (using tools or custom scripts with frameworks like DeepEval's Conversation Simulator or open architectures like ServiceNow's EVA).
To get through thousands of runs without taking days, you need asynchronous execution:
Manually listening to thousands of audio files is impossible. Instead, capture full call transcripts and run them through an automated evaluation judge. Score each conversation on quantifiable axes:
If you're setting this up, let me know:
I can help you map out the specific tech stack or script architecture to build this out.
The best approach is to treat a voice agent like a production system: **simulate realistic callers, run conversations at scale, and score outcomes automatically**. Don't start by generating thousands of random calls; build a test system that creates *meaningful failure coverage*. [Synthetic…
The best approach is to treat a voice agent like a production system: simulate realistic callers, run conversations at scale, and score outcomes automatically. Don't start by generating thousands of random calls; build a test system that creates meaningful failure coverage.
A strong architecture looks like this:
Create thousands of caller personas, not just scripts.
Examples:
Each simulated caller should have:
Persona-driven simulation tends to expose more issues than fixed scripts because real users rarely follow one path.
Use two layers:
Run millions of turns cheaply using text simulation:
This is where you find most logic bugs.
Run fewer but realistic audio calls:
A voice agent that works perfectly in text can still fail when audio enters the loop.
The highest-value test cases usually come from:
Convert failures into regression tests:
"Caller disputed a charge, refused verification twice, then requested cancellation." Then generate variations:
Some agent testing systems explicitly support turning real conversations into reusable simulations.
Avoid checking exact wording. Grade the result.
Bad:
"Agent must say: 'I understand your concern.'" Better:
For example:
Scenario:
Customer wants to cancel subscription.
Pass criteria:
✓ Identity verified
✓ Cancellation completed
✓ Retention offer followed policy
✓ Confirmation provided
✓ No unauthorized refund promised
Full-conversation evaluation is more useful than judging isolated replies.
Have synthetic callers intentionally stress the agent:
These users find the failures that happy-path testing misses.
For thousands of simulated calls, track:
A mature setup looks like CI/CD:
New agent version
|
v
Run 10,000 synthetic calls
|
v
Score outcomes
|
v
Compare against baseline
|
v
Block deployment if regression detected
A common implementation:
The biggest mistake is using only scripted conversations. The better pattern is scenario → simulated caller → real agent → automated evaluator → regression suite. That gives you thousands of realistic conversations without requiring humans to manually place calls.
If you're building this internally, the key design choice is whether you want to test the conversation brain, the full audio/telephony stack, or both—the architecture changes quite a bit depending on that.
The biggest mistake is using only scripted conversations. The better pattern is scenario → simulated caller → real agent → automated evaluator → regression suite. That gives you thousands of realistic conversations without requiring humans to manually place calls.
Simulating thousands of conversations to test a voice agent requires a shift away from brittle, hardcoded unit tests toward **LLM-driven multi-agent simulation** . Because voice interactions are non-deterministic and run through a multi-stage pipeline (Telephony → STT → LLM/Core Logic → TTS), you need a decoupled…
Simulating thousands of conversations to test a voice agent requires a shift away from brittle, hardcoded unit tests toward LLM-driven multi-agent simulation . Because voice interactions are non-deterministic and run through a multi-stage pipeline (Telephony → STT → LLM/Core Logic → TTS), you need a decoupled architecture that can run massively parallel, programmatic evaluations.
The industry-standard architecture to achieve this at scale involves four core components:
asyncio , Celery, or a dedicated testing framework) that spins up hundreds of concurrent simulation threads.asyncio combined with an LLM framework (like LangChain/LlamaIndex or raw instructor-backed OpenAI/Anthropic APIs) to play the dual roles of User Simulator and Judge, pushing results into a data warehouse for batch analysis.Are you looking to test pure conversational logic and tool-calling via text simulation, or do you need to stress-test the actual audio pipeline (STT/TTS latency and telephony) at scale?
The best way to simulate thousands of conversations for a voice agent is to deploy **automated LLM-to-LLM simulation testing combined with real-world audio injection** . Instead of relying on slow, expensive manual QA or simple static text testing, you use a secondary "User Simulator LLM" to interact dynamically with…
The best way to simulate thousands of conversations for a voice agent is to deploy automated LLM-to-LLM simulation testing combined with real-world audio injection . Instead of relying on slow, expensive manual QA or simple static text testing, you use a secondary "User Simulator LLM" to interact dynamically with your voice agent at scale.
🛠️ The Ideal 4-Step Testing Architecture
To test thousands of conversations efficiently, you must construct a specialized pre-production pipeline:
Configure a secondary LLM to act as the customer. Do not use generic prompts. Give the simulator highly specific persona guidelines:
Do not stream full voice-to-voice audio for all thousands of initial test runs; the compounding latency of STT → LLM → TTS will make the simulation too slow and expensive.
Once your agent handles text logic perfectly, you must test the actual voice pipeline (STT/TTS). An agent that succeeds in pristine text can fail miserably over the phone.
Manually reviewing 10,000 transcripts is impossible. Implement an automated Judge Agent.
🚀 Leading Platforms for Scale Testing (2026)
If you don't want to build this infrastructure from scratch using custom Python scripts, several platforms specialize exactly in high-volume voice agent simulation:
💡 Core Strategy: Surgical Testing over Broad Testing
When scale testing, avoid the temptation to make every simulation a long, open-ended conversation. The most effective method is to deploy "surgical" test scenarios . Create thousands of test cases that focus on a single, isolated decision point (e.g., testing only how the agent handles a specific curse word, or how it acts when a user says "Wait, hold on" mid-sentence). If a test fails, your automated judge can pinpoint exactly which prompt or line of code caused the break.
If you are currently building an agent, tell me a bit more about your tech stack (e.g., Retell, Vapi, Custom WebSockets) and your primary use case (e.g., customer support, booking appointments). I can provide a more tailored framework or script outline for your setup!
The best approach is **not** to generate 10,000 fixed scripts. Build a **synthetic-caller simulation harness** that conducts real audio conversations with your agent, varies the caller behavior, and automatically evaluates the outcome. Current voice-agent testing systems are converging on this architecture: an…
The best approach is not to generate 10,000 fixed scripts. Build a synthetic-caller simulation harness that conducts real audio conversations with your agent, varies the caller behavior, and automatically evaluates the outcome.
Current voice-agent testing systems are converging on this architecture: an LLM-driven user simulator generates the caller's behavior, TTS produces actual speech, the voice agent receives it over its normal transport, and the agent's audio is recorded/transcribed and evaluated.
Scenario generator
│
▼
┌──────────────────┐
│ Synthetic caller │
│ goal + persona │
│ behavior + state │
└────────┬─────────┘
│ text
▼
TTS
│ audio
▼
┌──────────────────┐
│ Voice Agent │
│ STT → LLM → TTS │
└────────┬─────────┘
│ audio
▼
STT
│
▼
┌──────────────────┐
│ Evaluation layer │
│ outcome + audio │
│ latency + tools │
└──────────────────┘
The important part is that the simulator talks to the agent through the same audio path as a real caller. Testing only with transcripts won't expose things like STT mistakes, barge-ins, silence thresholds, awkward turn-taking, or TTS latency.
Define scenarios at a higher level:
goal: "Change a flight reservation"
persona:
patience: low
familiarity: novice
speaking_style: rushed
emotional_state: frustrated
constraints:
has_booking: true
flight_is_changeable: true
behaviors:
- interrupt_agent
- provide incomplete_information
- change_topic_once
- ask_for_confirmation
success:
- correct_flight_changed
- correct_fee_explained
- no_unauthorized_action
Then generate hundreds/thousands of variations from those dimensions.
I'd create dimensions for:
This gives you combinatorial coverage without manually writing thousands of scripts. Microsoft similarly recommends generating simulation seeds/scenarios rather than authoring every conversation by hand.
This is probably the most important design decision.
Don't use:
"Generate the next user message." Use:
"You are a caller with goal X. Maintain this private state. React naturally to what the agent says. Do not reveal your goal unless it would be natural. Stop when your goal is satisfied or you decide the agent has failed." The simulator should maintain things like:
Goal: cancel reservation
Known information:
reservation_id = 83921
cancellation_reason = "price"
Hidden behavior:
impatient = true
will interrupt after long pauses
will accept alternative only if savings > $50
Termination:
success / failure / abandonment
That produces much more realistic conversations than a scripted dialogue tree.
This is an easy thing to overlook.
Suppose the caller simulator was supposed to say that it had a valid reservation, but it accidentally claims it doesn't have one. If your agent then fails, you don't have an agent failure—you have a bad test.
Modern voice-eval frameworks explicitly validate simulated conversations and regenerate invalid ones before scoring them.
So have a validator ask:
Did the simulated caller:
✓ maintain its assigned state?
✓ pursue the assigned goal?
✓ obey the scenario constraints?
✓ respond coherently to the agent?
✓ terminate for a valid reason?
Only then score the agent.
Don't reduce the result to one "LLM score."
I'd track at least:
| Metric | Example |
|---|---|
| Task success | 93% |
| Task correctness | 96% |
| Policy compliance | 99.4% |
| Tool correctness | 97% |
| Hallucination rate | 1.2% |
| Escalation correctness | 94% |
| Average latency | 720 ms |
| P95 latency | 1.8 s |
| Interruption handling | 91% |
| Turn-taking | 95% |
| STT robustness | 92% |
| Conversation abandonment | 3.1% |
Voice-specific evaluation needs to include interaction experience—not merely whether the final textual answer was correct. EVA, for example, separates task accuracy from conversational experience such as progression, conciseness and turn-taking.
Use deterministic assertions wherever possible:
assert booking.status == "cancelled"
assert refund.amount == expected_refund
assert tool_calls.count("cancel_booking") == 1
assert unauthorized_tools == []
Then use an LLM judge for things that are inherently fuzzy:
Was the agent's explanation understandable?
Did it acknowledge the user's frustration?
Did it unnecessarily repeat information?
Did the conversation feel natural?
Did the agent appropriately handle the interruption?
And periodically compare your automated judges against human judgments. Recent research specifically finds that LLM-judge reliability and calibration are important issues for voice-agent evaluation.
I'd use a distribution such as:
10,000 simulations
Normal cases 4,000 ████████████████████
Edge cases 2,000 ██████████
Adversarial 1,500 ███████
Noisy/voice 1,000 █████
Tool failures 750 ████
Rare scenarios 500 ██
Regression suite 250 █
And seed the randomness so a failed test can be reproduced.
Every conversation should produce an immutable test record:
{
"scenario_id": "cancel_042",
"seed": 193847,
"agent_version": "2026-09-07.14",
"user_persona": "impatient",
"outcome": "failure",
"failure_type": "wrong_refund",
"latency_p95_ms": 1840,
"tool_errors": [],
"audio": "...",
"transcript": "...",
"trace": "..."
}
I'd build the system in three levels:
Level 1 — Cheap: Thousands of text simulations to test agent logic and tool behavior.
Level 2 — Audio: Hundreds/thousands of TTS → agent → STT conversations to test the actual voice pipeline.
Level 3 — Realistic stress: Audio + interruptions + background noise + varied speaking rates + latency + API failures + concurrent calls.
This saves enormous amounts of money. You don't need to spend GPU/TTS/telephony resources testing a simple business-rule regression.
Tools such as LiveKit's agent testing and DeepEval's voice simulation already follow variants of this model, including full multi-turn simulated conversations and actual audio capture.
The killer feature is making every agent change trigger:
git push
↓
500 cheap simulations
↓
Regression suite
↓
100 audio simulations
↓
Evaluation
↓
Compare against previous version
↓
FAIL PR if:
task success ↓ > 2%
policy violations ↑
P95 latency ↑ > 15%
critical regression detected
Then run the 10k+ overnight suite rather than blocking every developer commit.
If you're building this yourself, my preferred stack would be:
There are now open-source frameworks specifically aimed at this bot-to-bot audio architecture; EVA is one notable example, while DeepEval and LiveKit provide simulation/testing infrastructure you can adapt rather than building everything from scratch.
The key insight: don't think of this as "generate 10,000 conversations." Think of it as generate 10,000 independent test environments with goals, users, world states, and failure modes—and let the conversations emerge from those conditions. That's what makes the results useful rather than 10,000 variations of the same happy-path demo.
Use:
"You are a caller with goal X. Maintain this private state. React naturally to what the agent says. Do not reveal your goal unless it would be natural. Stop when your goal is satisfied or you decide the agent has failed." The simulator should maintain things like:
Goal: cancel reservation
Known information:
reservation_id = 83921
cancellation_reason = "price"
Hidden behavior:
impatient = true
will interrupt after long pauses
will accept alternative only if savings > $50
Termination:
success / failure / abandonment
That produces much more realistic conversations than a scripted dialogue tree.
This is an easy thing to overlook.
Suppose the caller simulator was supposed to say that it had a valid reservation, but it accidentally claims it doesn't have one. If your agent then fails, you don't have an agent failure—you have a bad test.
Modern voice-eval frameworks explicitly validate simulated conversations and regenerate invalid ones before scoring them.
So have a validator ask:
Did the simulated caller:
✓ maintain its assigned state?
✓ pursue the assigned goal?
✓ obey the scenario constraints?
✓ respond coherently to the agent?
✓ terminate for a valid reason?
Only then score the agent.
Don't reduce the result to one "LLM score."
I'd track at least:
| Metric | Example |
|---|---|
| Task success | 93% |
| Task correctness | 96% |
| Policy compliance | 99.4% |
| Tool correctness | 97% |
| Hallucination rate | 1.2% |
| Escalation correctness | 94% |
| Average latency | 720 ms |
| P95 latency | 1.8 s |
| Interruption handling | 91% |
| Turn-taking | 95% |
| STT robustness | 92% |
| Conversation abandonment | 3.1% |
Voice-specific evaluation needs to include interaction experience—not merely whether the final textual answer was correct. EVA, for example, separates task accuracy from conversational experience such as progression, conciseness and turn-taking.
Use deterministic assertions wherever possible:
assert booking.status == "cancelled"
assert refund.amount == expected_refund
assert tool_calls.count("cancel_booking") == 1
assert unauthorized_tools == []
Then use an LLM judge for things that are inherently fuzzy:
Was the agent's explanation understandable?
Did it acknowledge the user's frustration?
Did it unnecessarily repeat information?
Did the conversation feel natural?
Did the agent appropriately handle the interruption?
And periodically compare your automated judges against human judgments. Recent research specifically finds that LLM-judge reliability and calibration are important issues for voice-agent evaluation.
I'd use a distribution such as:
10,000 simulations
Normal cases 4,000 ████████████████████
Edge cases 2,000 ██████████
Adversarial 1,500 ███████
Noisy/voice 1,000 █████
Tool failures 750 ████
Rare scenarios 500 ██
Regression suite 250 █
And seed the randomness so a failed test can be reproduced.
Every conversation should produce an immutable test record:
{
"scenario_id": "cancel_042",
"seed": 193847,
"agent_version": "2026-09-07.14",
"user_persona": "impatient",
"outcome": "failure",
"failure_type": "wrong_refund",
"latency_p95_ms": 1840,
"tool_errors": [],
"audio": "...",
"transcript": "...",
"trace": "..."
}
I'd build the system in three levels:
Level 1 — Cheap: Thousands of text simulations to test agent logic and tool behavior.
Level 2 — Audio: Hundreds/thousands of TTS → agent → STT conversations to test the actual voice pipeline.
Level 3 — Realistic stress: Audio + interruptions + background noise + varied speaking rates + latency + API failures + concurrent calls.
This saves enormous amounts of money. You don't need to spend GPU/TTS/telephony resources testing a simple business-rule regression.
Tools such as LiveKit's agent testing and DeepEval's voice simulation already follow variants of this model, including full multi-turn simulated conversations and actual audio capture.
The killer feature is making every agent change trigger:
git push
↓
500 cheap simulations
↓
Regression suite
↓
100 audio simulations
↓
Evaluation
↓
Compare against previous version
↓
FAIL PR if:
task success ↓ > 2%
policy violations ↑
P95 latency ↑ > 15%
critical regression detected
Then run the 10k+ overnight suite rather than blocking every developer commit.
If you're building this yourself, my preferred stack would be:
This is probably the most important design decision.
Don't use:
"Generate the next user message." Use:
The best way to simulate thousands of conversations for a voice agent is to deploy **automated LLM-to-LLM simulation testing combined with real-world audio injection** . Instead of relying on slow, expensive manual QA or simple static text testing, you use a secondary "User Simulator LLM" to interact dynamically with…
The best way to simulate thousands of conversations for a voice agent is to deploy automated LLM-to-LLM simulation testing combined with real-world audio injection . Instead of relying on slow, expensive manual QA or simple static text testing, you use a secondary "User Simulator LLM" to interact dynamically with your voice agent at scale.
🛠️ The Ideal 4-Step Testing Architecture
To test thousands of conversations efficiently, you must construct a specialized pre-production pipeline:
Configure a secondary LLM to act as the customer. Do not use generic prompts. Give the simulator highly specific persona guidelines:
Do not stream full voice-to-voice audio for all thousands of initial test runs; the compounding latency of STT → LLM → TTS will make the simulation too slow and expensive.
Once your agent handles text logic perfectly, you must test the actual voice pipeline (STT/TTS). An agent that succeeds in pristine text can fail miserably over the phone.
Manually reviewing 10,000 transcripts is impossible. Implement an automated Judge Agent.
🚀 Leading Platforms for Scale Testing (2026)
If you don't want to build this infrastructure from scratch using custom Python scripts, several platforms specialize exactly in high-volume voice agent simulation:
💡 Core Strategy: Surgical Testing over Broad Testing
When scale testing, avoid the temptation to make every simulation a long, open-ended conversation. The most effective method is to deploy "surgical" test scenarios . Create thousands of test cases that focus on a single, isolated decision point (e.g., testing only how the agent handles a specific curse word, or how it acts when a user says "Wait, hold on" mid-sentence). If a test fails, your automated judge can pinpoint exactly which prompt or line of code caused the break.
If you are currently building an agent, tell me a bit more about your tech stack (e.g., Retell, Vapi, Custom WebSockets) and your primary use case (e.g., customer support, booking appointments). I can provide a more tailored framework or script outline for your setup!
The best approach is to build a **synthetic-caller simulation harness** that exercises your *actual voice stack* end-to-end, rather than generating thousands of text transcripts. A good architecture looks like this: ```
The best approach is to build a synthetic-caller simulation harness that exercises your actual voice stack end-to-end, rather than generating thousands of text transcripts.
A good architecture looks like this:
Scenario generator
↓
Synthetic caller / persona
↓
Real-time audio
↓
Your actual voice agent
(STT → LLM → tools → TTS)
↓
Conversation trace + audio
↓
Independent evaluator
↓
Metrics / failures / regression report
This is increasingly the standard approach because voice failures often come from things text-only tests miss: interruptions, silence, accents, background noise, latency, turn-taking, and tool failures.
Instead, create a scenario × persona × behavior matrix.
For example:
You can then generate thousands of combinations from perhaps a few hundred carefully designed scenarios.
This is important.
Instead of:
Say "I'd like to cancel my appointment." Give the simulator:
goal:
primary: cancel appointment
appointment: March 14 at 3pm
persona:
mood: mildly frustrated
verbosity: high
constraints:
- Don't volunteer the appointment ID unless asked.
- If the agent asks an unnecessary question, complain.
- If the agent misunderstands you, correct it once.
- If cancellation succeeds, end the call.
The caller LLM should decide what to say next based on the agent's actual response.
That produces much more useful conversations than replaying predetermined scripts. Recent voice-agent benchmarks similarly emphasize dynamic multi-turn simulated callers rather than fixed dialogues.
If your production system is:
microphone → telephony → VAD → STT → LLM → tools → TTS → telephony
your simulator should ideally hit that same path.
Don't evaluate only:
LLM prompt → text response
because you'll miss things such as:
Realistic audio and turn-taking are particularly important for voice systems.
Don't have the same model decide:
"Did I, the caller, behave correctly and did the agent succeed?" Use an independent evaluator.
For every call, collect structured results such as:
{
"task_completed": true,
"policy_violation": false,
"hallucination": false,
"correct_tool_usage": true,
"unnecessary_escalation": false,
"turns": 17,
"latency_p95_ms": 1240,
"caller_hangup": false
}
And ideally evaluate against ground truth state, not merely the transcript.
For example, if the agent says:
"I've cancelled your appointment." the evaluator should check the backend:
appointment.status == "cancelled"
rather than trusting what the agent said. This kind of trace-level evaluation catches agents that sound successful while failing to perform the underlying action.
I'd use:
Best for things that must be objectively true:
Useful for:
Don't manually review thousands of calls.
Instead, review:
This hybrid approach is recommended in current voice-agent evaluation work.
This is one of the most important engineering details.
Store:
test_id
scenario_id
persona_id
random_seed
agent_version
prompt_version
model_version
STT version
TTS version
tool/backend version
full audio
transcript
tool trace
evaluation results
Then when test #7,438 fails, you can run:
replay 7438
and reproduce essentially the same interaction.
Otherwise "we had a weird failure somewhere in 10,000 calls" isn't very useful.
For every agent change:
┌─ critical scenarios
New agent version ──┼─ broad regression set
└─ adversarial/random set
↓
1,000–10,000 calls
↓
compare to baseline
↓
PASS / FAIL / investigate
I'd maintain three suites:
The exact numbers depend on cost and complexity; what's more important is that the scenario library grows whenever production exposes a new failure.
There are actually two different questions:
Does one conversation work? and
Does the system still work when 2,000 conversations happen simultaneously? Don't confuse them.
For the second test, progressively increase concurrency:
10 → 50 → 100 → 250 → 500 → 1,000 → 2,000
Track:
A voice agent can have excellent single-call performance while falling apart under concurrency.
If you're implementing this yourself, I'd make the core abstraction something like:
scenario = Scenario(
goal="cancel appointment",
initial_state=backend_state,
persona=persona,
behaviors=behaviors,
)
result = await simulator.run(
caller=scenario,
agent=production_voice_agent,
)
evaluation = await evaluator.score(
scenario=scenario,
result=result,
final_state=backend.snapshot(),
)
Then run thousands of these asynchronously with a queue/worker architecture.
The key insight: don't optimize for "10,000 conversations." Optimize for 10,000 independently generated attempts to break the agent, with every failure tied to ground truth and reproducible evidence.
If you're building this today, I'd strongly favor synthetic callers + real audio + stateful backend + independent evaluator + parallel execution. That's substantially more powerful than scripted calls or transcript-only LLM evals.
For the second test, progressively increase concurrency:
10 → 50 → 100 → 250 → 500 → 1,000 → 2,000
Track:
A voice agent can have excellent single-call performance while falling apart under concurrency.
If you're implementing this yourself, I'd make the core abstraction something like:
Does one conversation work? and
Simulating thousands of conversations to test a voice agent requires moving away from manual QA and adopting an **automated, agent-to-agent simulation pipeline** . Borrowing a page from autonomous vehicle testing, the modern approach uses a "Simulated User" powered by an LLM to talk to your "Agent Under Test" at…
Simulating thousands of conversations to test a voice agent requires moving away from manual QA and adopting an automated, agent-to-agent simulation pipeline . Borrowing a page from autonomous vehicle testing, the modern approach uses a "Simulated User" powered by an LLM to talk to your "Agent Under Test" at scale, supervised by an automated "Judge".
The standard architecture and step-by-step framework to execute this effectively involve several key components:
Step-by-Step Implementation Strategy
Happy Path: Direct, cooperative user completing a transaction.
Adversarial/Edge Case: User changes their mind mid-sentence, speaks in fragments, or goes off-topic.
Acoustic Variance: Inject background noise profiles or different accents into the simulation configuration.
Text-level Simulation (Fast & Cheap): Strip the STT (Speech-to-Text) and TTS (Text-to-Speech) layers and test the core conversational logic via text APIs. This lets you run 10,000 simulations in minutes for pennies to catch logical loops, prompt injections, or goal failures.
End-to-End Audio Simulation (Realistic & Costly): Route synthetic audio through text-to-speech generators for the user simulator, hitting your actual telephony endpoints. Use platforms designed for this scale.
Explore dedicated platforms like Cekura AI or Roark which specialize in running thousands of persona-driven voice simulations, handling telephony, and tracking aggregate success metrics.
Utilize evaluation and scenario orchestration libraries like the LangWatch Scenario framework to code custom multi-turn audio-to-audio agent tests.
Whenever a live user call fails in production, convert that exact conversation path into a programmatic test case.
Add it to your nightly batch simulation suite so that bug is permanently locked out from regressing.
To help narrow this down, are you looking to test pure conversational logic/prompts (text-based) at high volume, or do you need full audio-to-audio pipeline testing including latency and telephony integration?
The best approach is **LLM-driven user simulation + real audio + deterministic/LLM evaluation**, rather than simply generating thousands of text transcripts. A good architecture looks like this: ```
The best approach is LLM-driven user simulation + real audio + deterministic/LLM evaluation, rather than simply generating thousands of text transcripts.
A good architecture looks like this:
Scenario generator
↓
Synthetic caller personas
↓
TTS audio
↓
┌─────────────────┐
│ Voice Agent │
│ STT → LLM → TTS │
└─────────────────┘
↓
Transcript + audio + tool calls + timings
↓
Graders
↓
Pass/fail + metrics + failure clusters
Create perhaps 100–500 scenario templates, each specifying:
For example:
Goal: Reschedule a doctor's appointment Persona: Busy, impatient caller Facts: Appointment is Tuesday at 3 PM Behavior: Interrupts twice, initially gives the wrong date, asks an unrelated question Success: Appointment moved to an available slot and confirmation provided Then generate 10–100 variations of each scenario. Conversation simulation is increasingly being used specifically this way: scenario descriptions become simulated multi-turn conversations, allowing large-scale and repeatable testing.
This is probably the most important part.
Don't tell the simulator:
"Have a conversation that successfully completes the task." Instead give it an objective and behavioral characteristics:
Research on synthetic users suggests that naive simulators can be substantially more cooperative and predictable than real users, producing overly optimistic evaluations.
Don't run everything as text if the product is a voice agent.
For a representative subset—or ideally the entire suite—run:
simulated user → TTS → phone/WebRTC → agent → audio → simulated user
Vary:
This catches failures that a transcript-only simulator completely misses. Recent voice-agent evaluation work specifically emphasizes bot-to-bot audio conversations and validation of the simulated user's behavior.
Don't run one conversation per scenario.
If you have:
that's 30,000 conversations.
The repetitions matter because the agent itself is stochastic. You want:
"This scenario succeeds 97% of the time" rather than:
"This scenario worked."
I'd use several independent graders.
Hard/deterministic checks
LLM graders
Voice metrics
Then produce something like:
30,000 conversations
Task success 96.8%
Correct escalation 98.1%
Policy compliance 99.4%
Tool correctness 97.9%
Median latency 720 ms
P95 latency 1.8 s
Failures:
412 missed user intent
287 interruption failures
193 incorrect tool arguments
106 context loss
74 inappropriate escalation
This is where the system becomes genuinely powerful.
Production call
↓
Failure detected
↓
Anonymize + classify
↓
Convert into scenario
↓
Generate 20–100 variants
↓
Run against new agent
↓
Compare versions
That gives you a continuously growing test suite instead of repeatedly inventing hypothetical tests. OpenAI describes a related deployment-simulation approach in which realistic historical conversations are replayed against candidate systems to make pre-deployment evaluation more representative of actual traffic.
I'd structure a 30,000-test run approximately like:
| Layer | Example | Volume |
|---|---|---|
| Unit/tool tests | Correct API arguments | 10,000+ |
| Text simulations | Conversation logic | 10,000 |
| Audio simulations | STT/TTS/interruptions | 5,000 |
| Full real-call simulations | End-to-end | 5,000 |
That gives you scale without making every iteration expensive.
If you're building this yourself, I'd make the core test case a structured object:
{
"scenario": "reschedule_appointment",
"goal": "Move appointment to another available time",
"persona": {
"patience": 0.2,
"verbosity": 0.7,
"interruptions": 0.4,
"confusion": 0.3
},
"facts": {
"current_time": "Tuesday 3 PM"
},
"constraints": [
"Do not cancel without confirmation",
"Must verify identity"
],
"success_criteria": [
"identity_verified",
"new_slot_booked",
"confirmation_given"
]
}
Then your simulator can generate thousands of distinct callers from the same underlying scenario, while your evaluator checks the same objective ground truth.
If I were starting today, I'd prioritize this order:
The key insight is that "10,000 synthetic conversations" isn't inherently useful. Ten thousand nearly identical, cooperative LLM callers can give you a beautifully misleading 99.8% success rate. The value comes from distributional coverage, behavioral realism, audio realism, and reliable grading. Recent research specifically finds a gap between synthetic and real-user behavior, so I'd validate your simulator against a sample of real conversations before trusting its scores.
If you tell me what your stack is (e.g. Vapi, Retell, LiveKit, Twilio, ElevenLabs, custom WebRTC), I can sketch the exact architecture and a 10k-conversation test harness.