celestino.ai: Un agente de voz que habla por mí
La mayoría de los portafolios son PDFs. Un reclutador lo ojea seis segundos y sigue adelante. Yo quería algo distinto: un agente de IA que pueda conversar en tiempo real sobre mi trabajo. No un chatbot con respuestas enlatadas. Un agente de voz fundamentado en mi experiencia real, desplegado en una URL pública, corriendo 24/7. Ese agente es celestino.ai, y es la demostración en vivo detrás del CTA "Míralo funcionando" en toda mi marca.
Construirlo me obligó a resolver los mismos problemas que resuelvo para clientes: presupuestos de latencia, grounding con RAG, economía unitaria y fiabilidad bajo tráfico real.
Arquitectura: Dos pipelines, un agente
Voz y chat de texto comparten RAG, system prompt, sesiones y Supabase. La diferencia es el pipeline de I/O.
Voz:
Browser Mic -> WebRTC -> LiveKit Room
-> ElevenLabs Scribe v2 (STT)
-> Gemini 2.5 Flash (LLM)
-> ElevenLabs Flash v2.5 (TTS)
-> WebRTC -> Browser Speaker
Chat:
Browser Input -> POST /api/chat
-> RAG Retrieval (Supabase pgvector)
-> Gemini 2.5 Flash (AI SDK streamText)
-> SSE Stream -> Browser UI
Elegí LiveKit Agents porque resuelve lo difícil del audio en tiempo real: rooms, ciclo de vida de participantes, tracks y data channels. El agente corre como proceso Node.js separado, puede reiniciarse sin matar la sesión. Un selectModel() permite cambiar de proveedor (Anthropic, OpenAI, Google) sin tocar código, un vendor off-ramp por diseño.
Presupuesto de latencia
En voz, el usuario espera en silencio. Más de un segundo y siente que el sistema se rompió.
- WebRTC directo. Audio peer-to-peer, sin relay de WebSocket.
- Token exchange en el edge. Tokens LiveKit generados en API route edge, sin cold start.
- Silero VAD local. Detección de actividad de voz sin round-trip al servidor.
- Detección de turnos multilingüe. Distingue pausas conversacionales de hesitaciones a mitad de frase.
- ElevenLabs Flash v2.5. Streaming por chunks. Primera palabra audible ~300ms después del LLM.
- Generación preventiva. Empieza a responder antes de confirmar que el usuario terminó. Si sigue hablando, descarta.
- Barge-in. Si el usuario habla encima del agente (mínimo 800ms / 2 palabras), el agente se detiene y escucha.
RAG: Hacer que el agente sea factual
Sin grounding, el agente inventaría datos plausibles sobre mi carrera. RAG es la barrera.
- Ingestión. Contenido de celestinosalim.com vía sync API. Chunks de 500 tokens con 100 de overlap.
- Embeddings.
gemini-embedding-001 a 1536 dimensiones en Supabase pgvector.
- Retrieval. Similaridad coseno, umbral 0.7, top 5. Conservador: menos chunks muy relevantes es mejor que inundar el contexto.
- Tool use en voz.
search tool vía llm.tool() de LiveKit. RAG bajo demanda, no inyectado en cada respuesta.
Costos y rate limiting
Cada visitante cuesta dinero. Gemini 2.5 Flash es ~10x más barato por token que GPT-4, la palanca dominante. Voz añade STT/TTS de ElevenLabs, predecible y acotado por duración.
| Nivel | Límite | Caso de uso |
|-------|--------|-------------|
| Anónimo | 3/día | Visitantes casuales prueban el agente |
| Free (autenticado) | 15/día | Suficiente para una conversación real |
| Pro (suscriptor) | 500/día | Usuarios avanzados vía Stripe |
El rate limiter falla abierto ante errores de BD. Prefiero servir requests sin medir a mostrar una página de error.
Fiabilidad
- RAG falla gracefully. Si
retrieveContext() lanza error, retorna array vacío. Degrada de "experto fundamentado" a "generalista informado", no a crash.
- Filtrado de ruido.
shouldIgnoreTranscript() rechaza audio con 2 caracteres alfanuméricos. Toses no disparan llamadas al LLM.
- Cancelación de ruido.
BackgroundVoiceCancellation de LiveKit filtra antes del STT.
- Persistencia. Cada mensaje en Supabase con IDs de sesión y usuario. Refrescos restauran historial completo.
- Memoria. Para autenticados: corto plazo (mensajes recientes), largo plazo (datos extraídos) y summarización periódica. El agente te recuerda entre sesiones.
Resultados
celestino.ai está en producción en Vercel, con el agente LiveKit como proceso separado. Es el CTA principal en cada página, perfil y bio. No es un demo. Es un sistema con auth, rate limiting, persistencia, memoria y degradación graceful. La misma infraestructura que recomiendo a clientes.
Aprendizajes
- Voz es más difícil que chat, y la brecha es mayor de lo que esperas. En texto, 2 segundos de delay se sienten normales. En voz, 2 segundos de silencio se sienten como un crash. Generación preventiva, TTS en streaming y WebRTC directo no son optimizaciones. Son requisitos.
- El umbral de retrieval importa más que el tamaño del chunk. Probé 300, 500 y 800 tokens, diferencias marginales. Mover el umbral de 0.5 a 0.7 redujo drásticamente el contexto irrelevante.
- Rate limiting es decisión de producto, no solo de costos. Los tres niveles (3/15/500) crean un funnel natural: prueba gratis, regístrate, suscríbete.
- Falla abierto, no cerrado. Si Supabase está lento, el rate limiter deja pasar. Si RAG falla, el agente responde sin grounding. Cada modo de falla elige "servir al usuario" sobre "proteger el sistema". Para un portafolio, es el trade-off correcto.
Trabaja Conmigo en Algo Similar
Si estás construyendo un agente de voz en producción, un sistema de chat con RAG, o un producto de IA multimodal que necesita sobrevivir tráfico real - los presupuestos de latencia, patrones de rate limiting y estrategias de degradación documentados aquí aplican directamente. Este sistema practica lo que recomiendo a clientes.
Explorar Servicios de Consultoría de IA o enviar una consulta - respondo dentro de un día hábil.