Case study · 2nd round · Founding AI Voice Engineer

A voice companion people can talk to at 2 AM.
Here is how I would build it.

Three parts, the way you asked for them. BUILD is the architecture I would actually start tomorrow. DECIDE is the one question worth your attention as founder, and why I think the obvious question is the wrong one. SHIP is what one engineer can really have running by Day 30. Everything below is labeled and sourced, and I left the gaps as open questions instead of papering over them.

Sobhan Bahrami · case study for Volker Hein · November 2026
$4.97 / $2.04
my cost per 60 minute conversation on the managed stack vs the self assembled one, arithmetic included below
< 800 ms
time to first audio target at p50, with p95 under 1.5 s, measured end to end per turn
Day 30
Closed beta with the full safety stack running
2 live agents
below, one on the cascade I defend and one on the native realtime model. Talk to both

Two companions are live on this page. Talk to them.

Cascade Aria runs the cascade I defend below: Qwen 3.6, expressive voice with delivery tags, a grounding knowledge base, crisis procedures, and guardrails. Native Aria runs ElevenLabs' own native realtime model (v1 Max) end to end. Same persona, two architectures. Try "show me your range" on Cascade Aria, interrupt either one mid sentence, or stop talking for eight seconds and watch the silence handling.

Cascade Aria

Qwen 3.6expressive voicegrounding KBcrisis proceduresguardrails

The pipeline I defend in this document. Long pauses, barge in, delivery tags like [chuckles], and the safety stack around it.

Native Aria

Eleven Realtime v1 Maxnative speech to speechsame voicesame persona

The native path as a live pilot: one model, audio in and audio out, so you can feel the difference yourself.

Both agents use the platform's real features: procedures, knowledge base with retrieval, memory search, expressive tags like [chuckles], crisis guardrails, post-call evaluation criteria, and sentiment tracking. Honest note: this is a quick demo build I put together for this page. It is not fine tuned, not curated to its best level of capability, and it is missing details on purpose. Its job is to make the architecture tangible enough to challenge, not to be the product.
The one page view BUILD · DECIDE · SHIP▾

Build

ElevenLabs Agents in Custom voice mode. Scribe v2 Realtime for speech to text, turn_v3 endpointing in patient mode, Qwen 3.6 as the conversational model at low reasoning effort, Eleven v3 Conversational with Expressive Mode for the voice. React Native and Expo for iOS and Android, Next.js for the web client, FastAPI and Postgres behind it, Langfuse for tracing and secondary evals.

One pipeline, every stage behind a config seam, so nothing in this stack is a trap.

Full choice, why, and when to replace it in section 2.

Decide

The backbone question, cascade versus native speech to speech, is not the decision that matters. Latency has already reached parity and an abstraction layer keeps the choice reversible.

What I would want your call on this week is different: the crisis escalation posture, whether we serve minors, and the line between companion and therapy in everything we say out loud. Those are founder decisions because they define the product's legal and moral identity.

Evidence and trade offs in section 4.

Ship

  • Day 1: a real conversation, with latency measured per turn
  • Day 3: the long pause harness and the full safety path, end to end
  • Day 5: safety regression set in CI, consent and delete working
  • Day 14: grounded memory, a 45 to 60 minute soak, native speech to speech pilot
  • Day 30: closed beta with the safety stack running, real cost per session measured

Only what is shipped and testable, section 5.

The architecture I would start tomorrow BUILD▾

This is the whole system. The client is the product you described, iOS and Android with real time full duplex voice. The heart is the conversational pipeline, and the two blocks under it are what make it a mental health product rather than a voice demo: safety tools on one side, memory on the other. The green line is the audio going home.

