Cómo Construimos Voice AI Professional que Todos Pueden Costear

Voice AIConversational AIStartupInnovaciónTech17 min de lectura
Cómo Construimos Voice AI Professional que Todos Pueden Costear

Cómo Construimos Voice AI Professional que Todos Pueden Costear

El Problema: Voice AI Funcional es Caro. Voice AI Barato no Funciona.

Durante los últimos meses, construimos Formmy: una plataforma de agentes conversacionales que ayuda a negocios a vender, dar soporte, y calificar leads de forma automatizada.

Comenzamos con chat en la web. Funcionó. Agregamos WhatsApp. También funcionó. Pero siempre supimos que el objetivo final era voz.

La voz es más humana, más accesible, más rápida. Es el canal natural de comunicación. Pero también es el más complejo de implementar.

Cuando empezamos a investigar opciones en diciembre 2025, nos encontramos con un problema clásico:

  • Las soluciones que funcionaban bien (LiveKit + ElevenLabs, OpenAI Realtime API) explotaban el presupuesto

    • Costos prohibitivos para volúmenes medianos
    • Inviable para ofrecer a precio competitivo
  • Las soluciones baratas no funcionaban bien

    • Latencia de 2-3 segundos (conversaciones robóticas)
    • Sin interrupciones naturales (turno forzado)
    • Sin capacidad de ejecutar acciones (buscar en bases de datos, guardar leads)

Hasta que encontramos la solución perfecta.

Resultado final:

  • 97% reducción de costo vs soluciones tradicionales
  • Latencia < 1 segundo (speech-to-speech nativo)
  • Interrupciones naturales (barge-in bidireccional)
  • Acciones en tiempo real (búsqueda, guardar contactos)

Este post documenta los retos que enfrentamos, las soluciones que implementamos, y las lecciones aprendidas (incluyendo 3 bugs críticos que nos costaron días de debugging).


La Decisión: Speech-to-Speech Nativo (y por qué rechazamos 3 alternativas)

El Análisis de Costos

Evaluamos 4 opciones durante 2 semanas:

OpciónCostoLatenciaBarge-inTool Calling
LiveKit + ElevenLabs💰💰💰 Muy alto2-3sManualManual
OpenAI Realtime API💰💰 Alto<1s✅ Nativo✅ Nativo
Deepgram + ElevenLabs💰💰 Alto2-3sManualManual
Nuestra Solución💚 Accesible<1s✅ Nativo✅ Asíncrono

Resultado: Nuestra solución es 20x más económica que OpenAI Realtime y 30x más económica que LiveKit.

Por Qué Rechazamos las Alternativas

OpenAI Realtime API (nuestra primera opción)

  • ✅ Excelente calidad de voz
  • ✅ Latencia baja
  • ✅ Barge-in nativo
  • Costo por minuto muy alto (insostenible para pricing competitivo)
  • ❌ Limitado a modelos de OpenAI (queríamos flexibilidad)

LiveKit + ElevenLabs (nuestra implementación inicial)

  • ✅ Control total sobre infraestructura
  • ✅ Voces de alta calidad (ElevenLabs)
  • Orquestación compleja (4 servicios: WebRTC + STT + LLM + TTS)
  • Costo por minuto muy elevado (suma de múltiples servicios)
  • ❌ Costos ocultos (TURN servers, ancho de banda)
  • ❌ Latencia variable 2-3 segundos (pipeline secuencial)

ElevenLabs Conversational AI (evaluamos en beta)

  • ✅ Setup rápido
  • ✅ Calidad de voz excelente
  • ❌ No controlas el LLM interno
  • ❌ Difícil integrar base de conocimiento propia
  • ❌ Limitado a casos de uso simples (sin tools complejos)

Por Qué Elegimos Speech-to-Speech Nativo

1. Speech-to-speech nativo = latencia predecible

  • No hay pipeline STT → LLM → TTS (elimina 2 saltos de red)
  • Audio entra, audio sale
  • Latencia consistente < 1 segundo

