Przejdź do treści

Optymalizacja opóźnień agenta głosowego: przewodnik krok po kroku

Opublikowano
Ostatnia aktualizacja

PosłuchajPosłuchaj tego artykułu

Szybkość reakcji agenta głosowego zależy od łącznego opóźnienia między zakończeniem wypowiedzi użytkownika a rozpoczęciem odpowiedzi przez agenta. Rzadko powoduje je jeden wolny komponent. Narasta ono na kilku niezależnych etapach, z których każdy dodaje od kilkudziesięciu do kilkuset milisekund. Aby je zmniejszyć, trzeba wiedzieć, ile czasu zajmuje każdy etap.

Optymalizacja opóźnień agenta głosowego polega na znalezieniu miejsc, w których znika ten czas, i odzyskiwaniu go etap po etapie.

Ten artykuł uzupełnia koncepcyjny przegląd opóźnień. Tamta strona wyjaśnia, czym jest opóźnienie, a ta omawia architekturę i pomiary. Dzięki temu poznasz budżet opóźnień, z którym możesz porównać wyniki, oraz konkretne działania do wdrożenia.

Podsumowanie

  • Czas do pierwszego dźwięku obejmuje cały pipeline, a nie tylko czas inferencji jednego modelu.
  • Czas LLM do pierwszego tokenu i endpointing to dwie największe pozycje.
  • Nakładanie etapów zamiast uruchamiania ich kolejno odzyskuje większość budżetu.
  • Streaming, wybór kodeka i dostrojenie bufora odtwarzacza skracają opóźnienie o mierzalne milisekundy.
  • Mierz wyniki dla każdego regionu we własnym wdrożeniu i raportuj P50 oraz P95.

Definiowanie budżetu opóźnień agenta głosowego

Budżet opóźnień to docelowy łączny czas do pierwszego dźwięku, podzielony między etapy pipeline'u. Każdy etap dostaje limit, a ich suma musi mieścić się w celu. Jego określenie to pierwszy krok, ale też miejsce, w którym najczęściej pojawiają się błędy: inżynierowie mogą mylić dwie podobne, lecz różne wartości.

Pierwsza to opóźnienie inferencji modelu: czas generowania wyniku przez model. W przypadku naszych modeli Flash wynosi ono około 75 ms dla typowych krótkich danych wejściowych, bez narzutu sieci i aplikacji. To wewnętrzna wartość przydatna do porównywania modeli. Nie jest to jednak czas odczuwany przez użytkownika.

Z perspektywy użytkownika kluczowy jest czas do pierwszego dźwięku (TTFA): czas od zakończenia mówienia przez użytkownika do usłyszenia pierwszej próbki odpowiedzi agenta. TTFA jest zawsze większy niż opóźnienie inferencji pojedynczego modelu, ponieważ obejmuje cały pipeline.

Kaskadowy agent głosowy składa się z pięciu etapów:

  • przechwytywanie (mikrofon) -> STT -> LLM -> TTS -> odtwarzanie

Dźwięk jest przechwytywany z mikrofonu, transkrybowany na tekst, wysyłany do modelu językowego, a tekst modelu jest syntezowany z powrotem na mowę, buforowany i odtwarzany. Każdy etap dodaje opóźnienie, a na kilku z nich największy koszt nie jest tym, którego można się spodziewać.

Oto przykład dla anglojęzycznego agenta, którego serwery znajdują się stosunkowo blisko użytkownika. Liczby to orientacyjne zakresy, a nie gwarancje.

What it covers
Capture + endpointing
Mic capture, VAD/turn-detection delay before the turn is considered finished
STT finalization
Last partial to committed transcript after end-of-speech
Network (client to your server to our API)
Round-trips across the pipeline
LLM time-to-first-token
Prompt processing until the first usable token
TTS time-to-first-audio
First TTS request until first audio chunk leaves the model
Player buffering
Client-side buffer before playback begins
End-to-end TTFA
The total latency of the end-to-end pipeline
P50
Capture + endpointing
120 ms
STT finalization
60 ms
Network (client to your server to our API)
60 ms
LLM time-to-first-token
250 ms
TTS time-to-first-audio
110 ms
Player buffering
80 ms
End-to-end TTFA
~680 ms
P95
Capture + endpointing
280 ms
STT finalization
150 ms
Network (client to your server to our API)
160 ms
LLM time-to-first-token
600 ms
TTS time-to-first-audio
220 ms
Player buffering
150 ms
End-to-end TTFA
~1560 ms

