

# LangGraph
<a name="supported-frameworks-langgraph"></a>

En esta página se explica cómo instrumentar a un [LangGraph](https://langchain-ai.github.io/langgraph/)agente, cómo se identifican los intervalos y cómo se extraen los campos de evaluación. Termina con [las mejores prácticas](#langgraph-best-practices) para estructurar un LangGraph agente de modo que pueda evaluarse de forma fiable.

 **Temas** 
+  [Instrumente a su agente](#langgraph-instrument) 
+  [¿Cómo se identifican los tramos](#langgraph-span-identification) 
+  [Cómo se extraen los campos de evaluación](#langgraph-extraction) 
  +  [De los registros de eventos](#langgraph-extraction-event-records) 
  +  [A partir de los atributos de span](#langgraph-extraction-attributes) 
+  [Ejemplos de tramos con registros de eventos](#langgraph-examples-with) 
+  [Ejemplos de tramos sin registros de eventos](#langgraph-examples-without) 
+  [Mejores prácticas para los agentes LangGraph ](#langgraph-best-practices) 

## Instrumente a su agente
<a name="langgraph-instrument"></a>

Puede instrumentar un LangGraph agente con cualquiera de las dos bibliotecas de instrumentación: **OpenTelemetry**(`opentelemetry-instrumentation-langchain`) o **OpenInference**(`openinference-instrumentation-langchain`). Amazon Bedrock AgentCore Evaluations es compatible con ambas bibliotecas. Las bibliotecas emiten distintos nombres de ámbito y utilizan distintos atributos de ámbito. El servicio de evaluación extrae los mismos valores de cada uno.

Cuando su agente utiliza la AWS Distro for OpenTelemetry (ADOT), como en Amazon Bedrock AgentCore Runtime, no necesita añadir código de instrumentación explícito. Basta con añadir la biblioteca de instrumentación a las dependencias de su proyecto. ADOT la descubre al inicio y la activa automáticamente.

Añada la biblioteca de instrumentación de la ruta que desee a sus dependencias. Los siguientes ejemplos fijan una versión mínima; usa la última versión disponible a menos que tengas un motivo para marcarla.

**Example**  
NOTA: Utilice la versión `0.55.0` o posterior. La versión 0.55.0 agregó compatibilidad con las nuevas [convenciones OpenTelemetry generativas de intervalo de agentes de IA en las](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md) que se basa el servicio de evaluación.  
Añada `opentelemetry-instrumentation-langchain` a sus dependencias. El nombre del ámbito emitido es. `opentelemetry.instrumentation.langchain`  
 `requirements.txt`:  

```
opentelemetry-instrumentation-langchain>=0.55.0
```
 `pyproject.toml`:  

```
[project]
dependencies = [
    "opentelemetry-instrumentation-langchain>=0.55.0",
]
```
Añada `openinference-instrumentation-langchain` a sus dependencias. El nombre del ámbito emitido es`openinference.instrumentation.langchain`.  
 `requirements.txt`:  

```
openinference-instrumentation-langchain>=0.1.62
```
 `pyproject.toml`:  

```
[project]
dependencies = [
    "openinference-instrumentation-langchain>=0.1.62",
]
```

**nota**  
La instrumentación es un paso para configurar la observabilidad. [Para exportar la telemetría para su evaluación, complete la configuración completa en Configurar la observabilidad.](supported-frameworks.md#supported-frameworks-setup)

## Cómo se identifican los intervalos
<a name="langgraph-span-identification"></a>

El atributo utilizado para clasificar los intervalos difiere entre las dos bibliotecas de instrumentación.

**Example**  
La biblioteca de OpenTelemetry instrumentación clasifica los tramos mediante el `traceloop.span.kind` atributo y también los establece en las versiones recientes. `gen_ai.operation.name`  


| Tipo de tramo | Atributo identificativo | 
| --- | --- | 
| Invoca al agente |  `traceloop.span.kind`= `workflow` (también `gen_ai.operation.name` =`invoke_agent`) | 
| Ejecute la herramienta |  `traceloop.span.kind`= `tool` (también `gen_ai.operation.name` =`execute_tool`) | 
| Inferencia |  `gen_ai.operation.name` = `chat`  | 
La biblioteca de OpenInference instrumentación clasifica los tramos mediante el atributo. `openinference.span.kind`  


| Tipo de tramo | Atributo identificativo | 
| --- | --- | 
| Invoca al agente |  `openinference.span.kind`= `CHAIN` o `AGENT`  | 
| Ejecute la herramienta |  `openinference.span.kind` = `TOOL`  | 
| Inferencia |  `openinference.span.kind` = `LLM`  | 

## Cómo se extraen los campos de evaluación
<a name="langgraph-extraction"></a>

Para el intervalo de agentes de invocación, la entrada y la salida no contienen una lista limpia por mensaje. En cambio, el contenido es el **estado del LangChain gráfico serializado**: una cadena JSON que contiene el estado completo. La forma exacta de este estado serializado difiere entre las dos bibliotecas de instrumentación. En ambos casos, el servicio lo analiza para encontrar el mensaje del usuario (el mensaje humano) y la respuesta del agente (el mensaje de la IA).

LangGraph también serializa las funciones de los mensajes en más de una forma. Un rol puede aparecer como un valor en minúscula (`human`,`ai`,`tool`) o como un nombre de clase de LangChain mensaje (`HumanMessage`,,`AIMessage`). `ToolMessage` El servicio reconoce ambos formularios.

La ubicación de este contenido depende de cómo se recopiló la telemetría. El atributo de identificación (`traceloop.span.kind`o`openinference.span.kind`) está en el intervalo en ambos casos. Para obtener más información, consulte [Intervalos, registros de eventos y señales de telemetría](supported-frameworks-telemetry.md).

### De los registros de eventos
<a name="langgraph-extraction-event-records"></a>

Cuando se divide la telemetría, el servicio lee el contenido del registro de eventos correlacionado con cada intervalo:
+  **Mensaje del usuario** y **respuesta del agente**: del registro de eventos del intervalo de agentes invocado, en y. `body.input` `body.output`
+  **Llamada de herramienta**: el nombre de la herramienta que aparece en el intervalo de herramientas de ejecución. Los argumentos y el resultado de la herramienta provienen del registro de eventos de ese intervalo, en `body.input` y`body.output`.

Para ver ejemplos, consulte [Ejemplos de intervalos con registros de eventos](#langgraph-examples-with).

### De los atributos de span
<a name="langgraph-extraction-attributes"></a>

Cuando la telemetría no está dividida, el mismo contenido permanece en el tramo que los atributos. Los atributos dependen de la biblioteca de instrumentación:
+  **OpenTelemetry**:
  +  **Mensaje del usuario** y **respuesta del agente**: desde `gen_ai.task.input` y `gen_ai.task.output` en el intervalo de invocación del agente.
  +  **Llamada a** la herramienta: el nombre de la herramienta desde`gen_ai.tool.name`, y los argumentos y el resultado de `gen_ai.tool.call.arguments` y`gen_ai.tool.call.result`, en el intervalo de la herramienta de ejecución.
+  **OpenInference**:
  +  **Mensaje del usuario** y **respuesta del agente**: desde `input.value` y `output.value` en el intervalo del agente de invocación.
  +  **Llamada a** la herramienta: el nombre de la herramienta desde`tool.name`, y los argumentos y el resultado de `input.value` y`output.value`, en el intervalo de la herramienta de ejecución.

Para ver ejemplos, consulte [Ejemplos de intervalos sin registros de eventos](#langgraph-examples-without).

## Un ejemplo de tramos con registros de eventos
<a name="langgraph-examples-with"></a>

Cuando se divide la telemetría, el intervalo contiene los atributos de identificación y el contenido reside en un registro de eventos correlacionado. Los siguientes ejemplos provienen de un agente de LangGraph planificación de viajes desplegado en Amazon Bedrock AgentCore Runtime. En cada biblioteca de instrumentación se muestra el mismo agente.

**nota**  
Estos ejemplos no son períodos completos. Muestran datos representativos de una interacción real entre agentes, omitiendo algunos campos y truncando los valores largos para facilitar la lectura.

### OpenTelemetry
<a name="langgraph-examples-otel"></a>

**Example**  
El `traceloop.span.kind` atributo (`workflow`) lo identifica como un intervalo de agentes de invocación; las versiones recientes de la biblioteca también establecen el valor =. `gen_ai.operation.name` `invoke_agent`  

```
{
  "traceId": "6a01eef11066751d68f90def0da1f80a",
  "spanId": "ba1833fa7f097041",
  "parentSpanId": "836a5ccf9a2186cc",
  "name": "travel_agent.workflow",
  "kind": "INTERNAL",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain",
    "version": "0.60.0"
  },
  "startTimeUnixNano": 1778511607308521744,
  "endTimeUnixNano": 1778511610930280395,
  "durationNano": 3621758651,
  "attributes": {
    "traceloop.span.kind": "workflow",
    "gen_ai.operation.name": "invoke_agent",
    "gen_ai.agent.name": "travel_agent",
    "gen_ai.provider.name": "langgraph",
    "traceloop.workflow.name": "travel_agent",
    "session.id": "sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0"
  },
  "status": {
    "code": "OK"
  }
}
```
El registro de eventos correlacionados contiene la conversación. El de cada mensaje `content` es el estado del LangChain gráfico serializado. La entrada envuelve el estado bajo una `inputs` clave. La salida lo envuelve bajo una `outputs` clave, con cada mensaje como un objeto LangChain constructor. El mensaje del usuario es el mensaje humano y la respuesta del agente es el mensaje de la IA dentro de ese estado serializado.  

```
{
  "spanId": "ba1833fa7f097041",
  "traceId": "6a01eef11066751d68f90def0da1f80a",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain"
  },
  "body": {
    "input": {
      "messages": [
        {
          "content": "{\"inputs\": {\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}, \"tags\": [], \"metadata\": {\"ls_integration\": \"langchain_create_agent\", \"lc_agent_name\": \"travel_agent\", \"thread_id\": \"sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0\"}, \"kwargs\": {\"name\": \"travel_agent\"}}",
          "role": "user"
        }
      ]
    },
    "output": {
      "messages": [
        {
          "content": "{\"outputs\": {\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\", \"type\": \"human\", \"id\": \"12345678-1234-1234-1234-123456789012\"}}, {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"Hello! I'm your travel planning assistant ...\", \"type\": \"ai\"}}]}, \"kwargs\": {\"tags\": []}}",
          "role": "assistant"
        }
      ]
    }
  }
}
```
El `traceloop.span.kind` atributo (`tool`) lo identifica como un intervalo de herramientas de ejecución; `gen_ai.tool.name` contiene el nombre de la herramienta y `gen_ai.operation.name` =`execute_tool`.  

```
{
  "traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
  "spanId": "5b332f3cd15ace04",
  "parentSpanId": "922a21edc04eba29",
  "name": "execute_tool search_flights",
  "kind": "INTERNAL",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain",
    "version": "0.60.0"
  },
  "startTimeUnixNano": 1778511614892698232,
  "endTimeUnixNano": 1778511614893399618,
  "durationNano": 701386,
  "attributes": {
    "traceloop.span.kind": "tool",
    "gen_ai.operation.name": "execute_tool",
    "gen_ai.tool.name": "search_flights",
    "gen_ai.tool.type": "function",
    "gen_ai.tool.description": "Search for available flights between cities.",
    "gen_ai.provider.name": "langgraph",
    "traceloop.workflow.name": "travel_agent",
    "session.id": "sea-nyc-trip-2-turns-adot_v17_opentelemetry_0_60_0"
  },
  "status": {
    "code": "OK"
  }
}
```
El registro de eventos correlacionados contiene la entrada (argumentos) y la salida (resultado, serializado como a) de la herramienta. LangChain `ToolMessage`  

```
{
  "spanId": "5b332f3cd15ace04",
  "traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain"
  },
  "body": {
    "input": {
      "messages": [
        { "content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}" }
      ]
    },
    "output": {
      "messages": [
        {
          "role": "tool",
          "name": "search_flights",
          "content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"flights\": [ ... ]}"
        }
      ]
    }
  }
}
```

### OpenInference
<a name="langgraph-examples-openinference"></a>

En la OpenInference biblioteca, el tipo de intervalo se incluye en el `openinference.span.kind` atributo y la entrada y la salida del agente se serializan en el registro de eventos correlacionados.

**Example**  
El `openinference.span.kind` atributo (`CHAIN`o `AGENT` cuando el gráfico se compila con un nombre) lo identifica como un intervalo de agentes de invocación.  

```
{
  "traceId": "6a387ee61078243c1cc455ed45c6c313",
  "spanId": "0a7990d804132a9b",
  "parentSpanId": "29ae22014173881c",
  "name": "LangGraph",
  "kind": "INTERNAL",
  "scope": {
    "name": "openinference.instrumentation.langchain",
    "version": "0.1.66"
  },
  "startTimeUnixNano": 1782087405949310976,
  "endTimeUnixNano": 1782087408945828864,
  "durationNano": 2996517888,
  "attributes": {
    "openinference.span.kind": "CHAIN",
    "input.mime_type": "application/json",
    "output.mime_type": "application/json",
    "llm.input_messages.0.message.role": "user",
    "session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
  },
  "status": {
    "code": "OK"
  }
}
```
El registro de eventos correlacionados contiene la conversación. El mensaje del usuario es el mensaje de rol humano y la respuesta del agente es el AI-role mensaje de los mensajes serializados.  

```
{
  "spanId": "0a7990d804132a9b",
  "traceId": "6a387ee61078243c1cc455ed45c6c313",
  "scope": {
    "name": "openinference.instrumentation.langchain"
  },
  "body": {
    "input": {
      "messages": [
        {
          "role": "user",
          "content": "{\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}"
        }
      ]
    },
    "output": {
      "messages": [
        {
          "content": "{\"messages\": [{\"type\": \"human\", \"data\": {\"content\": \"Hey, how can you help me\", ...}}, {\"type\": \"ai\", \"data\": {\"content\": \"Hello! I'm your travel planning assistant ...\", ...}}]}",
          "role": "assistant"
        }
      ]
    }
  }
}
```
El `openinference.span.kind` atributo (`TOOL`) lo identifica como un intervalo de herramientas de ejecución; `tool.name` contiene el nombre de la herramienta.  

```
{
  "traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
  "spanId": "ab105c12cc40048f",
  "parentSpanId": "9b2d4e72760690b4",
  "name": "search_flights",
  "kind": "INTERNAL",
  "scope": {
    "name": "openinference.instrumentation.langchain",
    "version": "0.1.66"
  },
  "startTimeUnixNano": 1782087411724620032,
  "endTimeUnixNano": 1782087411725306880,
  "durationNano": 686848,
  "attributes": {
    "openinference.span.kind": "TOOL",
    "tool.name": "search_flights",
    "tool.description": "Search for available flights between cities.",
    "input.mime_type": "application/json",
    "output.mime_type": "application/json",
    "session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
  },
  "status": {
    "code": "OK"
  }
}
```
El registro de eventos correlacionados contiene la entrada (argumentos) y la salida (resultado, serializado como a) de la herramienta. LangChain `ToolMessage`  

```
{
  "spanId": "ab105c12cc40048f",
  "traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
  "scope": {
    "name": "openinference.instrumentation.langchain"
  },
  "body": {
    "input": {
      "messages": [
        {
          "role": "user",
          "content": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}"
        }
      ]
    },
    "output": {
      "messages": [
        {
          "content": "{\"type\": \"tool\", \"data\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"type\": \"tool\", \"name\": \"search_flights\", \"tool_call_id\": \"toolu_bdrk_01LzXXJCfpfuS7Bpf7e1qLMg\", \"status\": \"success\"}}",
          "role": "assistant"
        }
      ]
    }
  }
}
```

## El ejemplo abarca espacios sin registros de eventos
<a name="langgraph-examples-without"></a>

Cuando la telemetría no está dividida, el mismo contenido permanece en los atributos del tramo y no se genera ningún registro de eventos independiente. Los siguientes ejemplos son de un agente de planificación de LangGraph viajes. En cada biblioteca de instrumentación se muestra el mismo agente.

**nota**  
Estos ejemplos no son períodos completos. Muestran datos representativos de una interacción real entre agentes, omitiendo algunos campos y truncando los valores largos para facilitar la lectura.

### OpenTelemetry
<a name="langgraph-examples-without-otel"></a>

**Example**  
El `gen_ai.task.input` atributo contiene la solicitud del usuario y el `gen_ai.task.output` atributo contiene el estado serializado con la respuesta del agente. Ambos son el estado del LangChain gráfico serializado.  

```
{
  "traceId": "6a4de7b85e61747e6b568a1f4768e89d",
  "spanId": "31ea3d5882dac680",
  "name": "LangGraph.workflow",
  "kind": "INTERNAL",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain",
    "version": "0.62.1"
  },
  "attributes": {
    "traceloop.span.kind": "workflow",
    "gen_ai.operation.name": "invoke_agent",
    "gen_ai.agent.name": "LangGraph",
    "gen_ai.task.input": "{\"inputs\": {\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}, \"tags\": [], \"metadata\": { ... }, \"kwargs\": {\"name\": \"LangGraph\"}}",
    "gen_ai.task.output": "{\"outputs\": {\"messages\": [{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"HumanMessage\"], \"kwargs\": {\"content\": \"Hey, how can you help me\", \"type\": \"human\"}}, {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"AIMessage\"], \"kwargs\": {\"content\": \"Hello! I'm your travel planning assistant ...\", \"type\": \"ai\"}}]}, \"kwargs\": {\"tags\": []}}",
    "session.id": "sea-nyc-trip-2-turns-unified"
  },
  "status": {
    "code": "OK"
  }
}
```
El `gen_ai.tool.call.arguments` atributo contiene los argumentos de la herramienta y el `gen_ai.tool.call.result` atributo contiene el resultado de la herramienta, serializado como a. LangChain `ToolMessage`  

```
{
  "traceId": "6a4de7c376913db82e6f0f336a16731d",
  "spanId": "b64c37adefae74f0",
  "name": "execute_tool search_flights",
  "kind": "INTERNAL",
  "scope": {
    "name": "opentelemetry.instrumentation.langchain",
    "version": "0.62.1"
  },
  "attributes": {
    "traceloop.span.kind": "tool",
    "gen_ai.operation.name": "execute_tool",
    "gen_ai.tool.name": "search_flights",
    "gen_ai.tool.description": "Search for available flights between cities.",
    "gen_ai.tool.call.arguments": "{\"input_str\": \"{'origin': 'SEA', 'destination': 'NYC', 'date': '2025-03-15'}\", \"inputs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}, \"metadata\": { ... }}",
    "gen_ai.tool.call.result": "{\"output\": {\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"schema\", \"messages\", \"ToolMessage\"], \"kwargs\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"type\": \"tool\", \"name\": \"search_flights\", \"status\": \"success\"}}}",
    "session.id": "sea-nyc-trip-2-turns-unified"
  },
  "status": {
    "code": "OK"
  }
}
```

### OpenInference
<a name="langgraph-examples-without-openinference"></a>

**Example**  
El `input.value` atributo contiene la solicitud del usuario y el `output.value` atributo contiene el estado serializado con la respuesta del agente.  

```
{
  "traceId": "6a387ee61078243c1cc455ed45c6c313",
  "spanId": "b8c0b67876b78b91",
  "name": "LangGraph",
  "kind": "INTERNAL",
  "scope": {
    "name": "openinference.instrumentation.langchain",
    "version": "0.1.66"
  },
  "attributes": {
    "openinference.span.kind": "CHAIN",
    "input.value": "{\"messages\": [{\"role\": \"user\", \"content\": \"Hey, how can you help me\"}]}",
    "output.value": "{\"messages\": [{\"type\": \"human\", \"data\": {\"content\": \"Hey, how can you help me\"}}, {\"type\": \"ai\", \"data\": {\"content\": \"Hello! I'm your travel planning assistant ...\"}}]}",
    "session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
  },
  "status": {
    "code": "OK"
  }
}
```
El `input.value` atributo contiene los argumentos de la herramienta y el `output.value` atributo contiene el resultado de la herramienta, serializado como a. LangChain `ToolMessage`  

```
{
  "traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
  "spanId": "58752612d9b22ae1",
  "name": "search_flights",
  "kind": "INTERNAL",
  "scope": {
    "name": "openinference.instrumentation.langchain",
    "version": "0.1.66"
  },
  "attributes": {
    "openinference.span.kind": "TOOL",
    "tool.name": "search_flights",
    "tool.description": "Search for available flights between cities.",
    "input.value": "{\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}",
    "output.value": "{\"type\": \"tool\", \"data\": {\"content\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\", \"name\": \"search_flights\"}}",
    "session.id": "sea-nyc-trip-2-turns-oi-0-1-66"
  },
  "status": {
    "code": "OK"
  }
}
```

## Mejores prácticas para los agentes LangGraph
<a name="langgraph-best-practices"></a>

La forma en que se crea e invoca un LangGraph agente afecta a lo que aparece en su telemetría y, por lo tanto, a la fiabilidad con la que se puede evaluar el agente. Las siguientes prácticas ayudan a garantizar que se puedan recuperar el mensaje del usuario, la respuesta del agente y la actividad de la herramienta.

### 1. Elija un patrón de construcción de agentes
<a name="langgraph-bp-construction"></a>

Existen dos formas comunes de crear un LangGraph agente:
+  **Prediseñado `create_agent`**: la forma más rápida de empezar. Produce un único intervalo de agentes de invocación por turno, y la conversación pasa por el ciclo LangGraph de ejecución integrado. Úselo cuando desee un agente estándar de razón-acción sin un flujo de control personalizado.

  ```
  from langchain.agents import create_agent
  
  agent = create_agent(model=model, tools=[search_flights, book_flight])
  ```
+  **Personalizado `StateGraph`**: le brinda un control total sobre los nodos, los bordes y el enrutamiento condicional. La ejecución de cada nodo se convierte en su propio intervalo, por lo que las trazas son más granulares. Úselo cuando necesite una orquestación personalizada.

  ```
  from langgraph.graph import StateGraph, START, END
  from typing_extensions import TypedDict
  
  class State(TypedDict):
      messages: list
  
  graph = StateGraph(State)
  graph.add_node("generate_response", generate_response)
  graph.add_node("tools", run_tools)
  graph.add_edge(START, "generate_response")
  agent = graph.compile()
  ```

Ambos patrones se evalúan de la misma manera; la diferencia es la granularidad de la traza.

### 2. Usa `mensajes` en el estado del gráfico (recomendado)
<a name="langgraph-bp-messages"></a>

El servicio de evaluación reconstruye la conversación a partir de los mensajes de entrada y salida del agente. El uso de un `messages` campo no es obligatorio, pero permite una extracción más fiable. Como costumbre`StateGraph`, mantén la conversación en un `messages` campo de tu estado:
+  **`messages`Inclúyelo en tu estado (recomendado).** Puedes añadir otros campos personalizados (como `user_id` metadatos). Cuando `messages` está presente, la extracción estándar busca directamente el mensaje del usuario y la respuesta del agente. Si no `messages` está presente, el servicio recurre a reconstruir la conversación a partir de intervalos de inferencia individuales, lo que resulta menos fiable.
+  **Añada, no sustituya.** Sigue la LangGraph convención de añadir nuevos mensajes a la lista en lugar de sobrescribirlos, de forma que se conserve todo el historial de conversaciones.
+  **Usa tipos de LangChain mensajes canónicos** (`HumanMessage`,,,`AIMessage`). `ToolMessage` `SystemMessage` La instrumentación los serializa correctamente y el servicio reconoce sus funciones.

### 3. Transmita el mensaje del usuario en un formato compatible
<a name="langgraph-bp-invocation"></a>

Al invocar a un LangGraph agente, se añade el mensaje del usuario al `messages` estado del gráfico. LangGraph acepta el mensaje en tres formatos intercambiables y AgentCore Evaluations los admite todos. Cada uno produce intervalos y registros de eventos que el servicio puede leer.
+  **Tupla**: un `(role, content)` par:

  ```
  agent.invoke({"messages": [("user", user_message)]}, config=config)
  ```
+  **LangChain objeto de mensaje**: a `HumanMessage` (u otra clase de mensaje):

  ```
  from langchain_core.messages import HumanMessage
  
  agent.invoke({"messages": [HumanMessage(content=user_message)]}, config=config)
  ```
+  **Diccionario**: un `{"role", "content"}` diccionario:

  ```
  agent.invoke({"messages": [{"role": "user", "content": user_message}]}, config=config)
  ```

Los tres formatos tienen el mismo `messages` estado, por lo que el mensaje del usuario y la respuesta del agente se extraen de forma idéntica, independientemente del que se elija.