Sesli Aracılar İçin Gecikme İyileştirmesi
Akış TTS'si, yanıtı parçalara bölme ve ilk sözcük gecikmesini en aza indirme.
Sesli Aracılar İçin Gecikme İyileştirmesi, CoddyKit'te ücretsiz bir AI Agents dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, AI Agents öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. AI Agents kursu toplamda 4 dersten oluşur.
Ses İçin Gecikme Neden Önemlidir
Metin sohbetinde 3 saniyelik bir gecikme kabul edilebilir. Sesli konuşmada 1,5 saniyenin üzerindeki her gecikme doğal olmayan bir his verir ve konuşma akışını bozar.
Ses gecikmesinin üç ana bileşeni vardır: yazıya dökme süresi (STT), LLM işleme süresi (TTFT + üretim) ve TTS sentezleme süresi. Her birini optimize etmek, birleşerek kullanıcı deneyimini büyük ölçüde iyileştirir.
Gecikme Bütçesini Ölçme
Optimizasyondan önce her bileşeni ölçün. Zamanın gerçekten nerede harcandığını görmek için döngüye zamanlama çağrıları ekleyin.
import time
def voice_loop_timed():
timing = {}
# 1. Record
t0 = time.perf_counter()
audio, sr = record_until_silence()
timing['record'] = time.perf_counter() - t0
# 2. Transcribe
t0 = time.perf_counter()
audio_path = audio_to_file(audio, sr)
user_text = transcribe_file(audio_path)
timing['transcription'] = time.perf_counter() - t0
# 3. LLM
t0 = time.perf_counter()
agent_text = agent.respond(user_text)
timing['llm'] = time.perf_counter() - t0
# 4. TTS
t0 = time.perf_counter()
say(agent_text)
timing['tts'] = time.perf_counter() - t0
print('Latency breakdown:')
total = sum(timing.values())
for step, duration in timing.items():
print(f' {step:15} {duration*1000:.0f}ms ({duration/total*100:.0f}%)')TTS Akışı: Üretim Sırasında Oynatma
En büyük tekil gecikme kazanımı TTS akışından gelir. Tüm sesin sentezlenmesini beklemek yerine, geri kalanı eşzamanlı olarak oluşturulurken ilk ses parçasını yaklaşık 200 ms içinde oynatmaya başlayın.
import threading
import queue
import sounddevice as sd
import numpy as np
import io
def stream_tts_and_play(text, voice='nova'):
audio_queue = queue.Queue()
def synthesize():
from openai import OpenAI
import os
client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
with client.audio.speech.with_streaming_response.create(
model='tts-1', voice=voice, input=text
) as response:
for chunk in response.iter_bytes(chunk_size=4096):
audio_queue.put(chunk)
audio_queue.put(None) # sentinel
synth_thread = threading.Thread(target=synthesize, daemon=True)
synth_thread.start()
# Collect and play (buffering first 2 chunks for smooth start)
audio_buffer = b''
min_buffer = 8192
import pygame
pygame.mixer.init()
while True:
chunk = audio_queue.get()
if chunk is None:
break
audio_buffer += chunk
if len(audio_buffer) >= min_buffer:
# play buffer ...
pass # simplified — real impl streams to sounddevice
synth_thread.join()Cümle Cümle TTS Akışı
En pratik akış yaklaşımı, LLM yanıtını cümlelere bölüp bunları tek tek sentezlemek ve oynatmaktır. İlk cümle yaklaşık 300 ms içinde oynatılmaya başlar.
import re
import concurrent.futures
def split_sentences(text):
return [s.strip() for s in re.split(r'(?<=[.!?])\s+', text) if s.strip()]
def tts_and_play_streaming(text, voice='nova'):
sentences = split_sentences(text)
if not sentences:
return
# Prefetch next sentence while current is playing
executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
# Kick off synthesis of first sentence
futures = []
for sentence in sentences:
futures.append(executor.submit(cached_tts, sentence, voice))
# Play each sentence as soon as it's ready
for future in futures:
audio_path = future.result(timeout=10)
play_audio_file(audio_path)
executor.shutdown(wait=False)
# Key insight: while sentence 1 plays (~2 seconds), sentence 2 is being synthesized in parallelTTFT: İlk Belirtece Kadar Süreyi Optimize Etme
TTFT (İlk Belirtece Kadar Süre), LLM isteğinin gönderilmesiyle yanıtın ilk belirtecinin alınması arasındaki gecikmedir. TTFT'yi optimize etmek, kullanıcıların yanıtın başlangıcını daha erken duymasını sağlar.
Akışlı LLM yanıtlarını kullanın ve bir cümle sınırı algılanır algılanmaz belirteçleri TTS'ye aktarın.
import openai
import os
client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
def stream_llm_to_tts(user_text, conversation_history, voice='nova'):
buffer = ''
stream = client.chat.completions.create(
model='gpt-4o-mini',
messages=conversation_history + [{'role': 'user', 'content': user_text}],
stream=True # streaming enabled
)
for chunk in stream:
delta = chunk.choices[0].delta.content or ''
buffer += delta
# Check if a sentence is complete
if buffer.endswith(('.', '!', '?')) and len(buffer) > 20:
sentence = buffer.strip()
print(f'Queuing TTS: {sentence[:50]}')
# Synthesize and play immediately (non-blocking)
audio_path = cached_tts(sentence, voice)
play_audio_file(audio_path)
buffer = ''
# Flush remaining buffer
if buffer.strip():
audio_path = cached_tts(buffer.strip(), voice)
play_audio_file(audio_path)Yaygın Yanıtları Önceden Üretme
Bazı ajan yanıtları öngörülebilirdir: karşılama ifadeleri, hata iletileri ve düşünme göstergeleri ("Bunu sizin için kontrol edeyim."). Bunların seslerini başlangıçta önceden üretin; böylece sıfır gecikmeyle oynatılabilirler.
import os
PRE_GENERATED = {
'greeting': 'Hello! How can I help you today?',
'thinking': 'Let me look that up for you.',
'not_found': 'I could not find information on that. Could you rephrase?',
'error': 'Sorry, something went wrong. Please try again.',
'goodbye': 'Goodbye! Have a great day.',
'clarify': 'Could you give me a bit more detail?',
'working_on_it': 'Working on it, this may take a moment.'
}
pre_gen_cache = {}
def prewarm_responses(voice='nova'):
for key, text in PRE_GENERATED.items():
audio_path = cached_tts(text, voice=voice)
pre_gen_cache[key] = audio_path
print(f'Pre-generated {len(pre_gen_cache)} common responses')
def instant_response(key):
path = pre_gen_cache.get(key)
if path:
play_audio_file(path)
else:
say(PRE_GENERATED.get(key, ''))
# Usage: while LLM is thinking, play a stall message instantly
instant_response('thinking')Yerel TTS ile Bulut TTS Gecikmesi Karşılaştırması
Bulut TTS, ağa gidiş-dönüş süresi ekler (yaklaşık 100-300 ms). Kısa yanıtlar veya sık kullanılan ifadeler için yerel bir TTS altyapısı daha hızlı olabilir; ancak ses kalitesi düşebilir.
pyttsx3, Python için en basit çevrimdışı TTS seçeneğidir.
import pyttsx3
import time
# Local TTS with pyttsx3
def local_tts(text, voice_index=0, rate=175):
engine = pyttsx3.init()
voices = engine.getProperty('voices')
if voice_index < len(voices):
engine.setProperty('voice', voices[voice_index].id)
engine.setProperty('rate', rate) # words per minute
t0 = time.perf_counter()
engine.say(text)
engine.runAndWait()
print(f'Local TTS latency: {(time.perf_counter()-t0)*1000:.0f}ms')
# Comparison (rough benchmarks):
# pyttsx3 (local): ~50ms start, robotic quality
# OpenAI TTS-1: ~200-400ms, good quality
# ElevenLabs turbo: ~150-250ms, excellent quality
# OpenAI TTS-1-hd: ~400-800ms, best quality
# Recommendation:
# Real-time voice agent -> OpenAI TTS-1 or ElevenLabs turbo
# Quality recording -> OpenAI TTS-1-hd or ElevenLabs standardDaha Hızlı Bir LLM Modeli Seçme
Model seçimi TTFT'yi büyük ölçüde etkiler. GPT-4o-mini, çoğu ses ajanı görevinde GPT-4o'dan 5-10 kat daha hızlıdır. Kalite gereksinimlerini karşılayan en küçük modeli kullanın.
# Model latency comparison (rough benchmarks for voice agent use case):
MODEL_BENCHMARKS = {
'gpt-4o-mini': {'ttft_ms': 300, 'quality': 'good', 'cost': 'very low'},
'gpt-4o': {'ttft_ms': 800, 'quality': 'excellent', 'cost': 'medium'},
'claude-haiku': {'ttft_ms': 250, 'quality': 'good', 'cost': 'very low'},
'claude-sonnet': {'ttft_ms': 600, 'quality': 'excellent', 'cost': 'medium'},
'llama3-8b': {'ttft_ms': 100, 'quality': 'decent', 'cost': 'free (local)'},
}
# Strategy: use fast model for simple factual queries,
# fall back to powerful model for complex reasoning
def select_model(question):
# Short, simple questions -> fast model
if len(question.split()) < 15:
return 'gpt-4o-mini'
# Complex, multi-step -> better model
if any(kw in question.lower() for kw in ['analyze', 'compare', 'explain why', 'write a']):
return 'gpt-4o'
return 'gpt-4o-mini'
if __name__ == '__main__':
for q in ['What time is it in Tokyo?', 'Analyze why sales dropped last quarter and compare to competitors']:
print(f'{select_model(q)!r} chosen for: "{q}"')
Tekrarlanan Sorular için Yanıtları Önbelleğe Alma
Kullanıcılar genellikle aynı veya benzer soruları tekrar tekrar sorar. Tekrarlanan sorulara anında yanıt verebilmek için aynı sorgulara ait LLM + TTS yanıtlarını önbelleğe alın.
import hashlib
import json
RESPONSE_CACHE = {} # in production: use Redis with TTL
def get_cache_key(user_text):
# Normalize: lowercase, strip punctuation
import re
normalized = re.sub(r'[^a-z0-9 ]', '', user_text.lower()).strip()
return hashlib.md5(normalized.encode()).hexdigest()
def cached_agent_respond(user_text, voice='nova'):
key = get_cache_key(user_text)
if key in RESPONSE_CACHE:
print('Response cache hit!')
entry = RESPONSE_CACHE[key]
play_audio_file(entry['audio_path'])
return entry['text']
# Cache miss
text = agent.respond(user_text)
audio_path = cached_tts(text, voice=voice)
RESPONSE_CACHE[key] = {'text': text, 'audio_path': audio_path}
play_audio_file(audio_path)
return textUçtan Uca Gecikme Hedefi
Tüm optimizasyonlar uygulandığında, iyi tasarlanmış bir sesli ajan, kullanıcının konuşmasını bitirmesinden ajanın yanıt vermeye başlamasına kadar geçen süreyi 1 saniyenin altında tutmalıdır.
# Target latency budget breakdown (1000ms total):
LATENCY_BUDGET = {
'silence_detection_end': 0, # user stops speaking
'audio_processing': 50, # RMS check, noise gate
'transcription_whisper': 400, # STT API call
'llm_ttft': 300, # time to first token (gpt-4o-mini)
'tts_first_sentence': 200, # first sentence synthesized
'playback_start': 1000 # TOTAL: user hears response within 1 second
}
# Optimizations applied:
# - Streaming LLM responses (saves 200-500ms vs waiting for full response)
# - Sentence-by-sentence TTS (play while rest generates)
# - gpt-4o-mini instead of gpt-4o (saves 500ms TTFT)
# - TTS cache for common phrases (saves 200ms on cached phrases)
# - Pre-generated stall messages ('Let me check...' plays instantly)
print('Target: < 1000ms from speech end to first audio byte played')
print('Typical with optimizations: 600-900ms')Eşzamansız Metne Dönüştürme Çakışması
Ajan yanıtını oluşturup seslendirirken bir sonraki kullanıcı girdisini kaydetmeye hemen başlayın. İşlem hattı aşamalarını üst üste yürütmek, konuşma turları arasındaki boşta geçen süreyi azaltır.
import threading
import time
class PipelineOverlapAgent:
def __init__(self):
self.next_audio = None
self.recording_thread = None
def start_background_recording(self):
def record():
self.next_audio = record_until_silence()
self.recording_thread = threading.Thread(target=record, daemon=True)
self.recording_thread.start()
def get_recorded_audio(self, timeout=30):
if self.recording_thread:
self.recording_thread.join(timeout=timeout)
audio = self.next_audio
self.next_audio = None
return audio
def conversation_turn(self, audio, sr):
# Transcribe and run agent
text = transcribe_file(audio_to_file(audio, sr))
if not text.strip():
return
# Start recording NEXT turn BEFORE speaking
# (user can start speaking as soon as agent starts)
response = agent.respond(text)
# Start next recording while speaking
self.start_background_recording()
# Speak current response
speak_with_interrupt(response)
# Next audio is already being captured in background
return self.get_recorded_audio()Bilgi Kontrolü
Sesli ajanlarda genellikle en büyük gecikme azalmasını hangi tek optimizasyon sağlar?
Özet: Sesli Ajanlar için Gecikme Optimizasyonu
Ses gecikmesi optimizasyonu katmanları: LLM yanıtlarını akış halinde alma (belirteçler geldikçe cümle sınırlarında TTS'yi başlatma), cümle cümle TTS oynatma (sentezleme sürerken oynatma), TTS önbelleğe alma (tekrarlanan ifadeleri anında yeniden oynatma), yaygın yanıtları önceden oluşturma (selamlamalar, zaman kazandıran ifadeler) ve hızlı LLM modeli seçimi (basit sorgular için gpt-4o-mini).
Hedef: Kullanıcının konuşmasını bitirmesinden ilk ses baytına kadar 1 saniyenin altında bir süre. Her bileşeni ölçün — yazıya dönüştürme, toplam gecikmenin çoğu zaman %40'ını oluşturur. Yerel TTS, hız karşılığında kaliteden ödün verir; cümleleri akış halinde sunan bulut TTS, çoğu ajan için daha iyi bir dengedir.
Sıkça Sorulan Sorular
“Sesli Aracılar İçin Gecikme İyileştirmesi” dersi ücretsiz mi?
Evet — “Sesli Aracılar İçin Gecikme İyileştirmesi” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve AI Agents kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. AI Agents kursu toplamda 4 dersten oluşur.
“Sesli Aracılar İçin Gecikme İyileştirmesi” dersinde ne öğreneceğim?
Akış TTS'si, yanıtı parçalara bölme ve ilk sözcük gecikmesini en aza indirme. AI Agents ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
AI Agents öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te AI Agents, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.
“Sesli Aracılar İçin Gecikme İyileştirmesi” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu AI Agents dersinde kod yazıp çalıştırabilir miyim?
Evet. Her AI Agents dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Whisper ve Deepgram ile Konuşmadan Metne
- Aracı Yanıtlarında Metinden Sese
- Sesli Konuşma Döngüsü Oluşturma
- Sesli Aracılar İçin Gecikme İyileştirmesi