Zwykle dwie największe pozycje opóźnienia to czas LLM do pierwszego tokenu oraz opóźnienie endpointingu na początku łańcucha. 

Tabela ułatwia wizualizację pipeline'u, ale sugeruje, że etapy działają wyłącznie kolejno, a tak nie jest. Kilka najważniejszych optymalizacji opóźnień agenta głosowego polega na ich nakładaniu — i właśnie dzięki temu odzyskujesz większość budżetu poniżej.

Speech to Text: optymalizacja opóźnień transkrypcji i endpointingu

Transkrypcja to drugi etap pipeline'u. Jej faktycznym kosztem nie jest sama transkrypcja, lecz decyzja, kiedy użytkownik przestał mówić. Ta sekcja omawia oba aspekty, aby pomóc ci zoptymalizować opóźnienia agenta głosowego.

Transkrypcja odbywa się przed przekazaniem tekstu do LLM. Scribe v2 Realtime (scribe_v2_realtime) zwraca częściowe transkrypcje w około 150 ms i przesyła dane w chunkach audio, więc transkrypcja powstaje, gdy użytkownik jeszcze mówi. Obsługuje PCM od 8 kHz do 48 kHz oraz kodowanie mu-law, co ma znaczenie w sekcji o kodekach poniżej. Częściowe wyniki po 150 ms są mało kosztowne.

Większym kosztem opóźnienia jest endpointing: chwila, w której system uznaje, że użytkownik faktycznie zakończył swoją wypowiedź.

Voice Activity Detection (VAD) dzieli mowę na podstawie ciszy — i właśnie tu narasta czas. Jeśli na przykład czekasz 700 ms ciszy, zanim uznasz turę za zakończoną, dodajesz 700 ms do każdej tury, niezależnie od samej transkrypcji. Tego opóźnienia nie widać w benchmarku dokładności transkrypcji, ale jest bardzo odczuwalne w prawdziwej rozmowie. Często jest to największe kontrolowalne opóźnienie w całym pipeline'ie, więc warto zacząć właśnie od niego.

Endpointing to kompromis między szybkością reakcji a przerywaniem. Krótki próg ciszy sprawia, że agent odpowiada szybko, ale może przerwać użytkownikowi w środku zdania podczas naturalnej pauzy. Długi próg jest bezpieczny, lecz spowalnia działanie. W praktyce trzy zmiany optymalizujące opóźnienia w zamianie mowy na tekst to:

  1. Dostrój próg ciszy: Ustaw najniższą wartość, która nie ucina naturalnych pauz użytkowników, a potem mierz wskaźnik przerwań na produkcji zamiast zgadywać.
  2. Dodaj fizyczne zdarzenie sterujące: Użyj ręcznego potwierdzenia, gdy aplikacja rozpoznaje koniec tury na podstawie innego sygnału, np. zwolnienia przycisku push-to-talk lub zdarzenia UI, zamiast czekać na timer VAD.
  3. Nakładaj pracę z LLM: Wcześnie przekazuj częściowe wyniki dalej. Podawaj stabilne części transkrypcji do LLM i poprawiaj je, jeśli końcowa transkrypcja się różni. To forma wykonania spekulacyjnego, która ukrywa opóźnienie endpointingu za przetwarzaniem promptu przez LLM.

Więcej informacji o Scribe v2 Realtime znajdziesz na stronie funkcje zamiany mowy na tekst oraz na stronie produktu zamiana mowy na tekst w czasie rzeczywistym.

Wpływ LLM na opóźnienie

Model językowy zwykle w największym stopniu wpływa na TTFA, więc nakładanie etapów daje tu największe korzyści w optymalizacji opóźnień agenta głosowego. Kluczowe jest to, że agent nie potrzebuje całej odpowiedzi, zanim zacznie mówić.

Najwięcej budżetu opóźnień odzyskasz, streamując tokeny z LLM i przekazując je do TTS od razu po otrzymaniu, w chunkach wyznaczanych przez granice zdań lub fraz. Buforuj tokeny do granicy zdania, a następnie syntezuj to zdanie, gdy kolejne jest jeszcze generowane:

const SENTENCE_END = /(?<=[.!?])\s+/;

async function* speakLlmStream(tokens: AsyncIterable<string>) {
  let buffer = "";
  for await (const token of tokens) {
    buffer += token;
    const parts = buffer.split(SENTENCE_END);
    buffer = parts.pop() ?? ""; // keep the incomplete fragment
    for (const sentence of parts) {
      if (sentence.trim()) yield* synthesize(sentence.trim());
    }
  }
  if (buffer.trim()) yield* synthesize(buffer.trim());
}

