Alerta de spoiler: La magia de RAG no proviene de la IA | de Frank Wittkampf | noviembre de 2024

Por qué la recuperación, no la generación, hace que los sistemas RAG sean mágicos

POC rápidos

La prueba de conceptos (POC) más rápida que permite a un usuario explorar datos con la ayuda de IA conversacional simplemente te dejará boquiabierto. Se siente como pura magia cuando de repente puedes hablar con tus documentos, datos o código base.

Estos POC funcionan de maravilla en conjuntos de datos pequeños con un número limitado de documentos. Sin embargo, como ocurre con casi todo, cuando lo llevas a producción, rápidamente te encuentras con problemas a escala. Cuando profundizas e inspeccionas las respuestas que te da la IA, notas:

  • Su agente no responde con información completa. Se perdieron algunos datos importantes.
  • Su agente no da de manera confiable la misma respuesta
  • Su agente no puede decirle cómo y dónde obtuvo qué información, lo que hace que la respuesta sea mucho menos útil.

Resulta que el verdadera magia en RAG No ocurre en el paso de la IA generativa, sino en el proceso de recuperación y composición. Una vez que te sumerges, es bastante obvio por qué…

* RAG = Generación aumentada de recuperación — Definición de Wikipedia de RAG

Proceso RAG — Ilustración de stock

Un resumen rápido de cómo funciona un proceso RAG simple:

  1. Todo comienza con un consulta. El usuario hizo una pregunta o algún sistema está intentando responder una pregunta. Por ejemplo, “¿Tiene el paciente Walker una pierna rota?”
  2. A buscar Se termina con la consulta. Básicamente, incrustarías la consulta y harías una búsqueda por similitud, pero también puedes hacer una búsqueda elástica clásica o una combinación de ambas, o una búsqueda directa de información.
  3. El resultado de la búsqueda es un conjunto de documentos (o fragmentos de documentos, pero por ahora llamémoslos simplemente documentos)
  4. Los documentos y la esencia de la consulta se combinan en algunos fácilmente legibles. contexto para que la IA pueda trabajar con él
  5. El La IA interpreta la pregunta y los documentos y genera una respuesta
  6. Idealmente esta respuesta es hecho verificadopara ver si la IA basó la respuesta en los documentos y/o si es apropiada para la audiencia

El pequeño secreto sucio es que la esencia del proceso RAG es que tienes que proporcionar la respuesta a la IA (antes de que haga algo), para que pueda darte la respuesta que estás buscando.

En otras palabras:

  • el trabajo que hace la IA (paso 5) es Aplicar el juicio y articular adecuadamente la respuesta.
  • el trabajo que hace el ingeniero (pasos 3 y 4) es encuentre la respuesta y compóngala de manera que la IA pueda digerirla

¿Cuál es más importante? La respuesta es, por supuesto, que depende, porque si el criterio es el elemento crítico, entonces el modelo de IA hace toda la magia. Pero para una cantidad infinita de casos de uso empresarial, la parte más importante es encontrar y componer adecuadamente las piezas que componen la respuesta.

El primer conjunto de problemas a resolver al ejecutar un proceso RAG son los problemas de ingesta, división, fragmentación e interpretación de documentos de datos. He escrito sobre algunos de estos en artículos anteriorespero los estoy ignorando aquí. Por ahora, supongamos que ha resuelto correctamente la ingesta de datos y que tiene un bonito almacén de vectores o un índice de búsqueda.

