Arquitectura del asistente de chat
Stack por capas y flujos de petición del widget RAG del portfolio, handoff humano e ingesta del operador.
Capas del sistema
Cada capa tiene una sola responsabilidad. Los datos fluyen de arriba abajo; PubSub y webhooks conectan rutas asíncronas.
Widget del navegador
ChatWidgetLive · WebSocket · en/es
LiveViewTelegram
Bot del visitante + consola del operador
WebhookTLS / CDN
Cloudflare → misaelp.dev
HTTPSNginx
Proxy → 127.0.0.1:4001
Contabo VPSRouter
/:locale/* · /webhook/telegram
BanditControladores y LiveViews
ChatWidgetLive · TelegramController
Phoenix 1.8Orquestación del chat
Persistir mensajes · modo ai|human
MisaelParedes.ChatPipeline RAG
Embedding · recuperar · rerank · generar
MisaelParedes.AI.RAGHandoff y Telegram
Palabras clave · operador /reply · /ingest
Handoff · OperatorPostgreSQL
conversations · messages
Ectopgvector
document_chunks · búsqueda coseno
768-dimETS + PubSub
Límites · push en vivo al widget
OTPAPI de embeddings
Consulta + vectores de chunks
GeminiCompletado de chat
Respuesta fundamentada en el contexto
Gemini / OpenAIRerank opcional
Refinamiento top-k de chunks
CohereIteraciones de la petición
Tres bucles principales. La mayoría del tráfico sigue el Flujo A hasta que una palabra clave activa el Flujo B.
Respuesta RAG
Modo IA por defecto · según idioma
El visitante envía la pregunta
ChatWidgetLive → Chat.handle_visitor_message/3
Comprobación de límite
Bucket ETS por sesión · límite por hora
Embedding de la pregunta
AI.Provider.embed/1 → vector de 768 dimensiones
Recuperar chunks
Knowledge.search_similar/2 en pgvector
Rerank opcional
Rerank de Cohere si está configurado · si no, truncar top-k
Aumentar prompt
Idioma + contexto del portfolio + guardrails
Completado LLM
Provider.chat/2 → respuesta en primera persona + fuentes
Persistir y enviar
Conversations.add_message · PubSub → stream del widget
Handoff humano
Operador vía Telegram
Palabra clave de handoff detectada
p. ej. «quiero hablar contigo» · Handoff.activate/2
Cambiar a modo humano
conversation.mode = human · mensaje puente al visitante
Notificar al operador
Telegram: alerta + transcripción completa · chat marcado activo
Respuestas del operador
Texto libre o /reply ID · Telegram → store_operator_reply
Entrega en tiempo real
PubSub conversation:ID → ChatWidgetLive stream_insert
Devolver a la IA
/release en Telegram · el modo vuelve a ai
Ingesta de conocimiento
El operador actualiza pgvector
El operador envía /ingest
Idioma + slug de fuente · borrador o texto de una sola vez
Dividir en chunks
Párrafos · ~1200 caracteres máx. por chunk
Embedding e inserción
Indexer.index_chunks/1 → document_chunks
Disponible en la próxima consulta
La recuperación del Flujo A usa los nuevos vectores al instante
Estadísticas y reconstrucción
/kb cuenta por fuente · /reindex desde Content
Fuentes indexadas
- • Chunks del portfolio integrados (Content.knowledge_chunks/0)
- • Telegram /ingest — notas en vivo por idioma y fuente
- • /reindex reconstruye desde código; /kb muestra conteos de chunks
Barreras de seguridad
- • Límite horario de RAG por sesión de visitante (ETS)
- • Límite de herramientas solo en eventos LiveView
- • Prompts en primera persona · citar contexto · sin inventar hechos