Optimización de la latencia para agentes de voz
TTS en streaming, fragmentación de respuestas y minimización de la latencia hasta la primera palabra.
Optimización de la latencia para agentes de voz es una lección gratuita de AI Agents en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de AI Agents, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de AI Agents incluye 4 lecciones en total.
Por qué es importante la latencia en la voz
En un chat de texto, un retraso de 3 segundos es aceptable. En una conversación de voz, cualquier demora superior a 1,5 segundos resulta poco natural y rompe el flujo de la conversación.
La latencia de voz tiene tres componentes principales: el tiempo de transcripción (STT), el tiempo de procesamiento del LLM (TTFT + generación) y el tiempo de síntesis TTS. Optimizar cada uno de ellos produce una mejora considerable en la experiencia del usuario.
Medición del presupuesto de latencia
Antes de optimizar, mida cada componente. Instrumente el ciclo con llamadas de medición de tiempo para saber dónde se emplea realmente el tiempo.
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 en streaming: reproducir mientras se genera
La mayor mejora individual de latencia se obtiene con el TTS en streaming. En lugar de esperar a que se sintetice todo el audio, empiece a reproducir el primer fragmento en unos 200 ms mientras el resto se genera simultáneamente.
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()TTS en streaming oración por oración
El enfoque de streaming más práctico consiste en dividir la respuesta del LLM en oraciones y sintetizarlas y reproducirlas una por una. La primera oración comienza a reproducirse en unos 300 ms.
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: optimización del tiempo hasta el primer token
TTFT (Time to First Token) es el retraso entre el envío de la solicitud al LLM y la recepción del primer token de la respuesta. Optimizar el TTFT permite que los usuarios empiecen a escuchar la respuesta antes.
Utilice respuestas del LLM en streaming y envíe los tokens a TTS en cuanto se detecte el final de una oració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)Generación anticipada de respuestas habituales
Algunas respuestas del agente son predecibles: saludos, mensajes de error e indicadores de que está pensando («Permítame comprobarlo.»). Genere su audio por anticipado al iniciar el agente para reproducirlo al instante y sin latencia.
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')Latencia del TTS local frente al TTS en la nube
El TTS en la nube añade el tiempo de ida y vuelta de la red (unos 100-300 ms). Para respuestas cortas o frases de uso frecuente, un motor TTS local puede ser más rápido, aunque a costa de la calidad de la voz.
pyttsx3 es la opción de TTS sin conexión más sencilla para Python.
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 standardElección de un modelo LLM más rápido
La elección del modelo afecta considerablemente al TTFT. GPT-4o-mini es entre 5 y 10 veces más rápido que GPT-4o para la mayoría de las tareas de los agentes de voz. Utilice el modelo más pequeño que cumpla los requisitos de calidad.
# 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}"')
Caché de respuestas para preguntas repetidas
Los usuarios suelen hacer repetidamente las mismas preguntas o preguntas similares. Almacene en caché las respuestas del LLM y TTS para consultas idénticas, de modo que pueda servirlas al instante cuando se repitan.
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 textObjetivo de latencia de extremo a extremo
Con todas las optimizaciones implementadas, un agente de voz bien construido debería tardar menos de 1 segundo desde el final del habla del usuario hasta el inicio de la respuesta del agente.
# 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')Solapamiento de transcripción asíncrona
Mientras el agente genera y pronuncia su respuesta, comience inmediatamente a grabar la siguiente entrada del usuario. Solapar las etapas del pipeline reduce el tiempo de espera entre turnos.
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()Comprobación de conocimientos
¿Qué optimización individual suele proporcionar la mayor reducción de latencia en los agentes de voz?
Resumen: optimización de la latencia para agentes de voz
Conjunto de optimizaciones para la latencia de voz: transmisión de las respuestas del LLM (inicie la TTS en los límites de las frases a medida que llegan los tokens), reproducción de la TTS frase por frase (reproduzca el audio mientras se sintetiza), caché de TTS (reproducción instantánea de frases repetidas), respuestas frecuentes pregeneradas (saludos y frases de espera) y selección de un modelo LLM rápido (gpt-4o-mini para consultas sencillas).
Objetivo: menos de 1 segundo desde el final del habla del usuario hasta el primer byte de audio. Mida cada componente: la transcripción suele representar el 40 % de la latencia total. La TTS local sacrifica calidad por velocidad; para la mayoría de los agentes, la TTS en la nube con streaming por frases ofrece un mejor equilibrio.
Preguntas frecuentes
¿La lección «Optimización de la latencia para agentes de voz» es gratis?
Sí — el texto completo de «Optimización de la latencia para agentes de voz» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de AI Agents, actualiza a CoddyKit PRO. El curso de AI Agents incluye 4 lecciones en total.
¿Qué aprenderé en «Optimización de la latencia para agentes de voz»?
TTS en streaming, fragmentación de respuestas y minimización de la latencia hasta la primera palabra. Practicas AI Agents con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar AI Agents?
No se requiere experiencia previa. AI Agents en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Optimización de la latencia para agentes de voz»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de AI Agents?
Sí. Cada lección de AI Agents incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Conversión de voz a texto con Whisper y Deepgram
- Conversión de texto a voz en las respuestas de agentes
- Creación de un ciclo de conversación por voz
- Optimización de la latencia para agentes de voz