Implementación de patrones de recuperación para canalizaciones RAG
La generación aumentada de recuperación (RAG) mejora las respuestas del modelo de lenguaje proporcionando contexto relevante de los datos. El componente de recuperación busca en la base de conocimientos y devuelve documentos que el LLM usa para generar respuestas precisas y fundamentadas. Azure Database for PostgreSQL con pgvector sirve como un recuperador eficaz, almacenando las incrustaciones de documentos y ejecutando consultas de similitud que alimentan el paso de generación.
En esta unidad se tratan el diseño de esquemas para cargas de trabajo RAG, la implementación de consultas de recuperación de fragmentos, la creación de canalizaciones de ingesta de documentos, la devolución de metadatos de citas y la evaluación de la calidad de recuperación.
Comprender la arquitectura RAG y el rol del recuperador
Los sistemas RAG siguen un patrón de tres pasos:
- Inserción de consultas: Convertir la pregunta del usuario en un vector mediante un modelo de inserción
- Recuperación: buscar en el almacén de vectores documentos similares a la inserción de consultas
- Generación: pasar los documentos recuperados como contexto a un LLM para que genere una respuesta
PostgreSQL actúa como el recuperador en esta arquitectura. La calidad de la recuperación afecta directamente a la calidad de la generación. Si el recuperador devuelve documentos irrelevantes, LLM carece del contexto necesario para responder correctamente y podría generar información incorrecta. Si el sistema de recuperación omite documentos pertinentes, la respuesta podría estar incompleta.
Para un asistente de investigación legal, la recuperación efectiva significa encontrar los precedentes del caso, los estatutos y las cláusulas contractuales que abordan la pregunta del abogado. El LLM entonces sintetiza estas fuentes en una respuesta coherente con citas.
Diseñar esquemas para cargas de trabajo RAG
Normalmente, las aplicaciones RAG funcionan con fragmentos de documento en lugar de documentos completos. Los documentos largos superan los límites de contexto de LLM y pueden contener secciones irrelevantes para una consulta específica. La fragmentación divide los documentos en segmentos más pequeños y centrados que se pueden recuperar de forma independiente.
Separar documentos y fragmentos
Use dos tablas: una para documentos de origen y otra para fragmentos con incrustaciones:
CREATE TABLE source_documents (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
source_url TEXT,
document_type TEXT,
ingested_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE document_chunks (
id SERIAL PRIMARY KEY,
document_id INTEGER REFERENCES source_documents(id) ON DELETE CASCADE,
chunk_index INTEGER NOT NULL,
content TEXT NOT NULL,
embedding vector(1536),
token_count INTEGER,
start_char INTEGER,
end_char INTEGER,
UNIQUE (document_id, chunk_index)
);
Este diseño proporciona varias ventajas:
- Recuperación flexible: Puede recuperar fragmentos individuales o reconstruir secciones de documentos.
- Seguimiento de origen: Cada fragmento se vincula de nuevo a su origen para las citas
- Almacenamiento eficaz: Los metadatos del documento se almacenan una vez, no duplicados por fragmento
- Actualizaciones sencillas: Reemplazar un documento significa eliminar sus fragmentos y volver a crear
Adición de metadatos para el filtrado y el contexto
Incluya metadatos que le ayuden con el filtrado y la reconstrucción del contexto:
CREATE TABLE document_chunks (
id SERIAL PRIMARY KEY,
document_id INTEGER REFERENCES source_documents(id) ON DELETE CASCADE,
chunk_index INTEGER NOT NULL,
content TEXT NOT NULL,
embedding vector(1536),
token_count INTEGER,
section_title TEXT,
page_number INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Los títulos de sección y los números de página ayudan a los usuarios a comprobar la información recuperada y ayudar al LLM a comprender el contexto de cada fragmento.
Creación de índices para patrones de consulta RAG
Los índices de similitud de vectores (HNSW o OBJECTFlat) permiten búsquedas de inserción rápidas, como se ha descrito anteriormente en este módulo. Las cargas de trabajo RAG también se benefician de los índices B-tree que aceleran las uniones y los filtros únicos para la recuperación de fragmentos. Al recuperar fragmentos, a menudo vuelve a unirlos a los documentos de origen para los metadatos de cita y filtra u ordena por la posición del fragmento dentro de un documento. Sin estos índices, PostgreSQL examina toda la tabla de fragmentos para cada consulta de recuperación.
-- B-tree index for document lookups (speeds up JOINs to source_documents)
CREATE INDEX document_chunks_document_id_idx
ON document_chunks (document_id);
-- Composite index for chunk ordering (supports context window queries)
CREATE INDEX document_chunks_doc_chunk_idx
ON document_chunks (document_id, chunk_index);
El índice compuesto en (document_id, chunk_index) es especialmente importante para la recuperación de la ventana de contexto, donde se capturan fragmentos adyacentes para proporcionar el contexto circundante. Sin él, PostgreSQL debe examinar todos los fragmentos de un documento para buscar vecinos.
Implementación de la recuperación de fragmentos para la creación de contexto
Las consultas RAG recuperan fragmentos que se convierten en el contexto de LLM. El patrón de recuperación que elija afecta tanto a la calidad de respuesta como a la eficacia del token. Debe equilibrar tres factores en competencia: recuperar suficiente contenido relevante, mantenerse dentro de los límites de tokens y proporcionar un contexto suficiente para que el LLM comprenda cada fragmento.
El enfoque más sencillo recupera directamente los fragmentos más similares de la parte superior k. Esto funciona bien cuando los fragmentos son independientes y tus preguntas coinciden claramente con fragmentos únicos. Sin embargo, los documentos legales, las especificaciones técnicas y el contenido narrativo suelen distribuir conceptos en varios párrafos. Un fragmento puede hacer referencia a "las condiciones anteriores" o "como se ha descrito anteriormente" sin contener el texto al que se hace referencia.
En estos casos, la recuperación mediante ventana de contexto captura fragmentos adyacentes junto con cada coincidencia. Si el fragmento 47 es más similar a la consulta, también se recuperan fragmentos 46 y 48. Esto aumenta el uso de tokens, pero reduce el riesgo de respuestas incompletas. La compensación depende de la estructura de contenido: los documentos altamente estructurados con límites de sección claros necesitan menos contexto circundante que el texto narrativo que fluye.
Los límites de token agregan otra restricción. Las LLM tienen ventanas de contexto fijas y necesita espacio para la solicitud del sistema, la pregunta del usuario y la respuesta generada. Si recupera 10 fragmentos que promedian 500 tokens cada uno, ha consumido 5000 tokens antes de que LLM escriba una sola palabra. Realice un seguimiento de los recuentos de tokens acumulados durante la recuperación para mantenerse dentro del presupuesto.
La consulta siguiente combina estos patrones. Recupera los fragmentos más similares con sus vecinos, realiza un seguimiento de los tokens acumulados e incluye metadatos de citas.
WITH matched_chunks AS (
-- Find the most similar chunks
SELECT id, document_id, chunk_index, embedding <=> $1 AS distance
FROM document_chunks
ORDER BY embedding <=> $1
LIMIT 3
),
context_window AS (
-- Expand to include adjacent chunks for context
SELECT DISTINCT dc.id, dc.document_id, dc.chunk_index, dc.content,
dc.token_count, mc.distance
FROM matched_chunks mc
JOIN document_chunks dc ON dc.document_id = mc.document_id
AND dc.chunk_index BETWEEN mc.chunk_index - 1 AND mc.chunk_index + 1
),
token_limited AS (
-- Track cumulative tokens to respect LLM context limits
SELECT cw.*, sd.title AS source_title, sd.source_url,
SUM(cw.token_count) OVER (ORDER BY cw.distance, cw.chunk_index) AS cumulative_tokens
FROM context_window cw
JOIN source_documents sd ON cw.document_id = sd.id
)
SELECT id, content, source_title, source_url, distance
FROM token_limited
WHERE cumulative_tokens <= 3000
ORDER BY distance, chunk_index;
Ajuste los parámetros en función del caso de uso. En el caso de un asistente de investigación legal que responda a preguntas de cláusulas específicas, puede recuperar cinco coincidencias sin ventana de contexto. Para un bot de soporte técnico al cliente que responda preguntas abiertas sobre la documentación del producto, el sistema podría recuperar tres coincidencias, cada una con dos fragmentos de contexto circundante.
Gestión de canalizaciones de ingestión de documentos
Los nuevos documentos deben procesarse antes de poder realizar búsquedas. La canalización de ingesta divide los documentos en fragmentos, genera incrustaciones y almacena todo en PostgreSQL.
La forma de dividir documentos afecta directamente a la calidad de la recuperación. La estrategia de fragmentación correcta depende de la estructura de contenido y de los patrones de consulta:
Fragmentos de tamaño fijo: Divida cada N caracteres o tokens. Este enfoque es sencillo de implementar y genera recuentos de tokens predecibles, pero puede cortar frases o párrafos a mitad de camino. Use la fragmentación de tamaño fijo cuando el contenido no tenga límites estructurales claros o cuando necesite tamaños de fragmentos coherentes para planear el presupuesto de tokens.
Fragmentos semánticos: Se divide en límites naturales, como párrafos, secciones o oraciones. Esto conserva el significado dentro de cada fragmento, pero genera tamaños variables. Use la fragmentación semántica para documentos estructurados en los que las secciones representan pensamientos completos, como cláusulas legales, documentación de API o entradas de preguntas más frecuentes.
Fragmentos superpuestos: Incluya texto de fragmentos adyacentes para conservar el contexto en los límites. Por ejemplo, una superposición de 200 caracteres entre fragmentos de 1000 caracteres garantiza que los conceptos que abarcan los límites de fragmentos aparecen al menos en un fragmento completo. Use la superposición cuando las consultas puedan coincidir con el contenido cerca de los límites del fragmento.
Para el escenario del asistente de investigación legal, la fragmentación semántica en los límites de párrafo o sección funciona bien porque el texto legal se organiza en cláusulas y argumentos discretos. Cada fragmento representa un concepto legal completo que puede ser independiente en el contexto de LLM.
Una vez que haya fragmentado los documentos y generado inserciones, insértelos de forma eficaz mediante operaciones por lotes. El diseño de dos tablas requiere insertar primero el documento de origen para obtener su identificador y, a continuación, insertar todos los fragmentos en una sola fila INSERTmúltiple. Este enfoque minimiza los recorridos de ida y vuelta a la base de datos y mantiene intacta la relación de documento a fragmento. La mayoría de las API de inserción también aceptan varios textos por solicitud, por lo que puede generar incrustaciones para los fragmentos de un documento completo en una llamada API antes de insertar.
Las actualizaciones de documentos requieren una decisión: ¿puede versionarlos o reemplazarlos? Para la mayoría de las aplicaciones RAG, el reemplazo es más sencillo. Elimine los fragmentos existentes (la ON DELETE CASCADE restricción lo controla automáticamente al eliminar el documento de origen) y vuelva a recibir el contenido actualizado. Este enfoque garantiza que los resultados de la recuperación siempre reflejen el estado actual del documento. Si necesita historial de versiones, agregue una version columna a source_documents y mantenga los fragmentos antiguos junto con otros nuevos, filtre por versión en el momento de la consulta.
Los índices HNSW gestionan las eliminaciones de manera eficiente sin necesidad de reconstruir. Los índices IVFFlat pueden acumular fragmentación después de cambios significativos, lo que requiere una reconstrucción periódica para mantener el rendimiento de las consultas.
Implementar la recuperación con citas
Las citas transforman RAG de una caja negra en una herramienta de investigación transparente. Cuando el asistente de investigación legal cita una cláusula de contrato, el abogado debe comprobar esa cita con el documento original. Sin metadatos de cita, los usuarios deben confiar ciegamente en los resultados del LLM, un riesgo considerable en contextos legales, médicos o financieros donde la precisión es crítica.
Las citas eficaces requieren más que solo el contenido del fragmento. Las consultas de recuperación deben devolver el título del documento de origen, la dirección URL o el identificador del documento, el encabezado de sección y el número de página cuando estén disponibles. Estos metadatos permiten a la aplicación dar formato a las citas que los usuarios pueden seguir para llegar al origen. La puntuación de distancia también ayuda: puede mostrar citas de alta confianza de forma destacada y marcar las coincidencias de menor confianza para la comprobación por el usuario.
Se produce un desafío común cuando varios fragmentos del mismo documento coinciden con una consulta. Si los fragmentos 12, 15 y 18 de "Plantilla de contrato de empleo" aparecen en los resultados principales, se enumeran como tres citas independientes que desordenan la respuesta. En su lugar, agrupe fragmentos por documento de origen y presentelos como una sola cita con varios extractos pertinentes. Este enfoque genera una salida más limpia y ayuda a los usuarios a ver el contexto completo de cada origen.
En la consulta siguiente se muestra la recuperación agrupada en documentos. Clasifica los fragmentos dentro de cada documento, limita a tres fragmentos por documento para evitar sobrecargar el contexto y agrega el contenido para el formato de cita más limpio:
WITH ranked_chunks AS (
SELECT
dc.*,
sd.title AS document_title,
sd.source_url,
dc.embedding <=> $1 AS distance,
ROW_NUMBER() OVER (PARTITION BY dc.document_id ORDER BY dc.embedding <=> $1) AS rank_in_doc
FROM document_chunks dc
JOIN source_documents sd ON dc.document_id = sd.id
WHERE dc.embedding <=> $1 < 0.5
)
SELECT
document_id,
document_title,
source_url,
array_agg(content ORDER BY chunk_index) AS chunks,
MIN(distance) AS best_distance
FROM ranked_chunks
WHERE rank_in_doc <= 3
GROUP BY document_id, document_title, source_url
ORDER BY best_distance
LIMIT 5;
La aplicación puede dar formato a esto en citas fáciles de usar:
"El empleador podría terminar este acuerdo con 30 días de aviso." — Plantilla de acuerdo de empleo, Sección 4.2, Página 3
Evaluación y mejora de la calidad de recuperación
La calidad de recuperación determina la eficacia de RAG. Una recuperación deficiente conduce a una generación deficiente, independientemente de la capacidad de su LLM. Si el recuperador devuelve fragmentos irrelevantes, el LLM desperdicia la capacidad de la ventana de contexto en texto sin utilidad. Si el recuperador pierde los fragmentos pertinentes, el LLM carece de la información necesaria para responder correctamente. Medir la calidad de recuperación por separado de la calidad de generación le ayuda a diagnosticar en qué parte la canalización RAG necesita mejoras.
Tres métricas capturan distintos aspectos del rendimiento de la recuperación:
Precisión: Fracción de fragmentos recuperados que son realmente relevantes. La precisión baja significa que el LLM recibe un contexto irrelevante que podría confundirlo o provocar que genere información incorrecta. Mejore la precisión ajustando los umbrales de distancia o reduciendo el número de fragmentos recuperados.
Recuperación: fracción de fragmentos pertinentes que se recuperan. El bajo nivel de cobertura significa que el LLM pierde información importante, lo que conduce a respuestas incompletas o incorrectas. Mejore la recuperación mediante la reducción de los umbrales de distancia, el aumento del recuento de fragmentos recuperados o el ajuste de los parámetros de índice como
ef_search.Rango mutuo medio (MRR): Cuánto alto aparece el primer resultado relevante en la lista clasificada. El MRR es importante porque los LLM dan más peso al contexto anterior, y los usuarios que examinan las citas ven primero los resultados destacados. Mejore MRR mediante la refinación del modelo de inserción o el preprocesamiento de consultas.
Para medir estas métricas, necesita un conjunto de datos de evaluación: un conjunto de consultas representativas emparejadas con juicios humanos sobre qué fragmentos son relevantes. La creación de este conjunto de datos requiere esfuerzo inicial( alguien debe ejecutar consultas de ejemplo y etiquetar los resultados), pero se paga al permitirle realizar mejoras controladas por datos en lugar de adivinar. Comience con 20-50 consultas que representan los tipos de preguntas que los usuarios hacen realmente. Para cada consulta, recupere los 10 a 20 fragmentos más importantes y pida a un experto en el dominio que evalúe su relevancia en una escala simple (irrelevante, algo relevante, altamente relevante).
Con este conjunto de evaluación implementado, puede medir la precisión y la recuperación en diferentes umbrales (precision@5, recall@10) y realizar un seguimiento de cómo afecta la canalización a estas métricas. Ejecute las consultas de recuperación en el conjunto de evaluación, compare los resultados con los juicios humanos y calcule las métricas. La mayoría de los equipos automatizan esto en un script de puntuación que se ejecuta cada vez que cambian las estrategias de fragmentación, la inserción de modelos o los parámetros de índice.
Cuando las métricas se encuentran por debajo del objetivo, experimente sistemáticamente con parámetros que afectan al equilibrio de precisión y recuperación:
Tamaño del fragmento: Los fragmentos más pequeños mejoran la precisión devolviendo contenido más centrado, pero podrían afectar a la recuperación mediante la fragmentación de información relevante en varios fragmentos. Los fragmentos más grandes mejoran la recuperación pero diluyen la relevancia.
Superposición de fragmentos: Una mayor superposición conserva el contexto a través de los límites, lo que facilita las consultas que coinciden con el contenido cerca de los bordes de los fragmentos. Sin embargo, la superposición aumenta los requisitos de almacenamiento y podría devolver contenido redundante.
Modelo de inserción: Los diferentes modelos capturan relaciones semánticas diferentes. Un modelo entrenado en texto legal podría superar un modelo de uso general para la investigación legal. Considere los modelos específicos del dominio o optimizados si los modelos generales tienen un rendimiento inferior.
Parámetros de índice: Un mayor
ef_search(HNSW) oprobes(IVFFlat) mejora la recuperación al buscar más candidatos, a costa de la latencia de consulta. Comience con parámetros predeterminados y aumente solo si la recuperación no es suficiente.Umbrales de distancia: Los umbrales más estrictos mejoran la precisión excluyendo las coincidencias marginales. Los umbrales más flexibles mejoran la recuperación mediante la inclusión de más candidatos. Use el conjunto de datos de evaluación para encontrar el umbral que equilibra ambas métricas para el caso de uso.