2. Tool calling asíncrono = conversaciones reales

  • El usuario puede interrumpir MIENTRAS un tool se ejecuta
  • El sistema maneja el contexto automáticamente
  • Hace posible casos de uso complejos (búsqueda en bases de datos, cálculos en tiempo real)

3. Barge-in bidireccional = sensación humana

  • El usuario puede interrumpir al agente en cualquier momento
  • El modelo detecta la interrupción del lado del servidor
  • No necesitas implementar VAD complejo

4. Costo 97% menor = viable comercialmente

  • Costo operativo mínimo por minuto
  • Permite ofrecer voice AI a precio competitivo
  • Margen saludable incluso con descuentos por volumen

Los 4 Retos Técnicos Críticos (y Cómo los Resolvimos)

Reto #1: Barge-in que se Sienta Natural

El problema: En voice AI, "barge-in" es la capacidad de interrumpir al agente mientras habla. Sin esto, las conversaciones se sienten robóticas: habla el agente, esperas, hablas tú, esperas.

Suena simple, pero hay un problema oculto: audio generation es más rápido que playback.

Escenario típico:
1. el sistema genera audio chunk #1, #2, #3, #4, #5
2. Cliente reproduce chunk #1
3. Usuario interrumpe
4. ¿Qué haces con los chunks #2, #3, #4, #5 que ya están en tránsito?

Si no los manejas correctamente, el usuario escuchará "audio fantasma" después de interrumpir.

Nuestra solución (iteración 3):

Intentamos 2 enfoques que fallaron:

Enfoque 1: Solo detener playback local

  • Resultado: Audio seguía llegando del servidor, se acumulaba

Enfoque 2: Cerrar WebSocket y reconectar

  • Resultado: Lag de 2-3 segundos en cada interrupción

Enfoque 3 (el que funcionó): Barge-in bidireccional

Client-side (local, inmediato):

  1. Detectar voz del usuario con VAD (Voice Activity Detection)
  2. Si detecta voz MIENTRAS reproduce audio:
    • Detener playback actual
    • Limpiar cola de chunks pendientes (todos)
    • Enviar señal de nuevo turno al servidor
    • Marcar flag: "usuario interrumpió" (skip chunks futuros)

Server-side (confirmación): 3. El servidor detecta la interrupción automáticamente 4. Envía evento de confirmación al cliente 5. Cliente confirma: limpia flags, ready para nuevo input

Resultado: Interrupciones se sienten instantáneas (< 100ms), como conversaciones humanas reales.

Lección crítica: El barge-in es bidireccional o no es barge-in. Necesitas coordinación client-server.


Reto #2: Tool Calling sin Romper el Flujo

El problema: Nuestros agentes necesitan ejecutar acciones en tiempo real:

  • Buscar en base de conocimiento (RAG)
  • Guardar información de contacto (leads)
  • Consultar inventario de productos

Pero los tools toman tiempo (1-2 segundos para búsqueda en vector DB). ¿Cómo hacerlo sin romper el flujo de conversación?

Enfoque tradicional (no funciona bien):

Usuario: "¿Tienes disponible el producto X?"
→ Tool ejecuta (2 segundos de silencio)
→ Usuario piensa que el sistema se congeló
→ Usuario interrumpe frustrado

Nuestra solución: Tool Calling Asíncrono

Nuestro sistema soporta "async tools" nativamente. Esto significa:

✅ El tool se ejecuta EN PARALELO con la conversación ✅ El usuario puede seguir hablando ✅ El sistema usa el resultado cuando está listo ✅ Si el usuario interrumpe, el sistema adapta la respuesta

Ejemplo real:

Usuario: "¿Qué sabes sobre la Tumba 10 de Huitzo?"

