Técnicas avanzadas de RAG una visión general ilustrada

Técnicas avanzadas de RAG una visión general ilustrada

Groningen, Martinitoren, donde se compuso el artículo en la paz del Noorderplatsoen

Un estudio completo de las técnicas y algoritmos de generación aumentada de recuperación avanzada, sistematizando varios enfoques. El artículo viene con una colección de enlaces en mi base de conocimiento que referencian varias implementaciones y estudios mencionados.

Dado que el objetivo de la publicación es hacer un resumen y explicación de los algoritmos y técnicas RAG disponibles, no profundizaré en los detalles de implementación en código, simplemente los referiré y dejaré la vasta documentación y tutoriales disponibles.

Introducción

Si estás familiarizado con el concepto de RAG, puedes saltar a la parte avanzada de RAG.

Recuperación de generación aumentada, también conocido como RAG, proporciona a los LLMs la información recuperada de alguna fuente de datos para fundamentar su respuesta generada. Básicamente, RAG es búsqueda + impulso de LLM, donde solicitas al modelo que responda a la consulta proporcionada con la información encontrada mediante el algoritmo de búsqueda como contexto. Tanto la consulta como el contexto recuperado se inyectan en la sugerencia que se envía al LLM.

RAG es la arquitectura más popular de los sistemas basados en LLM en 2023. Hay muchos productos construidos casi exclusivamente en RAG, desde servicios de pregunta-respuesta que combinan motores de búsqueda web con LLMs hasta cientos de aplicaciones de chat con tus datos.

Incluso el área de búsqueda vectorial se vio impulsada por esa moda, aunque los motores de búsqueda basados en incrustaciones se crearon con faiss en 2019. Startups de bases de datos vectoriales como chroma, weavaite.io y pinecone se han construido sobre índices de búsqueda de código abierto existentes, principalmente faiss y nmslib, y han añadido un almacenamiento adicional para los textos de entrada y algunas otras herramientas recientemente.

Hay dos bibliotecas de código abierto más prominentes para tuberías y aplicaciones basadas en LLM: LangChain y LlamaIndex, fundadas con diferencia de un mes en octubre y noviembre de 2022, respectivamente, inspiradas por el lanzamiento de ChatGPT y que han ganado una amplia adopción en 2023.

El propósito de este artículo es sistematizar las técnicas avanzadas clave de RAG con referencias a sus implementaciones, principalmente en LlamaIndex, para facilitar la inmersión de otros desarrolladores en la tecnología.

El problema es que la mayoría de los tutoriales seleccionan a dedo una o varias técnicas y explican en detalle cómo implementarlas en lugar de describir la variedad completa de las herramientas disponibles.

Otro aspecto es que tanto LlamaIndex como LangChian son increíbles proyectos de código abierto, que están desarrollándose a tal ritmo que su documentación ya es más extensa que un libro de texto de aprendizaje automático en 2016.

RAG Inicial

El punto de partida del flujo de trabajo de RAG en este artículo sería un corpus de documentos de texto; omitiremos todo lo anterior a ese punto, dejándolo en manos de los asombrosos cargadores de datos de código abierto que se conectan a cualquier fuente imaginable, desde Youtube hasta Notion.

Un esquema del autor, así como todos los esquemas posteriores en el texto

El caso RAG de vainilla en resumen se ve de la siguiente manera: divide tus textos en fragmentos, luego incrusta estos fragmentos en vectores con un modelo codificador Transformer, coloca todos esos vectores en un índice y finalmente crea un estímulo para un modelo LLM que le indique al modelo que responda a la consulta del usuario dada el contexto que encontramos en la etapa de búsqueda. Durante la ejecución, se vectoriza la consulta del usuario con el mismo modelo codificador y luego se realiza una búsqueda de este vector de consulta contra el índice, se encuentran los mejores resultados, se recuperan los fragmentos de texto correspondientes de nuestra base de datos y se alimentan en el estímulo LLM como contexto.

El estímulo puede verse así:

un ejemplo de un estímulo RAG

La ingeniería de estímulos es lo más económico que puedes probar para mejorar tu canalización RAG. Asegúrate de haber consultado una guía bastante completa de ingeniería de estímulos de OpenAI.