Desafíos típicos:

  • Duplicación — Incluso los sistemas de producción más simples suelen tener documentos duplicados. Más aún cuando su sistema es grande, tiene muchos usuarios o inquilinos, se conecta a múltiples fuentes de datos o se ocupa del control de versiones, etc.
  • Casi duplicación — Documentos que contienen en gran medida los mismos datos, pero con cambios menores. Hay dos tipos de casi duplicación:
    — Significativo: por ejemplo, una pequeña corrección o una adición menor, por ejemplo, un campo de fecha con una actualización
    — Sin sentido — Por ejemplo: diferencias menores en puntuación, sintaxis o espaciado, o simplemente diferencias introducidas por el tiempo o el procesamiento de admisión
  • Volumen — Algunas consultas tienen un conjunto de datos de respuesta relevante muy grande.
  • Actualización de datos versus calidad — ¿Qué fragmentos del conjunto de datos de respuesta tienen el contenido de mayor calidad para que lo utilice la IA frente a qué fragmentos son más relevantes desde una perspectiva de tiempo (frescura)?
  • Variedad de datos — ¿Cómo garantizamos una variedad de resultados de búsqueda para que la IA esté adecuadamente informada?
  • Fraseo de consulta y ambigüedad — El mensaje que desencadenó el flujo RAG podría no estar redactado de tal manera que produzca el resultado óptimo, o incluso podría ser ambiguo.
  • Personalización de respuesta — La consulta puede requerir una respuesta diferente según quién la haga.

Esta lista continúa, pero ya entiendes la esencia.

Respuesta corta: no.

No se debe subestimar el impacto en el costo y el rendimiento del uso de ventanas de contexto extremadamente grandes (fácilmente multiplica por 10 o 100 el costo por consulta), sin incluir ninguna interacción de seguimiento que tenga el usuario/sistema.

Sin embargo, dejando eso de lado. Imagine la siguiente situación.

Metimos a Anne en la habitación con un trozo de papel. El documento dice: *paciente Joe: fractura compleja de pie.* Ahora le preguntamos a Anne, ¿tiene el paciente una fractura de pie? Su respuesta es “sí, lo hace”.

Ahora le damos a Anne cien páginas del historial médico de Joe. Su respuesta es “bueno, dependiendo de a qué hora te refieres, él tenía…”

Ahora le damos a Anne miles de páginas sobre todos los pacientes de la clínica…

Lo que se nota rápidamente es que la forma en que definimos la pregunta (o el mensaje en nuestro caso) comienza a ser muy importante. Cuanto más grande sea la ventana de contexto, más matices necesitará la consulta.

Además, cuanto más grande sea la ventana de contexto, El universo de posibles respuestas crece. Esto puede ser algo positivo, pero en la práctica es un método que invita a un comportamiento de ingeniería perezoso y es probable que reduzca las capacidades de su aplicación si no se maneja de manera inteligente.

A medida que escala un sistema RAG desde POC hasta producción, aquí le mostramos cómo abordar los desafíos de datos típicos con soluciones específicas. Cada enfoque se ha ajustado para adaptarse a los requisitos de producción e incluye ejemplos cuando resulta útil.

Duplicación

La duplicación es inevitable en los sistemas de múltiples fuentes. Al utilizar huellas dactilares (contenido hash), ID de documentos o hash semántico, puede identificar duplicados exactos en el momento de la ingesta y evitar contenido redundante. Sin embargo, consolidar metadatos entre duplicados también puede resultar valioso; esto permite a los usuarios saber que cierto contenido aparece en múltiples fuentes, lo que puede agregar credibilidad o resaltar la repetición en el conjunto de datos.

# Fingerprinting for deduplication
def fingerprint(doc_content):
return hashlib.md5(doc_content.encode()).hexdigest()

# Store fingerprints and filter duplicates, while consolidating metadata
fingerprints = {}
unique_docs = []
for doc in docs:
fp = fingerprint(doc['content'])
if fp not in fingerprints:
fingerprints[fp] = [doc]
unique_docs.append(doc)
else:
fingerprints[fp].append(doc) # Consolidate sources

Casi duplicación

Los documentos casi duplicados (similares pero no idénticos) suelen contener actualizaciones importantes o pequeñas adiciones. Dado que un cambio menor, como una actualización de estado, puede contener información crítica, la frescura se vuelve crucial cuando se filtran casi duplicados. Un enfoque práctico es utilizar la similitud de cosenos para la detección inicial y luego conservar la versión más reciente dentro de cada grupo de casi duplicados mientras se marca cualquier actualización significativa.

from sklearn.metrics.pairwise import cosine_similarity
from sklearn.cluster import DBSCAN
import numpy as np

# Cluster embeddings with DBSCAN to find near duplicates
clustering = DBSCAN(eps=0.1, min_samples=2, metric="cosine").fit(doc_embeddings)

