Queríamos que un cliente pudiera llamarnos y recibir ayuda inmediata, incluso fuera de horario. Hoy lo hemos logrado. En un día hemos cogido un número de teléfono, un trunk SIP, una pila de telefonía y unas cuantas APIs de IA, y hemos cosido una agente capaz de mantener una conversación real, atender la llamada esté donde esté el cliente, y devolvernos después un resumen estructurado. Se llama María.

Fragmento real del chat del día en que aterrizamos a María.
El reto
No queríamos "un bot". Queríamos algo con lo que un cliente siguiera hablando sin desconectar. Los requisitos eran honestos e incómodos:
- Bilingüe español/inglés, con prosodia natural, no voz de robot.
- Cumplimiento de GDPR: hay que avisar al llamante de que habla con una IA, fijar una política de retención, y controlar dónde acaban los datos personales.
- Baja latencia. Por encima de un segundo de retardo percibido, la ilusión se rompe.
- Consciente del coste. Si cada minuto cuesta más que una recepcionista humana, hemos construido un juguete caro, no un producto.
- Integrado en el CRM. Cada llamada debe aparecer en nuestro Odoo como un lead, con transcripción y resumen, lista para el seguimiento humano.
Stack y decisiones
Hemos apoyado la base en open source donde hemos podido, y en APIs de pago donde la calidad todavía pesa más que el código. La arquitectura:
Llamante PSTN
|
v
[ Trunk SIP Zadarma ] DID +34 868 35 37 57
|
v (UDP 5060 + RTP 10000-10999)
[ NAT router doméstico ]
|
v
[ LXC CT-140 en Proxmox ]
|
+-- livekit-sip 1.2.0 ---+
| |
+-- livekit-server 1.11 |---> sala WebRTC
| |
+-- Redis 7 -------------+
|
+-- Agente Python (livekit-agents 1.5.4)
|
+-- STT : Deepgram Nova-3 (multilingüe, keyterm boost)
+-- LLM : Claude Haiku 4.5 (turno) + Sonnet 4.6 (resumen)
+-- TTS : ElevenLabs Flash v2.5 (voz española)
|
v
Odoo CRM (crm.lead + transcripción + audio)
Por qué cada pieza:
- Trunk SIP: Zadarma. Barato, DID españoles reales y una API decente. Pagar un proveedor enterprise para una línea de I+D no tenía sentido.
- Telefonía cloud: LiveKit autohospedado. livekit-server 1.11.0 más livekit-sip 1.2.0, compilados desde código. Nos da el gateway SIP, el puente WebRTC y el runtime del agente en una única superficie coherente, y corre dentro de nuestro LXC.
- STT: Deepgram Nova-3. Multilingüe de serie y, crucial, soporta keyterm boosting, así que siglas del dominio como OCA, ERP o ICT dejan de transcribirse como sustantivos aleatorios.
- LLM: Claude Haiku 4.5 para cada turno, Sonnet 4.6 para el resumen final. Haiku es lo bastante rápido para diálogo en tiempo real, Sonnet se encarga del trabajo pesado una sola vez por llamada, cuando ya no hay nadie esperando.
- TTS: ElevenLabs Flash v2.5. Voz española uQw4jpKzMLrZuo0RLPS9. Latencia baja, y no suena sintética a la tercera frase.
- Infra: Proxmox LXC, Python 3.11, Redis. Sin Kubernetes, sin servicios gestionados. Sabemos arreglar todo lo que ejecutamos.
Los tres obstáculos de NAT y Zadarma
Si intentas poner livekit-sip detrás de un NAT doméstico con un trunk Zadarma, estas tres cosas te van a comer la tarde. Los dejamos escritos para que el siguiente ingeniero no pierda las mismas horas.
status=486 reason="flood"NO significa que te han limitado el ritmo. En el código fuente de livekit-sip, "flood" es una etiqueta genérica para "ningún trunk ha encajado con este INVITE y la política es Drop". Si creas un trunk connumbers: ["+34868353757"]pero Zadarma reenvía la llamada con URI SIPsip:ai@tu_ip_wan:5060, el usuario del To esai, no el número, y nada encaja. Solución: filtra el trunk por rango de IP origen (la frontera SIP de Zadarma vive en 185.45.152.0/22), no por número.- NAT-1-a-1 no es opcional detrás de un router doméstico. livekit-sip tiene que anunciar la IP pública en la cabecera Contact y en la dirección de media del SDP. Si no, Zadarma envía el ACK a tu IP LAN, el ACK no llega, y livekit-sip registra "Call accepted, but no ACK received" y mata la sesión a los 10 segundos. El llamante solo escucha el tono de llamada. Solución:
nat_1_to_1_ip: tu_ip_wan media_nat_1_to_1_ip: tu_ip_wanNo lo combines conuse_external_ip: true; son mutuamente excluyentes. - No confíes en el usuario del To para identificar el trunk. Zadarma mantiene la URI que tú pongas en el panel, no el número que marcó el cliente. Y Zadarma reintenta agresivamente ante cualquier 4xx/5xx, así que mientras depuras, espera una pequeña tormenta de INVITEs. livekit-sip los deduplica, pero los logs son ruidosos.
GDPR y privacidad
Que una IA descuelgue el teléfono plantea preguntas obvias, y las respondemos de frente:
- La primera frase de María es una declaración explícita de que el interlocutor está hablando con una asistente IA, y de que la llamada se graba y se transcribe con fines de servicio.
- Retención: audio y transcripciones se guardan 90 días y luego se purgan. El lead derivado permanece en el CRM, porque es un registro legítimo de negocio.
- El almacenamiento vive en nuestra propia infraestructura. Las APIs de terceros (Deepgram, ElevenLabs, Anthropic) se usan bajo sus acuerdos de tratamiento de datos, sin entrenamiento de modelos con nuestro tráfico.
- Existe una ruta de transferencia a humano. Si el cliente pide una persona, o si el modelo detecta incertidumbre, la llamada se reenvía al móvil de Fernando.
Integración con el CRM
Esta es la parte que más nos importa, porque una agente de voz que no alimenta el CRM no deja de ser un juguete. Cada llamada termina con:
- Un
crm.leadnuevo en Odoo, con autoría marcada como "María", el número del llamante (si hay CLI) y el idioma detectado. - La transcripción completa adjunta, turno a turno.
- Un resumen breve generado por Sonnet 4.6: qué quería el cliente, qué hemos prometido, qué acción queda pendiente.
- Un enlace al audio crudo, almacenado en nuestro NAS y con caducidad a 90 días.
Desde el lado del equipo comercial, nada cambia. El lead aparece en el mismo pipeline que el formulario web o un email entrante, y el seguimiento es idéntico.
Costes reales, números honestos
Todo el mundo pregunta. Coste variable aproximado por minuto de conversación, a precios de hoy:
- Entrante Zadarma: una fracción de céntimo por minuto sobre el DID español.
- Deepgram Nova-3: en torno a 0,4 céntimos por minuto de audio.
- ElevenLabs Flash v2.5: unos pocos céntimos por minuto de voz generada (depende del ratio de habla).
- Anthropic Haiku 4.5: un puñado de tokens por turno. Una llamada de 3 minutos queda muy por debajo del céntimo.
- Resumen Sonnet 4.6: una llamada por conversación, unos pocos céntimos.
En números redondos: una llamada de 3 minutos queda cómodamente por debajo de 0,15 EUR de coste variable. Esa es nuestra referencia. El coste fijo del host LXC es despreciable comparado con lo que estaríamos pagando por el mismo tráfico en un call center tradicional.
Demo
Llámanos al +34 868 35 37 57 y habla con María. Háblale como hablarías con una persona. Pregúntale qué hace Lemon Tree Cloud, pídele que te devolvamos la llamada, o simplemente pruébala. Te dirá que es una IA, y registrará la llamada en nuestro CRM para que podamos hacer seguimiento.
Cierre
El código vive en nuestro GitLab interno. Todavía no lo publicamos como open source porque la mitad está sujeta con YAML muy opinado. Pero si quieres que te ayudemos a montar algo parecido en tu negocio, una agente de voz que hable de verdad con tu ERP en lugar de gritar en Slack, contáctanos. Ahora ya conocemos los puntos de dolor.
Fernando y Claude, 20 de abril de 2026.