→ Agente: "Déjame consultar..." (empieza a responder)
→ [Tool: searchContext ejecutándose EN PARALELO]
→ Usuario interrumpe: "Olvídalo, mejor dime sobre la Tumba 7"
→ [Tool termina, retorna resultado sobre Tumba 10]
→ Agente adapta: "Entiendo, te cuento sobre la Tumba 7..."
   (usa el resultado del tool si es relevante, o lo ignora)

Ventaja clave: Las conversaciones se sienten fluidas. No hay pausas incómodas. El usuario tiene control total.

Lección crítica: Los tools asíncronos son la diferencia entre un bot telefónico y un agente conversacional real.


Reto #3: Detección de Voz sin False Positives

El problema: Para implementar barge-in, necesitas detectar cuando el usuario habla (Voice Activity Detection).

Pero el mundo real es ruidoso:

  • Ruido ambiente (tráfico, oficina, café)
  • Clics del mouse
  • Respiración del usuario
  • Eco del audio del agente

Si tu VAD es muy sensible → false positives (interrupciones fantasma) Si tu VAD es poco sensible → lag (usuario habla y tarda en detectarlo)

Nuestra solución: VAD con Multi-Frame Confirmation

Conceptualmente:

  1. Smoothing: Promediar volumen de los últimos 10 frames (~1 segundo)
  2. Threshold dual: Detectar picos de voz O habla constante
  3. Confirmación: Requiere 2 frames consecutivos de voz (200ms buffer)
  4. Decay asimétrico: Rápido al detectar voz (+2), lento al perderla (-1)

Por qué decay asimétrico:

Usuario: "Quiero comprar [pausa de 200ms] el producto X"
                        ↑
                 Sin decay asimétrico: falsa interrupción aquí
                 Con decay asimétrico: tolera la pausa

Resultado: 0 false positives en testing con ruido ambiente, latencia de detección < 200ms.

Lección crítica: VAD robusto requiere confirmar patrones, no reaccionar a eventos individuales.


Reto #4: Streaming Bidireccional sin Explotar el Servidor

El problema: Voice AI bidireccional significa:

  • Audio entrante del usuario (4096 bytes cada 100ms)
  • Audio saliente de el sistema (chunks variables)
  • Events de control (start, stop, tools)
  • Todo simultáneamente, en tiempo real

Si no manejas esto correctamente:

  • ❌ Memory leaks (audio se acumula en RAM)
  • ❌ Buffer overflows (descartas chunks críticos)
  • ❌ Race conditions (audio llega antes que el "start")

Nuestra solución: Arquitectura de Colas

Conceptualmente:

  1. Input Queue: Bufferear chunks que llegan antes de "audioStart"

    • Max 50 chunks (~2 segundos)
    • Libera cuando se abre el canal de audio
  2. Output Queue: Polling cada 100ms para chunks de el sistema

    • No bloqueante (no espera a que lleguen chunks)
    • Limpia automáticamente al cerrar sesión
  3. Session State Machine: Estados explícitos

    idle → connecting → ready → listening → processing → speaking
    
    • Cada estado tiene acciones permitidas específicas
    • Evita race conditions
  4. Resource Cleanup: Al cerrar sesión

    • Cerrar contenidos abiertos (audio, tools)
    • Liberar WebSocket
    • Calcular duración y créditos

Resultado: Zero memory leaks, maneja 50+ sesiones concurrentes sin problemas.

Lección crítica: Streaming bidireccional requiere arquitectura explícita de colas y estados. No confíes en "just make it work".


Los 3 Bugs Que Casi Matan el Proyecto (y Cómo los Resolvimos)

Bug #1: "Unable to parse input chunk" — 3 Días de Debugging

El síntoma: Sistema funcionaba perfecto. Conversación fluida. Hasta que el usuario preguntaba algo que requería búsqueda en la base de conocimiento.

Usuario: "¿Qué sabes sobre envíos internacionales?"
→ Tool: searchContext ejecuta (2 segundos)
→ Error: "Unable to parse input chunk"
→ Sesión muerta

Siempre después de ejecutar tools. 100% reproducible.