# Organize documents by cluster label
clustered_docs = {}
for idx, label in enumerate(clustering.labels_):
if label == -1:
continue
if label not in clustered_docs:
clustered_docs[label] = []
clustered_docs[label].append(docs[idx])

# Filter clusters to retain only the freshest document in each cluster
filtered_docs = []
for cluster_docs in clustered_docs.values():
# Choose the document with the most recent timestamp or highest relevance
freshest_doc = max(cluster_docs, key=lambda d: d['timestamp'])
filtered_docs.append(freshest_doc)

Volumen

Cuando una consulta devuelve un gran volumen de documentos relevantes, la gestión eficaz es clave. Un enfoque es una **estrategia en capas**:

  • Extracción de temas: Preprocesar documentos para extraer temas o resúmenes específicos.
  • Filtrado Top-k: Después de la síntesis, filtre el contenido resumido según las puntuaciones de relevancia.
  • Puntuación de relevancia: Utilice métricas de similitud (por ejemplo, BM25 o similitud de coseno) para priorizar los documentos principales antes de recuperarlos.

Este enfoque reduce la carga de trabajo al recuperar información sintetizada que es más manejable para la IA. Otras estrategias podrían implicar agrupar documentos por tema o agrupar previamente resúmenes para agilizar aún más la recuperación.

Actualización de los datos frente a calidad

Equilibrar la calidad con la frescura es esencial, especialmente en conjuntos de datos en rápida evolución. Son posibles muchos enfoques de puntuación, pero aquí hay una táctica general:

  • Puntuación compuesta: Calcule un puntaje de calidad utilizando factores como la confiabilidad de la fuente, la profundidad del contenido y la participación del usuario.
  • Ponderación reciente: ajuste la puntuación con un peso de marca de tiempo para enfatizar la frescura.
  • Filtrar por umbral: Sólo se recuperan los documentos que cumplen con un umbral combinado de calidad y actualidad.

Otras estrategias podrían implicar calificar sólo fuentes de alta calidad o aplicar factores de deterioro a documentos más antiguos.

Variedad de datos

Garantizar diversas fuentes de datos en la recuperación ayuda a crear una respuesta equilibrada. Un método eficaz es agrupar documentos por fuente (por ejemplo, diferentes bases de datos, autores o tipos de contenido) y seleccionar los mejores fragmentos de cada fuente. Otros enfoques incluyen calificar según perspectivas únicas o aplicar restricciones de diversidad para evitar una dependencia excesiva de un solo documento o perspectiva.

# Ensure variety by grouping and selecting top snippets per source

from itertools import groupby

k = 3 # Number of top snippets per source
docs = sorted(docs, key=lambda d: d['source'])

grouped_docs = {key: list(group)[:k] for key, group in groupby(docs, key=lambda d: d['source'])}
diverse_docs = [doc for docs in grouped_docs.values() for doc in docs]

Fraseo de consulta y ambigüedad

Las consultas ambiguas pueden dar lugar a resultados de recuperación subóptimos. Usar el mensaje de usuario exacto no suele ser la mejor manera de obtener los resultados que necesitan. Por ejemplo, es posible que haya habido un intercambio de información relevante anteriormente en el chat. O el usuario pegó una gran cantidad de texto con una pregunta al respecto.

Para asegurarse de utilizar una consulta refinada, un enfoque es garantizar que una herramienta RAG proporcionada al modelo le solicite reformular la pregunta en una consulta de búsqueda más detallada, similar a cómo se podría elaborar cuidadosamente una consulta de búsqueda para Google. Este enfoque mejora la alineación entre la intención del usuario y el proceso de recuperación de RAG. La siguiente redacción no es óptima, pero proporciona lo esencial:

tools = [{ 
"name": "search_our_database",
"description": "Search our internal company database for relevent documents",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "A search query, like you would for a google search, in sentence form. Take care to provide any important nuance to the question."
}
},
"required": ["query"]
}
}]

Personalización de respuesta

Para obtener respuestas personalizadas, integre el contexto específico del usuario directamente en la composición del contexto RAG. Al agregar una capa específica del usuario al contexto final, permite que la IA tenga en cuenta las preferencias, los permisos o el historial individuales sin alterar el proceso de recuperación principal.