paint-brush
IA para la gestión del conocimiento: iteración en RAG con la arquitectura QE-RAGpor@shanglun
4,222 lecturas
4,222 lecturas

IA para la gestión del conocimiento: iteración en RAG con la arquitectura QE-RAG

por Shanglun Wang27m2023/09/12
Read on Terminal Reader

Demasiado Largo; Para Leer

Recuperación-Generación Aumentada, o RAG, es una arquitectura popular para desarrollar potentes aplicaciones LLM. Sin embargo, la arquitectura actual tiene algunas limitaciones reales. Analizamos la creación de una aplicación RAG y luego analizamos cómo podemos mejorarla utilizando una nueva arquitectura llamada QE-RAG.
featured image - IA para la gestión del conocimiento: iteración en RAG con la arquitectura QE-RAG
Shanglun Wang HackerNoon profile picture


A medida que la revolución LLM comienza a tomar forma, el entusiasmo ha dado paso al desarrollo comercial. A medida que la ola inicial de entusiasmo disminuye, la IA generativa ya no se ve como una caja negra omnisciente, sino más bien como una herramienta constituyente, aunque extremadamente poderosa, del arsenal de un ingeniero. Como resultado, los empresarios y tecnólogos ahora cuentan con un conjunto cada vez más maduro de herramientas y técnicas para desarrollar aplicaciones LLM.


Uno de los casos de uso más interesantes de los LLM ha sido en el campo de la gestión del conocimiento. Los LLM especializados, basados en la tecnología GPT de OpenAI o en modelos de código abierto como LLaMa 2 y Flan-T5, se están utilizando de forma inteligente para gestionar grandes cantidades de datos. Mientras que antes las organizaciones con grandes conjuntos de datos de texto tenían que depender de técnicas de búsqueda de texto como la coincidencia aproximada o la indexación de texto completo, ahora tienen acceso a un potente sistema que no sólo puede encontrar la información sino también resumirla en un formato fácil de leer y que ahorra tiempo. moda.


Dentro de este caso de uso, la arquitectura de generación aumentada de recuperación , o RAG, se ha convertido en una arquitectura destacada con enorme flexibilidad y rendimiento. Con esta arquitectura, las organizaciones pueden indexar rápidamente un conjunto de trabajos, realizar consultas semánticas sobre él y generar respuestas informativas y convincentes a consultas definidas por el usuario basadas en el corpus. Han surgido varias empresas y servicios para respaldar las implementaciones de la arquitectura RAG, lo que destaca su capacidad de permanencia.


Por muy eficaz que pueda ser RAG, esta arquitectura también tiene varias limitaciones reales. En este artículo, exploraremos la arquitectura RAG, identificaremos sus limitaciones y propondremos una arquitectura mejorada para resolver estas limitaciones.


Como ocurre con todos los demás artículos, busco conectarme con otros tecnólogos y entusiastas de la IA. Si tiene alguna idea sobre cómo se puede mejorar esta arquitectura o tiene ideas sobre la IA que le gustaría discutir, ¡no dude en comunicarse con nosotros ! Puedes encontrarme en Github o LinkedIn, los enlaces están en mi perfil y al final de este artículo.


Descripción general del contenido

  • Arquitectura de recuperación de generación aumentada (RAG)
  • Limitaciones de la arquitectura RAG
  • Proponer QE-RAG, o RAG mejorado con preguntas
  • Conclusión


Arquitectura de recuperación de generación aumentada (RAG)

Con nombres como RAG, Flan y LLaMa, es probable que la comunidad de IA no gane premios por nombres futuristas y elegantes en el corto plazo. Sin embargo, la arquitectura RAG ciertamente merece un premio por su combinación de dos técnicas extremadamente poderosas disponibles gracias al desarrollo de LLM: incrustación de documentos contextuales e ingeniería rápida.


En su forma más simple, la arquitectura RAG es un sistema que utiliza la búsqueda de vectores incorporados para encontrar las partes del corpus más relevantes para una pregunta, inserta las partes en un mensaje y luego usa la ingeniería de mensajes para garantizar que el La respuesta se basa en los extractos proporcionados en el mensaje. Si todo esto le parece un poco confuso, siga leyendo porque explicaré cada componente por separado. También incluiré código de ejemplo para que puedas seguirlo.


El modelo de incrustación

En primer lugar, un sistema RAG eficaz requiere un modelo de integración potente. El modelo de incrustación transforma un documento de texto natural en una serie de números, o un "vector", que representa aproximadamente el contenido semántico del documento. Suponiendo que el modelo de incrustación sea bueno, podrá comparar los valores semánticos de dos documentos diferentes y determinar si los dos documentos son semánticamente similares usando aritmética vectorial.