Diagnóstico inicial (equivocado): Pensamos: "Es una race condition. Audio chunks llegan antes de que el tool termine."

Intentamos:

  • ❌ Delays entre eventos (50ms, 100ms, 300ms)
  • ❌ Buffers más grandes
  • ❌ Limpiar queues después de tools

Nada funcionó.

3 días después... el breakthrough:

Estábamos revisando los logs de el proveedor los logs del sistema cuando notamos algo raro:

[ERROR] Tool result format invalid: nested JSON detected

El problema NO era timing. Era formato.

Nuestros tools retornaban objetos JSON:

javascript
// ❌ Lo que hacíamos
return {
  success: true,
  results: "info del RAG..."
}

el sistema esperaba strings simples:

javascript
// ✅ Lo correcto
return "info del RAG..."

Cuando retornábamos un objeto, el proveedor lo serializaba automáticamente a JSON, generando JSON anidado inválido que el sistema no podía parsear.

La solución (15 minutos de implementación): Cambiar todos los tools para retornar strings directos. No objetos. No wrapping.

Lección brutal:

  • Lee los samples oficiales ANTES de implementar
  • Los mensajes de error genéricos de el proveedor ocultan la causa real
  • No asumas que es un problema de timing si ves "parse error"

Bug #2: "Tool Response parsing error" — El Error de $100 Dólares

El síntoma: Arreglamos el bug #1. Celebramos. Desplegamos a staging.

5 minutos después:

Usuario: [hace pregunta que requiere RAG]
→ Tool: ejecuta correctamente
→ Resultado: retorna string (correcto)
→ Error: "Tool Response parsing error"
→ Debugging costoso en infraestructura cloud

Cada vez que intentábamos debuggear, generaba costos. El debugging se volvió caro.

El proceso de debugging: Día 1: Comparar nuestros eventos con los samples de el proveedor (línea por línea) Día 2: Descubrir que había 3 diferencias sutiles

Diferencia #1: Tipo de evento incorrecto

  • Nosotros: type: "TEXT", role: "USER"
  • los samples oficiales: type: "TOOL", role: "TOOL"
  • el sistema necesita identificar explícitamente que es un tool result

Diferencia #2: Campo extra donde no debía estar

  • Nosotros incluíamos toolUseId en el evento toolResult
  • los samples oficiales: toolUseId SOLO en contentStart.toolResultInputConfiguration
  • Incluirlo dos veces → "unexpected error during processing"

Diferencia #3: Content NO era JSON stringified

  • Nosotros: content: "texto simple"
  • los samples oficiales: content: "{\"result\": \"texto\"}"
  • el sistema espera JSON string, NO plain string

La solución: Copiar el formato de los samples oficiales exactamente. Sin "mejoras". Sin "optimizaciones".

Lección costosa:

  • Los samples oficiales NO son sugerencias. Son requisitos
  • Si tu implementación difiere en 1 campo → falla silenciosamente
  • Cuando la documentación dice "JSON stringified", NO es opcional
  • Usa staging para debuggear antes de producción

Bug #3: "All contents must be closed before ending prompt" — El Loop Infinito

El síntoma: Sistema funcionaba perfecto. Tools funcionaban. Barge-in funcionaba.

Hasta que el usuario colgaba la llamada:

[LOG] Closing el sistema session
[ERROR] All contents must be closed before ending prompt
[LOG] Buffer full
[LOG] Buffer full
[LOG] Buffer full (x10000)

WebSocket se quedaba colgado. Servidor consumía CPU. Sesión zombie.

El diagnóstico: Este fue el más frustrante porque el error era claro: "All contents must be closed".

El problema: ¿qué contenidos? ¿Dónde están abiertos?

El proceso:

  • Revisamos la secuencia de eventos (sessionStart → promptStart → contentStart...)
  • Notamos un patrón: después de ejecutar un tool, dejábamos un content abierto
  • Pensamos: "Ah, hay que cerrar el content después del tool result"

