Agente 404
Volver al blog
Inteligencia Artificial

RAG en producción sobre pgvector: chunking semántico y rerank eficiente

Implementar RAG sólido en producción sobre pgvector implica aciertos y errores en chunking, rerank y costes a volumen. En Agente 404 desglosamos los patrones que escalan y ahorran €.

20 de abril de 20265 min de lectura
RAG en producción sobre pgvector: chunking semántico y rerank eficiente

Integrar Retrieval-Augmented Generation (RAG) basado en PostgreSQL y pgvector permite incorporar conocimiento propio a modelos de IA generativa. El flujo típico ””indexar textos, recuperar embeddings, consultar con LLM”” parece trivial en entorno demo, pero la fricción real llega con miles o millones de consultas, latencias constantes de sub-600ms, y datasets con cientos de millones de tokens.

En este artículo veremos cómo llevamos RAG en producción usando chunking semántico y rerank avanzado con OpenAI y Anthropic sobre pgvector, optimizando costes, throughput y calidad para cargas reales de negocio.

Arquitectura RAG sobre pgvector: mínimo necesario para escalar

Stack y patrones de integración

  • Backend en Node.js (TypeScript 5.4) o Python (FastAPI 0.110+, asyncio) para servir queries y orquestar pipelines.
  • PostgreSQL Aurora con extensión pgvector 0.7+ para el almacenamiento de embeddings y metadatos.
  • Embeddings generados con OpenAI text-embedding-3-large (1536 dims) o Anthropic claude-3-embeddings-v1.
  • Redis (Upstash) opcional para caching semántico y control de consultas repetidas.
  • AWS Lambda y Vercel Functions para ejecución sin servidor y autoescalado crítico.
«Una consulta típica RAG a 10 documentos candidatos consume ~0,0025$ en embeddings y LLM (OpenAI), pero cada 100ms extra y cada consulta fallida suma en costes de soporte y frustración»

Diagrama simplificado del pipeline

  • Usuario realiza una consulta (prompt).
  • El backend genera embedding del prompt.
  • Consulta a SELECT ... ORDER BY embedding <=> $embedding LIMIT k en pgvector para k candidatos.
  • Opcional: rerank semántico en backend o con LLM.
  • Prompt final a LLM (OpenAI, Anthropic) con contexto top-N.

Fragmento real de consulta con pgvector

WITH query_embedding AS (\n  SELECT '[[embedding vector aquí]]'::vector(1536) AS embedding\n)\nSELECT id, content, metadata, embedding <=> query_embedding.embedding AS distance\nFROM documents, query_embedding\nWHERE metadata->>'status' = 'active'\nORDER BY embedding <=> query_embedding.embedding\nLIMIT 10;\n

Chunking semántico en la indexación: errores típicos y patrones que escalan

¿Por qué importa el chunking?

  • Chunks demasiado pequeÁ±os (ej. 100-200 tokens): contexto poco relevante, incremento de queries, más coste en prompt.
  • Chunks grandes (>1.500 tokens): embeddings diluidos, latencias altas en postgres, pérdida de granularidad.
Chunk sizeMétricaVentajaProblema típico
100-200 tokens~96% recall@10Rápido, cheapContexto pobre
400-600 tokens~91% precision@3Equilibrio memoria/calidadPrompt largo si top-k grande
1500-2000 tokens~70% recall@10Menos queriesLatencia y embeddings peores

Implementar chunking semántico en Python

from nltk.tokenize import sent_tokenize\nfrom typing import List\n\nMAX_TOKENS = 512\n\ndef chunk_text_semantic(text: str) -> List[str]:\n    sentences = sent_tokenize(text)\n    chunks = []\n    buffer = []\n    tokens = 0\n    for sentence in sentences:\n        sentence_tokens = len(sentence.split())\n        if tokens + sentence_tokens > MAX_TOKENS:\n            chunks.append(' '.join(buffer))\n            buffer = [sentence]\n            tokens = sentence_tokens\n        else:\n            buffer.append(sentence)\n            tokens += sentence_tokens\n    if buffer:\n        chunks.append(' '.join(buffer))\n    return chunks\n
  • La variabilidad semántica se maximiza usando puntuación y entidades como delimitadores, no cortes ciegos por token.
  • Nuestros experimentos muestran reducción de 12% en queries fallidas a LLM ajustando de 200 a 500 tokens por chunk.

Rerank: cuándo y cómo aplicar reranqueado embebido y con LLM

¿Por qué rerank?

  • PostgreSQL/pgvector ofrece ANN exacto o aproximado, pero ignora matices sintácticos y órdenes lógicos.
  • El rerank mejora la relevancia real según el usuario y permite filtrar «falsos positivos semánticos».

Opciones de rerank aplicadas en Agente 404

