Realtime Speech to Text onder 200 ms: een architectuurgids
- Gepubliceerd
- Laatst bijgewerkt
LuisterenLuister naar dit artikel
Realtime Speech to Text (STT) transcribeert audio actief terwijl iemand spreekt en geeft de woorden binnen enkele honderden milliseconden als tekst terug. STT-latency laag houden is echter evenzeer een architectuurvraagstuk als een modelvraagstuk. Engineers moeten rekening houden met transport, chunking, end-pointing en het capturepad, die elk latency toevoegen. Inefficiëntie in een van deze onderdelen kan je budget van 200 ms overschrijden.
Deze gids biedt een praktisch systeem waarmee je realtime Speech to Text-pipelines kunt bouwen, vanaf de transportlaag. We richten ons op Scribe v2 Realtime, dat gedeeltelijke transcripties produceert met ongeveer 150 ms modellatency, meer dan 90 talen ondersteunt, PCM-audio (8 kHz-48 kHz) en mu-law accepteert, en Voice Activity Detection en handmatige commitcontrole biedt voor het finaliseren van segmenten.
We volgen hoe audio de server bereikt, hoe hypotheses uitgroeien tot vastgelegde tekst, wat in-streamfuncties kosten en hoe je audio correct vastlegt en doorstuurt.
Samenvatting
- Voor het bouwen van realtime Speech to Text-systemen is architectonische afstemming nodig, zodat de latency in de hele pipeline laag blijft.
- WebSocket is voor de meeste pipelines de juiste standaardkeuze, al biedt WebRTC diverse voordelen en is het complexer.
- Voice Activity Detection verzorgt handsfree segmentatie, terwijl handmatige commit je applicaties een override geeft wanneer ze weten dat de beurt voorbij is.
- Partials zijn voorlopig en finals zijn vastgelegd, dus je moet ze verschillend weergeven.
- Kleine PCM-chunks van ongeveer 100 ms minimaliseren de latency tot de eerste partial.
WebSocket versus WebRTC voor realtime Speech to Text
Voordat transcriptie kan plaatsvinden, moet audio van de bron naar de herkenner reizen. Het kanaal dat je kiest, bepaalt de minimale latency voor alles wat volgt. Er zijn twee bruikbare opties om audio bij de transcriptielaag te krijgen.
WebSocket is een langdurig, geordend, betrouwbaar en bidirectioneel kanaal via TCP. Je opent een verbinding, stuurt binaire audioframes omhoog en leest transcriptgebeurtenissen terug. Het is eenvoudig aan zowel client- als serverzijde, werkt door bedrijfsproxies en firewalls die HTTPS al toestaan, en wordt ondersteund door elke browser en serverruntime.
De beperking van WebSocket is dat het op TCP draait. Als een pakket verloren gaat, verzendt TCP het opnieuw en houdt het latere data tegen totdat het gat is opgevuld. Onder goede netwerkomstandigheden merk je dit niet. Bij pakketverlies leidt dit tot head-of-line blocking: een korte onderbreking waarbij audio zich ophoopt en vervolgens in een burst arriveert.
WebRTC is gebouwd voor realtime media. Het verstuurt media via UDP (met SRTP), waardoor een verloren pakket de stream niet stillegt; de pipeline gaat door. Het bevat een jitterbuffer die variatie in aankomsttijden van pakketten opvangt, regelt NAT-traversal met ICE/STUN/TURN zodat peers achter routers verbinding kunnen maken, en heeft eigen mechanismen voor audiocapture en encoding.
Meestal heb je TURN-servers nodig voor clients die niet rechtstreeks verbinding kunnen maken, en moet de serverzijde een mediastream beëindigen in plaats van een bytestream te lezen.
Dit zijn de afwegingen in één oogopslag:
Voor de meeste use cases is WebSocket de juiste optie. Gebruik het wanneer je clients een degelijke verbinding hebben en jij het capturepad beheert: server-naar-serverpipelines, desktopapps, browserapps op breedband en de meeste contactcenterbackends waarbij audio al op een andere manier op je server arriveert.
Kies WebRTC wanneer je rechtstreeks audio vastlegt op consumentenapparaten met onbetrouwbare mobiele netwerken, wanneer je al een WebRTC-stack gebruikt voor tweerichtingsaudio (bijvoorbeeld een voice agent die ook terugspreekt), of wanneer realtimegedrag met weinig verlies belangrijker is dan eenvoud van implementatie.
De rest van deze gids gebruikt WebSocket-transport voor de verbinding met de herkenner, omdat dit de bewegende onderdelen zichtbaar houdt en voor de meeste teams het juiste startpunt is. Niets hiervan is specifiek voor WebSocket, dus je kunt later een WebRTC-mediapad ervoor plaatsen, de audio op de server naar PCM decoderen en dezelfde chunks doorsturen naar de pipeline.
Partials en definitieve transcripties: tussentijdse resultaten uitgelegd
Een realtimeherkenner wacht niet op een volledige zin voordat hij tekst teruggeeft. In plaats daarvan produceert hij een voortdurende stroom van gissingen die nauwkeuriger worden naarmate er meer audio arriveert, en legt ze vervolgens vast. Het verschil tussen die twee statussen begrijpen, maakt het onderscheid tussen een transcript dat levendig aanvoelt en een transcript dat kapot aanvoelt.
Een partiale (tussentijdse) hypothese is de beste inschatting van het model op basis van de tot nu toe ontvangen audio. Partials zijn bewust instabiel. Naarmate er meer audio binnenkomt, herziet het model eerdere woorden: "Ik wil" kan "Ik wil twee kaartjes" worden zodra latere context de ambiguïteit oplost. Ze arriveren snel (dit is wat het latencycijfer van ~150 ms beschrijft) en zijn bedoeld om overschreven te worden.
Een definitieve hypothese is een vastgelegd segment dat niet meer verandert. Zodra een segment is gefinaliseerd, gaat de herkenner verder en beschrijven volgende hypotheses latere audio. Finals zijn wat je opslaat, naar een LLM stuurt of als transcript bewaart.
Het onderscheid tussen partials en finals bepaalt drie dingen die misgaan als je dit onderscheid vervaagt:
- Gebruikerservaring: Door partials te tonen voelt een transcript live: de gebruiker ziet woorden verschijnen terwijl die spreekt, wat bevestigt dat de microfoon werkt en het systeem luistert.
- End-pointing: Partials geven je een continu signaal van spraakactiviteit. Samen met VAD helpen ze je bepalen wanneer de spreker echt is gestopt.
- Timing in vervolgstappen: In een voice agent-pipeline zijn de stappen: audio in, daarna Speech to Text, dan een LLM, vervolgens Text to Speech, en ten slotte audio uit. Je kunt al speculatief werk starten op basis van partials en dit bevestigen bij finals. Dat verlaagt de waargenomen reactietijd, maar soms moet je speculatief werk weggooien.
Geef partials en finals verschillend weer. Een eenvoudig, effectief patroon is om één aanpasbare "huidige regel" te koppelen aan de nieuwste partial en deze toe te voegen aan een transcript waar alleen aan wordt toegevoegd wanneer er een final arriveert:
Geef vastgelegde tekst visueel weer als definitieve tekst en de huidige tekst in een lichtere of cursieve stijl, zodat de gebruiker begrijpt dat die nog kan veranderen.
End-pointing en Voice Activity Detection (VAD)
Weten wat er is gezegd, is slechts de helft van het werk. Een herkenner moet ook weten wanneer een gedachte is geëindigd. Die beslissing bepaalt wanneer je een segment finalizeert en, bij een agent, wanneer het systeem begint te reageren.
End-pointing is de beslissing dat een uiting is geëindigd. Te vroeg finaliseren onderbreekt gebruikers midden in een zin. Te laat finaliseren laat een agent stil blijven nadat de gebruiker duidelijk klaar is.
Scribe v2 Realtime biedt twee aanvullende mechanismen:
- Voice Activity Detection segmenteert audio op basis van stilte: De herkenner detecteert wanneer spraak overgaat in aanhoudende stilte en gebruikt die grens om automatisch een segment te finaliseren. VAD is de juiste standaard voor conversatie-interfaces, omdat het zich aanpast aan een natuurlijk spreekritme zonder dat je timings handmatig hoeft bij te houden.
- Handmatige commitcontrole: Met handmatige commitcontrole bepaalt je applicatie onafhankelijk van stilte wanneer het huidige segment wordt gefinaliseerd. Je stuurt een commit-signaal, de herkenner sluit het huidige segment af en geeft een final terug. Dit is het juiste hulpmiddel wanneer je applicatie al weet dat de beurt voorbij is: wanneer een push-to-talk-knop wordt losgelaten, bij een actie als "verzenden" of door een extern beurtnamebeleid.
De twee werken goed samen. Een typische voice agent gebruikt VAD voor handsfree gebruik en biedt handmatige commit als override, zodat een gebruiker die pauzeert om na te denken niet wordt onderbroken, maar een gebruiker die op een knop tikt onmiddellijk een grens krijgt.
De stiltedrempel is een echte afweging zonder universeel juiste waarde:
- Een korte timeout na einde van spraak (bijvoorbeeld finaliseren na ~200-400 ms stilte) zorgt dat het systeem responsief voelt. Maar het onderbreekt ook gebruikers die van nature tussen zinsdelen pauzeren, waardoor één gedachte in meerdere segmenten wordt gesplitst en bij een agent een voortijdige reactie wordt geactiveerd.
- Een lange timeout (bijvoorbeeld ~800-1200 ms) tolereert natuurlijke pauzes en houdt uitingen intact, maar zorgt voor een merkbare vertraging voordat het systeem reageert.
Er is hiervoor geen globale constante; stem de drempel af op de interactie:
- Dicteren en notities maken tolereren langere pauzes, omdat gebruikers midden in een zin nadenken. Kies eerder voor langere time-outs en vertrouw op VAD.
- Command-and-control en transactionele agents profiteren van kortere time-outs met handmatige commit, omdat beurten kort en duidelijk zijn.
- Meertalige sprekers of sprekers die de taal niet als moedertaal hebben, pauzeren vaker. Reken daarom op meer stilte voordat je finalizeert.
Met deze tips kun je een effectief end-pointing-systeem bouwen en dichter bij realtime Speech to Text komen.
In-streamfuncties: taalherkenning en sprekerdiarisatie
Streamingherkenning kan meer dan alleen woorden produceren. Elk extra signaal dat je opvraagt, beïnvloedt echter latency en stabiliteit. De vuistregel is om alleen in te schakelen wat de live ervaring nodig heeft en de rest uit te stellen tot een batchverwerking.
Met automatische taalherkenning kan Scribe v2 Realtime de gesproken taal identificeren uit de meer dan 90 ondersteunde talen, zonder dat je die vooraf hoeft op te geven. Het model heeft daarvoor wel een kort stuk audio nodig om dit met vertrouwen te bepalen, dus de eerste partials van een stream kunnen minder stabiel zijn terwijl de taal wordt vastgesteld. Als je de taal al weet, neemt het opgeven daarvan deze ambiguïteit weg en levert het doorgaans stabielere vroege partials op.
Sprekerdiarisatie koppelt spraak aan afzonderlijke sprekers en bepaalt wie wat zei. Bij batchtranscriptie is dit relatief eenvoudig, omdat het model het hele bestand ziet. Bij streaming is het lastiger: de herkenner moet een sprekerlabel toewijzen op basis van alleen de tot dan toe ontvangen audio, en een label voor vroege audio moet mogelijk worden herzien zodra er meer van de stem van die spreker te horen is. Behandel sprekerlabels in streaming op dezelfde manier als partiale tekst: voorlopig totdat het segment is gefinaliseerd.
Timing op woordniveau en entiteitscontext volgen dezelfde logica. Hoe meer metadata per token je opvraagt, hoe meer zowel het model als de verbinding moet verwerken. Voor de meeste realtime-UI's heb je alleen live tekst en segmentgrenzen nodig; gedetailleerde metadata kun je uitstellen tot een batchverwerking na het gesprek met Scribe v2.
Audioformaten voor streaming: PCM en mu-law
Transport- en herkenningslogica krijgen de meeste aandacht, maar een verrassend groot deel van bugs in de praktijk ontstaat een laag lager: in de manier waarop je audio encodeert en in chunks verdeelt. Het juiste formaat en de juiste chunkgrootte kiezen is de goedkoopste winst voor Speech to Text-latency.
PCM (lineair, 16-bits signed, little-endian) is het formaat om te gebruiken wanneer je de capture beheert. Hogere sample rates bevatten meer akoestische details: 16 kHz is de standaardondergrens voor spraakherkenning en doorgaans voldoende; 8 kHz is van telefoonkwaliteit en verliest hoogfrequente inhoud. Gebruik de sample rate die bij je bron past. Het heeft geen voordeel om telefonieaudio van 8 kHz te upsamplen naar 48 kHz, omdat die informatie niet terug te halen is.
Mu-law op 8 kHz is het telefonieformaat. Als je gesprekken inneemt van een provider zoals Twilio, arriveert de audio als mu-law van 8 kHz en kun je die beter in dat formaat doorsturen dan twee keer transcoderen. Door het bronformaat te behouden, voorkom je resamplingartefacten en een onnodige conversiestap.
Chunkgrootte is de factor die de waargenomen latency het meest rechtstreeks bepaalt. Je verstuurt audio in chunks en de herkenner produceert partials zodra chunks aankomen. Kleinere chunks zorgen voor vaker updates en minder latency tot de eerste partial; grotere chunks betekenen minder berichten en iets meer context per inferentie. Een praktisch bereik is 20-250 ms audio per chunk. Als concreet referentiepunt: bij mono 16-bits PCM van 16 kHz is één seconde audio 32.000 bytes, dus een chunk van 100 ms is ongeveer 3.200 bytes.
Microfooninput vastleggen in de browser
In de browser is het juiste hulpmiddel de Web Audio API met een AudioWorklet. De worklet draait op de audiothread voor rendering, ontvangt audio in kleine frames en heeft geen last van jank op de main thread zoals de oudere ScriptProcessorNode. De taak is om de native float-samples van de browser om te zetten naar 16-bits PCM en die door te geven aan de main thread, die ze via de WebSocket doorstuurt.
De kern van de workletprocessor is de conversie van float naar PCM:
De pipeline in code
De pipeline heeft drie bewegende onderdelen: een browserclient die de microfoon vastlegt en PCM naar je server streamt, een Node-server die audio doorstuurt naar Scribe v2 Realtime en transcripties terugstuurt, en een scriptbare client die PCM streamt vanuit een bestand of telefoniebridge.
De server stuurt door in plaats van de herkenner rechtstreeks aan de browser bloot te stellen, om één belangrijke reden: je ElevenLabs API-sleutel is geheim en mag nooit in client-side code verschijnen. De server bewaart de sleutel. Als de browser toch rechtstreeks met de herkenner moet communiceren, maak dan server-side een kortdurend token voor eenmalig gebruik aan en geef dat aan de client in plaats van de API-sleutel.
Browserclient
De client opent een WebSocket naar je server, legt de microfoon vast via de bovenstaande worklet en stuurt elk PCM-frame door zodra het wordt geproduceerd. Binnenkomende events (door de server al genormaliseerd naar { type, text }) bepalen de eerdere partial/final-status:
Serverrelay
De server opent één herkennerverbinding per client, bewaart de API-sleutel op de server, stuurt binaire PCM rechtstreeks door en normaliseert herkenner-events naar de stabiele vorm { type, text } die de client gebruikt:
Alles wat endpoint-specifiek is, is beperkt tot de twee adapterfuncties hieronder. Vervang de veldnamen door de exacte namen uit de Speech to Text-referentie; de rest van de pipeline verandert niet:
Scriptbare backendclient
Voor backendpipelines en voor de benchmark hieronder werkt dezelfde herkennerverbinding zonder browser: lees PCM uit elke bron, verstuur het in het realtime tempo van de chunks en lees events terug. De API-sleutel en URL komen, net als op de server, uit de omgeving.
Speech to Text-latency en woordfoutpercentage benchmarken
Zowel latency als woordfoutpercentage varieert met de spreker, de taal, de akoestische omstandigheden, de audiolengte, je netwerkpad naar de dichtstbijzijnde regio van elke provider en de huidige belasting van elke service.
Een resultaat dat je meet vanaf een laptop in de ene stad, is niet representatief voor je productie-infrastructuur in een andere stad. Voer de harness uit vanaf infrastructuur die op productie lijkt, met audio die op je echte input lijkt, en rapporteer bereiken en verdelingen in plaats van losse getallen.
De enige latency- en nauwkeurigheidscijfers die ertoe doen, zijn de cijfers die je meet met je eigen audio vanaf infrastructuur die op productie lijkt. Hier volgt een gids voor het benchmarken van Speech to Text-latency.
Wat je moet meten voor Speech to Text-latency
Hieronder staan de belangrijkste metrics die je moet meten bij het benchmarken van realtime Speech to Text-latency:
- Tijd tot eerste partial: Van het versturen van de eerste audiochunk tot het ontvangen van de eerste niet-lege partial.
- Vertraging van partial tot final: Van de laatste audiochunk van een uiting tot de definitieve hypothese.
- Woordfoutpercentage (WER): WER op het gefinaliseerde transcript vergeleken met een menselijke referentie, identiek berekend voor alle systemen.
- Stabiliteitsveranderingen: Hoeveel partials worden herschreven vóór finalisering. Deze metric geeft een indicatie van hoeveel de live-UI zichtbaar zal veranderen.
Controles
Voer verschillende controles in je experiment uit om onbetrouwbare data te voorkomen en alles consistent te houden.
Dit zijn de belangrijkste controles voor het benchmarken van Speech to Text-latency:
- Identieke audio: Gebruik voor elk systeem dezelfde bestanden, sample rate en encoding.
- Identiek tempo: Stream elk systeem met dezelfde realtime chunkcadans (bijvoorbeeld chunks van 100 ms).
- Herhaal en rapporteer verdelingen: Voer elk bestand gedurende de dag vaak uit; rapporteer de mediaan en staartwaarden (p50/p95).
- Identieke referenties en scoring: Normaliseer tekst op dezelfde manier (hoofdletters, interpunctie, getallen) voordat je WER berekent.
- Vermeld regio en netwerk: Geef aan waar de harness draaide en wat het pad naar elke provider was.
Door al deze elementen gelijk te houden, genereer je nauwkeurigere metrics.
Basisstructuur van de harness
De meetkern neemt een provideradapter en registreert de tijd tot de eerste partial, de finaliseringsvertraging en veranderingen in partials:
Het woordfoutpercentage is een standaard Levenshtein-afstand op tokenniveau voor genormaliseerde tekst. Zet zowel de referentie als de hypothese op dezelfde manier om naar kleine letters en verwijder interpunctie voordat je het berekent, anders meet je je normalizer in plaats van het model. Plaats deze meting in een loop die elk bestand ongeveer tien keer per provider uitvoert en de mediane tijd tot de eerste partial en mediane WER (p50/p95) rapporteert, omdat één sample sterk wordt beïnvloed door netwerkvariatie.
Om dit te laten werken, lever je twee dingen aan. Schrijf eerst één StreamFn-adapter per systeem. De scriptbare client hierboven is er al één; adapters voor de andere systemen volgen hetzelfde contract (audioPath, onEvent, result) en zetten result.lastChunkSentAt wanneer de laatste audiochunk wordt verstuurd. Laad vervolgens je audiobestanden en referenties en roep measures daarop aan. Voer dit uit vanaf een machine die je deployment vertegenwoordigt, met audio die je gebruikers vertegenwoordigt, en je hebt een vergelijking die je kunt reproduceren.
Samenvatting: realtime Speech to Text bereiken
In dit artikel hebben we veel architectuurwijzigingen behandeld waarmee je je systeem iteratief kunt verbeteren en dichter bij realtime Speech to Text kunt komen.
Een realtime STT-systeem voor productie draait om een handvol beslissingen:
- Transport: Kies WebSocket voor eenvoud en gecontroleerde netwerken, en WebRTC wanneer je verliesbestendigheid nodig hebt en audio vastlegt op consumentenapparaten.
- Partials en finals: Behandel partials als voorlopig en finals als vastgelegd, en geef ze verschillend weer zodat gebruikers de live tekst vertrouwen.
- End-pointing: Gebruik VAD voor handsfree segmentatie, handmatige commit als override en stem de stiltedrempel af op de interactie in plaats van op een constante.
- In-streamfuncties: Schakel in-streamfuncties alleen in waar de live ervaring ze nodig heeft en stel de rest uit tot een batchverwerking met Scribe v2.
- Audioformaat: Leg audio vast in kleine PCM-frames, verstuur chunks van ~100 ms en gebruik voor telefonie het bronformaat.
- Benchmarking: Stel de afwegingen tussen nauwkeurigheid en latency empirisch af op je eigen audio en doelmetric.
- API-beveiliging: Bewaar je API-sleutel op de server, of maak tokens voor eenmalig gebruik aan voor directe clientverbindingen.
Als je wilt zien hoe je latency in een voice agent optimaliseert, hebben we daar ook een gids voor geschreven.
Bouw realtime Speech to Text-systemen met Scribe v2 Realtime
Scribe v2 Realtime produceert partials met ongeveer 150 ms modellatency. Of je gebruikers die waarde ervaren of iets hogers, hangt af van de architectuur eromheen, het deel dat jij beheert. Met de strategieën uit dit artikel bouw je een betere pipelinearchitectuur die latency verlaagt en de klantervaring verbetert.
Als je meer wilt weten, bekijk dan het overzicht van Speech to Text-mogelijkheden, lees onze modelreferentie voor de volledige lijst met functies en talen, en bekijk de realtimeproductpagina's: realtime Speech to Text API en realtime Speech to Text.
Wanneer je klaar bent om te bouwen, maak je gratis ElevenLabs-account en stream vandaag nog je eerste transcript.
Veelgestelde vragen over realtime Speech to Text-latency
Tadas Petra is Developer Relations Engineer en helpt ontwikkelaars bouwen met de productreeks van ElevenLabs. Hij is ook de oprichter van Hungrimind, een onderwijsplatform voor ontwikkelaars. Eerder was hij Lead Developer Advocate bij Agora en docent bij Zero To Mastery.