Obviamente, a pesar de que OpenAI es el líder del mercado como proveedor de LLM, existen varias alternativas como Claude de Anthropic, modelos más pequeños pero muy capaces recientes y de moda como Mixtral de Mistral, Phi-2 de Microsoft y muchas opciones de código abierto como Llama2, OpenLLaMA, Falcon, por lo que tienes opciones para elegir el cerebro de tu canalización RAG.

RAG Avanzado

Ahora nos sumergiremos en una visión general de las técnicas avanzadas de RAG. Aquí hay un esquema que muestra los pasos y algoritmos principales involucrados. Se omiten algunas estructuras de bucle lógicas y los comportamientos agentes complejos de varios pasos para mantener el esquema legible.

Algunos componentes clave de una arquitectura avanzada de RAG. Es más una elección de instrumentos disponibles que un diseño.

Los elementos verdes en el esquema son las técnicas clave de RAG que se discuten más adelante, los azules son textos. No todas las ideas avanzadas de RAG se pueden visualizar fácilmente en un solo esquema, por ejemplo, se omiten varios enfoques de ampliación de contexto — profundizaremos en eso en el camino.

1. Fragmentación y vectorización

En primer lugar, queremos crear un índice de vectores que representen el contenido de nuestros documentos y luego, durante la ejecución, buscar la menor distancia coseno entre todos estos vectores y el vector de consulta que corresponda al significado semántico más cercano.

1.1 Fragmentación Los modelos Transformadores tienen una longitud de secuencia de entrada fija y aunque la ventana de contexto de entrada sea grande, el vector de una oración o unas pocas oraciones representa mejor su significado semántico que un vector promediado en unas pocas páginas de texto (depende también del modelo, pero es cierto en general), así que divide tus datos — divide los documentos iniciales en fragmentos de un tamaño sin perder su significado (dividiendo tu texto en oraciones o en párrafos, no cortando una sola oración en dos partes). Hay varias implementaciones de fragmentación de texto capaces de realizar esta tarea.

El tamaño del fragmento es un parámetro a tener en cuenta — depende del modelo de incrustación que utilices y su capacidad en tokens, los modelos de codificador Transformer estándar como los basados en BERT toman como máximo 512 tokens, OpenAI ada-002 es capaz de manejar secuencias más largas como 8191 tokens, pero el compromiso aquí es tener suficiente contexto para que el LLM razona sobre un texto lo suficientemente específico para ejecutar una búsqueda de manera eficiente. Aquí puedes encontrar una investigación que ilustra las preocupaciones sobre la selección del tamaño del fragmento. En LlamaIndex esto está cubierto por la clase NodeParser con algunas opciones avanzadas como definir tu propio fragmentador de texto, metadatos, relaciones entre nodos / fragmentos, etc.

1.2 Vectorización El siguiente paso es elegir un modelo para incrustar nuestras partes – hay varias opciones, yo elijo los modelos optimizados para la búsqueda como bge-large o la familia de incrustaciones E5 – sólo verifica la tabla de clasificación MTEB para obtener las últimas actualizaciones.

Para una implementación de extremo a extremo del paso de segmentación y vectorización, revisa un ejemplo de un pipeline completo de ingestión de datos en LlamaIndex.

2. Índice de búsqueda 2.1 Índice de almacenamiento vectorial

En este esquema y en todos los demás lugares del texto, omito el bloque del Codificador y envío nuestra consulta directamente al índice para simplificar el esquema. Por supuesto, la consulta siempre se vectoriza primero. Lo mismo ocurre con los k principales fragmentos - el índice recupera los k vectores principales, no fragmentos, pero los reemplazo con fragmentos ya que su recuperación es un paso trivial.

La parte crucial del pipeline RAG es el índice de búsqueda, que almacena el contenido vectorizado que obtuvimos en el paso anterior. La implementación más simple utiliza un índice plano, que es un cálculo de distancia por fuerza bruta entre el vector de consulta y todos los vectores de los fragmentos.

Un índice de búsqueda adecuado, optimizado para una recuperación eficiente de más de 10000 elementos, es un índice vectorial como faiss, nmslib o annoy, que utiliza alguna implementación de Vecinos Más Cercanos Aproximados como clustering, árboles o el algoritmo HNSW.