MétodoCoste consultaLatencia mediaPrecisión top-3
Solo embedding~0,00002$30ms72%
Rerank ML (bm25+ o reranker MiniLM)~0,00012$110ms81%
LLM rerank (OpenAI v4)~0,00110$620ms93%
import { Configuration, OpenAIApi } from 'openai';\nconst openai = new OpenAIApi(new Configuration({ apiKey: process.env.OPENAI_API_KEY }));\n\nasync function rerankWithLLM(query: string, docs: Array<{id: string, content: string}>): Promise<string[]> {\n  const prompt = `Dado la consulta: "${query}", ordénalos por relevancia:\n` +\n                docs.map((d, i) => `${i+1}. ${d.content}`).join('\n');\n  const res = await openai.createChatCompletion({\n    model: 'gpt-4-1106-preview',\n    messages: [{ role: 'user', content: prompt }],\n    functions: [\n      {\n        name: "rank_documents",\n        parameters: {\n          type: "object",\n          properties: {\n            order: {\n              type: "array",\n              items: { type: "string" }\n            }\n          },\n          required: ["order"]\n        }\n      }\n    ],\n    function_call: { name: 'rank_documents' },\n    temperature: 0.0,\n    max_tokens: 80\n  });\n  return res.data.choices[0].message.function_call.arguments.order;\n}\n
  • Restringimos el rerank LLM a los top-7 chunks para controlar el coste (<0,0015$/query rondando 500 tokens totales).
  • Alternar entre embeddings-only o rerank LLM puede hacerse con threshold sobre score, ajustando precisión y presupuesto.

Optimización de consultas de alto volumen: claves prácticas

  1. Batch embeddings en backend: cada llamada a embedding API ahorra hasta 70% de latencia agrupando 10-20 queries (< 320ms OpenAI, 16ms/embedding).
  2. Caching semántico: Redis Upstash reduce hasta un 38% el tráfico a LLM en queries repetitivas, con hit rate >70% en flujos internos.
  3. CTEs para filtrado y logging: aÁ±ade trazabilidad y filtros de permisos en SQL en una sola consulta.
  4. Colas y reintentos: integración con AWS SQS o Upstash Queue, backoff exponencial de hasta 5 reintentos en errores 429/5xx.
WITH context AS (\n    SELECT id, content, embedding <=> $embedding AS dist\n    FROM documents\n    WHERE org_id = $org AND published = TRUE\n    ORDER BY embedding <=> $embedding\n    LIMIT 15\n),\nfiltered AS (\n    SELECT * FROM context WHERE dist < 0.35\n)\nINSERT INTO rag_queries(query, docs, org_id, ts)\nSELECT $query, array_agg(id), $org, NOW()\nFROM filtered;\n
  • Con currencía de 50+ queries/s y sizing correcto de Aurora (r6g.xlarge), mantenemos P95 < 170ms en retrieval incluyendo CTE.

Evaluación: LLM-as-judge y métricas objetivas en producción

Evaluar relevance en pipelines reales

  • Recurrimos a LLM-as-judge con prompts que piden «score relevance 1-5» y explicaciones de error para 2000+ queries de test cada semana.
  • Automatizamos evals con OpenAI SDK v4.77+ y script de logging continuo a S3/Aurora con anomalías >25% detectadas vía SQL y alertadas por Slack/GitHub.
import openai\n\nasync def llm_judge_eval(query, candidates, answer):\n    prompt = f"""\n    Consulta de usuario: {query}\n    Contexto proporcionado: {candidates}\n    Respuesta LLM: {answer}\n    Evalúa la relevancia del contexto (1-5) y justifica.\n    """\n    completion = await openai.ChatCompletion.acreate(\n        model="gpt-4-1106-preview",\n        messages=[{"role": "user", "content": prompt}],\n        max_tokens=120,\n        temperature=0\n    )\n    return completion.choices[0].message.content\n
Estrategia evaluaciónAutomatizaciónCoberturaInsourcing necesario
Annotadores humanosNo<25%~120h/mes
LLM-as-judge>95%<5h/mes

Insight para CTO

«Automatizar la evaluación RAG con LLM reduce necesidad de insourcing hasta 40x, sacrificando < 8 puntos de correlación humana»

Impacto en la operación: cifras y riesgos de no optimizar

  • Reducir el chunk size a límites óptimos (400-600 tokens) recorta prompts de LLM un 33%, baja latencias pico de >1.4s a ~700ms y reduce coste de OpenAI en ~28% (casos reales retail y seguros).
  • Caching semántico y rerank solo LLM en top-5 ha bajado gasto mensual de inferencia de 960€ a 620€ en clientes con >50.000 queries/mes.
  • Sin evals automatizadas con LLM, la detección de regresión de calidad llevaba semanas; ahora, minutos (< 5 min MTTR secuencia incidentes-contexto mal recuperado).
  • Requisitos directos para CTO/director IT: escalar a 200QPS sin pérdidas de precisión, costes controlados bajo 0,005€/query, trazabilidad para auditoría y supervisión.
«Detectar errores de chunking o rerank tardíamente puede dilapidar hasta 2 FTEs mensuales en soporte/QA manual»

En Agente 404 implementamos diagnósticos RAG con pruebas de chunking, benchmarking y trazabilidad para sistemas sobre pgvector: encajando cifra, patrón y vínculo técnico-negocio. Consúltanos si necesitas un assessment de RAG en producción.

Te resulto util?

Compartelo con quien pueda necesitarlo

Listo para automatizar tu operacion?

Agenda una llamada de 30 minutos. Sin compromiso.