async function* synthesize(text: string) {
  const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
    text,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  yield* stream;
}

W długich rozmowach wybierz TTS WebSocket, aby otwarte połączenie mogło odbierać tekst stopniowo bez ponownego kosztu ustanawiania połączenia dla każdego zdania. Do limitu współbieżności liczy się tylko czas aktywnego generowania audio przez model, więc bezczynny otwarty WebSocket jest niemal bezkosztowy.

Text to Speech: streaming i wybór głosu

Text to Speech to etap, na którym możesz najdokładniej określić opóźnienie. Są tu dwie główne dźwignie: sposób streamowania audio oraz wybrany głos.

Flash v2.5 (eleven_flash_v2_5) to model do użycia w agencie. Zapewnia około 75 ms inferencji dla krótkich danych wejściowych, obsługuje 32 języki i przyjmuje do 40 000 znaków na żądanie.

Wartość 75 ms dotyczy tylko inferencji. Pozycja TTS TTFA w budżecie powyżej jest większa, ponieważ oprócz inferencji uwzględnia czas podróży danych w obie strony oraz harmonogramowanie na serwerze.

Największą dźwignią jest tu streaming. Jeśli poprosisz o pełne audio i na nie zaczekasz, użytkownik będzie czekać na syntezę całego klipu, zanim cokolwiek usłyszy. Przy streamingu użytkownik słyszy pierwszy chunk zaraz po jego wygenerowaniu, a reszta dociera, gdy już słucha. Streaming nie przyspiesza modelu — po prostu zaczyna przekazywać wynik użytkownikowi, gdy model wciąż go generuje.

Przewodnik jak streamować omawia streaming HTTP, a przewodnik po WebSocket w czasie rzeczywistym opisuje ścieżkę WebSocket, której potrzebujesz, gdy przekazujesz tokeny z LLM.

Zainicjuj klienta raz i używaj go ponownie przy każdym wywołaniu poniżej:

import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";

const elevenlabs = new ElevenLabsClient({ apiKey: process.env.ELEVENLABS_API_KEY });

Następnie utwórz strumień i przekazuj go dalej na bieżąco:

const stream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
  text: "Your call is connected. How can I help today?",
  modelId: "eleven_flash_v2_5",
  outputFormat: "mp3_44100_128",
});

for await (const chunk of stream) {
  // forward each chunk to your audio sink as it arrives
}

Drugą dźwignią jest wybór głosu, który także wpływa na opóźnienie. Głosy domyślne, syntetyczne i Instant Voice Clones (IVC) syntezują szybciej niż Professional Voice Clones (PVC), ponieważ PVC mają dodatkową złożoność modelu zwiększającą narzut każdej generacji. W przypadku agenta z rygorystycznymi wymaganiami co do opóźnień opcją o najmniejszym opóźnieniu jest Flash z IVC lub głosem domyślnym.

Wybór rozmiaru chunków streamingu

Gdy tokeny płyną do TTS, a audio wraca, kolejną decyzją jest rozmiar fragmentów i wielkość bufora odtwarzacza przed rozpoczęciem odtwarzania.

Mniejsze chunki szybciej docierają do odtwarzacza, zmniejszając opóźnienie do pierwszego bajtu, kosztem większej liczby wiadomości i nieco większego narzutu na chunk. Większe chunki są wydajniejsze w przesyle, ale użytkownik dłużej czeka na pierwszy. W agentach interaktywnych wybieraj mniejsze chunki na początku wypowiedzi, bo użytkownik czeka właśnie na pierwszy; kolejne docierają, gdy audio jest już odtwarzane, więc ich rozmiar ma mniejsze znaczenie.

Odtwarzacz odpowiada za znaczną część pozostałego opóźnienia. Większość odtwarzaczy audio nie zaczyna odtwarzania po pierwszym bajcie. Buforują niewielką ilość danych, aby uniknąć zacięć, jeśli strumień na chwilę zwolni. Domyślny bufor 500 ms jest powszechny i bezpośrednio zwiększa odczuwane opóźnienie. Jego zmniejszenie oznacza niewielki wzrost ryzyka zacięć w zamian za niższe TTFA, a właściwa wartość zależy od jittera sieciowego między serwerem a klientem:

  • Przy stabilnym połączeniu — odtwarzaniu po stronie serwera lub kliencie w tej samej lokalizacji — bufor 50–150 ms jest zwykle bezpieczny i zauważalnie skraca TTFA.
  • Przy niestabilnym połączeniu mobilnym lub między regionami większy bufor zapobiega słyszalnym przerwom, które są gorsze niż powodowane przez niego opóźnienie.