Para ver esto en acción, pegue el siguiente código en un archivo Python y ejecútelo:


 import openai from openai.embeddings_utils import cosine_similarity openai.api_key = [YOUR KEY] EMBEDDING_MODEL = "text-embedding-ada-002" def get_cos_sim(input_1, input_2): embeds = openai.Embedding.create(model=EMBEDDING_MODEL, input=[input_1, input_2]) return cosine_similarity(embeds['data'][0]['embedding'], embeds['data'][1]['embedding']) print(get_cos_sim('Driving a car', 'William Shakespeare')) print(get_cos_sim('Driving a car', 'Riding a horse'))



El código anterior genera las incrustaciones de las frases "Conducir un automóvil", "William Shakespeare" y "Montar a caballo" antes de compararlas entre sí utilizando el algoritmo de similitud del coseno. Esperaríamos que la similitud del coseno fuera mayor cuando las frases son semánticamente similares, por lo que “Conducir un automóvil” y “Montar a caballo” deberían ser mucho más similares, mientras que “Conducir un automóvil” y “William Shakespeare” deberían ser diferentes.


Debería ver que, según el modelo de integración de OpenAI, ada-002, la frase "conducir un automóvil" es 88% similar a la frase "montar a caballo" y 76% similar a la frase "William Shakespeare". Esto significa que el modelo de incorporación está funcionando como esperábamos. Esta determinación de la similitud semántica es la base del sistema RAG.


La idea de la similitud del coseno es notablemente sólida cuando se extiende a comparaciones de documentos mucho más grandes. Tomemos, por ejemplo, el poderoso monólogo de Macbeth de Shakespeare, “ Mañana, y mañana, y mañana ”:


 monologue = '''Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing.''' print(get_cos_sim(monologue, 'Riding a car')) print(get_cos_sim(monologue, 'The contemplation of mortality'))


Deberías ver que el monólogo es sólo un 75% similar a la idea de “viajar en coche” y un 82% similar a la idea de “La contemplación de la mortalidad”.


Pero no sólo tenemos que comparar monólogos con ideas, sino que también podemos comparar los monólogos con preguntas. Por ejemplo:


 get_cos_sim('''Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing.''', 'Which Shakespearean monologue contemplates mortality?') get_cos_sim('''Full of vexation come I, with complaint Against my child, my daughter Hermia. Stand forth, Demetrius. My noble lord, This man hath my consent to marry her. Stand forth, Lysander. And my gracious Duke, This man hath bewitch'd the bosom of my child. Thou, thou, Lysander, thou hast given her rhymes, And interchanged love-tokens with my child: Thou hast by moonlight at her window sung With feigning voice verses of feigning love, And stol'n the impression of her fantasy With bracelets of thy hair, rings, gauds, conceits, Knacks, trifles, nosegays, sweetmeats (messengers Of strong prevailment in unharden'd youth): With cunning hast thou filch'd my daughter's heart, Turn'd her obedience, which is due to me, To stubborn harshness. And, my gracious Duke, Be it so she will not here, before your Grace, Consent to marry with Demetrius, I beg the ancient privilege of Athens: As she is mine, I may dispose of her; Which shall be either to this gentleman, Or to her death, according to our law Immediately provided in that case.''', 'Which Shakespearean monologue contemplates mortality?')



Debería ver que la incorporación muestra que el monólogo de Macbeth está mucho más cerca, contextualmente, de la pregunta "¿Qué monólogo de Shakespeare contempla la mortalidad?" que el monólogo de Egeus, que menciona la muerte pero no aborda directamente el concepto de mortalidad.


La búsqueda de vectores

Ahora que tenemos la integración, ¿cómo la usamos en nuestro sistema RAG? Bueno, supongamos que quisiéramos darle a nuestro sistema RAG el conocimiento de todos los monólogos de Shakespeare para que pueda responder preguntas sobre Shakespeare. En este caso, descargaríamos todos los monólogos de Shakespeare y generaríamos sus incrustaciones. Si sigue las instrucciones, puede generar la incrustación de esta manera:



 embedding = openai.Embedding.create(model=EMBEDDING_MODEL, input=[monologue])['data'][0]['embedding']