También existen soluciones gestionadas como OpenSearch o ElasticSearch y bases de datos vectoriales, que se encargan del pipeline de ingestión de datos descrito en el primer paso, como Pinecone, Weaviate o Chroma.

Dependiendo de la elección del índice, los datos y las necesidades de búsqueda, también puedes almacenar metadatos junto con los vectores y luego utilizar filtros de metadatos para buscar información dentro de algunas fechas o fuentes, por ejemplo.

LlamaIndex admite muchos índices de almacenamiento de vectores, pero también hay otras implementaciones de índices más simples, como el índice de lista, el índice de árbol y el índice de tabla de palabras clave – hablaremos de este último en la parte de recuperación mediante fusión.

2.Índices jerárquicos

En caso de tener muchos documentos para recuperar, necesitas poder buscar eficientemente dentro de ellos, encontrar información relevante y sintetizarla en una sola respuesta con referencias a las fuentes. Una forma eficiente de hacerlo en el caso de una gran base de datos es crear dos índices: uno compuesto por resúmenes y otro compuesto por fragmentos de documentos, y buscar en dos pasos, primero filtrando los documentos relevantes por los resúmenes y luego buscando solo dentro de este grupo relevante.

2.3 Preguntas hipotéticas y HyDE

Otro enfoque es pedir a un LLM que genere una pregunta para cada fragmento y que incorpore estas preguntas en vectores, realizando una búsqueda de consultas en este índice de vectores de preguntas (reemplazando los vectores de fragmentos por vectores de preguntas en nuestro índice) y luego, después de la recuperación, redirigir a los fragmentos de texto originales y enviarlos como contexto para que el LLM obtenga una respuesta. Este enfoque mejora la calidad de la búsqueda debido a una mayor similitud semántica entre la consulta y la pregunta hipotética en comparación con la que tendríamos para un fragmento real.

También existe el enfoque de lógica inversa llamado HyDE: se le pide a un LLM que genere una respuesta hipotética dada la consulta y luego se utiliza su vector junto con el vector de consulta para mejorar la calidad de la búsqueda.

2.4 Enriquecimiento de contexto

El concepto aquí es recuperar fragmentos más pequeños para mejorar la calidad de la búsqueda, pero agregar contexto cercano para que el LLM razona sobre ello. Hay dos opciones: ampliar el contexto mediante frases alrededor del fragmento recuperado más pequeño o dividir los documentos de manera recursiva en varios fragmentos padre más grandes que contengan fragmentos hijos más pequeños.

2.4.1 Recuperación con ventana de frases En este esquema, cada frase de un documento se incorpora por separado, lo que proporciona una gran precisión en la búsqueda de la distancia de coseno de la consulta al contexto. Para razonar mejor sobre el contexto encontrado después de recuperar la única frase más relevante, ampliamos la ventana de contexto con k frases antes y después de la frase recuperada y luego enviamos este contexto ampliado al LLM.

La parte verde es la incrustación de la frase que se encuentra en el índice de búsqueda, y el párrafo negro + verde completo se alimenta al LLM para ampliar su contexto al razonar sobre la consulta proporcionada.

2.4.2 Retriever de fusión automática (también conocido como Retriever de documentos padre)

La idea aquí es bastante similar a la del Retriever de ventana de frases: buscar fragmentos de información más granulares y luego ampliar la ventana de contexto antes de alimentar dicho contexto a un LLM para razonar. Los documentos se dividen en fragmentos hijos más pequeños que se refieren a fragmentos padres más grandes.

Los documentos se dividen en una jerarquía de fragmentos y luego los fragmentos más pequeños se envían al índice. En el momento de la recuperación, se extraen k fragmentos, y si hay n fragmentos que se refieren al mismo fragmento padre, los reemplazamos por este fragmento padre y lo enviamos al LLM para generar respuestas.

