

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

Esta página explica como instrumentar um [LangGraph](https://langchain-ai.github.io/langgraph/)agente, como os intervalos são identificados e como os campos de avaliação são extraídos. Ele termina com as [melhores práticas](#langgraph-best-practices) para estruturar um LangGraph agente para que ele possa ser avaliado de forma confiável.

 **Tópicos** 
+  [Instrumente seu agente](#langgraph-instrument) 
+  [Como os vãos são identificados](#langgraph-span-identification) 
+  [Como os campos de avaliação são extraídos](#langgraph-extraction) 
  +  [De registros de eventos](#langgraph-extraction-event-records) 
  +  [De atributos de extensão](#langgraph-extraction-attributes) 
+  [Exemplos de períodos com registros de eventos](#langgraph-examples-with) 
+  [Exemplos de períodos sem registros de eventos](#langgraph-examples-without) 
+  [Melhores práticas para LangGraph agentes](#langgraph-best-practices) 

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

Você pode instrumentar um LangGraph agente com qualquer uma das duas bibliotecas de instrumentação: **OpenTelemetry**(`opentelemetry-instrumentation-langchain`) ou **OpenInference**(`openinference-instrumentation-langchain`). O Amazon Bedrock AgentCore Evaluations oferece suporte às duas bibliotecas. As bibliotecas emitem nomes de escopo diferentes e usam atributos de extensão diferentes. O serviço de avaliação extrai os mesmos valores de cada um.

Quando seu agente é executado com a AWS Distro for OpenTelemetry (ADOT), como no Amazon Bedrock AgentCore Runtime, você não precisa adicionar código de instrumentação explícito. Adicionar a biblioteca de instrumentação às dependências do seu projeto é suficiente. O ADOT o descobre na inicialização e o ativa automaticamente.

Adicione a biblioteca de instrumentação para o caminho que você deseja para suas dependências. Os exemplos a seguir fixam uma versão mínima; use a versão mais recente disponível, a menos que você tenha um motivo para fixar.

**Example**  
NOTA: Use a versão `0.55.0` ou posterior. A versão 0.55.0 adicionou suporte às novas [convenções de amplitude do agente OpenTelemetry Generative-AI](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md) nas quais o serviço de avaliação depende.  
Adicione `opentelemetry-instrumentation-langchain` às suas dependências. O nome do escopo emitido é`opentelemetry.instrumentation.langchain`.  
 `requirements.txt`:  

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

```
[project]
dependencies = [
    "opentelemetry-instrumentation-langchain>=0.55.0",
]
```
Adicione `openinference-instrumentation-langchain` às suas dependências. O nome do escopo emitido é`openinference.instrumentation.langchain`.  
 `requirements.txt`:  

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

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

**nota**  
A instrumentação é uma etapa na configuração da observabilidade. Para exportar a telemetria para avaliação, conclua a configuração completa em [Configurar](supported-frameworks.md#supported-frameworks-setup) observabilidade.

## Como os vãos são identificados
<a name="langgraph-span-identification"></a>

O atributo usado para classificar extensões difere entre as duas bibliotecas de instrumentação.

**Example**  
A biblioteca de OpenTelemetry instrumentação classifica as extensões usando o `traceloop.span.kind` atributo, e as versões recentes também são definidas. `gen_ai.operation.name`  


| Tipo de extensão | Atributo de identificação | 
| --- | --- | 
| Invocar agente |  `traceloop.span.kind`= `workflow` (também `gen_ai.operation.name` =`invoke_agent`) | 
| Ferramenta de execução |  `traceloop.span.kind`= `tool` (também `gen_ai.operation.name` =`execute_tool`) | 
| Inferência |  `gen_ai.operation.name` = `chat`  | 
A biblioteca de OpenInference instrumentação classifica as extensões usando o atributo. `openinference.span.kind`  


| Tipo de extensão | Atributo de identificação | 
| --- | --- | 
| Invocar agente |  `openinference.span.kind`= `CHAIN` ou `AGENT`  | 
| Ferramenta de execução |  `openinference.span.kind` = `TOOL`  | 
| Inferência |  `openinference.span.kind` = `LLM`  | 

## Como os campos de avaliação são extraídos
<a name="langgraph-extraction"></a>

Para o intervalo do agente de invocação, a entrada e a saída não contêm uma lista limpa por mensagem. Em vez disso, o conteúdo é o **estado do LangChain gráfico serializado**: uma string JSON que envolve o estado completo. A forma exata desse estado serializado difere entre as duas bibliotecas de instrumentação. Em ambos os casos, o serviço o analisa para encontrar o prompt do usuário (a mensagem humana) e a resposta do agente (a mensagem de IA).

LangGraph também serializa as funções das mensagens em mais de um formulário. Uma função pode aparecer como um valor minúsculo (`human`,`ai`,`tool`) ou como um nome de classe de LangChain mensagem (`HumanMessage`,`AIMessage`,`ToolMessage`). O serviço reconhece os dois formulários.

A localização desse conteúdo depende de como a telemetria foi coletada. O atributo de identificação (`traceloop.span.kind`ou`openinference.span.kind`) está no intervalo em ambos os casos. Para obter mais informações, consulte [Espaços, registros de eventos e sinais de telemetria](supported-frameworks-telemetry.md).

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

Quando a telemetria é dividida, o serviço lê o conteúdo do registro do evento correlacionado a cada período:
+  **Solicitação do usuário** e **resposta do agente**: do registro de eventos do invoke agent span, em `body.input` e. `body.output`
+  **Chamada de ferramenta**: o nome da ferramenta a partir da extensão da ferramenta de execução. Os argumentos e o resultado da ferramenta vêm do registro de eventos desse intervalo, em `body.input` `body.output` e.

Para ver exemplos, consulte [Exemplos de períodos com registros de eventos](#langgraph-examples-with).

### De atributos de extensão
<a name="langgraph-extraction-attributes"></a>

Quando a telemetria não é dividida, o mesmo conteúdo permanece na extensão como atributos. Os atributos dependem da biblioteca de instrumentação:
+  **OpenTelemetry**:
  +  **Solicitação do usuário** e **resposta do agente**: de `gen_ai.task.input` e `gen_ai.task.output` sobre o período de invocação do agente.
  +  **Chamada** de ferramenta: o nome da ferramenta de`gen_ai.tool.name`, os argumentos e o resultado de `gen_ai.tool.call.arguments` e`gen_ai.tool.call.result`, na extensão da ferramenta de execução.
+  **OpenInference**:
  +  **Solicitação do usuário** e **resposta do agente**: de `input.value` e `output.value` sobre o período de invocação do agente.
  +  **Chamada** de ferramenta: o nome da ferramenta de`tool.name`, os argumentos e o resultado de `input.value` e`output.value`, na extensão da ferramenta de execução.

Por [exemplo, consulte Exemplos de períodos sem registros de eventos](#langgraph-examples-without).

## Exemplos de períodos com registros de eventos
<a name="langgraph-examples-with"></a>

Quando a telemetria é dividida, o intervalo carrega os atributos de identificação e o conteúdo fica em um registro de evento correlacionado. Os exemplos a seguir são de um agente de LangGraph planejamento de viagens implantado no Amazon Bedrock Runtime. AgentCore O mesmo agente é mostrado em cada biblioteca de instrumentação.

**nota**  
Esses exemplos não são extensões completas. Eles mostram dados representativos de uma interação real do agente, com alguns campos omitidos e valores longos truncados para facilitar a leitura.

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

**Example**  
O `traceloop.span.kind` atributo (`workflow`) identifica isso como uma extensão do agente de invocação; versões recentes da biblioteca também `gen_ai.operation.name` definem =. `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"
  }
}
```
O registro do evento correlacionado carrega a conversa. Cada mensagem `content` é o estado do LangChain gráfico serializado. A entrada envolve o estado sob uma `inputs` chave. A saída a envolve em uma `outputs` chave, com cada mensagem como um objeto LangChain construtor. O prompt do usuário é a mensagem humana e a resposta do agente é a mensagem de IA dentro desse 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"
        }
      ]
    }
  }
}
```
O `traceloop.span.kind` atributo (`tool`) identifica isso como uma extensão da ferramenta de execução; `gen_ai.tool.name` contém o nome da ferramenta e `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"
  }
}
```
O registro do evento correlacionado carrega a entrada (argumentos) e a saída da ferramenta (resultado, serializado como a 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>

Com a OpenInference biblioteca, o tipo de intervalo é transportado no `openinference.span.kind` atributo e a entrada e a saída do agente são serializadas no registro do evento correlacionado.

**Example**  
O `openinference.span.kind` atributo (`CHAIN`, ou `AGENT` quando o gráfico é compilado com um nome) identifica isso como uma extensão do agente de invocação.  

```
{
  "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"
  }
}
```
O registro do evento correlacionado carrega a conversa. O prompt do usuário é a mensagem da função humana e a resposta do agente é a AI-role mensagem nas mensagens serializadas.  

```
{
  "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"
        }
      ]
    }
  }
}
```
O `openinference.span.kind` atributo (`TOOL`) identifica isso como uma extensão da ferramenta de execução; `tool.name` contém o nome da ferramenta.  

```
{
  "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"
  }
}
```
O registro do evento correlacionado carrega a entrada (argumentos) e a saída da ferramenta (resultado, serializado como a 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"
        }
      ]
    }
  }
}
```