Una vez que tengamos las incrustaciones, querremos almacenarlas de una manera que nos permita consultarlas y compararlas con una nueva incrustación. Normalmente los colocaríamos en lo que se llama una base de datos vectorial , que es un almacén de datos especializado que permite comparaciones rápidas de dos vectores. Sin embargo, a menos que su corpus sea extremadamente grande, las comparaciones de fuerza bruta son sorprendentemente tolerables para la mayoría de los casos de uso experimentales que no son de producción donde el rendimiento no es crítico.


Ya sea que elija utilizar una base de datos o no, querrá crear un sistema que pueda encontrar elementos en su corpus que mejor se ajusten a la pregunta. En nuestro ejemplo, querremos tener la capacidad de encontrar el monólogo que sea más relevante para la pregunta del usuario en cuestión. Es posible que desee hacer algo como:



 monologues_embeddings = [ ['Tomorrow, and tomorrow, and tomorrow...', [...]], # text in the left position, embedding in the right position ['Full of vexation come I...', [...]], … # More monologues and their embeddings as you see fit. ] def lookup_most_relevant(question): embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=[question])['data'][0]['embedding'] top_monologue = sorted(monologues_embeddings, key=lambda x: cosine_similarity(embed, x[1]), reverse=True)[0] return top_monologue lookup_most_relevant(“How does Macbeth evaluate his life when he is confronted with his mortality?“)


Si ejecuta este ejemplo, debería ver seleccionado el monólogo de Macbeth, con aproximadamente un 82% de similitud con la pregunta.


La ingeniería rápida

El último paso en el modelo RAG es la ingeniería rápida. En nuestro caso, no es demasiado difícil. Ahora que tenemos el monólogo a mano, podemos construir un mensaje simplemente incrustando el monólogo en nuestra consulta y luego haciendo la pregunta:


 completion = openai.ChatCompletion.create( model="gpt-4", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": """ Consider the following monologue: Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing. How does Macbeth evaluate his life when he is confronted with his mortality? """}, ] )


Deberías ver una respuesta como:


 In the well-known "Tomorrow and tomorrow and tomorrow" monologue from Shakespeare's Macbeth, the titular character plunges into existential despair when confronted with his impending death. Macbeth evaluates his life as hollow, futile, and meaningless when facing his mortality. He sees it as a "walking shadow" and himself as a "poor player," highlighting his view of life as a fleeting, contrived performance with no lasting substance or impact. The "brief candle" is a metaphor for his own mortality, suggesting that life's flame can be extinguished suddenly and unceremoniously. By stating "It is a tale told by an idiot, full of sound and fury, signifying nothing," Macbeth is expressing his belief that life, despite all its noise and action, is ultimately empty, absurd, and void of meaning. Overall, Macbeth's examination of his life is profoundly pessimistic, revealing his deep despair and cynicism.


Por supuesto, este ejemplo en particular no es la demostración más poderosa de la arquitectura RAG, ya que la mayoría de los modelos GPT ya conocen los monólogos de Shakespeare y han sido entrenados en la gran cantidad de análisis de Shakespeare públicamente en Internet. De hecho, si le hace a GPT-4 esta pregunta exacta sin el monólogo incorporado, probablemente obtendrá una muy buena respuesta, aunque probablemente no incluirá tantas citas del soliloquio. Sin embargo, debería ser evidente que, en un entorno comercial, esta técnica se puede aplicar de forma cruzada a conjuntos de datos esotéricos o propietarios que no son accesibles para las implementaciones GPT existentes.


De hecho, los lectores que estén familiarizados con mi artículo anterior, Creación de un analizador de documentos con ChatGPT, Google Cloud y Python , pueden reconocer que la última parte de la técnica es muy similar a la ingeniería rápida que hice en ese artículo. Partiendo de esa idea, podemos imaginar muy fácilmente un sistema RAG construido sobre publicaciones del gobierno japonés (los datos de muestra de ese artículo), que permitiría a los usuarios buscar y hacer preguntas sobre la política económica japonesa. El sistema recuperaría rápidamente los documentos más relevantes, los resumiría y produciría una respuesta basada en un conocimiento profundo de un dominio específico que no está disponible para los modelos GPT básicos. Este poder y simplicidad es precisamente la razón por la que la arquitectura RAG está ganando mucha popularidad entre los desarrolladores de LLM.


Ahora que hemos repasado la arquitectura RAG, exploremos algunas de las deficiencias de esta arquitectura.


Limitaciones de la arquitectura RAG

Incorporación de depuración

Debido a que muchos sistemas RAG se basan en la incrustación de documentos y la búsqueda vectorial para conectar la pregunta y los documentos relevantes, todo el sistema suele ser tan bueno como el modelo de incrustación utilizado. El modelo de incrustación de OpenAI es increíblemente flexible y existen muchas técnicas para ajustar las incrustaciones. LLaMa, el competidor de código abierto de Meta para GPT, ofrece modelos de integración ajustables. Sin embargo, hay un aspecto de caja negra ineludible en el modelo de incrustación. Esto es algo manejable cuando se comparan cadenas de texto cortas con documentos mucho más largos. En nuestro ejemplo anterior, tenemos que dar un ligero acto de fe en que la búsqueda de incrustación es capaz de conectar la "mortalidad" con el monólogo de "mañana, mañana y mañana". Esto puede resultar bastante incómodo para cargas de trabajo en las que la transparencia y la depuración son fundamentales.

Sobrecarga de contexto

Otra limitación del modelo RAG es la cantidad relativamente limitada de contexto que se le puede pasar. Debido a que el modelo de incrustación requiere un contexto a nivel de documento para funcionar bien, debemos tener cuidado al dividir el corpus para la incrustación. El monólogo de Macbeth puede tener un 82% de similitud con la pregunta sobre la mortalidad, pero ese número se reduce al 78% cuando se compara la pregunta con la inserción de las dos primeras líneas del monólogo, es decir, “Mañana, y mañana, y mañana. Se arrastra en este mezquino ritmo de día a día, hasta la última sílaba del tiempo registrado”.


Como resultado, el contexto que se pasa al mensaje RAG debe ser bastante grande. Actualmente, los modelos GPT de mayor contexto todavía están limitados a 16.000 tokens, lo cual es bastante texto, pero cuando trabaja con transcripciones de entrevistas largas o artículos ricos en contexto, estará limitado en la cantidad de contexto que puede brindar. en el mensaje de generación final.

Terminología novedosa

La última limitación del modelo RAG es su incapacidad para trabajar con terminología novedosa. Las personas que trabajan en campos específicos tienden a desarrollar terminologías y formas de hablar que son exclusivas de ese campo. Cuando estas terminologías no están presentes en los datos de entrenamiento del modelo de incorporación, el proceso de búsqueda se verá afectado.


Por ejemplo, es posible que el modelo de incrustación ada-002 no sepa que el "lenguaje de programación Rust" está relacionado con "LLVM". De hecho, devuelve una similitud de coseno relativamente baja del 78%. Esto significa que los documentos que hablan sobre LLVM pueden no mostrar una gran similitud en una consulta sobre Rust, aunque las dos ideas están estrechamente relacionadas en la vida real.


Por lo general, el problema de la terminología novedosa se puede superar con un poco de ingeniería rápida, pero en el contexto de una búsqueda de incorporación, eso es relativamente difícil de hacer. Como se mencionó anteriormente, es posible ajustar un modelo de incrustación, pero enseñarle al modelo de incrustación la nueva terminología en todos los contextos puede ser propenso a errores y consumir mucho tiempo.

Proponer QE-RAG, o RAG mejorado con preguntas

Dadas estas limitaciones, me gustaría proponer una arquitectura modificada que permitiría la implementación de una nueva clase de sistemas RAG que evite muchas de las limitaciones descritas anteriormente. La idea se basa en hacer búsquedas vectoriales sobre preguntas frecuentes, además del corpus, y utilizar un LLM para preprocesar el corpus en el contexto de las preguntas. Si ese proceso parece complicado, no se preocupe, repasaremos los detalles de implementación en esta sección junto con ejemplos de código que puede utilizar para seguirlo.


Una cosa a tener en cuenta es que QE-RAG debe ejecutarse junto con una implementación básica de RAG para que pueda recurrir a otra implementación si es necesario. A medida que la implementación madure, debería necesitar cada vez menos el respaldo, pero QE-RAG todavía pretende ser una mejora, en lugar de un reemplazo, de la arquitectura RAG básica.


La arquitectura

Las líneas generales de la arquitectura QE-RAG son las siguientes:

  1. Cree una base de datos vectorial de preguntas que se pueden hacer o que probablemente se harán sobre el corpus.
  2. Preprocesar y resumir el corpus con las preguntas de la base de datos de vectores.
  3. Cuando llegue una consulta de usuario, compare la consulta del usuario con las preguntas en la base de datos de vectores.
  4. Si una pregunta en la base de datos es muy similar a la consulta del usuario, recupere la versión del corpus que se resume para responder la pregunta.
  5. Utilice el corpus resumido para responder la pregunta del usuario.
  6. Si ninguna pregunta en la base de datos es muy similar a la consulta del usuario, recurra a una implementación básica de RAG.


Repasemos cada parte por turno.


Incrustaciones de preguntas

La arquitectura comienza, al igual que el RAG básico, con una incrustación y una base de datos vectorial. Sin embargo, en lugar de incorporar los documentos, incluiremos una serie de preguntas.

Para ilustrar esto, supongamos que estamos tratando de crear un LLM que sea experto en Shakespeare. Es posible que queramos que responda preguntas como:


 questions = [ "How does political power shape the way characters interact in Shakespeare's plays?", "How does Shakespeare use supernatural elements in his plays?", "How does Shakespeare explore the ideas of death and mortality in his plays?", "How does Shakespeare explore the idea of free will in his plays?" ]


Querremos crear una incrustación para ellos así y guardarlos o usarlos más tarde:


 questions_embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=questions)


Preprocesamiento y resumen

Ahora que tenemos las preguntas, querremos descargar y resumir el corpus. Para este ejemplo, descargaremos las versiones HTML de Macbeth y Hamlet:


 import openai import os import requests from bs4 import BeautifulSoup plays = { 'shakespeare_macbeth': 'https://www.gutenberg.org/cache/epub/1533/pg1533-images.html', 'shakespeare_hamlet': 'https://www.gutenberg.org/cache/epub/1524/pg1524-images.html', } if not os.path.exists('training_plays'): os.mkdir('training_plays') for name, url in plays.items(): print(name) file_path = os.path.join('training_plays', '%s.txt' % name) if not os.path.exists(file_path): res = requests.get(url) with open(file_path, 'w') as fp_write: fp_write.write(res.text)


Luego procesamos las obras en escenas, usando las etiquetas HTML como guía:


 with open(os.path.join('training_plays', 'shakespeare_hamlet.txt')) as fp_file: soup = BeautifulSoup(''.join(fp_file.readlines())) headers = soup.find_all('div', {'class': 'chapter'})[1:] scenes = [] for header in headers: cur_act = None cur_scene = None lines = [] for i in header.find_all('h2')[0].parent.find_all(): if i.name == 'h2': print(i.text) cur_act = i.text elif i.name == 'h3': print('\t', i.text.replace('\n', ' ')) if cur_scene is not None: scenes.append({ 'act': cur_act, 'scene': cur_scene, 'lines': lines }) lines = [] cur_scene = i.text elif (i.text != '' and not i.text.strip('\n').startswith('ACT') and not i.text.strip('\n').startswith('SCENE') ): lines.append(i.text)


Y aquí está la parte que hace que QE-RAG sea único: en lugar de crear incrustaciones para escenas específicas, creamos resúmenes para ellas, dirigidos a cada una de las preguntas:


 def summarize_for_question(text, question, location): completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that provides helpful summaries."}, {"role": "user", "content": """Is the following excerpt from %s relevant to the following question? %s === %s === If so, summarize the sections that are relevant. Include references to specific passages that would be useful. If not, simply say: \"nothing is relevant\" without additional explanation""" % ( location, question, text )}, ] ) return completion