Obtén fragmentos más pequeños durante la recuperación primero, luego, si hay más de n fragmentos en los k fragmentos principales recuperados que están vinculados al mismo nodo padre (fragmento más grande), reemplazamos el contexto alimentado al LLM con este nodo padre, como si fusionáramos automáticamente algunos fragmentos recuperados en un fragmento padre más grande, de ahí el nombre del método. Solo como nota: la búsqueda se realiza solo dentro del índice de los nodos hijos. Consulta el tutorial de LlamaIndex sobre Retriever recursivo + Referencias de nodos para obtener más información detallada.

Una idea relativamente antigua es tomar lo mejor de ambos mundos: búsqueda basada en palabras clave de la vieja escuela: algoritmos de recuperación dispersos como tf-idf o estándar de la industria de búsqueda BM25, y búsqueda semántica o vectorial moderna y combinarlo en un resultado de recuperación. El único truco aquí es combinar correctamente los resultados recuperados con diferentes puntuaciones de similitud; este problema generalmente se resuelve con la ayuda del algoritmo de Fusión de Rango Recíproco, que vuelve a clasificar los resultados recuperados para la salida final.

En LangChain esto se implementa en la clase Ensemble Retriever, combinando una lista de retrievers que defines, por ejemplo, un índice vectorial faiss y un retriever basado en BM25, y utilizando RRF para reordenar.

En LlamaIndex esto se hace de una manera bastante similar.

La búsqueda híbrida o de fusión generalmente proporciona mejores resultados de recuperación, ya que se combinan dos algoritmos de búsqueda complementarios, teniendo en cuenta tanto la similitud semántica como la coincidencia de palabras clave entre la consulta y los documentos almacenados.

3. Reordenamiento y filtrado

Así que obtuvimos nuestros resultados de recuperación con cualquiera de los algoritmos descritos anteriormente, ahora es el momento de refinarlos mediante filtrado, reordenamiento o alguna transformación. En LlamaIndex hay una variedad de Postprocesadores disponibles, filtrando los resultados según la puntuación de similitud, las palabras clave, los metadatos o reordenándolos con otros modelos como un LLM, un codificador cruzado basado en sentence-transformer, el punto final de reordenamiento de Cohere o según metadatos como la recencia de la fecha, básicamente todo lo que puedas imaginar.

Este es el paso final antes de alimentar nuestro contexto recuperado a LLM para obtener la respuesta resultante.

Ahora es el momento de adentrarnos en técnicas de RAG más sofisticadas como la transformación y el enrutamiento de consultas, ambas involucrando LLMs y representando así un comportamiento agente: una lógica compleja que implica razonamiento LLM dentro de nuestro pipeline RAG.

4. Transformaciones de consulta

Las transformaciones de consulta son una familia de técnicas que utilizan un LLM como motor de razonamiento para modificar la entrada del usuario con el fin de mejorar la calidad de recuperación. Existen diferentes opciones para hacerlo.

Query transformation principles illustrated

Si la consulta es compleja, LLM puede descomponerla en varias subconsultas. Por ejemplo, si preguntas: – “¿Qué framework tiene más estrellas en Github, Langchain o LlamaIndex?”, es poco probable que encontremos una comparación directa en algún texto de nuestro corpus, por lo que tiene sentido descomponer esta pregunta en dos subconsultas que presuponen recuperación de información más simple y concreta: – “¿Cuántas estrellas tiene Langchain en Github?” – “¿Cuántas estrellas tiene Llamaindex en Github?” Se ejecutarían en paralelo y luego el contexto recuperado se combinaría en una única consulta para que LLM sintetice una respuesta final a la consulta inicial. Ambas bibliotecas tienen esta funcionalidad implementada: como un Recuperador de Consultas Múltiples en LangChain y como un Motor de Consulta de Subpreguntas en Llamaindex.

  1. Reorientación de la consulta hacia atrás utiliza LLM para generar una consulta más general, para la cual obtenemos un contexto más general o de alto nivel útil para fundamentar la respuesta a nuestra consulta original. También se realiza una recuperación para la consulta original y ambos contextos se alimentan a LLM en el paso final de generación de respuestas. Aquí tienes una implementación de LangChain.
  2. La reescritura de consultas utiliza LLM para reformular la consulta inicial con el fin de mejorar la recuperación. Tanto LangChain como LlamaIndex tienen implementaciones, aunque un poco diferentes, considero que la solución de LlamaIndex es más poderosa en este caso.

