programa
RAG Agenética: Tutorial paso a paso con proyecto de demostración
¿Cuántas veces te gustaría que tu IA pudiera hacer algo más que repetir lo que ya sabe? Como alguien que ha pasado incontables horas perfeccionando y ajustando sistemas de IA, puedo decirte que los modelos tradicionales, aunque impresionantes, a menudo dan la sensación de estar atrapados en una burbuja limitada a aquello en lo que han sido entrenados. Aquí es donde AgenticRAG entra en escena.
En el GAR agéntico, la capacidad de decisión de la IA agéntica se unen a la adaptabilidad de la generación aumentada por recuperación (RAG). Juntos, forman un sistema que puede acceder, razonar y generar información relevante de forma independiente.
Anteriormente escribí un artículo sobre GAR Agéntico que te ayudará a comprenderlo todo desde un punto de vista teórico. Este artículo será más práctico, así que centrémonos en eso.
Visión general del proyecto Agentic RAG
Deja que te explique paso a paso lo que estamos construyendo. Se trata de crear una canalización RAG basada en la arquitectura que se muestra aquí:
Paso 1: Consulta del usuario
Tanto si se trata de una consulta sencilla como de un problema complejo, todo empieza con una pregunta del usuario. Esta es la chispa que pone en marcha nuestra tubería.
Paso 2: Enrutamiento de la consulta
A continuación, el sistema comprueba: ¿Puedo responder a esto?
¿Sí? Se nutre de los conocimientos existentes y ofrece la respuesta inmediatamente.
¿No? ¡Es hora de profundizar! La consulta se encamina al siguiente paso.
Paso 3: Recuperar los datos
Si la respuesta no está fácilmente disponible, el conducto se sumerge en dos posibles fuentes:
- Documentos locales: Utilizaremos un PDF preprocesado como base de conocimientos, donde el sistema buscará trozos de información relevantes.
- Busca en Internet: Si se necesita más contexto, la canalización puede recurrir a fuentes externas para obtener información actualizada.
Paso 4: Construir el contexto
Los datos recuperados, ya sea del PDF o de la web, se compilan después en un contexto coherente y recuperado. Piensa en ello como si reunieras todas las piezas del puzzle antes de unirlas.
Paso 5: Generación de la respuesta final
Por último, este contexto se pasa a un gran modelo lingüístico (LLM) para que elabore una respuesta clara y precisa. No se trata sólo de recuperar datos, sino de comprenderlos y presentarlos de la mejor manera posible.
Al final, tendremos una canalización RAG inteligente y eficiente que podrá responder dinámicamente a las consultas con el contexto del mundo real.
Fuente de datos local
Para empezar, voy a utilizar un documento del mundo real como fuente de datos local. El documento con el que trabajaremos no es otro que Principios de la IA Generativa. Está repleto de información valiosa, por lo que será el caso de prueba perfecto para nuestro pipeline. También necesitarías un resumen del archivo que estoy utilizando a efectos de enrutamiento. Puedes obtener el archivo resumen desde aquí.
Aquí tienes todo lo que necesitas para empezar, paso a paso.
Requisitos previos
Antes de entrar en materia, hay un par de cosas que tendrás que tener preparadas:
- Clave API Groq: Necesitarás una clave API de Groq, que puedes obtener aquí: Consola API Groq
- Clave API Gemini: Géminis te ayudará a la hora de orquestar con los agentes, Groq da respuestas superrápidas pero puede que te quedes atascado con los límites de tarifa que tienen actualmente: Consola API Gemini
- Clave API de Serper.dev: Para cualquier función de búsqueda en Internet, utilizaremos Serper.dev. Consigue tu clave API aquí: Serper.dev API Key
Instalar paquetes
Asegurémonos de que tenemos instaladas las herramientas adecuadas. Abre tu terminal y ejecuta los siguientes comandos para instalar los paquetes de Python necesarios:
pip install langchain-groq faiss-cpu crewai serper pypdf2 python-dotenv setuptools sentence-transformers huggingface distutils`
Configurar el entorno
Una vez que tengas las llaves y los paquetes listos, ¡ya puedes empezar! Te recomiendo que guardes tus claves API en un archivo.env
o de forma segura en tu base de código. Aquí tienes un ejemplo de cómo podría ser tu archivo .env
:
import os from dotenv
import load_dotenv from langchain.vectorstores
import FAISS from langchain.document_loaders
import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_huggingface.embeddings import HuggingFaceEmbeddings
from langchain_groq import ChatGroq
from crewai_tools import SerperDevTool
from crewai import Agent, Task, Crew, LLM
load_dotenv()
GROQ_API_KEY = os.getenv("GROQ_API_KEY")
SERPER_API_KEY = os.getenv("SERPER_API_KEY")
GEMINI=os.getenv("GEMINI")
Cargué variables de entorno para poder gestionar con seguridad las claves API y los datos sensibles sin codificarlos. Esto garantiza que el script permanezca seguro, y puedo cambiar las claves en un solo lugar ( archivo.env
) si es necesario.
En pocas palabras, esto es lo que harán estos paquetes y funciones importados:
- os: Proporciona utilidades de interfaz del sistema operativo.
- dotenv: Carga variables de entorno de los archivos
.env
. - FAISS: Almacén vectorial para la búsqueda y recuperación de similitudes.
- PyPDFLoader: Extrae el contenido de texto de los documentos PDF.
- RecursiveCharacterTextSplitter: Divide el texto en trozos manejables de forma recursiva.
- AbrazandoCarasBodas: Genera incrustaciones de texto utilizando modelos HuggingFace.
- ChatGroq: Interfaz de chat con aceleración de hardware Groq.
- SerperDevTool: Herramienta para realizar búsquedas en Internet.
- ScrapeWebsiteTool: Extrae datos de páginas web.
- Agente: Define una entidad de IA con funciones y objetivos.
- Tarea: Representa un objetivo o una acción concreta para un agente.
- Tripulación: Orquesta agentes y tareas para flujos de trabajo coordinados.
- LLM: Gran interfaz de modelo lingüístico para generar respuestas de texto.
Inicializar los LLM
Comenzamos inicializando dos modelos lingüísticos:
llm
: Para tareas generales como enrutar y generar respuestas. Utilizaremos el modelollama-3.3-70b-specdec
.crew_llm
: Específicamente para el agente de web-scraping, ya que necesita una configuración ligeramente diferente (como la temperatura para salidas más creativas). Utilizaremos el modelogemini/gemini-1.5-flash
.
# Initialize LLM
llm = ChatGroq(
model="llama-3.3-70b-specdec",
temperature=0,
max_tokens=500,
timeout=None,
max_retries=2,
)
crew_llm = LLM(
model="gemini/gemini-1.5-flash",
api_key=GEMINI,
max_tokens=500,
temperature=0.7
)
Añadir el responsable de la toma de decisiones
Esta función check_local_knowledge()
que aparece a continuación actúa como decisor. He creado una consulta a la que he pasado la consulta del usuario y algo de contexto local (del PDF). El modelo responde con un "Sí" o un "No", indicándome si tiene suficiente información a nivel local para responder a la consulta. Si no, recurriremos al web scraping.
def check_local_knowledge(query, context):
"""Router function to determine if we can answer from local knowledge"""
prompt = '''Role: Question-Answering Assistant
Task: Determine whether the system can answer the user's question based on the provided text.
Instructions:
- Analyze the text and identify if it contains the necessary information to answer the user's question.
- Provide a clear and concise response indicating whether the system can answer the question or not.
- Your response should include only a single word. Nothing else, no other text, information, header/footer.
Output Format:
- Answer: Yes/No
Study the below examples and based on that, respond to the last question.
Examples:
Input:
Text: The capital of France is Paris.
User Question: What is the capital of France?
Expected Output:
Answer: Yes
Input:
Text: The population of the United States is over 330 million.
User Question: What is the population of China?
Expected Output:
Answer: No
Input:
User Question: {query}
Text: {text}
'''
formatted_prompt = prompt.format(text=context, query=query)
response = llm.invoke(formatted_prompt)
return response.content.strip().lower() == "yes"
Agente de búsqueda y raspado web
A continuación, configuramos un agente de búsqueda y raspado web utilizando la crewai
biblioteca. Este agente utiliza una herramienta de búsqueda (SerperDevTool
) para encontrar artículos relacionados con la consulta del usuario. La descripción de la tarea garantiza que el agente sepa qué debe recuperar, y resume el contenido web relevante. Es como enviar a un trabajador especializado a buscar datos en Internet.
A continuación, la función get_web_content()
ejecuta el agente de raspado web. Envía la consulta como entrada y recupera un resumen conciso del artículo más relevante. Devuelve el resultado bruto, que se convierte en nuestro contexto si el encaminador decide que no tenemos suficiente información local.
def setup_web_scraping_agent():
"""Setup the web scraping agent and related components"""
search_tool = SerperDevTool() # Tool for performing web searches
scrape_website = ScrapeWebsiteTool() # Tool for extracting data from websites
# Define the web search agent
web_search_agent = Agent(
role="Expert Web Search Agent",
goal="Identify and retrieve relevant web data for user queries",
backstory="An expert in identifying valuable web sources for the user's needs",
allow_delegation=False,
verbose=True,
llm=crew_llm
)
# Define the web scraping agent
web_scraper_agent = Agent(
role="Expert Web Scraper Agent",
goal="Extract and analyze content from specific web pages identified by the search agent",
backstory="A highly skilled web scraper, capable of analyzing and summarizing website content accurately",
allow_delegation=False,
verbose=True,
llm=crew_llm
)
# Define the web search task
search_task = Task(
description=(
"Identify the most relevant web page or article for the topic: '{topic}'. "
"Use all available tools to search for and provide a link to a web page "
"that contains valuable information about the topic. Keep your response concise."
),
expected_output=(
"A concise summary of the most relevant web page or article for '{topic}', "
"including the link to the source and key points from the content."
),
tools=[search_tool],
agent=web_search_agent,
)
# Define the web scraping task
scraping_task = Task(
description=(
"Extract and analyze data from the given web page or website. Focus on the key sections "
"that provide insights into the topic: '{topic}'. Use all available tools to retrieve the content, "
"and summarize the key findings in a concise manner."
),
expected_output=(
"A detailed summary of the content from the given web page or website, highlighting the key insights "
"and explaining their relevance to the topic: '{topic}'. Ensure clarity and conciseness."
),
tools=[scrape_website],
agent=web_scraper_agent,
)
# Define the crew to manage agents and tasks
crew = Crew(
agents=[web_search_agent, web_scraper_agent],
tasks=[search_task, scraping_task],
verbose=1,
memory=False,
)
return crew
def get_web_content(query):
"""Get content from web scraping"""
crew = setup_web_scraping_agent()
result = crew.kickoff(inputs={"topic": query})
return result.raw
Crear la base de datos de vectores
La función setup_vector_db()
configura la base de datos vectorial a partir de un archivo PDF. He aquí cómo lo hice paso a paso:
- Carga el PDF: He utilizado
PyPDFLoader
para extraer el contenido. - Trocea el texto: He dividido el contenido del PDF en trozos más pequeños (1000 caracteres con 50 caracteres de solapamiento) utilizando
RecursiveCharacterTextSplitter
. Esto hace que los datos sean manejables y se puedan buscar. - Crear Vector DB: He incrustado los trozos utilizando un modelo transformador de frases y los he almacenado en un archivo FAISS vectorial FAISS. Esto me permite buscar texto relevante de forma eficaz.
Después, la función get_local_content()
consulta la base de datos vectorial en busca de los 5 trozos más relevantes relacionados con la consulta del usuario. Combina estos trozos en una única cadena de contexto.
def setup_vector_db(pdf_path):
"""Setup vector database from PDF"""
# Load and chunk PDF
loader = PyPDFLoader(pdf_path)
documents = loader.load()
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=1000,
chunk_overlap=50
)
chunks = text_splitter.split_documents(documents)
# Create vector database
embeddings = HuggingFaceEmbeddings(
model_name="sentence-transformers/all-mpnet-base-v2"
)
vector_db = FAISS.from_documents(chunks, embeddings)
return vector_db
def get_local_content(vector_db, query):
"""Get content from vector database"""
docs = vector_db.similarity_search(query, k=5)
return " ".join([doc.page_content for doc in docs])
Generar la respuesta final
Una vez que tengo el contexto (ya sea de documentos locales o de web scraping), lo paso al modelo lingüístico junto con la consulta del usuario. El LLM genera la respuesta final combinando el contexto y la consulta en un formato conversacional.
Éste es el flujo del procesamiento de la consulta principal:
- Enrutamiento: Utilizo
check_local_knowledge()
para decidir si el contenido local del PDF tiene datos suficientes para responder a la consulta. - Si "Sírecupero los trozos relevantes de la base de datos de vectores.
- Si "nobusco artículos relevantes en Internet.
- Respuesta final: Una vez que tengo el contexto, se lo paso al LLM para que genere la respuesta final.
def generate_final_answer(context, query):
"""Generate final answer using LLM"""
messages = [
(
"system",
"You are a helpful assistant. Use the provided context to answer the query accurately.",
),
("system", f"Context: {context}"),
("human", query),
]
response = llm.invoke(messages)
return response.content
def process_query(query, vector_db, local_context):
"""Main function to process user query"""
print(f"Processing query: {query}")
# Step 1: Check if we can answer from local knowledge
can_answer_locally = check_local_knowledge(query, local_context)
print(f"Can answer locally: {can_answer_locally}")
# Step 2: Get context either from local DB or web
if can_answer_locally:
context = get_local_content(vector_db, query)
print("Retrieved context from local documents")
else:
context = get_web_content(query)
print("Retrieved context from web scraping")
# Step 3: Generate final answer
answer = generate_final_answer(context, query)
return answer
Por último, lo unimos todo con la función main()
:
def main():
# Setup
pdf_path = "genai-principles.pdf"
# Initialize vector database
print("Setting up vector database...")
vector_db = setup_vector_db(pdf_path)
# Get initial context from PDF for routing
local_context = get_local_content(vector_db, "")
# Example usage
query = "What is Agentic RAG?"
result = process_query(query, vector_db, local_context)
print("\nFinal Answer:")
print(result)
if __name__ == "__main__":
main()
Arriba, nosotros:
- Configura la base de datos de vectores: Carga y procesa el PDF.
- Inicializa el contexto local: Obtuvimos algunos contenidos generales del PDF para pasarlos como contexto al enrutador.
- Ejecuta una consulta de ejemplo: Ejecutamos una consulta de ejemplo (
"What is Agentic RAG?"
) e imprimimos la respuesta final.
Este es el resultado del programa:
Agentic RAG is a technique for building Large Language Model (LLM) powered applications that incorporates AI agents. It is an extension of the traditional Retrieval-Augmented Generation (RAG) approach, which uses an external knowledge source to provide the LLM with relevant context and reduce hallucinations.
In traditional RAG pipelines, the retrieval component is typically composed of an embedding model and a vector database, and the generative component is an LLM. At inference time, the user query is used to run a similarity search over the indexed documents to retrieve the most similar documents to the query and provide the LLM with additional context.
Agentic RAG, on the other hand, introduces AI agents that are designed to interact with the user query and provide additional context to the LLM. These agents can be thought of as "virtual assistants" that help the LLM to better understand the user's intent and retrieve relevant documents.
The key components of Agentic RAG include:
1. AI agents: These are the virtual assistants that interact with the user query and provide additional context to the LLM.
2. Retrieval component: This is the component that retrieves the most similar documents to the user query.
3. Generative component: This is the component that uses the retrieved documents to generate the final output.
Agentic RAG has several benefits, including:
1. Improved accuracy: By providing additional context to the LLM, Agentic RAG can improve the accuracy of the generated output.
2. Enhanced user experience: Agentic RAG can help to reduce the complexity of the user interface and provide a more natural and intuitive experience.
3. Increased flexibility: Agentic RAG can be easily extended to support new use cases and applications.
However, Agentic RAG also has some limitations, including:
1. Increased complexity: Agentic RAG requires additional components and infrastructure, which can increase the complexity of the system.
2. Higher computational requirements: Agentic RAG requires more computational resources to handle the additional complexity of the AI agents and the retrieval component.
3. Training requirements: Agentic RAG requires more data and training to learn the behaviour of the AI agents and the retrieval component.
Salida Explicación
Cuando formulé la pregunta "¿Qué es la RAG Agentic?" que no figuraba explícitamente en el documento proporcionado, el sistema demostró su flexibilidad e inteligencia. Los agentes de la crewAI enrutaron la consulta correctamente, aprovechando que el enrutador entendía que era necesario un contexto externo. Los agentes colaboraron para raspar el artículo más relevante de la web, analizar su contenido y generar una respuesta bien informada.
El sistema ofrecía una explicación clara de la GAR agéntica, sus componentes (agentes de IA, recuperación y elementos generativos), ventajas (precisión, experiencia del usuario y flexibilidad) y limitaciones (complejidad, necesidades computacionales y requisitos de formación).
Esto pone de relieve la capacidad de la canalización para obtener contexto de forma dinámica y proporcionar información precisa, concisa y valiosa, incluso cuando se enfrenta a consultas que van más allá de su conjunto de datos inicial.
Conclusión
El pipeline que construimos es un proceso dinámico de varios pasos que gestiona eficazmente las consultas de los usuarios combinando el conocimiento existente y el externo.
El sistema puede adaptarse dinámicamente a diversas consultas y proporcionar respuestas precisas y fáciles de usar. Con la integración de datos locales, búsquedas en directo en Internet y una interfaz de usuario sin fisuras, la tubería RAG demuestra ser una solución sólida y práctica para aplicaciones del mundo real. Como siguiente paso, intenta construir algo por tu cuenta utilizando el flujo de trabajo que hemos tratado.
Ingeniero Senior de GenAI y creador de contenidos que ha conseguido 20 millones de visitas compartiendo conocimientos sobre GenAI y ciencia de datos.
Aprende IA con estos cursos
curso
Retrieval Augmented Generation (RAG) with LangChain
curso
Fine-Tuning with Llama 3

blog
Cinco proyectos que puedes crear con modelos de IA generativa (con ejemplos)
tutorial
RAG Con Llama 3.1 8B, Ollama y Langchain: Tutorial

Ryan Ong
12 min
tutorial
RankGPT como Agente de Re-Ranking para RAG (Tutorial)

Ryan Ong
8 min
tutorial
Construir agentes LangChain para automatizar tareas en Python
tutorial
Tutorial de DeepChecks: Automatizar las pruebas de aprendizaje automático
tutorial