Esta función le pide a ChatGPT que haga 2 cosas: 1) identificar si el pasaje es realmente útil para responder la pregunta en cuestión y 2) resumir las partes de la escena que son útiles para responder la pregunta.


Si prueba esta función con algunas escenas fundamentales de Macbeth o Hamlet, verá que GPT3.5 es bastante bueno para identificar si una escena es relevante para la pregunta y el resumen será un poco más corto que la escena misma. Esto hace que sea mucho más fácil de integrar más adelante en el paso de ingeniería inicial.


Ahora podemos hacer esto para todas las escenas.


 for scene in scenes: scene_text = ''.join(scene['lines']) question_summaries = {} for question in questions: completion = summarize_for_question(''.join(scene['lines']), question, "Shakespeare's Hamlet") question_summaries[question] = completion.choices[0].message['content'] scene['question_summaries'] = question_summaries


En cargas de trabajo de producción, colocaríamos los resúmenes en una base de datos, pero en nuestro caso, simplemente los escribiremos como un archivo JSON en el disco.


Búsqueda de vectores en dos etapas

Ahora supongamos que recibimos una pregunta de usuario como la siguiente:


 user_question = "How do Shakespearean characters deal with the concept of death?"


Como en Vanilla RAG, querremos crear una incrustación para la pregunta:


 uq_embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=[user_question])['data'][0]['embedding']


