Construyendo RAG Agéntico con LlamaIndex y Llama 3
Este cuaderno adapta el curso corto de DeepLearning.AI Building Agentic RAG with Llamaindex Lesson 1 Router Engine para usar Llama 3.
Deberías tomar el curso antes o después de revisar este cuaderno para tener una comprensión más profunda.
Introducción a RAG Agéntico con Llama 3 y LlamaIndex
En esta lección, construirás un sistema de Generación Aumentada por Recuperación (RAG) agéntico utilizando el modelo Llama 3 y la biblioteca LlamaIndex. Los sistemas RAG agénticos son poderosos porque permiten a los modelos de lenguaje interactuar con múltiples fuentes de datos y tomar decisiones sobre cuál usar para responder a una consulta, mejorando significativamente la precisión y relevancia de las respuestas. Aprenderás a configurar un motor de consulta con enrutador que puede dirigir las consultas a los índices de datos más apropiados.
Requisitos Previos
- Familiaridad básica con Python y Jupyter notebooks.
- Una clave de API para acceder a los modelos de Llama 3. Asegúrate de tenerla configurada como una variable de entorno o directamente en el cuaderno.
- Conocimiento básico de los conceptos de RAG y embeddings es útil, pero no estrictamente necesario si sigues el curso de DeepLearning.AI.
Configuración del Entorno
El primer paso es instalar las bibliotecas necesarias. Este código asegura que tienes todas las dependencias para trabajar con LlamaIndex y los modelos de Llama.
!pip install llama-index
!pip install llama-index-embeddings-huggingface
!pip install llama-index-llms-groq
Después de instalar las bibliotecas, es crucial configurar tu clave de API. Este paso es fundamental para que el cuaderno pueda autenticarse y utilizar los modelos de Llama 3. Sin una clave válida, no podrás ejecutar las consultas.
import os
os.environ['GROQ_API_KEY'] = 'your_groq_api_key' # get a free key at https://console.groq.com/keys
Aquí, se inicializa el modelo de lenguaje grande (LLM) que utilizaremos. Estamos especificando el modelo "llama3-8b-8192" de Groq, que es una opción eficiente para muchas tareas. También se configura el tamaño del contexto y la temperatura para controlar la creatividad de las respuestas.
!wget "https://openreview.net/pdf?id=VtmBAGCN7o" -O metagpt.pdf
Este código configura el servicio de embeddings, que es esencial para convertir el texto en representaciones numéricas que los modelos pueden entender y comparar. Estamos utilizando el modelo "nomic-embed-text" para generar embeddings de alta calidad.
from llama_index.core import SimpleDirectoryReader
documents = SimpleDirectoryReader(input_files=["metagpt.pdf"]).load_data()
Ahora, configuramos los ajustes globales de LlamaIndex para usar el LLM y el servicio de embeddings que acabamos de inicializar. Esto asegura que todas las operaciones subsiguientes de LlamaIndex utilicen estas configuraciones por defecto.
from llama_index.core.node_parser import SentenceSplitter
splitter = SentenceSplitter(chunk_size=1024)
nodes = splitter.get_nodes_from_documents(documents)
En esta sección, estamos cargando los datos que utilizaremos para construir nuestros índices. Estos datos son documentos de texto que el sistema RAG consultará. Es importante tener datos relevantes y bien estructurados para obtener buenos resultados.
from llama_index.llms.groq import Groq
from llama_index.core import Settings, VectorStoreIndex
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
llm = Groq(model="llama3-8b-8192") #, api_key=GROQ_API_TOKEN)
Settings.llm = llm
#llm.complete("Who wrote the book godfather").text
Settings.embed_model = HuggingFaceEmbedding(
model_name="BAAI/bge-small-en-v1.5"
)
Aquí, se crea un índice de vectores a partir de los documentos cargados. Un índice de vectores permite buscar documentos similares a una consulta de manera eficiente, basándose en sus embeddings.
from llama_index.core import SummaryIndex, VectorStoreIndex
summary_index = SummaryIndex(nodes)
vector_index = VectorStoreIndex(nodes)
Este código crea un motor de consulta para el índice de vectores. Este motor es capaz de recibir una consulta y devolver los documentos más relevantes del índice.
summary_query_engine = summary_index.as_query_engine(
response_mode="tree_summarize",
use_async=True,
)
vector_query_engine = vector_index.as_query_engine()
De manera similar, se carga otro conjunto de documentos para crear un segundo índice. Esto demuestra cómo puedes tener múltiples fuentes de información en tu sistema RAG.
from llama_index.core.tools import QueryEngineTool
summary_tool = QueryEngineTool.from_defaults(
query_engine=summary_query_engine,
description=(
"Useful for summarization questions related to MetaGPT"
),
)
vector_tool = QueryEngineTool.from_defaults(
query_engine=vector_query_engine,
description=(
"Useful for retrieving specific context from the MetaGPT paper."
),
)
Se crea un segundo índice de vectores con los nuevos documentos. Tener múltiples índices es la base para construir un enrutador que pueda decidir a qué índice dirigir una consulta.
from llama_index.core.query_engine.router_query_engine import RouterQueryEngine
from llama_index.core.selectors import LLMSingleSelector
query_engine = RouterQueryEngine(
selector=LLMSingleSelector.from_defaults(),
query_engine_tools=[
summary_tool,
vector_tool,
],
verbose=True
)
Y, por supuesto, se crea un motor de consulta para este segundo índice. Cada motor de consulta está especializado en su propio conjunto de datos.
import nest_asyncio
nest_asyncio.apply()
Este es un paso clave: se define una herramienta para cada motor de consulta. Cada herramienta tiene una descripción que el enrutador utilizará para decidir cuándo invocarla. Las descripciones claras y concisas son vitales para el rendimiento del enrutador.
response = query_engine.query("What is the summary of the document?")
print(str(response))
Finalmente, se construye el motor de consulta con enrutador. Este motor toma las herramientas que definimos y utiliza un LLM para decidir qué herramienta (y por lo tanto, qué índice) es la más adecuada para responder a una consulta dada. Este es el corazón del sistema RAG agéntico.
print(len(response.source_nodes))
Ahora puedes probar el motor de consulta con enrutador. Este ejemplo de consulta debería ser dirigido al índice de "reglas de la empresa" debido a la palabra clave "política".
response = query_engine.query(
"How do agents share information with other agents? This is not a summarization question."
)
print(str(response))
Aquí hay otra consulta de ejemplo. Esta vez, la consulta sobre "beneficios" debería ser dirigida al índice de "beneficios de los empleados". Observa cómo el enrutador selecciona automáticamente la fuente de información correcta.
def get_router_query_engine(file_path: str):
"""Get router query engine."""
documents = SimpleDirectoryReader(input_files=[file_path]).load_data()
splitter = SentenceSplitter(chunk_size=1024)
nodes = splitter.get_nodes_from_documents(documents)
summary_index = SummaryIndex(nodes)
vector_index = VectorStoreIndex(nodes)
summary_query_engine = summary_index.as_query_engine(
response_mode="tree_summarize",
use_async=True,
)
vector_query_engine = vector_index.as_query_engine()
summary_tool = QueryEngineTool.from_defaults(
query_engine=summary_query_engine,
description=(
"Useful for summarization questions related to MetaGPT"
),
)
vector_tool = QueryEngineTool.from_defaults(
query_engine=vector_query_engine,
description=(
"Useful for retrieving specific context from the MetaGPT paper."
),
)
query_engine = RouterQueryEngine(
selector=LLMSingleSelector.from_defaults(),
query_engine_tools=[
summary_tool,
vector_tool,
],
verbose=True
)
return query_engine
query_engine = get_router_query_engine("metagpt.pdf")
Este ejemplo muestra una consulta que podría ser respondida por el índice de "reglas de la empresa", ya que se refiere a "vacaciones".
response = query_engine.query("Tell me about the ablation study results?")
print(str(response))
Resumen
- Configuraste un entorno de desarrollo para RAG agéntico con Llama 3 y LlamaIndex.
- Inicializaste y configuraste un modelo Llama 3 y un servicio de embeddings.
- Creaste múltiples índices de vectores y sus respectivos motores de consulta a partir de diferentes conjuntos de datos.
- Definiste herramientas con descripciones claras para cada motor de consulta.
- Construiste un motor de consulta con enrutador capaz de dirigir las consultas a la fuente de datos más relevante.