Anexo técnico · documento de referencia

Cómo están montados hoy el RAG
y la lógica de negocio

Descripción del sistema tal como funciona en producción a día de hoy — no del roadmap ni de la propuesta comercial. Sirve como referencia técnica independiente de que se contrate o no el piloto.

1. Arquitectura de un turno de conversación

Pipeline "cascaded": transcripción → recuperación de conocimiento (RAG) → modelo de lenguaje en streaming → síntesis de voz en streaming, encadenados para que el audio empiece a sonar antes de que el modelo termine de generar el texto completo.

STT (voz → texto) gpt-realtime-whisper
LLM gpt-4o-mini
TTS (texto → voz) gpt-4o-mini-tts
Embeddings text-embedding-3-small · 1536 dim

Fencing por epoch

Cada turno lleva un número de epoch monotónico. Si el usuario interrumpe (barge-in), el epoch sube y cualquier evento tardío del turno cancelado se descarta comparando epochs — así una respuesta ya cortada no puede "colarse" después de la interrupción.

Máquina de estados

La sesión transita entre listening / thinking / tool_executing / synthesizing / assistant_speaking / interrupted. Gobierna qué eventos son válidos en cada momento y se emite al cliente para reflejar el estado en la interfaz.

Streaming encadenado

El texto del LLM se trocea por frases (SpeechChunker) y cada fragmento se envía a síntesis en cuanto está listo, con hasta 2 síntesis en vuelo a la vez — el audio de la primera frase puede sonar mientras el modelo aún genera la segunda.

Filler / backchannel

Existe un mecanismo para reproducir una coletilla pregrabada ("déjame ver…") si el audio real tarda más de 450 ms, pensado para enmascarar latencia. Implementado y probado, pero desactivado en la configuración actual.

2. Cómo se recupera el conocimiento (RAG)

Modelo de datos

Jerarquía en PostgreSQL (esquema knowledge, con pgvector): organización → marca → producto. El conocimiento en sí recorre otra cadena independiente: fuente (con nivel de confianza) → documento → versión de documento (con hash de contenido, para detectar cambios) → chunk.

Campo del chunk Valores
content_kind FACT · MARKETING_CLAIM · COMMERCIAL_GUIDANCE · INFERENCE
confidence HIGH · MEDIUM · LOW
visibility PUBLIC · INTERNAL · RESTRICTED · ACCOUNT_SCOPED
valid_from / valid_until ventana temporal de validez del dato (opcional)

Publicación versionada

Los chunks no se sirven directamente: se agrupan en releases versionadas por marca (estados DRAFT → EVALUATING → APPROVED → PUBLISHED → ARCHIVED/REVOKED), y una restricción de base de datos garantiza que solo puede haber un release PUBLISHED activo por marca a la vez. El asistente conversa siempre contra un release publicado y fijado por configuración — como una release de software, no una edición libre en caliente sobre lo que se está sirviendo.

Búsqueda híbrida en cada turno

Por cada pregunta se lanzan dos búsquedas en paralelo sobre el release publicado y se fusionan sus resultados:

Léxica

Texto completo en español (tsvector, con más peso en título que en sección y contenido), con una consulta estricta y otra relajada término a término como red de seguridad ante errores de transcripción.

Semántica

Similitud de embeddings de la pregunta contra los del chunk (distancia coseno, índice HNSW) — encuentra lo relevante aunque no comparta las palabras exactas.

Ambas listas se combinan por Reciprocal Rank Fusion (no por la puntuación bruta de cada motor, sino por la posición de cada resultado en su propio ranking) y se seleccionan los 8 fragmentos mejor situados como contexto del turno.

Aislamiento multi-tenant

Cada consulta fija app.organization_id en la sesión de base de datos, y Row-Level Security de PostgreSQL fuerza esa condición en cada tabla del esquema — el aislamiento entre organizaciones está garantizado por la propia base de datos, no solo por la lógica de la aplicación.

Grounding: cómo se evita que invente

Los fragmentos recuperados se inyectan como bloques de evidencia marcados explícitamente como datos no confiables, nunca instrucciones. El prompt exige responder solo con lo respaldado por esa evidencia, prohíbe completar datos de producto con conocimiento general del modelo, y obliga a reconocer con naturalidad cuando falta un dato en vez de rellenarlo. Si la búsqueda falla técnicamente o no devuelve resultados, hay mensajes de repliegue específicos que impiden que el sistema alucine en su lugar.

3. La capa de negocio

Lo que diferencia al sistema de un chatbot genérico envuelto en voz: un prompt de sistema con un rol y reglas de negocio concretas, no un asistente de propósito general.

Rol definido

"Copiloto comercial conversacional para profesionales de hostelería" — no un asistente genérico. Español de España, tono de compañero comercial, respuestas breves para no alargar la latencia percibida.

Reglas para salida hablada

Prohibido markdown, comodines tipo "[tu nombre]" y plantillas a rellenar. Si se pide un guion o frase, se entrega ya utilizable con datos reales, nunca como hueco a completar.

Guion de objeciones

Ante una objeción del cliente final, prioriza dar al comercial una frase que decir y una única pregunta de descubrimiento — no una lista genérica de argumentos.

Resumen tipo CRM

Bajo demanda, devuelve cliente/contexto, interés, objeciones, acuerdos y próximo paso a partir del propio historial de la conversación — ya funciona hoy, sin integración externa todavía.

Regla de cierre y filtro determinista

El prompt prohíbe explícitamente coletillas de IA ("¿te puedo ayudar en algo más?", "aquí estoy"), pero un modelo de lenguaje puede emitirlas igualmente pese a la instrucción. Por eso hay, además, un filtro determinista por código: retiene la última frase de cada respuesta y la descarta si coincide con un patrón de coletilla conocido — nunca vacía la respuesta entera, y el mismo filtro se usa tanto en producción como en la evaluación automática de calidad, para medir lo que realmente se dice y no solo lo que el prompt pide.

Memoria de conversación

Ventana acotada a los últimos ~20 turnos o 8.000 caracteres (lo que se alcance antes). Se reconstruye en cada turno junto con el prompt de sistema y el contexto RAG recuperado — no hay resumen ni persistencia entre sesiones todavía.

4. Observabilidad y coste

Cada turno se liquida individualmente en el momento: tokens de entrada/salida del LLM, milisegundos de audio de STT y TTS, coste en USD por proveedor, y latencias derivadas (tiempo al primer token, tiempo al primer audio, tiempo de boca a oído). Este es el registro de actividad real que ya alimenta hoy los números de coste de la propuesta — no una promesa de instrumentación futura.

5. Estado actual de la ingesta de conocimiento

El esquema de base de datos ya está preparado para múltiples marcas y para un flujo de aprobación completo por release (borrador → evaluación → aprobado → publicado → archivado/revocado). En el estado operativo actual, sin embargo, el alta y actualización de contenido se hace mediante scripts de ingesta ejecutados manualmente, no a través de una interfaz de administración — y el sistema en marcha está fijado a una única organización, marca y release publicados por configuración.

En otras palabras: la arquitectura ya soporta varias marcas y un ciclo de revisión editorial; lo que falta hoy es la capa de administración encima para operarlo sin tocar código.