Client iOS / Android, React Native + Expo Next.js web, shared TypeScript Transport Managed WebRTC LiveKit based, zero ops ElevenLabs Agents, Custom voice mode Scribe v2 Realtime speech to text turn_v3 endpointing patient, speculative, fillers Qwen 3.6 effort low, tool calls Eleven v3 Conversational Expressive Mode, emotional control Pilot lane, native speech to speech measured at Day 14 before we commit Safety tools crisis triage as a structured procedure locale correct escalation resources guardrail retry, or end call Memory tools rolling summary plus typed facts honest answers about what she remembers hard delete path for GDPR erasure Backend, FastAPI modular monolith Postgres for facts, consent, sessions. Redis. S3 recording vault behind explicit consent session state machine, resume via summary cost and latency telemetry from Day 1 Observability and evals Langfuse traces and secondary evals time to first audio p50/p95, barge-in success blind listening sessions, safety regression CI platform Experiments for safe rollouts Async safety pass a second look at the transcript, in parallel post call eval criteria, human review queue on call escalation SOP why: Llama Guard recall alone is 69% Latency numbers in this document always say what was measured. Vendor stage latency and end to end conversational latency are different things and I never compare them without saying so. Every box has a replacement trigger in section 2. That is the part I care about most.
Why one pipeline and not a pool of listeners. I built a dual listener setup on my interview platform, so I know what it buys and what it costs. For this product it adds latency budget risk and cost without buying safety. The one parallel process I keep is the async safety pass over the transcript, and it never touches the live turn.
Every important choice, and when I would undo it BUILD▾

The format is the one you asked for. My pick first, then why, then the trigger that would make me swap it out. If a row has no honest replacement trigger, it is a bet, not a decision.

LayerMy pickWhyWhen I would replace it
ClientReact Native + Expo, Next.js webOne codebase for iOS and Android, and I can share the API layer with the web client. This is also what I proposed to you earlier and I stand behind it.Native modules if WebRTC stability or thermal behavior on long calls forces my hand.
TransportElevenLabs managed WebRTCZero transport ops on Day 1. I ran this exact transport live in production on my interview platform for months and I know its failure modes.Data residency or self hosting requirements (LiveKit Cloud or OSS), or scale economics flipping the math in section 6.
Turn takingturn_v3, patient, speculativeIt is the only option with an independent duplex behavior score today, 95.8% on Full Duplex Bench. Patient mode fits therapeutic pauses. Soft timeout fillers kill dead air without false interruptions.My own long pause harness showing false cutoffs above 5% at the patience level users tolerate.
Speech to textScribe v2 RealtimeBundled in the platform minute, and it captures non verbal events like laughs and pauses, which carry emotional context.At scale, AssemblyAI bills session time including idle at about a third of the streamed rate, which matters when people sit in silence. Or medical vocabulary, where Scribe Medical exists.
Conversational modelQwen 3.6 (qwen36-35b-a3b), effort lowCo located inside the platform pipeline, no cross provider tail latency. Non deprecated as of my 2026-11-01 catalog check. Your report of Gemini 3 and 3.1 hiccups is documented in real bug trails, and Speko measured 63.1% dead air turns on gemini-3.5-flash-lite.Silent turn rate above 2% over a rolling week, or p95 first audio above 1.2 s, and I move to Claude Haiku, the only model measured with zero dead air and zero tool silence.
VoiceEleven v3 Conversational + Expressive ModeIt is the only off the shelf voice with explicit emotional control plus emotional continuity across turns. For an empathic companion that is the product.Cost at scale, or if I need prosody guarantees nobody sells: fine tuning a self hosted Kokoro class model, which is also the 40x cost lever.
MemoryRolling summary + typed fact storeSteady state context stays around 2 to 5k tokens at any session length, and the hard delete path for GDPR lives in tables I own.When cross session recall needs temporal provenance, I add a temporal knowledge graph, but only after building the erasure overlay first.
SafetyFour layers, not one modelStreaming triage as a structured procedure, async classifier over the transcript, post call evals, human SOP. No single classifier is trustworthy, Llama Guard recall is 69%.Classifier models swap freely behind the tool seam. The escalation policy is yours to change, not mine.
ObservabilityLangfuse + platform evals + blind listeningTraces stay vendor neutral because I plan to swap stages. Voice quality claims only survive if people actually listen.Add LiveKit simulations if I ever self assemble the stack.
The curation story worth one minute. My first draft config used gemini-2.5-flash. When I checked the platform's live model catalog rather than the blog, it turned out to be deprecated with a provider shutdown date of 2026-11-30. The docs page still lists it as supported. I re picked against the live catalog, and I would put a monthly deprecation check in CI from week one. A config is a living thing in late 2026.