Dokładna konfiguracja zależy od twojego przypadku użycia i priorytetów.

Wybór kodeka

Miejsce docelowe audio powinno decydować o żądanym kodeku. Zwracamy formaty takie jak mp3_44100_128, mp3_22050_32, pcm_16000, pcm_24000 i ulaw_8000. Dopasowanie natywnego formatu transportu usuwa etap transkodowania, co pomaga zoptymalizować opóźnienia agenta głosowego.

W telefonii, np. Twilio i podobnych usługach, używaj ulaw_8000. Sieć telefoniczna działa end-to-end w 8 kHz mu-law, więc żądanie tego formatu bezpośrednio eliminuje etap transkodowania w pipeline'ie i odpowiada wymaganiom operatora. Synteza audio o wyższej jakości nie daje tu korzyści, bo sieć telefoniczna natychmiast obniży jego próbkowanie; tylko zwiększysz opóźnienie, nie zyskując nic słyszalnego.

Do WebRTC i odtwarzania w przeglądarce używaj PCM (pcm_24000 lub pcm_16000) albo formatu MP3. PCM nie jest skompresowany, więc klient nie musi go dekodować. Usuwa to niewielkie opóźnienie dla każdego chunka i jest wygodne, gdy bezpośrednio zasilasz pipeline Web Audio. MP3 zajmuje mniej miejsca w transmisji, co pomaga przy ograniczonych połączeniach, kosztem lekkiego dekodowania po stronie klienta.

Geografia i odległości sieciowe

Każda optymalizacja powyżej zakłada, że dane mają do pokonania krótką drogę. Geografia wyznacza dolną granicę budżetu opóźnień, dlatego warto ją sprawdzić przed dostrajaniem czegokolwiek innego.

Obsługujemy żądania z klastrów w Ameryce Północnej, Europie i Azji Południowo-Wschodniej oraz automatycznie kierujemy każde żądanie do najbliższego klastra. Przejście danych w obie strony przez publiczny internet trwa zwykle od 20 do 200 ms, zależnie od bliskości geograficznej, i nie da się tego skrócić bez zmiany lokalizacji infrastruktury.

Agent, który działa niemal natychmiast w San Francisco, niedaleko klastra w Ameryce Północnej, może wydawać się powolny użytkownikowi w Azji Południowej, którego ruch dwukrotnie przekracza ocean w każdej turze.

Rozwiązaniem jest umieszczenie serwerów aplikacji blisko użytkowników, a nie tylko blisko nas. Jeśli twoi użytkownicy są w Europie, uruchom backend agenta w Europie, aby odcinek od użytkownika do twojego serwera był krótki; nasze routowanie obsłuży wtedy odcinek od twojego serwera do modelu z pobliskiego klastra.

Samodzielny pomiar opóźnień agenta głosowego

Wartości w tabeli budżetu opóźnień powyżej są orientacyjnymi zakresami do planowania. Wartości, według których wdrażasz rozwiązanie, powinny pochodzić ze skryptu takiego jak ten, uruchomionego we własnym środowisku.

Poniższa instrumentacja mierzy TTFA dla samego etapu TTS — czas od żądania do pierwszego chunka audio — w wielu próbach i raportuje percentyle. Uruchom ją w tym samym regionie, w którym działają twoje serwery, a nie na komputerze deweloperskim. Zakłada użycie klienta elevenlabs z wcześniejszego przykładu:

const VOICE_ID = "JBFqnCBsd6RMkjVDRZzb";
const TEXT = "Thanks for waiting. I have pulled up your account and I can help with that now.";
const TRIALS = 50;

async function measureTtfa(): Promise<number | null> {
  const start = performance.now();
  const stream = await elevenlabs.textToSpeech.stream(VOICE_ID, {
    text: TEXT,
    modelId: "eleven_flash_v2_5",
    outputFormat: "mp3_44100_128",
  });
  for await (const _chunk of stream) {
    return performance.now() - start; // first chunk -> stop the clock
  }
  return null;
}

function percentile(values: number[], p: number): number {
  const v = [...values].sort((a, b) => a - b);
  const k = (v.length - 1) * (p / 100);
  const lo = Math.floor(k);
  const hi = Math.min(lo + 1, v.length - 1);
  return v[lo] + (v[hi] - v[lo]) * (k - lo);
}