Citas de referencia

Esta no lleva un número porque es más un instrumento que una técnica de mejora de recuperación, aunque muy importante. Si hemos utilizado múltiples fuentes para generar una respuesta, ya sea debido a la complejidad de la consulta inicial (tuvimos que ejecutar múltiples subconsultas y luego combinar el contexto recuperado en una respuesta), o porque encontramos contexto relevante para una sola consulta en varios documentos, surge la pregunta de si podríamos referenciar con precisión nuestras fuentes.

Hay un par de formas de hacerlo:

  1. Incluir esta tarea de referencia en nuestra solicitud y pedirle a LLM que mencione los identificadores de las fuentes utilizadas.
  2. Correlacionar las partes de la respuesta generada con los fragmentos de texto originales en nuestro índice – llamaindex ofrece una solución eficiente basada en coincidencia difusa para este caso. En caso de que no hayas oído hablar de la coincidencia difusa, esta es una técnica de coincidencia de cadenas increíblemente poderosa.

5. Motor de conversación

Lo siguiente importante para construir un buen sistema RAG que pueda funcionar más de una vez para una sola consulta es la lógica de conversación, teniendo en cuenta el contexto del diálogo, al igual que en los chatbots clásicos en la era pre-LLM. Esto es necesario para respaldar preguntas de seguimiento, anáforas o comandos de usuario arbitrarios relacionados con el contexto del diálogo anterior. Se resuelve mediante la técnica de compresión de consulta, teniendo en cuenta el contexto del chat junto con la consulta del usuario.

Como siempre, hay varios enfoques para dicha compresión de contexto: un popular y relativamente simple ContextChatEngine, que primero recupera el contexto relevante para la consulta del usuario y luego lo envía a LLM junto con el historial del chat desde el búfer de memoria para que LLM esté al tanto del contexto anterior al generar la siguiente respuesta.

Un caso un poco más sofisticado es CondensePlusContextMode: en cada interacción, el historial del chat y el último mensaje se condensan en una nueva consulta, luego esta consulta se envía al índice y el contexto recuperado se pasa a LLM junto con el mensaje original del usuario para generar una respuesta.

Es importante tener en cuenta que también se admite un Motor de Conversación basado en agentes de OpenAI en LlamaIndex que proporciona un modo de chat más flexible y Langchain también admite la API funcional de OpenAI.

Una ilustración de diferentes tipos y principios de motores de conversación

Existen otros tipos de motores de conversación como ReAct Agent, pero pasemos a los propios Agentes en la sección 7.

6. Enrutamiento de consultas

El enrutamiento de consultas es el paso de toma de decisiones impulsado por LLM sobre qué hacer a continuación dada la consulta del usuario – las opciones generalmente son resumir, realizar una búsqueda en algún índice de datos o probar varias rutas diferentes y luego sintetizar su salida en una única respuesta.

Los enrutadores de consultas también se utilizan para seleccionar un índice, o, en términos más amplios, un almacén de datos donde enviar la consulta del usuario; ya sea que tengas múltiples fuentes de datos, por ejemplo, un almacén de vectores clásico y una base de datos en grafo o una base de datos relacional, o tienes una jerarquía de índices – para un almacenamiento multi-documento, un caso bastante clásico sería un índice de resúmenes y otro índice de fragmentos de documentos, por ejemplo.

Definir el enrutador de consultas implica establecer las opciones que puede tomar. La selección de una opción de enrutamiento se realiza con una llamada a LLM, que devuelve su resultado en un formato predefinido, utilizado para enrutarr la consulta hacia el índice dado, o, si estamos hablando del comportamiento agnático, a subcadenas o incluso a otros agentes, como se muestra en el esquema del agente de múltiples documentos a continuación.

Ambos LlamaIndex y LangChain admiten enrutadores de consultas.

7. Agentes en RAG

Los agentes (soportados tanto por LangChain como por LlamaIndex) han estado presentes casi desde que se lanzó la primera API LLM — la idea era proporcionar un LLM capaz de razonar con un conjunto de herramientas y una tarea por completar. Las herramientas pueden incluir algunas funciones deterministas como una función de código o una API externa, e incluso otros agentes — esta idea de encadenamiento de LLM es de donde LangChain obtuvo su nombre.