What I decided not to build in the first 30 days: multi listener pools, telephony, voice cloning, and any fine tuning. Fine tuning starts after the beta harvests consented data, because training on user conversations without a designed consent path is exactly the trap that sank other products in this space.

The decision that actually matters DECIDE▾

You asked for the single most important technical decision or uncertainty. I want to be direct about my answer, because it is a small twist on the expected one.

The expected answer is the backbone. I think that is the wrong layer. Cascade versus native speech to speech determines latency ceilings, interruption feel, emotion, transcripts, cost, and lock in. All true. But the 2026 evidence says latency parity has arrived, and with an abstraction layer plus a Week 1 eval harness the backbone is reversible. The decisions that are genuinely irreversible are the ones about safety posture and claims, because in this product they become legal identity.
AxisStreaming cascade (my foundation)Native speech to speech (my pilot lane)
Latency, measured755 ms best cascade, time to first audio (arXiv 2603.05413v2, 2026-03, independent)494 ms p50, gpt-realtime conversational latency (Speko live harness, 2026-07-08). Eleven Realtime at 570 to 620 ms TTFA (Artificial Analysis, 2026-10)
Interruptions and silenceConfigurable, and patient mode fits long emotional pausesImplicit but aggressive. Moshi takes the floor on 98% of user pauses and talks through interruptions (Full Duplex Bench, Talking Turns at ICLR 2025)
Transcripts for safety and memoryStructural. Every stage produces text, which is why ElevenLabs' own realtime product is still cascaded under the hoodSeparate ASR with documented mismatch errors. Long session recall falls to 25 to 50% with 17 to 42% hallucinated transcripts. Moshi has no user transcript at all
Emotional controlExplicit. Expressive Mode, delivery rules, tags, and tone that carries across turnsImplicit prosody, no direction API
Cost per 60 minute session$4.97 managed, $2.04 self assembledAbout $5 with cached audio tokens, and about $115 without, because audio context gets re read every turn
Lock inLow. Custom mode keeps every stage swappableModel API lock, softened by realtime compatible endpoints

Now the part I would want your call on. These three are yours, not mine, and this week is not too early:

DecisionWhy it is yours, today
Crisis escalation postureCalifornia SB 243 and the New York companion law require a published self harm protocol, with a private right of action attached. The Garcia settlement showed disclaimers do not protect anyone. What we promise a user alone at two in the morning is a product and moral decision.
Minors, yes or noThe amended COPPA rule treats voiceprints as personal information. Character.AI removed open ended minor chat entirely and 40 state attorneys general still called their voluntary safeguards circumventable.
Companion, never therapyIllinois, Nevada, Rhode Island and Vermont ban unlicensed AI psychotherapy. The words in our marketing copy are evidence in a courtroom, so the boundary has to be drawn before launch copy exists.
Session length reality checkOne platform constraint I found while building the demo: the self hosted speech engine path caps sessions at 40 minutes without a sales conversation. If 60 minute sessions are contractual for us, that is a negotiation, not an engineering problem.

And the strongest argument against my own recommendation, because you should hear it from me first. The counter argument to any flexibility play is that a solo engineer maintaining optionality burns the runway that should go to safety and emotion work. It is a fair hit. My answer is that the optionality here is one eval harness and one config seam, built in Week 1, not a permanent second stack to maintain. The kill criteria in section 5 exist so the architecture can be swapped by measurement, not by taste.

How one turn flows, and what happens when someone asks for help at two in the morning BUILD · UML▾

Two sequences. The top half is an ordinary turn with a barge in and a long pause, the behaviors that decide whether talking to this thing feels human. The bottom half is the situation the whole product exists for: it is late at night, the user is alone, and at some point they say something that means they might hurt themselves. I call it the mid-night case throughout, and how the system behaves in it is the first thing I would want to be challenged on.