En un RAG básico, compararíamos la incrustación de preguntas del usuario con las incrustaciones de las escenas de Shakespeare, pero en QE-RAG, comparamos con las incrustaciones de las preguntas:


 print([cosine_similarity(uq_embed, q) for q in question_embed])


Vemos que la búsqueda vectorial ha identificado (correctamente) la pregunta 3 como la pregunta más relevante. Ahora, recuperamos los datos resumidos de la pregunta 3:


 relevant_texts = [] for scene in hamlet + macbeth: # hamlet and macbeth are the scene lists from the above code if "NOTHING IS RELEVANT" not in scene['question_summaries'][questions[2]].upper() and \ "NOTHING IN THIS EXCERPT" not in scene['question_summaries'][questions[2]].upper() and \ 'NOTHING FROM THIS EXCERPT' not in scene['question_summaries'][questions[2]].upper() and \ "NOT DIRECTLY ADDRESSED" not in scene['question_summaries'][questions[2]].upper(): relevant_texts.append(scene['question_summaries'][questions[2]])


Tenga en cuenta que, debido a que el resumen GPT no es determinista, es posible que obtenga varias cadenas diferentes para indicar que una escena no es relevante para la pregunta en cuestión. La clave es incluir únicamente los extractos relevantes en la lista de resúmenes relevantes.


