Construyendo Integraciones de Voz sobre Chatbots Asíncronos
¿Qué se rompe cuando enfrentas un chatbot asíncrono con Amazon Connect + Lex, y cómo mantener la latencia, la interrupción y la transferencia de contexto en un nivel razonable?
Parte de Voice Systems Field Notes
La voz es un medio sincrónico que se encuentra sobre una pila cada vez más asincrónica. La mayoría de los backends de chatbots asumen presupuestos de latencia de varios segundos — los que llaman por voz notan 300 ms.
La forma del problema
Cuando un llamador habla, el flujo típico es:
- Amazon Connect captura el audio y lo transmite a Lex.
- Lex resuelve la intención e invoca un gancho de cumplimiento de Lambda.
- Lambda se distribuye a servicios posteriores — CRM, ticketing, LLM.
- La respuesta regresa, Polly sintetiza, el llamador la escucha.
Cada salto es un presupuesto que no tienes. El backend del chatbot fue construido para chat, donde una respuesta de 2s se siente rápida. En voz, 2s de silencio se siente roto.
Lo que hago en su lugar
async def fulfill(intent, session):
# Pre-fetch de llamadas posteriores probables en el momento en que el llamador comienza una expresión,
# no después de que Lex regrese.
async with asyncio.TaskGroup() as tg:
customer = tg.create_task(crm.lookup(session.caller_id))
history = tg.create_task(history_store.recent(session.id))
return compose_response(intent, customer.result(), history.result())
El truco es pre-fetch especulativo: en el momento en que el llamador comienza a hablar, ya sabes quién es (ANI), de qué cola vino y, por lo general, qué quiere. Comienza las llamadas posteriores de inmediato. Para cuando Lex resuelve la intención, la mitad de la entrada/salida ya está resuelta.
El barge-in lo cambia todo
Si no soportas barge-in, los llamadores que conocen el sistema se sienten castigados. Si lo haces, cada síntesis de Polly en curso se vuelve cancelable. Eso significa que tu Lambda necesita ser idempotente bajo cancelación — y tus métricas necesitan distinguir "el llamador colgó" de "el llamador interrumpió" de "tiempo de espera". Aprendí esto de la manera difícil cuando la "tasa de llamadas caídas" aumentó porque contábamos las interrupciones como caídas.
Transferencia de contexto
El verdadero lío es cuando la voz se escala a un agente. Cualquier cosa que capturaste en el bot — intención, entidades, puntajes de confianza, estado de ánimo del llamador — tiene que llegar a la pantalla del agente antes de que llegue la voz del llamador. Un retraso de 2 segundos se siente como si el agente no estuviera escuchando.
La conclusión
La voz sobre asincrónico no es más difícil que el chat asincrónico. Es un presupuesto diferente. Diseña para barge-in, pre-fetch agresivamente y mide las señales de calidad de llamada por separado de las señales de éxito de intención.
Escrito por
Adrian Romo
Ingeniero Backend Senior que diseña APIs escalables en Python, arquitecturas sobre AWS Lambda, sistemas de voz e integraciones empresariales.
Relacionado
Sigue leyendo
Primitivas Ensambladas vs. una Plataforma
Construí un agente de voz usando primitivas en la nube, y funcionó. Desde entonces, fue reemplazado por una plataforma de voz diseñada específicamente para ese fin, y creo que fue la decisión correcta.
Seis publicaciones al día y el programador que aprendió a decir cuándo
Un pipeline social que publicaba un Reel al día y nada más, porque las cuotas por formato eran techos y nadie solicitaba los otros formatos.
Un planificador que no incorporará nada
La herramienta que decide cómo incorporar un nuevo servicio a mi homelab no tiene la capacidad de incorporarlo. Esa separación es el diseño, no una limitación.
Continúa
¿A dónde sigues?
Explora más textos técnicos, revisa los casos de estudio o escríbeme directo.