Inicio / Artículos

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.

Editor: REACTAPP.TOP9 min de lectura2059 palabras

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

  1. 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.

6. Compromiso entre agilidad y fiabilidad

7. Resumen final

Lista de verificación operativa