## Exemplos de períodos sem registros de eventos
<a name="langgraph-examples-without"></a>

Quando a telemetria não é dividida, o mesmo conteúdo permanece nos atributos de span e nenhum registro de evento separado é produzido. Os exemplos a seguir são de um agente de LangGraph planejamento de viagens. O mesmo agente é mostrado em cada biblioteca de instrumentação.

**nota**  
Esses exemplos não são extensões completas. Eles mostram dados representativos de uma interação real do agente, com alguns campos omitidos e valores longos truncados para facilitar a leitura.

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

**Example**  
O `gen_ai.task.input` atributo contém o prompt do usuário e o `gen_ai.task.output` atributo mantém o estado serializado com a resposta do agente. Ambos são o estado do 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"
  }
}
```
O `gen_ai.tool.call.arguments` atributo contém os argumentos da ferramenta e o `gen_ai.tool.call.result` atributo contém o resultado da ferramenta, 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**  
O `input.value` atributo contém o prompt do usuário e o `output.value` atributo mantém o estado serializado com a resposta do 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"
  }
}
```
O `input.value` atributo contém os argumentos da ferramenta e o `output.value` atributo contém o resultado da ferramenta, 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"
  }
}
```

## Melhores práticas para LangGraph agentes
<a name="langgraph-best-practices"></a>

A forma como você cria e invoca um LangGraph agente afeta o que aparece em sua telemetria e, portanto, a confiabilidade com que o agente pode ser avaliado. As práticas a seguir ajudam a garantir que a solicitação do usuário, a resposta do agente e a atividade da ferramenta sejam recuperáveis.

### 1. Escolha um padrão de construção do agente
<a name="langgraph-bp-construction"></a>

Há duas maneiras comuns de criar um LangGraph agente:
+  **Pré-construído `create_agent`**: a maneira mais rápida de começar. Ele produz um único intervalo de agente de invocação por turno, com a conversa LangGraph transmitida pelo loop de execução integrado. Use isso quando quiser um agente de ação racional padrão sem fluxo de controle personalizado.

  ```
  from langchain.agents import create_agent
  
  agent = create_agent(model=model, tools=[search_flights, book_flight])
  ```
+  **Personalizado `StateGraph`**: oferece controle total sobre nós, bordas e roteamento condicional. A execução de cada nó se torna sua própria extensão, portanto, os rastreamentos são mais granulares. Use isso quando precisar de uma orquestração 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 os padrões são avaliados da mesma forma; a diferença é a granularidade do traço.

### 2. Use `mensagens` no estado do seu gráfico (recomendado)
<a name="langgraph-bp-messages"></a>

O serviço de avaliação reconstrói a conversa a partir das mensagens de entrada e saída do agente. Usar um `messages` campo não é obrigatório, mas permite a extração mais confiável. Para fins de personalização`StateGraph`, mantenha a conversa em um `messages` campo em seu estado:
+  **Inclua `messages` em seu estado (recomendado).** Você pode adicionar outros campos personalizados (como `user_id` metadados). Quando `messages` está presente, a extração padrão encontra diretamente o prompt do usuário e a resposta do agente. Se `messages` estiver ausente, o serviço volta a reconstruir a conversa a partir de períodos de inferência individuais, o que é menos confiável.
+  **Anexe, não substitua.** Siga a LangGraph convenção de acrescentar novas mensagens à lista em vez de sobrescrevê-la, para que o histórico completo da conversa seja preservado.
+  **Use tipos de LangChain mensagens canônicas** (`HumanMessage`,, `AIMessage``ToolMessage`,`SystemMessage`). A instrumentação os serializa corretamente e o serviço reconhece suas funções.

### 3. Passe a mensagem do usuário em um formato compatível
<a name="langgraph-bp-invocation"></a>

Ao invocar um LangGraph agente, você adiciona a mensagem do usuário ao `messages` estado do gráfico. LangGraph aceita a mensagem em três formatos intercambiáveis, e o AgentCore Evaluations suporta todos eles. Cada um produz intervalos e registros de eventos que o serviço pode ler.
+  **Tupla**: um `(role, content)` par:

  ```
  agent.invoke({"messages": [("user", user_message)]}, config=config)
  ```
+  **LangChain objeto de mensagem**: a `HumanMessage` (ou outra classe de mensagem):

  ```
  from langchain_core.messages import HumanMessage
  
  agent.invoke({"messages": [HumanMessage(content=user_message)]}, config=config)
  ```
+  **Dicionário**: um `{"role", "content"}` dicionário:

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

Todos os três formatos resultam no mesmo `messages` estado, portanto, o prompt do usuário e a resposta do agente são extraídos de forma idêntica, independentemente de qual você escolher.