Lo implementamos:

[Tool ejecuta]
[Enviamos tool result]
[Cerramos audio content] ← ERROR

Nueva sesión de debugging:

  • Sistema funcionaba... hasta la próxima interrupción del usuario
  • Barge-in fallaba después de tools
  • el sistema no recibía el nuevo audio input

La epifanía (docs de el proveedor):

"Async tools: El audio content debe permanecer abierto después de tool results para permitir interrupciones del usuario."

¡NO debíamos cerrar el content después de tools!

La solución correcta:

  1. Después de tool result: NO cerrar audio content
  2. Al cerrar sesión: Verificar si hay content abierto
  3. Si sí: cerrar explícitamente ANTES de promptEnd
  4. Agregar delay de 300ms para que el proveedor procese el cierre

Resultado: Zero sesiones zombie. Cleanup correcto en 100% de casos.

Lección anti-intuitiva:

  • "Close before ending" NO significa "close immediately after using"
  • Tool calling asíncrono REQUIERE que el content permanezca abierto
  • Solo cierra cuando estés SEGURO de que no habrá más audio
  • Los docs de el proveedor no siempre son obvios (necesitas leer entre líneas)

Resultados: Formmy Voice AI en Producción

Los Números

Costo operativo:

  • 97% reducción vs LiveKit + ElevenLabs
  • ✅ Costo operativo mínimo para volúmenes medianos
  • ✅ Pricing público competitivo con margen saludable

Performance:

  • Latencia < 1 segundo (speech-to-speech nativo)
  • ✅ 0 false positives de barge-in (después de ajustar VAD)
  • ✅ 50+ sesiones concurrentes sin degradación

Robustez:

  • Zero memory leaks en 2 semanas de testing continuo
  • Zero sesiones zombie (cleanup automático funciona)
  • 3 bugs críticos resueltos (todos documentados)

Lo Que Aprendimos Sobre Calidad

1. Las conversaciones se sienten humanas

Esto no es marketing. Los primeros testers reportaron:

  • "No sabía que era un bot hasta que pregunté"
  • "Se siente más natural que hablar con soporte humano por teléfono"
  • "Puedo interrumpir sin que se pierda el contexto"

El barge-in bidireccional hace la diferencia. No es un feature nice-to-have. Es el feature.

2. Los tools son invisibles (y eso es bueno)

Los usuarios no notan que el agente está ejecutando búsquedas en bases de datos.

Ejemplo real:

Usuario: "¿Cuál es su política de devoluciones?"
→ [searchContext ejecuta - 1.5s]
→ Agente: "Claro, te explico nuestra política..."
→ Usuario no nota el delay

El tool calling asíncrono permite que el agente responda MIENTRAS busca, manteniendo el flujo natural.

3. La infraestructura importa (pero no es lo único)

Tenemos un sistema robusto:

  • Arquitectura de colas para manejar audio bidireccional
  • State machine explícito (evita race conditions)
  • Logging estructurado (debug en producción sin downtime)
  • Resource cleanup automático

Pero la robustez viene de resolver problemas reales:

  • 3 bugs críticos que nos costaron días
  • Debugging costoso en infraestructura cloud
  • Iteraciones de VAD hasta eliminar false positives

No hay framework mágico que te salve. Hay que invertir el tiempo.

Lo Que Viene

Corto plazo (2-4 semanas):

  • ✅ Búsqueda de productos optimizada para voz
  • ✅ Transcripciones automáticas guardadas
  • ✅ Dashboard de analytics para clientes

Medio plazo (2-3 meses):

  • 🔄 Más voces (inglés, portugués, francés)
  • 🔄 Soporte para llamadas salientes (outbound)
  • 🔄 Integración con Twilio para telefonía

Largo plazo (6+ meses):

  • 🔮 Voice cloning para marcas
  • 🔮 Multi-idioma en la misma llamada
  • 🔮 Emotional intelligence (detectar frustración, ajustar tono)