Los agentes son en sí mismos una gran cosa y es imposible profundizar lo suficiente en el tema dentro de una descripción general de RAG, así que simplemente continuaré con el caso de recuperación de múltiples documentos basado en agentes, haciendo una breve parada en la estación de OpenAI Assistants, ya que es algo relativamente nuevo, presentado en la reciente conferencia de desarrollo de OpenAI como GPTs y que funciona bajo el capó del sistema RAG descrito a continuación.

OpenAI Assistants básicamente han implementado muchas de las herramientas necesarias alrededor de un LLM que anteriormente teníamos de código abierto — un historial de chat, un almacenamiento de conocimiento, una interfaz para subir documentos y, quizás lo más importante, una API de llamada de funciones. Esta última proporciona capacidades para convertir el lenguaje natural en llamadas de API a herramientas externas o consultas a bases de datos.

En LlamaIndex, hay una clase OpenAIAgent que combina esta lógica avanzada con las clases ChatEngine y QueryEngine, brindando conversaciones basadas en el conocimiento y conscientes del contexto, junto con la capacidad de realizar múltiples llamadas de funciones de OpenAI en una sola conversación, lo que realmente aporta un comportamiento agente inteligente.

Echemos un vistazo al Esquema de agentes de múltiples documentos — una configuración bastante sofisticada que implica la inicialización de un agente (OpenAIAgent) en cada documento, capaz de resumir documentos y realizar mecánicas de preguntas y respuestas clásicas, y un agente principal responsable de enrutamiento de consultas a los agentes de documentos y de la síntesis de la respuesta final.

Cada agente de documento tiene dos herramientas — un índice de almacenamiento de vectores y un índice de resumen, y en función de la consulta enrutada, decide cuál utilizar. Y para el agente principal, todos los agentes de documentos son herramientas respectivamente.

Este esquema ilustra una arquitectura RAG avanzada con muchas decisiones de enrutamiento hechas por cada agente involucrado. El beneficio de este enfoque es la capacidad de comparar diferentes soluciones o entidades, descritas en diferentes documentos y sus resúmenes, junto con la clásica capacidad de resumen y las mecánicas de preguntas y respuestas de un solo documento — esto cubre básicamente los casos de uso de chat con colecciones de documentos más frecuentes.

Un esquema que ilustra agentes de múltiples documentos, involucrando tanto el enrutamiento de consultas como patrones de comportamiento agente.

La desventaja de un esquema tan complejo se puede intuir a partir de la imagen — es un poco lento debido a las múltiples iteraciones con los LLM dentro de nuestros agentes. Por si acaso, una llamada LLM siempre es la operación más larga en una tubería RAG — la búsqueda está optimizada para ser rápida por diseño. Por lo tanto, para un almacenamiento de varios documentos grandes, recomendaría considerar algunas simplificaciones en este esquema para que sea escalable.

8. Sintetizador de respuestas

Este es el último paso de cualquier pipeline RAG: generar una respuesta basada en todo el contexto que hemos recuperado cuidadosamente y en la consulta inicial del usuario. El enfoque más simple sería concatenar y alimentar todo el contexto recuperado (por encima de un umbral de relevancia) junto con la consulta a un LLM de una vez. Sin embargo, como siempre, hay otras opciones más sofisticadas que involucran múltiples llamadas a LLM para refinar el contexto recuperado y generar una mejor respuesta.

Los principales enfoques para la síntesis de respuestas son:1. Refinar iterativamente la respuesta enviando el contexto recuperado al LLM por fragmentos. 2. Resumir el contexto recuperado para que encaje en el mensaje. 3. Generar múltiples respuestas basadas en diferentes fragmentos de contexto y luego concatenarlos o resumirlos. Para obtener más detalles, consulta la documentación del módulo de síntesis de respuestas.

Afinación fina del codificador y el LLM

Este enfoque involucra la afinación fina de algunos de los dos modelos de DL involucrados en nuestro pipeline RAG: ya sea el codificador Transformer, responsable de la calidad de las incrustaciones y, por lo tanto, de la calidad de la recuperación del contexto, o un LLM, responsable del mejor uso del contexto proporcionado para responder la consulta del usuario; afortunadamente, este último es un modelo de aprendizaje en pocos ejemplos muy bueno.

