Calidad de RAG en tiempo de indexación: tipos de fragmentos, limpieza y etiquetas de recuperación
Calidad de RAG en el momento del índice: crear fragmentos de texto, tablas e imágenes, eliminar ruido del analizador y agregar etiquetas de recuperación escritas por modelos LLM que redujeron a la mitad aproximadamente las búsquedas fallidas.
Donde una demostración se convierte en un sistema de producción
Un analizador RAG entrega una lista ordenada de nodos, y cada nodo sabe de qué sección proviene. Todo lo que ocurre desde ese momento hasta que el modelo lee una consulta corresponde al proceso de indexación, y es precisamente esta etapa la que diferencia una demostración de algo que se puede ejecutar en producción. Este proceso se divide en tres tareas: los nodos se convierten en fragmentos, de los cuales existen tres tipos con sus propios generadores; a los fragmentos se les elimina el material que el analizador extrajo pero que el modelo no debe ver; y cada fragmento recibe una etiqueta breve generada por un modelo de lenguaje. En una evaluación interna con documentos bancarios, esas etiquetas redujeron aproximadamente a la mitad el número de búsquedas fallidas, convirtiéndose así en el mayor beneficio de todo el proceso.
También es el menos glamoroso. Casi nadie escribe sobre la eliminación de ruido, y ese es precisamente el motivo por el cual existen tantos casos de éxito. Las cifras que se muestran a continuación provienen de una pequeña evaluación interna y no de una prueba de rendimiento rigurosa, por lo que deben interpretarse en ese sentido.
Tres tipos de fragmentos, tres herramientas de creación
El enfoque simplista utiliza un único fragmentador: se divide el texto y se sigue adelante. Los documentos reales contienen al menos tres tipos de contenido que se comportan de manera completamente distinta. Un párrafo de prosa, una tabla de tarifas y una captura de pantalla requieren un tratamiento propio, y al pasarlos todos por el mismo divisor es como aparecen las tablas incompletas y los pasos perdidos.
Los fragmentos de texto siguen una estructura
Dividir por el número de caracteres no es una opción viable. En su lugar, cada línea se escribe primero, ya sea como encabezado, como paso numerado o como oración simple, y las reglas de unión dependen de esos tipos. Esto evita que un paso numerado se una a un párrafo no relacionado. El texto demasiado extenso se corta al final de las oraciones, y cortar en medio de una oración es la solución de último recurso. Los fragmentos adyacentes se superponen ligeramente, de modo que un procedimiento que cruza un límite sigue siendo comprensible desde ambos lados.
Las tablas permanecen completas
Las tablas se crean por separado porque su significado radica en su diseño. El generador encuentra la fila de encabezados, la repite en cada parte si la tabla debe dividirse, y organiza las filas. También rechaza las tablas que no contienen contenido real, con frecuencia el índice, que los analizadores muestran como una cuadrícula ordenada de encabezados y números de página.
La iteración anterior de este sistema presentaba un defecto justo aquí. Los índices de contenidos se detectaban mediante una prueba rudimentaria, lo que hacía que muchas filas terminaran con un número pequeño. Las tablas de tarifas también encajaban en esa descripción, por lo que un horario de tarifas real podía desaparecer del índice sin ninguna advertencia. La prueba de reemplazo es más específica: en una página de contenidos real, los números de página solo aumentan, pero las cantidades de las tarifas, como $35, $30 y $7, pueden disminuir o aumentar. Una tabla solo se considera un índice si los números finales nunca disminuyen. Ahora los horarios de tarifas permanecen, las páginas de contenidos siguen existiendo, y una sola condición eliminó el error.
Las imágenes se determinan una por una
Cada imagen puede costar dinero, por lo que cada una prueba tres métodos en orden y se detiene en el primero que funciona.
- La ruta gratuita utiliza el texto que el analizador ya ha extraído. Si el documento proporciona una leyenda o anotación utilizable que no sea un marcador de posición como “image”, se utiliza ese texto y no se llama a ningún modelo de visión. En muchos documentos, entre un tercio y la mitad de las imágenes siguen este camino, lo que representa un ahorro real.
- La ruta de pago llama a un modelo de visión. Esto se aplica cuando no hay texto utilizable disponible y la imagen es más grande que un divisor diminuto. Una instrucción bien redactada hace que el modelo realice la clasificación primero. Si la imagen es un logotipo u ornamento, responde con la palabra DECORATIVE y el fragmento se descarta. De lo contrario, llena dos campos. SCREEN es una sola línea que indica para qué sirve la pantalla, por ejemplo, una pantalla de entrada de datos de cuentas empresariales, escrita de manera que quede cerca de las preguntas del usuario en el espacio vectorial. CONTENT enumera todas las etiquetas de campos, botones y códigos visibles, en orden de lectura, proporcionando a los buscadores las cadenas exactas que podrían escribir. De este modo, se puede encontrar una captura de pantalla por su finalidad y también por su texto impreso.
- La ruta de respaldo utiliza el encabezado. Si ambas fallan pero la sección es conocida, se almacena un marcador de posición que indica qué es la imagen y dónde se encuentra, de modo que siga siendo accesible a través de su sección en el momento de la consulta.
Existe un pequeño defecto en la verificación de tamaño. Las imágenes muy pequeñas omiten la llamada a la visión basada en un umbral de ancho y alto, pero ambas dimensiones deben ser pequeñas; por lo tanto, una línea divisoria muy delgada y muy ancha pasa desapercibida y aún así se envía al modelo. Esto desperdicia algo de recursos en decoración sin afectar la precisión, y está en la lista de tareas pendientes.
El diagrama muestra los tres caminos de imagen probados en orden. El modelo de visión se ejecuta una vez al indexarse, y cada consulta posterior es gratuita.
Mejorar lo que el analizador hizo bien
La fidelidad es precisamente lo que hace que los analizadores sean una molestia aquí. Extraen todo de una página: un sello de CONFIDENCIAL repetido en 200 páginas, números de página, pies de copyright, una oración dividida en dos por un salto de página. Cada uno de estos elementos se convierte en un fragmento, y todos son basura. La basura también distorsiona el ranking, ya que una consulta del usuario puede encontrar fácilmente un anuncio publicitario tanto como un procedimiento real.
Así que, una vez que existen los fragmentos, se realiza un proceso de limpieza en el que cada paso se enfoca en un tipo de basura que realmente se encuentra en los documentos reales. En orden:
- El filtrado de texto genérico elimina los números de página simples, los sellos de revisión y las líneas de enlace como “contáctenos” o “leer más” cerca del inicio. El conjunto de reglas varía según el tipo de archivo, ya que los PDF, los archivos de Word y las presentaciones tienen cada uno su propio tipo de basura.
- Eliminar elementos repetidos. El texto que aparece idéntico en muchas páginas se considera contenido no deseado. Frases como “CONFIDENTIAL, USE INTERNO SOLAMENTE” en quince páginas se contabilizan y se eliminan, mientras que “Ver página 3” que aparece dos veces en una misma página se mantiene, ya que no abarca varias páginas.
- Reparar divisiones incorrectas. Un fragmento que comienza a mitad de oración o con un viñeta suelta fue dividido en el lugar equivocado. Si puede unirse al fragmento anterior en la misma sección, se fusionan. De lo contrario, se marca como continuación para que su etiqueta incluya ese contexto.
- Fusionar fragmentos aislados. Un fragmento de 40 caracteres que queda atrapado en el límite entre secciones es absorbido por uno vecino, pero solo cuando ambos comparten exactamente la misma sección y encabezado. Nada se fusiona entre secciones, y una breve indicación que realmente está sola se deja tal como está.
- La deduplicación convierte en un único bloque una oración repetida bajo un mismo encabezado. Si aparece bajo dos encabezados, se conservan ambas copias, ya que, al llevar el camino de la sección, contienen información diferente. Las imágenes están completamente exentas, ya que dos pantallas de aspecto similar siguen siendo dos capturas de pantalla separadas.
Ninguna de las reglas es sofisticada. Cada una surgió al observar cómo un documento real superaba a la versión más simple, y juntas explican por qué una consulta llega a un procedimiento y no a una línea relacionada con derechos de autor.
La etiqueta de recuperación
El paso con el mayor beneficio, y el que la mayoría de los sistemas omiten, es el siguiente. Tome un bloque simple como este:
Introduzca la cantidad y presione F4.
Contiene su ruta de sección, Wire Transfer > Initiation > Amount Entry, lo cual ya es de ayuda. Sin embargo, antes de incrustarlo, un modelo de lenguaje también escribe una breve etiqueta de recuperación de 18 a 22 palabras, que se almacena junto con el fragmento. Para este fragmento, la etiqueta dice algo como:
Paso del procedimiento: escriba la cantidad a transferir y luego presione F4 para confirmar al iniciar la transferencia bancaria.
Considere el efecto. Sin una etiqueta, la instrucción simple queda en el espacio de incrustación junto a todos los demás pasos que indican escribir un valor y presionar una tecla. Con la etiqueta, se encuentra cerca de las transferencias bancarias y las confirmaciones, que son términos que usaría un usuario real. Una pregunta reformulada como “¿cómo confirmo la cantidad en una transferencia bancaria?” entonces localiza este fragmento. En la evaluación interna, las etiquetas redujeron en aproximadamente la mitad los fallos de recuperación. Se trató de una prueba pequeña en un único corpus, así que considérela como una pista sólida y no como una constante universal.
La técnica deriva de la recuperación contextual de Anthropic, la cual descubrió que colocar una oración de contexto específica para cada fragmento antes de indexarlo reduce significativamente los fallos en la recuperación. Aquí se ajustó para contenidos en los que los identificadores exactos son importantes. Los códigos de transacción y las teclas de función deben copiarse sin cambios y nunca parafrasearse, y cada etiqueta comienza con una palabra que indica su función, como “Paso del procedimiento” o “Tabla de referencia”, de modo que los fragmentos se agrupen con los tipos de preguntas adecuados.
Qué ve el responsable de crear las etiquetas
Una etiqueta solo es tan buena como el contexto que se le proporciona al modelo que la crea. El fragmento por sí solo no es suficiente, ya que precisamente es eso lo que perdió su significado al ser extraído de la página. Por lo tanto, cada solicitud de etiqueta incluye varios elementos:
- el texto del fragmento en sí
- la ruta de la sección y su título
- los encabezados de las columnas, cuando el fragmento es una tabla
- un fragmento anterior y uno siguiente, para mostrar lo que lo rodea
- un breve resumen del documento completo, para tener una visión general
El resumen del documento proviene de una llamada separada realizada antes de que comience el etiquetado. Se toman muestras de fragmentos del principio, el medio y el final, además de una tabla y una imagen, y se devuelven dos o tres oraciones que indican el tipo de documento, su público objetivo y los productos y códigos involucrados. Cada solicitud de etiquetado lo incluye posteriormente. La frase “introducir la cantidad” debe etiquetarse de manera diferente en un manual de transferencias bancarias que en un documento de información sobre préstamos, y es el resumen el que permite al modelo determinar qué documento está leyendo.
Los vecinos merecen una revisión más detallada, ya que “anterior y siguiente” no significa que los dos fragmentos estén físicamente adyacentes. El fragmento de al lado puede pertenecer a un procedimiento completamente diferente. Por lo tanto, los vecinos se seleccionan según su relevancia, en tres niveles, tomando el primero que coincida:
- el fragmento más cercano en la misma ruta de sección
- de lo contrario, el fragmento más cercano en la misma sección padre
- de lo contrario, el fragmento más cercano bajo el mismo encabezado
Se escanean los candidatos desde el fragmento actual hacia afuera, y se omite todo lo que está fuera de la sección adecuada. Así, el modelo identifica el siguiente fragmento que realmente pertenece a este. Cada vecino se reduce a unos pocos cientos de caracteres, lo cual proporciona suficiente contexto sin el costo de transmitir fragmentos completos.
En el ejemplo F4, el modelo observa que el fragmento anterior de su sección trataba sobre elegir un beneficiario y el siguiente sobre confirmar la transferencia. Eso le permite generar una etiqueta precisa sobre la inserción del monto de la transferencia bancaria, en lugar de un resumen vago. Vecinos bien seleccionados mantienen las etiquetas exactas.
La figura muestra cómo el modelo de etiquetas lee a sus vecinos de la misma sección y luego escribe una oración específica, que se almacena junto al fragmento y se proporciona a ambas vías de búsqueda.
Por qué esto es económico
Tres características hacen que este proceso sea práctico y no costoso.
- Costo único. La etiqueta se genera durante el indexado y se guarda, por lo que las consultas nunca pagan por ella.
- Bajo costo unitario. Un modelo pequeño y rápido etiqueta los fragmentos en grupos de 25, con varios grupos funcionando simultáneamente, y el gasto es de menos de un centavo por fragmento.
- Fallo elegante. Un lote cuyos errores de etiquetado hacen que quede sin etiquetar simplemente se indexa así mientras continúa la ejecución. Esos fragmentos conservan su texto y la ruta de sección, pero no reciben el refuerzo correspondiente; por lo tanto, una interrupción afecta la calidad, pero nunca detiene el proceso de indexación.
La etiqueta se encuentra en su propio campo, separada del cuerpo del fragmento. Esa separación es importante más adelante, en el momento de la consulta, cuando la etiqueta recibe un peso adicional en la búsqueda por palabras clave. Lo importante por ahora es que el cálculo más costoso se realiza antes de que alguien realice una búsqueda, y eso es lo que hace que funcionen las consultas parafraseadas.
Determinismo y el prompt versionado
La generación de etiquetas es determinista: una temperatura de cero y una semilla fija significan que volver a indexar un documento produce las mismas etiquetas. Esto es lo que sustenta la afirmación de que el costo se paga solo una vez. Volver a indexar nunca reordena los vectores, solo los recrea.
El determinismo también depende de la versionación de la instrucción. Una semilla solo genera un resultado idéntico para una entrada idéntica, y el texto de la instrucción forma parte de dicha entrada. Al editar la instrucción de enriquecimiento entre versiones, cada reindexación posterior produce etiquetas diferentes, por lo que el índice se divide silenciosamente en dos generaciones sin que nada lo indique. Por eso, la instrucción se guarda con una etiqueta de versión, se carga mediante esa etiqueta al ejecutarse el proceso de indexación y solo se modifica a través de actualizaciones intencionadas y registradas. La reproducibilidad entre versiones debe construirse, ya que una semilla por sí sola no lo logrará.
Incrustación y almacenamiento
Después de la limpieza, colocación y etiquetado, la tarea final en el momento del indexación consiste en generar el vector. Un modelo de incrustación cubre todos los tipos de fragmentos: text-embedding-3-large, reducido a 1536 dimensiones, de modo que el texto, las tablas y las capturas de pantalla se evalúen juntos frente a una consulta en el mismo espacio.
Lo que se introduce en el incrustador es una cadena compuesta en una secuencia fija: prefijo estructural, etiqueta y luego texto del cuerpo. El prefijo se basa en datos ya conocidos sobre el fragmento. Estos incluyen el tipo de documento deducido a partir de la ruta de la sección, como un calendario de tarifas o el procedimiento de transferencia bancaria, junto con el encabezado y la ruta de la sección; en el caso de las imágenes, también se incluyen la página y la ubicación. Al etiquetar un fragmento similar a un procedimiento como tal, se lo orienta hacia preguntas que comienzan con “cómo hacer algo”.
En esta etapa también se agrega la ruta de la sección al texto, que era donde estaba el error en la versión anterior. En aquel entonces, el prefijo se escribía en el bloque durante la limpieza, y cualquier edición posterior podía añadirlo una segunda vez, dañando silenciosamente el vector. El código actual elimina cualquier prefijo almacenado y luego crea uno nuevo en el momento de la integración. Este prefijo existe en un único lugar y se agrega exactamente una vez, justo antes de que el modelo lo lea, lo que eliminó toda una serie de errores por doble prefijo que no se detectaban.
El vector final se guarda en el almacenamiento junto con el cuerpo del bloque, la etiqueta, los metadatos estructurales y una columna de texto completo de la que se extraen las palabras clave para las búsquedas. Luego el documento pasa a estar activo. Si algún paso del proceso falla, el documento se marca como rechazado y se conserva la razón para la depuración, mientras que una versión activa anterior sigue siendo buscable en todo momento. Un documento con indexación parcial nunca es visible.
Así se ve una fila completada
Para ilustrarlo, aquí está el bloque “Introduce la cantidad y presiona F4” tal como aparece en la tienda. Cada campo proviene del paso anterior.
text : "Enter amount and press F4."
(built + cleaned + section-prefixed)
retrieval_context : "Procedure step entering the amount
and pressing F4 during wire transfer
initiation." (the label)
chunk_type : TEXT
section_path : "Wire Transfer > Initiation >
Amount Entry" (Part 2)
preceding_heading : "Amount Entry"
table_headers : null (TABLE only)
page_start / end : 12 / 12
image_object_key : null (IMAGE only)
embedding_model : text-embedding-3-large
embedding_dim : 1536
embedding : [ ...1536 floats... ] (body+label)
text_search_vector: label weighted high, body lower
En un bloque de tabla, los encabezados de las columnas ocupan el lugar donde un bloque de texto tiene valores nulos. Un bloque de imagen almacena una clave de blob, el tipo MIME y la posición en la página, con el contenido en formato text y la línea de pantalla en retrieval_context. Las tres variantes comparten el mismo diseño de fila. La recuperación se basa en dos columnas: embedding para la búsqueda vectorial y text_search_vector para la búsqueda por palabras clave, ambas obtenidas a partir del cuerpo del texto más la etiqueta. Las demás columnas localizan el bloque, lo muestran o lo limitan al tenant correspondiente.
Ese es el resultado completo del proceso de indexación: filas como estas, una por cada bloque, limpiadas, etiquetadas y vectorizadas, esperando la primera consulta.
Leer más
- Notas prácticas: Llevar RAG a producción: Errores integrales de la práctica real — Guía detallada de las Notas prácticas: Llevar RAG a producción: Errores integrales de la práctica real: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Diez errores silenciosos en la recuperación de información en RAG en producción y cómo solucionar cada uno — Desde el tamaño y la superposición de los fragmentos hasta la búsqueda híbrida, RRF, el reclasificado, la elección de embeddings y las evaluaciones de CI: diez errores en la recuperación de información que causan respuestas incorrectas en RAG y sus soluciones.