Por Qué Esto Importa (Más Allá de la Tecnología)

Voice AI no es nuevo. Llevamos años con IVRs telefónicos, asistentes de voz, y bots conversacionales.

Lo nuevo es que ahora es viable comercialmente.

Antes de nuestra solución:

  • ❌ Opciones baratas = calidad mala (latencia, sin barge-in)
  • ❌ Opciones de calidad = costo prohibitivo
  • ❌ Resultado: solo empresas grandes podían ofrecer voice AI

Después de optimizar nuestra arquitectura:

  • ✅ Costo 97% menor
  • ✅ Calidad igual o mejor (speech-to-speech nativo)
  • ✅ Features avanzados (barge-in, tool calling asíncrono)
  • ✅ Resultado: democratización de voice AI

Esto significa que un negocio mediano (tienda online, despacho legal, consultorio médico) puede tener un agente de voz profesional que:

  • Atiende 24/7
  • Califica leads automáticamente
  • Agenda citas en tiempo real
  • Busca información en bases de datos
  • Transfiere a humano cuando es necesario

Todo a un precio accesible.

Las 3 Lecciones Principales

1. Resuelve el problema real, no el problema técnico

Podríamos haber construido la arquitectura más elegante del mundo. Pero si las conversaciones no se sienten naturales, nadie lo usaría.

Enfócate en:

  • ¿Se siente como hablar con una persona?
  • ¿El usuario puede interrumpir naturalmente?
  • ¿Los tools son invisibles?

La tecnología es el medio, no el fin.

2. Los samples oficiales NO son opcionales

Gastamos días debuggeando porque no seguimos los ejemplos oficiales al pie de la letra.

Cuando la documentación dice "JSON stringified", NO es una sugerencia. Es un requisito.

Copia el formato exacto. No "mejores". No "optimices". Copia.

3. La robustez viene de resolver problemas reales

Nuestro sistema no es robusto porque usamos frameworks fancy o patrones de diseño complejos.

Es robusto porque:

  • Resolvimos 3 bugs críticos que mataban sesiones
  • Iteramos el VAD hasta eliminar false positives
  • Implementamos cleanup automático que FUNCIONA
  • Probamos con tráfico real por semanas
  • Invertimos tiempo en debugging exhaustivo

No hay shortcuts. Hay que invertir el tiempo.


¿Quieres Probar Formmy Voice AI?

Si tienes un negocio y quieres explorar cómo voice AI puede:

  • Calificar leads automáticamente
  • Dar soporte 24/7 en múltiples idiomas
  • Agendar citas sin intervención humana
  • Responder preguntas basándose en tu base de conocimiento

Estamos aceptando early access.

👉 Solicitar Early Access

Preguntas Frecuentes

¿Puedo usar mis propias voces? Actualmente soportamos voces de alta calidad en español, inglés, francés, italiano, y alemán. Voice cloning está en roadmap para Q2 2026.

¿Funciona en otros idiomas además de español? Sí. Soportamos inglés (US/UK), español, francés, italiano, y alemán con voces nativas. Multi-idioma en la misma llamada viene en Q2 2026.

¿Puedo integrar con mi CRM/base de datos? Sí. Formmy tiene sistema de tools custom para conectar con APIs externas (Salesforce, HubSpot, bases de datos propias, etc.).

¿Cuánto cuesta realmente? Voice AI está disponible en planes Pro y Enterprise. Consulta los detalles de pricing y minutos incluidos en formmy.app/planes.

Contacto


Sobre el autor:

Este post fue escrito por el equipo de Formmy después de 2 meses implementando voice AI en producción. Invertimos tiempo significativo en debugging, resolvimos 3 bugs críticos, y ahora tenemos un sistema robusto que maneja conversaciones reales.

Si tienes preguntas sobre la implementación, escríbenos a hola@formmy.app.


Publicado: Febrero 2026 Tiempo de lectura: 18 minutos Tags: voice-ai, conversational-ai, formmy