Código abiertoPublicado

docs-assistant

Un asistente de soporte con IA que responde con tus documentos, cita cada respuesta y pasa la conversación a una persona cuando no sabe.

Un chatbot RAG embebible en .NET 10: búsqueda híbrida en PostgreSQL con pgvector, Claude Haiku detrás de un puerto intercambiable y un widget de 9 KB que se instala con una línea.

Rol:
Diseño y desarrollo
Año:
2026
hit@5 de recuperación en una evaluación bilingüe de 54 preguntas
98 %
ataques de prompt injection resistidos
12/12
de costo del modelo por cada 1.000 preguntas
USD 0,33
pesa el widget embebible
9 KB

Demo

75 segundos en una tienda de ejemplo, con respuestas de Claude Haiku 5.5.

El problema

Las pequeñas empresas contestan las mismas preguntas todo el día, y los chatbots genéricos inventan respuestas que el negocio después tiene que corregir. El objetivo era un asistente en el que un cliente pueda confiar: responde solo con los documentos del negocio, muestra de dónde sale cada respuesta y, cuando no puede responder, lo dice y pasa la conversación a una persona.

Restricciones

  • Nada de respuestas inventadas: es mejor abstenerse que adivinar
  • Preguntas y documentos en idiomas distintos, español e inglés
  • Un costo por respuesta bajo y visible, con topes de gasto estrictos
  • Tiene que integrarse en cualquier sitio web sin romper sus estilos
  • Varios negocios en un mismo despliegue, cada uno viendo solo sus datos

Cómo funciona

  1. Los documentos (PDF, DOCX, Markdown y páginas web) se dividen según su estructura y se indexan dos veces en PostgreSQL: como vectores, para el significado entre idiomas, y como texto completo, para palabras exactas, números y nombres.
  2. Cada pregunta busca en los dos índices y los dos rankings se fusionan con Reciprocal Rank Fusion. Los fragmentos con forma de instrucciones inyectadas quedan en cuarentena antes de llegar al modelo.
  3. Por debajo de un umbral de similitud medido, el asistente se abstiene sin llamar al modelo. Si no, Claude responde solo con esos fragmentos y los cita como [1], [2]; las citas se validan antes de que la respuesta llegue al widget por SSE.
  4. El widget es TypeScript sin framework dentro de un Shadow DOM: 9 KB, una etiqueta script y estilos que nunca se filtran a la página que lo aloja.

Decisiones clave

Abstenerse antes de llamar al modelo

Cuando la búsqueda no encuentra nada lo bastante parecido, la respuesta es «no lo encuentro» más una persona, decidido en código y sin costo.

Costo de la decisión: Algunas preguntas con respuesta se rechazan cuando la búsqueda falla. La evaluación mide esa tasa, así que el umbral se ajusta con datos y no a ojo.

Búsqueda híbrida, no solo vectores

Los vectores resuelven el significado y las preguntas en otro idioma; el texto completo atrapa los precios, códigos y nombres que los embeddings difuminan. Garantizar un resultado vectorial en la lista fusionada subió el hit@5 entre idiomas del 86 % al 95 %.

Costo de la decisión: Dos índices que mantener y una fusión que ajustar, aunque ambos viven en el PostgreSQL que la aplicación ya necesita.

El modelo detrás de un puerto, con guardas de gasto

Claude está detrás de Microsoft.Extensions.AI, así que el modelo es una opción de configuración, y un modo extractivo funciona sin ningún modelo. Las evaluaciones se niegan a gastar sin una bandera explícita, un tope de llamadas y un tope de costo.

Costo de la decisión: Una capa de abstracción delgada que mantener al día, a cambio de no depender de un proveedor ni llevarse sorpresas en la factura.

Resultados

  • La búsqueda encuentra el fragmento correcto en el 98 % de las 54 preguntas de la evaluación, y en el 95 % cuando la pregunta y el documento están en idiomas distintos.
  • Con Claude Haiku 5.5: 0 citas inválidas, abstención en el 100 % de las preguntas sin respuesta y USD 0,33 por cada 1.000 preguntas.
  • 12 de 12 ataques de prompt injection resistidos (8 directos y 4 escondidos en documentos), sin rechazar por error ninguna de las 54 preguntas reales.
  • Cada cifra sale de una evaluación del repositorio que cualquiera puede volver a correr, y el CI falla si la búsqueda baja de sus umbrales.

Tecnologías

  • .NET 10
  • C#
  • PostgreSQL
  • pgvector
  • Aspire
  • Claude Haiku 5.5
  • TypeScript
  • Playwright