En esta etapa, podemos hacer una búsqueda vectorial de segundo nivel para incluir solo los resúmenes más relevantes en nuestro mensaje, pero dado el tamaño de nuestro corpus, simplemente podemos usar toda la lista relevant_texts en nuestro mensaje.


Ingeniería rápida

Ahora que tenemos todos los extractos, podemos crear el mensaje de esta manera:

 completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that answers questions based on excerpts."}, {"role": "user", "content": """Consider the following passages: %s ==== Answer this question: %s Be detailed and complete in your analysis. Make references to specific passages where helpful. Answer only based on passages provided. """ % ( '\n===\n'.join(relevant_texts), user_question )}, ] )


Deje que se ejecute la llamada API y debería ver algo como lo siguiente:


 Based on the passages provided, Shakespearean characters deal with the concept of death in various ways. In Hamlet, for example, the characters contemplate the nature of death and its implications. Hamlet himself reflects on the brevity of life and the corrupting influence of vices. He questions the purpose of existence and contemplates suicide as a release from the burdens of life. In the passage, Hamlet says, "To die, to sleep— / To sleep, perchance to dream. Ay, there's the rub, / For in that sleep of death what dreams may come" (Lines 65-67). This shows his contemplation of the afterlife and the uncertainty surrounding it. In Macbeth, characters are confronted with the consequences of their actions and the fragility of life. Lady Macbeth, for instance, experiences guilt and remorse for her involvement in the murder of King Duncan. She is haunted by visions of blood on her hands and expresses the desire to escape the consequences of her actions. In the passage, Lady Macbeth says, "Out, damned spot! Out, I say!" (Line 30). This demonstrates her struggle to cope with the guilt and the psychological toll it takes on her. Furthermore, both Macbeth and Lady Macbeth reflect on the inevitability and the consequences of their actions. In the passage, Macbeth laments the decay of life and the loss of purpose and meaning. He reflects on the transitory nature of existence and the insignificance of worldly achievements. Macbeth states, "Life's but a walking shadow, a poor player / That struts and frets his hour upon the stage" (Lines 217-218). This shows his acceptance of mortality and his realization that material possessions and power do not bring true fulfillment. In summary, Shakespearean characters deal with the concept of death in various ways. They contemplate the nature of life and the afterlife, struggle with guilt and remorse, and question the meaning and purpose of their existence. Shakespeare's exploration of death and mortality through his characters provides insight into the complexities of human nature and the universal human experience of confronting one's mortality.


Es un muy buen resumen que se basa en muchas partes diferentes de Hamlet y Macbeth.

A modo de comparación, creé incrustaciones para escenas completas y ejecuté una búsqueda RAG básica usando el mismo mensaje, encontrando las N escenas más relevantes hasta llegar a 10,000 tokens.


 relevant_texts = [] for i in range(10): if len(encoding.encode('\n===\n'.join(relevant_texts))) > 10000: break relevant_texts.append(''.join(macbeth[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(macbeth_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) relevant_texts.append(''.join(hamlet[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(hamlet_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines']))


Si envía esto al mensaje, debería ver algo como lo siguiente:


 Based on the provided passages, Shakespearean characters deal with the concept of death in various ways. In Hamlet, the characters reflect on death and mortality extensively. Hamlet himself contemplates suicide, expressing his desire to end his suffering and questioning the purpose of life. He says, "To be, or not to be: that is the question" (Hamlet, Act III, Scene I, Lines 56). This soliloquy reveals his struggle with the concept of death and his contemplation of the consequences of choosing either life or death. Additionally, in the same play, the appearance of the Ghost prompts discussions about death. The characters question the meaning and significance of encountering the dead, and Hamlet grapples with the idea of mortality in relation to his father's death. He reflects, "Oh God! a beast that wants discourse of reason / Would have mourn'd longer" (Hamlet, Act I, Scene II, Lines 152-153). This passage highlights Hamlet's grief and his pondering of the brevity of life and the transitory nature of existence. In Macbeth, the characters also confront death and its consequences. Macbeth, after killing King Duncan, reflects on the significance of the act and its implications. He says, "Will all great Neptune's ocean wash this blood Clean from my hand? No, this my hand will rather The multitudinous seas incarnadine" (Macbeth, Act II, Scene II, Lines 77-79). This passage showcases Macbeth's awareness of the guilt associated with murder and his realization that the blood on his hands cannot be cleansed. Lady Macbeth, on the other hand, shows a different perspective on death. She suppresses her guilt and tries to detach herself from the consequences of their actions. She states, "A little water clears us of this deed" (Macbeth, Act II, Scene II, Line 69). This passage reveals her denial and determination to move forward without remorse. In conclusion, Shakespearean characters deal with the concept of death in various ways. Some contemplate the meaning of life and question the purpose of existence, while others grapple with the guilt and consequences that come with taking a life. Shakespeare explores the complexities of death and mortality through his characters' introspection and their different responses to the inevitability of death.


Este es un análisis muy convincente, pero no aborda muchos de los pasajes más importantes de Hamlet y Macbeth. Como puede ver, QE-RAG tiene una clara ventaja al poder incorporar un contexto más relevante que un sistema RAG estándar.


Sin embargo, el ejemplo anterior no demuestra otra ventaja del QE-RAG, que es la capacidad de brindar al desarrollador un mejor control del proceso de incorporación. Para ver cómo el QE-RAG logra esto, veamos una extensión de este problema: abordar la nueva terminología.


Ampliación del QE-RAG a nueva terminología

Donde realmente brilla el QE-RAG es cuando se introduce una nueva terminología. Por ejemplo, supongamos que está introduciendo un concepto nuevo, como la palabra japonesa “zetsubou”, que es un término que se ubica entre la desesperación y la desesperanza, y específicamente transmite una rendición a las circunstancias propias. No se trata de una catástrofe tan inmediata como el concepto inglés de desesperación, sino más bien de la aquiescencia ante cosas desagradables que están sucediendo.


Supongamos que queremos responder una pregunta como:


user_question = "How do Shakespearean characters cope with Zetsubou?"


Con Vanilla RAG haríamos una búsqueda de incrustaciones y luego agregaríamos una explicación en el paso final de ingeniería:


 relevant_texts = [] for i in range(10): if len(encoding.encode('\n===\n'.join(relevant_texts))) > 10000: break relevant_texts.append(''.join(macbeth[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(macbeth_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) relevant_texts.append(''.join(hamlet[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(hamlet_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that answers questions based on excerpts."}, {"role": "user", "content": """Zetsubou is the concept of hopelessness and despair, combined with a surrender to whim of one's circumstances. Consider the following passages: %s ==== Answer this question: %s Be detailed and complete in your analysis. Make references to specific passages where helpful. Answer only based on passages provided. """ % ( '\n===\n'.join(relevant_texts), user_question )}, ] )