:Client (Expo) :Turn engine :Model + tools :Voice (v3 Expr.) :Safety layer audio streams in over WebRTC, continuously stable partials feed the model early; turn_v3 decides when the turn is really over prompt, memory context, and a safety tool call when risk signals appear streaming audio out, first audible word is what I measure as latency barge in: she talks over me, audio ducks and the turn cancels cleanly 8 second silence: she waits. No nagging. That is the patient config doing its job the disclosure. "I do not want to be here anymore." turn and transcript reach the risk triage, same structured path every time severity read, locale correct resources pulled (988, Samaritans, local) she slows down, grounds, stays present. No panic, no lecture she offers the resources and asks one caring direct question after the call: async classifier confirms, eval criteria run, human review queue the review feeds the regression set. Every incident makes the next one less likely
What is really working, day by day SHIP▾

Only what is shipped and testable. If I cannot demonstrate it on the milestone day, it goes to the next milestone or it gets cut.

Day 1
  • A real companion conversation, Expo web client
  • Latency measured per turn and logged
  • Traces in Langfuse from session one
Day 3
  • Long pause harness: 2, 5, 8, 12 second silences with false cutoff rates
  • Full safety path live end to end
  • Rolling summary and fact store on every session
  • Active listening behaviors scored as events
Day 5
  • Safety regression set green in CI
  • Eval suite with p50/p95 dashboards
  • Consent gate and delete endpoint verified
  • Clinical guideline RAG v0 with citation audit
Day 14
  • Grounded memory with the honesty policy
  • 45 to 60 minute soak: drift, loops, reconnects
  • Native speech to speech pilot, blind listened
  • Session duration cap tested head on
Day 30
  • Closed beta, real users, real 30 to 60 minute sessions
  • Full safety stack running, human on call SOP
  • Cost per session measured against the model
  • Kill criteria dashboard running
Kill criteria for my own architecture. Any two of these, for a week, on real beta traffic, and the backbone gets swapped by measurement: first audio p95 above 1.5 s, false cutoffs above 5% on long pauses, native winning blind listening 2 to 1, cost per session above twice the model, or one safety true positive missed by both detection layers. I would rather write the death certificate for my architecture in advance than defend it out of pride.

What genuinely cannot be shortcut, with honest durations: safety review and the published crisis protocol (1 to 2 weeks), consent and the GDPR DPIA (3 to 7 days), the on call SOP (2 to 3 days plus drills), and app store review once mobile ships (1 to 3 weeks, unpredictable). Anything else is negotiable under pressure. These four are not.

The numbers, with the arithmetic BUILD · DECIDE▾

Cost per 60 minute conversation, three complete stacks. Factors sourced, arithmetic shown, and the unknowns flagged as unknowns.

LineManaged platform (Custom mode)Self assembled cascadeNative speech to speech
Platform or transport60 min at $0.08 = $4.80. Silence beyond 10 s bills at 5%, which helps a product where people pause, and I did not count that discount60 min at $0.010 = $0.60included in audio tokens
Speech to textincluded60 min at $0.0025 (idle inclusive) = $0.15included
Model60 min at about $0.003 = $0.17$0.17audio tokens below
Voiceincluded30 min of speech, about 30k characters at $37 per million = $1.12in and out audio tokens
Audio tokensnot applicablenot applicableinput about $0.03 cached at $0.40 per million, or $2.59 uncached. Output about $3.46
Per session$4.97$2.04about $6 cached, or about $115 uncached

At 10,000 conversations a day this is roughly 417 average concurrent calls and enterprise contract territory on any managed stack. The dominant line at scale is the voice, and a fine tuned self hosted TTS is the honest 40x lever there. That is the same model that solves the prosody guarantees problem, which is why the fine tune is planned, not improvised.

Long session context, same discipline. A 45 minute conversation at 150 words per minute is about 10k transcript tokens, which fits comfortably in any modern context window. The expensive regime is native audio, about 81k audio tokens re read on every turn, roughly $115 per session uncached versus $1.44 cached. My rolling summary design holds 2.2 to 4.9k tokens in steady state at any session length. The real risk in long sessions is not context size anyway, it is quality: prosody drift, repetition loops, and memory hallucination. Those get their own soak tests, because no vendor has published 30 to 60 minute streaming evidence and I am not going to pretend otherwise.