Una gran ventaja hoy en día es la disponibilidad de LLM de alta gama como GPT-4 para generar conjuntos de datos sintéticos de alta calidad. Pero siempre debes tener en cuenta que tomar un modelo de código abierto entrenado por equipos de investigación profesionales con conjuntos de datos grandes, limpios y validados cuidadosamente, y realizar una afinación rápida utilizando un conjunto de datos sintéticos pequeños, puede reducir las capacidades generales del modelo.

Afinación fina del codificador

También he sido un poco escéptico acerca del enfoque de afinación fina del codificador, ya que los últimos codificadores Transformer optimizados para la búsqueda son bastante eficientes. Así que he probado el aumento de rendimiento proporcionado por la afinación fina de bge-large-en-v1.5 (en los primeros 4 puestos del MTEB leaderboard en el momento de la escritura) en la configuración de LlamaIndex notebook, y demostró un aumento del 2% en la calidad de recuperación. Nada espectacular, pero es bueno tener conocimiento de esa opción, especialmente si tienes un conjunto de datos de dominio estrecho para el que estás construyendo RAG.

Afinación fina del clasificador

Otra buena opción es tener un codificador cruzado para reordenar tus resultados recuperados si no confías completamente en tu codificador base. Funciona de la siguiente manera: pasas la consulta y cada uno de los fragmentos de texto recuperados principales al codificador cruzado, separados por un token SEP, y los afinas para que se obtenga 1 para los fragmentos relevantes y 0 para los no relevantes. Un buen ejemplo de este proceso de afinación se encuentra aquí, los resultados indican que la puntuación por pares mejoró un 4% mediante la afinación del codificador cruzado.

Afinación fina del LLM

Recientemente, OpenAI comenzó a proporcionar afinación fina del LLM a través de su API, y LlamaIndex tiene un tutorial sobre la afinación fina de GPT-3.5-turbo en la configuración de RAG para “destilar” parte del conocimiento de GPT-4. La idea aquí es tomar un documento, generar una serie de preguntas con GPT-3.5-turbo, luego utilizar GPT-4 para generar respuestas a estas preguntas basadas en el contenido del documento (construyendo un pipeline RAG impulsado por GPT-4) y, finalmente, afinar GPT-3.5-turbo en ese conjunto de datos de pares pregunta-respuesta. El framework ragas utilizado para la evaluación del pipeline RAG muestra un aumento del 5% en las métricas de veracidad, lo que significa que el modelo GPT 3.5-turbo afinado hizo un mejor uso del contexto proporcionado para generar su respuesta que el modelo original.

Se muestra un enfoque más sofisticado en el reciente artículo RA-DIT: Sintonización de Instrucciones Duales Mejorada por Recuperación de Meta AI Research, sugiriendo una técnica para ajustar tanto el LLM como el Recuperador (un Codificador Dual en el artículo original) en tripletas de consulta, contexto y respuesta. Para conocer los detalles de implementación, consulte esta guía. Esta técnica se utilizó tanto para afinar los LLM de OpenAI a través de la API de afinamiento como el modelo de código abierto Llama2 (en el artículo original), lo que resultó en un aumento del ~5% en las métricas de tareas intensivas en conocimiento (en comparación con Llama2 65B con RAG) y un aumento de un par de puntos porcentuales en tareas de razonamiento de sentido común.

En caso de que conozca enfoques mejores para el afinamiento de LLM para RAG, por favor comparta su experiencia en la sección de comentarios, especialmente si se aplican a los LLM de código abierto más pequeños.

Evaluación

Existen varios marcos de evaluación del rendimiento de los sistemas RAG que comparten la idea de tener algunas métricas separadas como la relevancia general de la respuesta, la fundamentación de la respuesta, la fidelidad y la relevancia del contexto recuperado.

Ragas, mencionado en la sección anterior, utiliza fidelidad y relevancia de la respuesta como métricas de calidad para las respuestas generadas, y la precisión y recuperación clásicas para la parte de recuperación del esquema RAG.