El resultado es una respuesta muy bien escrita y convincente, pero un poco exagerada, que se centra en algunas escenas de Hamlet. Macbeth no se menciona en absoluto en esta respuesta, porque ninguna de las escenas pasó la búsqueda de incrustación. Al observar las incrustaciones, queda muy claro que el significado semántico de “zetsubou” no se capturó adecuadamente y, por lo tanto, no se pudieron recuperar los textos relevantes.


En QE-RAG, podemos inyectar la definición del nuevo término en la etapa de resumen, mejorando dramáticamente la calidad del texto accesible por el sistema:


 def summarize_for_question(text, question, location, context=''): completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that provides helpful summaries."}, {"role": "user", "content": """%s Is the following excerpt from %s relevant to the following question? %s === %s === If so, summarize the sections that are relevant. Include references to specific passages that would be useful. If not, simply say: \"nothing is relevant\" without additional explanation""" % ( context, location, question, text )}, ] ) return completion questions = [ "How do characters deal with Zetsubou in Shakespearean plays?" ] summarize_for_question(''.join(scene['lines']), questions[0], "Shakespeare's Macbeth", "Zetsubou is the concept of hopelessness and despair, combined with a surrender to whim of one's circumstances." )


Utilice este mensaje de resumen con los pasajes y verá resúmenes que son extremadamente precisos y contextuales. Estos resúmenes podrán utilizarse posteriormente en el QE-RAG posterior.


