IA agente con LangChain — Parte 5: RAG agente con ReAct y
Parte 5 de la IA agente con LangChain: RAG agente, donde un agente ReAct decide cuándo recuperar la información y un paso de reflexión verifica la respuesta antes de devolverla.
Fuentes: Agentic AI with LangChain — Part 5: Agentic RAG with ReAct and Reflection
Utilícelo como una versión reestructurada dirigida a operadores de las ideas presentadas en “Agentic AI with LangChain — Part 5: Agentic RAG with ReAct and Reflection”: etapas claras, secciones de código ordenadas y notas de recuperación que perduran tras el traspaso de tareas. La visión general funciona mejor cuando se considera como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Conceptos técnicos
En cuanto a los conceptos técnicos, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Cite los pasajes que realmente sustentan la respuesta. Sin citaciones, los operadores no pueden distinguir entre alucinaciones y lagunas en el indexado.
1. Configuraciones del sistema
Para las 1. Configuraciones del sistema, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. La visibilidad temprana del costo evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Cite los pasajes que realmente sirvieron de base para la respuesta. Sin citaciones, los operadores no pueden distinguir entre alucinaciones y brechas en el indexado.
OPENAI_API_KEY="<Your OpenAI API Key>"
VECTOR_DB=pinecone
PINECONE_API_KEY=<your Pinecone API Key>
PINECONE_ENVIRONMENT=gcp-starter
LANGSMITH_TRACING=true
LANGSMITH_ENDPOINT="https://api.smith.langchain.com"
LANGSMITH_API_KEY="<Your LangSmith API Key"
LANGSMITH_PROJECT="agent-ai"
TAVILY_API_KEY=<Your TAVILY API Key>
class BaseConfig(BaseSettings):
OPENAI_API_KEY: Optional[str]
PINECONE_API_KEY: Optional[str]
TAVILY_API_KEY: Optional[str]
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
2. Estructura del proyecto
Para el punto 2, Estructura del proyecto: defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación; los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema.
project/
├── rag_process/ # Pinecone RAG operations
│ ├── __init__.py
│ ├── extractor.py
| └── service.py
│
├── graphs # implement ReAct and Reflection StateGraph
│ ├── nodes.py # graph nodes. Defined as Python functions
│ ├── graph.py # graph workflow
│ ├── consts.py # define node names as constants
│ └── state.py # typed dictionary to store graph states
|
|
├── tools # defines Pinecone retriever and get_weather tools
│ ├── retriever_tools.py # Python function tool to retrieve Pinecone RAG
| └── weather.py # typed dictionary to store graph states
|
|── schemas.py # pydantic data models
|── upload.py # python functions to upload files asynchronously
├── main.py # fastAPI app
├── config.py # pydantic BaseConfig
│── dependencies.py # dependency inject to fastAPI endpoint function
├── .env # environment variable definition
├── client.py # streamlit client
├── .gitignore
└── requirements.txt # package requirements
3. Integración del patrón ReAct
Para el punto 3, Integración del patrón ReAct, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Cite los pasajes que realmente sustentan la respuesta. Sin citas, los operadores no pueden distinguir entre alucinaciones y brechas en el indexado.
3.1. Herramienta de recuperación RAG
Para 3.1. Herramienta de recuperación RAG, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el error debe indicar una única responsabilidad y no un proceso complicado. Cite los pasajes que realmente sirvieron de base para la respuesta. Sin citaciones, los operadores no pueden distinguir entre alucinaciones y lagunas en el indexado.
@tool
async def search_agentic_docs(query: str) -> str:
"""
Good for questions about generative agents, prompt engineering, and adversarial attacks.
Pass a natural language search query to retrieve context from the agentic ai database.
"""
# Simply invoke your existing vector service retriever
docs = await vector_service.retriever.ainvoke(query)
# Flatten the document content into a single string for the LLM
return "\n\n".join([d.page_content for d in docs])
3.2. GraphState
Para 3.2. GraphState, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta fase como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas. Cite los pasajes que realmente sustentan la respuesta. Sin citaciones, los operadores no pueden distinguir entre alucinaciones y brechas en el indexado.
class GraphState(TypedDict):
"""
Represents the state of our graphs.
Attributes:
question: question
generation: LLM generation
acceptable: whether the answer is qualified to be acceptable
messages: list of messages
"""
question: str
generation: str
acceptable: bool
messages: Annotated[list[AnyMessage], add_messages]
loop_count: int
3.3. Nodos ReAct
Para 3.3. Nodos ReAct, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa desde un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. La visibilidad temprana de los costos evita facturas inesperadas cuando el camino pasa de entornos de demostración a entornos compartidos. Cite los pasajes que realmente sustentan la respuesta; sin citas, los operadores no pueden distinguir entre alucinaciones y brechas en el indexado.
4. Integración del patrón de reflexión
Para 4. Integración del patrón de reflexión, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Cite los pasajes que realmente sustentan la respuesta. Sin citaciones, los operadores no pueden distinguir entre alucinaciones y lagunas en el indexado. Para 4. Integración del patrón de reflexión, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando una tarea falla, el error debe indicar una única responsabilidad y no un conjunto confuso de elementos.
eline.4.1. Cómo funciona la reflexión
Al trabajar en la sección 4.1. Cómo funciona la reflexión, anote primero el contrato: entradas requeridas, señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas. Mida la capacidad de recuperación con un conjunto fijo de preguntas antes de ajustar los prompts. El cambio constante de prompts rara vez soluciona un sistema de recuperación deficiente.
4.2. Prompts
Al trabajar en la sección 4.2. Prompts, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación ayuda a mantener honestos los cambios posteriores en el código. Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Almacene en caché las instrucciones del sistema estables y los esquemas de herramientas. Reenviar un preámbulo idéntico es una causa común de consumo excesivo.
GENERATE_SYSTEM_PROMPT = f"""You are an assistant for question-answering tasks with access to multiple tools.
use these tools to retrieve context to answer the question. If you don't know the answer,
just say that you don't know. Use three sentences maximum and keep the answer concise.
Tool Use Instructions:
- Use tools as much as possible.
- Chain tools when needed (e.g., search for info, then use that to search
for relevant hotels)
- Be conversational and helpful
- If you choose to answer a question using your internal knowledge instead of a tool,
you must be completely certain of the facts. If there is any ambiguity,
or if the question requires up-to-date or highly specific details, you MUST use a tool to verify.
"""
GRADER_SYSTEM_PROMPT = """""You are a grader assessing whether an LLM generation addresses/resolves a
question using the context. Generate critique and recommendations for LLM that generated the answer.
always provide detailed recommendations, including requests for search more relevant context, generate
answer based on context to reduce hallucination, and generate answer relevant to the question.
The LLM generating this answer has the access to the following tools to obtain context:
**get_weather**: search for weather information given a city name
**search_agentic_docs**: Good for questions about generative agents, prompt engineering, and adversarial attacks
**TavilySearch**: General search tool from the internet.
INSTRUCTIONS:
(a) Evaluate if the context is relevant to the question
Provide recommendation if context is not relevant to the question. You can suggest the LLM to use an
appropriate tool. If there is no context, you must be completely certain of the facts. If the question is
covered by provided tools, or there is any ambiguity,
or if the question requires up-to-date or highly specific details, you MUST suggest to use a tool to verify answer.
(b) Evaluate if the answer is based on the context
if the answer is not based on the context, it is a hallucination. You should suggest to regenerate the answer
based on the context.
(c) Evaluate if the answer resolves the question
if the answer does not resolves the question, suggest to regenerate the answer
The LLM generated this answer is strictly instructed to keep its answer CONCISE (maximum of 3 sentences).
Do NOT penalize the answer for omitting minor details if the core question is answered accurately.
If all the evaluations are passed, no suggestions should be provided.
CRITERIA FOR ACCEPTABLE (True):
- If the answer is accurate, addresses the user's question using the context, and does not hallucinate,
you MUST set acceptable to True, even if it missed some details from the context.
- Only set acceptable to False if there is a fundamental flaw (hallucination, wrong information,
or completely missing the point).
OUTPUT REQUIREMENTS:
You must return a structured output with the following fields:
- acceptable (boolean): True if the answer passed all evaluation,
False if any of the evaluation fails and recommendations are provided
- recommendations (string): recommendations you provide
INPUTS:
question: {question}
answer: {answer}
context: {context}
"""
4.3. Nodos de reflexión
Al trabajar en la sección 4.3. Nodos de reflexión, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Mida la capacidad de recuperación con un conjunto fijo de preguntas antes de ajustar los prompts. El cambio constante de prompts rara vez soluciona un sistema de recuperación deficiente. Al trabajar en la sección 4.3. Nodos de reflexión, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Prefiera unidades pequeñas y verificables a scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
5. Flujo de trabajo completo
- El flujo de trabajo completo funciona mejor cuando se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Trate esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace completaciones parciales silenciosas. Separe la política de fragmentación de la política de recuperación. Cambiar una no debe obligar a reescribir la otra cuando cambian las métricas de calidad.