When we fine tune, and how we move to our own stack BUILD · SHIP▾

Staying on a managed platform forever is not the plan, and waiting too long to leave is not the plan either. Here is when each move happens and what forces it.

MoveWhenHowWhat triggers it
Fine tune our own TTSAfter the beta harvests consented conversations, so month two at the earliestA Kokoro class model, full fine tune with my own G2P style pipeline. I have done this end to end on an 8 GB GPU before, with an ASR round trip evaluation harness, so this is a known path, not a research projectVoice cost dominating the bill at scale (it is a roughly 40x lever), or we need prosody guarantees nobody sells: emotion arcs across 40 minutes, stable identity, warmth calibration
Behavior fine tuning of the conversational modelOnce transcripts are curated and labeled, around the same windowSupervised fine tuning on curated multi turn examples, then preference tuning on hand labeled pairs. Prompting stays the tool of choice until volume justifies itEval scores plateauing on empathy or safety behavior where prompting is not moving them
Our own model endpoint in the platformAny time, it is a config changeThe platform accepts any OpenAI compatible endpoint, so our FastAPI LLM service slots in without leaving the platformLatency tails from the shared catalog, or cost at scale, or we want a model the catalog does not carry
Self hosted voice stackWhen a contract or regulation forces it, or unit economics say soThe platform's Speech Engine lets our server be the brain while it runs speech to text and voice, or we move to the self assembled cascade with the same eval harness. Agent configs export as JSON through the CLI, so nothing is trappedData residency requirements, HIPAA tier constraints, session length caps, or the per minute platform fee exceeding the cost of running it ourselves
The rule underneath all of it. Every month the eval harness runs against both the current stack and the best alternative. A move happens when a measurement says so, not when a blog post says so.
What the platform gives us, and when I would use each piece BUILD▾

One of the reasons I picked this platform is that most of what a mental health companion needs is already a first class feature instead of custom code. Here is the honest map, including what is live in the demo on this page and what is not.

CapabilityWhat it isWhy and when to use it hereIn the demo?
Knowledge BaseUpload sources (files, URLs, text). Retrieval modes: on demand, every turn, or prompt only. Plus a memory store for cross session factsGrounding techniques, active listening patterns, and crisis resources live here so answers come from a document we control and can audit, with source attribution on every retrieval. On demand mode for facts the agent should pull only when relevant, every turn mode for a short safety card that must always be in reachLive: grounding playbook, retrieval on
ProceduresPlaybooks for one specific task, triggered by what the user says. Free form ones adapt their wording, structured ones run typed steps in a fixed orderFree form for grounding exercises where tone should adapt. Structured for the crisis escalation, because that is exactly the case where a skipped step costs too much. This is how safety behavior stays consistent instead of depending on prompt luckLive: 3 procedures (crisis escalation, grounding, emotional range)
WorkflowsA graph of sub agents with routing and per step controlFor flows with real branching: intake and triage, escalation to a human, multi stage journeys. Not needed for a companion conversation that should feel like one continuous talk, so I would not start hereNot in demo, by choice
GuardrailsFocus, prompt injection, content thresholds (including self harm and medical or legal advice), and custom rules with retry or end call actionsContent guardrails on self harm and medical advice thresholds as a second line behind our procedures. Custom guardrail for the never pretend to be a therapist boundaryLive: content thresholds on
ToolsSystem tools (flag for review, end call, memory search, transfer, skip turn), webhook tools, and MCP servers. Interruptions can be disabled while a tool runsFlag for review on any crisis signal. Interruption suppression during the flag tool so the safety action cannot be talked over. Webhook tools later for on call handoff and human review queuesLive: flag for review, end call, memory search
AnalysisPost call evaluation criteria, structured data collection, sentiment, topic discovery, and source attribution, over the transcriptEvaluation criteria like empathy before advice and safety handled turn quality into numbers we can regress against. Data collection of mood trend and risk flags feeds the learning loop and the review queueLive: 3 criteria, sentiment, topics
TestsSimulation tests with a simulated user, next reply scenario tests, and tool call tests, runnable from dashboard or CLIThe safety regression set runs here in CI from Day 5: crisis cases, escalation cases, tone under distress. Text level tests here, audio level behavior in my own listening harnessNot yet attached, first tests are a Day 5 item
Experiments and versioningImmutable versions, traffic split A/B, instant rollback. Every change to a procedure or prompt is a versionHow a prompt change reaches real users safely, and how a kill criterion reversal actually happens in practiceVersioning on by default
ChannelsWidget today, and WhatsApp, Slack, SMS, telephony behind the same agentWeb widget first because it is where the demo and the beta live. Telephony matters later for accessibility and for crisis scenarios, and it is one of the things I would want your priorities onLive: widget
ObservabilityConversation search, per call transcripts and traces, latency metrics, and an observation layer that groups topics and flags shiftsBetween this and our Langfuse traces we get both the platform view and the vendor neutral one. The vendor neutral one matters because stages will changeTraces on, Langfuse in the plan
How I would challenge myself DECIDE · prep▾