const samples: number[] = [];
for (let i = 0; i < TRIALS; i++) {
  const ttfa = await measureTtfa();
  if (ttfa !== null) samples.push(ttfa);
  await new Promise((r) => setTimeout(r, 300)); // space requests, don't measure your own queueing
}

console.log(`trials: ${samples.length}`);
console.log(`P50:    ${percentile(samples, 50).toFixed(0)} ms`);
console.log(`P95:    ${percentile(samples, 95).toFixed(0)} ms`);

Kilka rzeczy, o których warto pamiętać:

  • Raportuj P50 i P95: Skup się na nich, a nie na średniej. Średnia ukrywa ogon rozkładu, a to on sprawia, że agent wydaje się zawodny. P95 opisuje doświadczenie z jednej na dwadzieścia tur. 
  • Testuj według lokalizacji: Uruchamiaj ten sam skrypt z każdego obsługiwanego regionu i przechowuj wyniki osobno.
  • Rozstawiaj żądania dla dokładności: Zachowuj odstępy między żądaniami (setTimeout powyżej). Jeśli wyślesz je wszystkie naraz, zmierzysz własne kolejkowanie zamiast usługi. Po przekroczeniu limitu współbieżności żądania są kolejkowane według priorytetu, co zwykle dodaje około 50 ms, a po przekroczeniu przepustowości otrzymasz HTTP 429.
  • Mierz cały łańcuch opóźnień: Rozszerz ten sam schemat pomiaru na pozostałe etapy. Umieść finalizację STT, pierwszy token LLM i uruchomienie odtwarzacza w tych samych nawiasach performance.now(), a wypełnisz pełną tabelę budżetu własnymi wartościami i zobaczysz, który etap zaatakować najpierw.

Dzięki tym wskazówkom samodzielnie zmierzysz opóźnienia agenta głosowego. Następnie będziesz wiedzieć, którymi priorytetami zająć się najpierw.

Co najbardziej zmniejsza opóźnienia agenta głosowego?

Jeśli szukasz szybkich działań, na których warto się skupić, te zmiany dadzą największy efekt.

Mniej więcej w kolejności wpływu możesz zastosować te metody, aby zmniejszyć opóźnienie agenta:

  • Rozpoczynaj pracę LLM na stabilnych częściach STT, aby ukryć opóźnienie endpointingu.
  • Streamuj tokeny LLM do TTS na granicach zdań, aby synteza pierwszego zdania nakładała się na generowanie drugiego.
  • Streamuj audio TTS do odtwarzacza i zmniejsz jego bufor do najniższej wartości tolerowanej przez jitter sieciowy.
  • Aby uzyskać TTS o najmniejszym opóźnieniu, używaj Flash z głosem domyślnym lub IVC i dopasuj kodek do transportu (ulaw_8000 dla telefonii, PCM lub MP3 dla przeglądarki/WebRTC).
  • Umieść serwery blisko użytkowników i mierz wyniki dla każdego regionu, ponieważ odcinki sieciowe są realne i nierówne.

Więcej szczegółowych technik znajdziesz w przewodniku dla deweloperów jak optymalizować opóźnienia. Kompletne przykłady znajdziesz w szybkim starcie API i przewodniku po streamingu. 

Chcesz szybciej uzyskać dostęp do dostrojonych kaskad agentów? ElevenAgents wdraża ten pipeline z gotowymi optymalizacjami nakładania etapów.

Twórz agentów głosowych z niskimi opóźnieniami dzięki ElevenAgents

Optymalizacja opóźnień agenta głosowego wymaga mierzenia każdego etapu, a następnie nakładania etapów, aby najwolniejsze działały w tle już wykonywanej pracy. Możesz ręcznie zbudować i dostrajać taką kaskadę przez kilka iteracji, korzystając z opisanych wzorców, albo zacząć od pipeline'u z gotowymi optymalizacjami opóźnień.

ElevenAgents wdraża pełną kaskadę — od streamowanego STT, przez przekazywanie tokenów z LLM, po Flash TTS — z wbudowanymi technikami nakładania etapów. Zamiast zaczynać od zera, dostroisz progi pod wydajność najważniejszą dla ciebie.

Zacznij z ElevenAgents i utwórz agenta już dziś lub skontaktuj się ze sprzedażą , aby dowiedzieć się więcej.

Najczęstsze pytania o optymalizację opóźnień agenta głosowego 

Podobne artykuły

Twórz z najwyższej jakości audio AI