Además, la incrustación de preguntas será extremadamente similar, porque aunque ada-002 no conoce el significado preciso de "zetsubou", la presencia de esta palabra en ambas preguntas hace que las incrustaciones de preguntas sean extremadamente similares.


Por lo tanto, utilizando QE-RAG para responder la pregunta original sobre Zetsubou, obtenemos la siguiente respuesta:


 Based on the passages provided, Shakespearean characters cope with Zetsubou, or hopelessness and despair, in different ways. In "Macbeth," Lady Macbeth copes with Zetsubou through guilt and anguish. She is consumed by the guilt of her and her husband's actions, and this guilt manifests in her sleepwalking and attempts to wash her hands of imagined blood stains. This can be seen in her utterances of "Out, damned spot!" and her preoccupation with the blood on her hands. Lady Macbeth's coping mechanism is to face the consequences of her actions head-on, even if it means descending into madness. The Doctor and Gentlewoman observe her behavior and acknowledge that her condition requires divine intervention. In "Hamlet," the excerpt does not provide specific passages or examples of characters coping with Zetsubou. However, it does address Hamlet's inner turmoil and struggle to cope with his circumstances. Hamlet's state of mind, confusion, and madness are a reflection of despair. The characters in this scene are attempting to understand Hamlet's condition and find ways to deal with it, but the excerpt does not provide details on how they cope with Zetsubou. In "Macbeth," Macbeth himself copes with Zetsubou by surrendering to his dire circumstances. He becomes desensitized to fear and horror, indicating a kind of resignation to his grim circumstances. He acknowledges that there is no escape from his fate and chooses to face it head-on, even though he knows it will lead to his downfall. Macbeth's reaction to the news of his wife's death and his subsequent soliloquy reflect a deep despair and hopelessness. He sees life as meaningless, a "tale Told by an idiot, full of sound and fury, Signifying nothing." Macbeth's surrender to his circumstances and his belief in the futility of life demonstrate his coping mechanism for Zetsubou. In "Macbeth," Lady Macduff copes with Zetsubou by expressing her feelings of despair and hopelessness. She feels betrayed and abandoned by her husband, who has fled and left their family behind. She questions his actions and believes that they show a lack of love and wisdom. Lady Macduff experiences a sense of abandonment, which aligns with the concept of Zetsubou. She tries to make her son understand the severity of their circumstances, but he questions the definition of a traitor. Lady Macduff ultimately meets a tragic end, indicating that her coping mechanism for Zetsubou is not successful. In summary, Shakespearean characters cope with Zetsubou in different ways. Lady Macbeth copes through guilt and faces the consequences of her actions, even if it means descending into madness. Macbeth copes through surrendering to his dire circumstances and embracing his fate. Lady Macduff copes through expressing her feelings of despair and hopelessness but ultimately meets a tragic end. These characters' coping mechanisms reflect different responses to Zetsubou in Shakespearean plays


El resultado todavía lucha un poco con este concepto, pero debería ser evidente que QE-RAG es mucho más capaz de abordar el meollo de la pregunta y aprovechar una variedad de fuentes.

Y con eso, implementamos QE-RAG y demostramos su caso de uso.


Conclusión

En el artículo de hoy, examinamos la cada vez más popular arquitectura RAG y sus limitaciones. Luego ampliamos la arquitectura RAG con una nueva arquitectura llamada QE-RAG, que busca utilizar más plenamente las capacidades de los modelos de lenguaje grandes. Además de mejorar la precisión y el acceso contextual, QE-RAG permite que todo el sistema crezca a medida que interactúa con los usuarios y se familiariza más con los tipos de preguntas que se formulan, lo que permite a las empresas desarrollar propiedad intelectual única además del código abierto. o LLM disponibles comercialmente .

Por supuesto, como idea experimental, el QE-RAG no es perfecto. Si tiene ideas sobre cómo se puede mejorar esta arquitectura, o simplemente desea tener una discusión sobre las tecnologías LLM, no dude en escribirme a través de mi Github o LinkedIn .