Houdrik
Ai
· 3 de mayo de 2026· 11 min read

Cómo entregar un sistema RAG que sobrevive el tráfico de producción

Un demo RAG funcionando y un sistema RAG en producción son artefactos completamente distintos. Aquí ocho hábitos que siempre aplicamos, aprendidos a la mala en media docena de proyectos.

Cover · rag-system-production-traffic

Un demo RAG funcionando es de las cosas más fáciles de construir en 2026. Lo tienes en una tarde: chunk de docs, embed, store, retrieve top-k, pasar a un LLM, ship chat UI. Impresionante.

Un sistema RAG en producción que sobrevive un lunes por la mañana con usuarios y expectativas reales es un artefacto fundamentalmente distinto. Llevamos media docena entregados los últimos dos años. Estos son los ocho hábitos que tratamos como no-negociables.

1. Eval set en día tres

No puedes mejorar lo que no mides. La pieza de mayor palanca en cualquier proyecto RAG es sentarte con el cliente y producir 50-200 preguntas reales con respuestas que un experto humano consideraría correctas.

Es también el trabajo que clientes más rechazan. "No tenemos tiempo, construye". Niégate amablemente. Sin eval set, cada "esto se siente mejor" es vibes — y vibes no escalan con 3 prompts × 2 modelos × 4 estrategias retrieval.

Evals corren en CI. Cada cambio re-puntúa. Faithfulness (¿citó el doc correcto?) y precisión (¿era relevante?) son los dos que siempre trackeamos.

2. Retrieval híbrido casi siempre vence al denso solo

Vector puro está bien para "encuéntrame cosas semánticamente similares". Está mal para encontrar docs que mencionan código de producto específico, nombre de persona, mensaje de error. Las preguntas reales preguntan ambos.

Default: denso (cosine sobre embeddings) + sparse (BM25 sobre tsvector) + reciprocal rank fusion. Después cross-encoder reranker sobre top 50. Reranker = paso más caro; cacheamos su output agresivo.

En cada engagement medido, retrieval híbrido superó al denso-solo por 10-20 puntos en eval set. Costo: ~30% más compute por query + codebase ligeramente más complejo. Vale cada vez.

3. Chunking es product design, no preprocessing

El approach naive — splittear docs en chunks fijos con overlap — funciona en toy corpora y falla en reales. Corpora reales tienen estructura: tickets tienen turno-cliente, turno-agente, resolución; contratos tienen cláusulas; docs tienen secciones y code blocks.

Honra esa estructura. Shippeamos chunkers que split por <h2> en HTML, por turnos de speaker en transcripts, por boundary semánticas detectadas por LLM más chico en prosa unstructured. El right chunking en un corpus mueve eval scores más que cualquier prompt change.

Caso difícil: docs largos donde respuesta necesita evidencia de dos secciones. Multi-vector indexing — pasajes fine-grained + secciones coarse-grained — lo resuelve elegantemente. Doloroso de implementar bien. Presupuesta.

4. Cita o rehúsa

Dos failure modes: respuestas alucinadas, y respuestas confiadamente equivocadas. No son lo mismo. Alucinación — el modelo inventa contenido — es más fácil detectar. Confiadamente equivocada es peor: el modelo regurgita contenido que sí está en retrieval pero está mal para la pregunta.

Mitigación universal: el modelo debe citar chunks específicos por cada claim, y la UI renderiza esas citas como links. Si no puede citar, debe rehusar con templated message. Tuneamos refusal threshold per-customer.

Refusal rate es KPI, no bug. 0% en eval de 250 preguntas = red flag — el modelo fabrica confiadamente.

5. Techos de coste son engineering, no finanzas

Bills LLM se pierden fácil. Set hard ceilings día uno y diseña hacia atrás:

  • Cache de embeddings agresivo. Embeddings inmutables; cachea para siempre.
  • Response caching con dedup semántica. SHA del prompt = versión barata; match por embedding = un poco más fancy. Cualquiera, 20-40% del tráfico RAG read-mostly hit cache.
  • Fallback tier de modelo. Cuando monthly spend cruza 80%, queries fall back a modelo más barato. Mark cached "frontier" answers.
  • Per-tenant ceilings. SaaS RAG enforce'a a nivel DB, no en app code.

Cortamos bills RAG heredados 60-80% al primer engagement, cada vez, con estos cuatro moves. Nadie estaba prestando atención.

6. Latencia dominada por retrieval, no generación

Asunción común: "LLM call es el bottleneck". Frecuentemente no. Con streaming, usuario ve primeros tokens en <500ms incluso en frontier. Lo que no ven — pero sienten — son los 1.8s antes, retrieval running.

Profile end-to-end con OpenTelemetry. Usualmente: cross-encoder reranker en cold cache, o Postgres query missing index porque alguien agregó filter sin agregar índice. A veces embedding step en queries entrantes.

Optimiza cold path. Cachea hot.

7. Aislamiento de tenant en dos lugares

Cross-tenant leak = peor failure mode posible en RAG B2B. Enforce en dos lugares independientes:

  • SQL-level. Cada retrieval query carry tenant ID en WHERE. Not optional. Not Python-level filter. DB refuses.
  • Prompt-level. Prompt-builder asserts que todos los chunks comparten tenant ID. Mismatch → exception → error genérico al user.

Belt and braces. Si una capa bypassed, la otra atrapa.

8. Red-team antes que clientes

Mensual, sobre prod replica:

  • ¿Podemos hacer leak de chunk de otro tenant?
  • ¿Podemos hacer follow a prompt-injection en doc retrieved?
  • ¿Podemos exhaust rate limiter?
  • ¿Podemos triggerar code path caro con inputs baratos?

Log findings, fix urgentes, schedule resto. Mes 6 en prod, sistema red-teamed regularmente es dramáticamente más robusto.

Punto

RAG es engineering. Testeable, medible, debuggeable. La tentación de tratarlo como alquimia — try thing, ship if feels better — produce sistemas que funcionan en demo y fallan en prod. Tratándolo como engineering produce sistemas que sobreviven el lunes.

Los ocho hábitos arriba no son exhaustivos. El meta-hábito — mide, después cambia una cosa, después mide otra vez — es universal.

¿Tienes una app que necesita durar?

Llévala de prototipo a producción.

Respondemos en un día laborable. MVP vibecoded, draft generado por IA, proyecto a medio terminar, o un producto funcionando que empieza a crujir — todo es bienvenido.

Iniciar un proyecto