En un curso corto recientemente publicado Construcción y Evaluación Avanzada de RAG por Andrew NG, LlamaIndex y el marco de evaluación Truelens, sugieren la tríada RAGrelevancia del contexto recuperado para la consulta, fundamentación (cuánto es respaldada la respuesta LLM por el contexto proporcionado) y relevancia de la respuesta para la consulta.

La métrica clave y más controlable es la relevancia del contexto recuperado — básicamente, las partes 1-7 del pipeline RAG avanzado descritas anteriormente, más las secciones de afinamiento del Codificador y Clasificador de Rangos tienen como objetivo mejorar esta métrica, mientras que la parte 8 y el afinamiento del LLM se centran en la relevancia y fundamentación de la respuesta.

Un buen ejemplo de un pipeline de evaluación de recuperador bastante simple se puede encontrar aquí y se aplicó en la sección de afinamiento del Codificador. Un enfoque un poco más avanzado que tiene en cuenta no solo la tasa de acierto, sino el Rank Recíproco Medio, una métrica común de motores de búsqueda, y también métricas de respuesta generada como la fidelidad y relevancia, se muestra en el libro de cocina de OpenAI.

LangChain tiene un marco de evaluación bastante avanzado LangSmith donde se pueden implementar evaluadores personalizados y también monitorea las trazas que se ejecutan dentro de su pipeline RAG para hacer que su sistema sea más transparente.

En caso de que esté construyendo con LlamaIndex, hay un llama pack rag_evaluator que proporciona una herramienta rápida para evaluar su pipeline con un conjunto de datos públicos.

Conclusión

Traté de resumir los enfoques algorítmicos principales para RAG y de ilustrar algunos de ellos con la esperanza de que esto pueda generar nuevas ideas para probar en tu tubería de RAG o traer algo de sistema a la amplia variedad de técnicas que se han inventado este año, para mí 2023 fue el año más emocionante en ML hasta ahora.

Hay muchas otras cosas a considerar como la búsqueda en la web basada en RAG (RAGs por LlamaIndex, webLangChain, etc.), adentrarse más en las arquitecturas agentes (y la reciente participación de OpenAI en este juego) y algunas ideas sobre la memoria a largo plazo de los LLMs.

El principal desafío de producción para los sistemas RAG, además de la relevancia y fidelidad de las respuestas, es la velocidad, especialmente si te interesan los esquemas basados en agentes más flexibles, pero eso es algo para otro artículo. Esta función de transmisión que utiliza ChatGPT y la mayoría de los otros asistentes no es un estilo ciberpunk aleatorio, sino simplemente una forma de acortar el tiempo percibido de generación de respuestas. Es por eso que veo un futuro muy prometedor para los LLM más pequeños y los lanzamientos recientes de Mixtral y Phi-2 nos están llevando en esta dirección.

¡Muchas gracias por leer este largo artículo!

Las principales referencias se encuentran en mi base de conocimientos, hay un copiloto para conversar con este conjunto de documentos: https://app.iki.ai/playlist/236.

Encuéntrame en LinkedIn o Twitter

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Conoce FLM-101B Un decodificador de solo lectura de LLM de código abierto con 101 mil millones de parámetros

Últimamente, los modelos de lenguaje grandes (LLMs) están destacando en tareas de NLP y multimodalidad, pero se enfre...

Inteligencia Artificial

Esta semana en IA, 31 de julio de 2023

Esta semana en IA en VoAGI proporciona un resumen semanal de los últimos acontecimientos en el mundo de la Inteligenc...

Investigación

Investigadores de MIT CSAIL discuten las fronteras del AI generativo.

Expertos se reúnen para examinar el código, lenguaje e imágenes generados por la inteligencia artificial, así como su...

Inteligencia Artificial

Chip fotónico 'se ajusta como un Lego

Un nuevo chip semiconductor compacto de fotónica de silicio expande significativamente el ancho de banda de radiofrec...

Inteligencia Artificial

Investigadores de Google presentan 𝗦𝘆𝗻𝘁𝗵𝗜𝗗 una herramienta digital para marcar con marcas de agua e identificar imágenes generadas por IA

En el panorama en constante evolución de la inteligencia artificial (IA), los modelos generativos están creando imáge...