These are the questions I would ask me if I were in your chair. One sentence each, evidence attached in the detailed document.

Why not native speech to speech from day one?
Latency parity already arrived (755 ms cascade versus 494 ms native, independent 2026 measurements), while native still loses transcripts, the thing my safety and memory layers live on, so I run cascade with duplex behavior and pilot native on the same scripts at Day 14, blind listened.
What happens when someone says they want to end their life, alone, at two in the morning?
Structured triage on the turn, she stays present and de escalates, locale correct resources are offered, a parallel classifier confirms, post call evals always run, and the on call SOP governs human follow up, all as a published tested protocol because the law now requires exactly that and disclaimers did not save anyone in the 2025 cases.
What does a 45 minute conversation cost you?
$4.97 managed or $2.04 self assembled per 60 minutes, with the voice line dominating at scale and the self hosted fine tune as the 40x lever.
Where does it break first at 10,000 daily conversations?
Concurrency and the voice bill (417 average concurrent calls, enterprise tier everywhere), then long session quality, which no vendor has evidence for and my Day 14 soak exists to measure.
What is your kill criterion for the launch architecture?
Any two for a week on real traffic: first audio p95 over 1.5 s, false cutoffs over 5% on long pauses, native winning blind listening 2 to 1, cost over twice the model, or one safety miss by both layers.
What did you decide not to build, and why?
Multi listener pools, telephony, voice cloning, and fine tuning in the first 30 days, because each either duplicates what the platform already gives or belongs after consented data exists, and the safety regression set won the time instead.
How do you know it sounds empathic, and stays that way for 40 minutes?
Expressive Mode gives promptable emotional control with cross turn continuity today and I measure it with blind listening and tone under distress regression cases, while saying plainly that long session prosody stability is unproven territory my soak exists to test.
How do you handle GDPR deletion when memory lives in summaries and embeddings?
I store what I own in Postgres with a hard delete path that cascades through transcripts, summaries, facts and embeddings within a month, and no knowledge graph gets adopted before its erasure overlay exists.
Why ElevenLabs rather than the cheapest possible stack?
Day 1 is about learning speed and the empathy layer I cannot build in week one, the Custom mode keeps every stage swappable, and the roughly $3 per session delta buys the only off the shelf emotional control voice on the market, with the $2.04 stack as the planned scale path.
What is your safety evidence that this does not become a lawsuit?
Layered detection because no single classifier is trustworthy, a published crisis protocol in the SB 243 shape, a safety regression set in CI from Day 5, explicit consent data handling, no therapy claims anywhere in copy, and a kill criterion that includes any missed safety true positive.
Sources and dates for every number are in the detailed document and in the w0 to w9 registers. Where I could not verify something, this page says so instead of guessing. Both demo agents run the configuration described above.

Sobhan Bahrami · sobhan.bahrami.v@gmail.com · linkedin.com/in/sobhanbahrami