

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

Questa pagina spiega come strumentare un [LangGraph](https://langchain-ai.github.io/langgraph/)agente, come vengono identificati gli intervalli e come vengono estratti i campi di valutazione. Si chiude con le [migliori pratiche](#langgraph-best-practices) per strutturare un LangGraph agente in modo che possa essere valutato in modo affidabile.

 **Argomenti** 
+  [Strumenta il tuo agente](#langgraph-instrument) 
+  [Come vengono identificate le campate](#langgraph-span-identification) 
+  [Come vengono estratti i campi di valutazione](#langgraph-extraction) 
  +  [Dai registri degli eventi](#langgraph-extraction-event-records) 
  +  [Dagli attributi span](#langgraph-extraction-attributes) 
+  [L'esempio include i record degli eventi](#langgraph-examples-with) 
+  [Esempio di intervalli senza record di eventi](#langgraph-examples-without) 
+  [Le migliori pratiche per gli agenti LangGraph ](#langgraph-best-practices) 

## Strumenta il tuo agente
<a name="langgraph-instrument"></a>

Puoi strumentare un LangGraph agente con una delle due librerie di strumentazione: **OpenTelemetry**(`opentelemetry-instrumentation-langchain`) o **OpenInference**(`openinference-instrumentation-langchain`). Amazon Bedrock AgentCore Evaluations supporta entrambe le librerie. Le librerie emettono nomi di ambito diversi e utilizzano attributi span diversi. Il servizio di valutazione estrae gli stessi valori da ciascuna di esse.

Quando il tuo agente utilizza AWS Distro for OpenTelemetry (ADOT), ad esempio su Amazon Bedrock AgentCore Runtime, non è necessario aggiungere codice di strumentazione esplicito. È sufficiente aggiungere la libreria di strumentazione alle dipendenze del progetto. ADOT la rileva all'avvio e la attiva automaticamente.

Aggiungi la libreria di strumentazione per il percorso che desideri alle tue dipendenze. Gli esempi seguenti aggiungono una versione minima; utilizzate l'ultima versione disponibile a meno che non abbiate un motivo per bloccarla.

**Example**  
NOTA: utilizza la versione `0.55.0` o successiva. La versione 0.55.0 ha aggiunto il supporto per il nuovo [agente di OpenTelemetry intelligenza artificiale generativa, convenzioni su cui si basa il servizio di valutazione](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md).  
`opentelemetry-instrumentation-langchain`Aggiungilo alle tue dipendenze. Il nome dell'ambito emesso è. `opentelemetry.instrumentation.langchain`  
 `requirements.txt`:  

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

```
[project]
dependencies = [
    "opentelemetry-instrumentation-langchain>=0.55.0",
]
```
Aggiungilo `openinference-instrumentation-langchain` alle tue dipendenze. Il nome dell'ambito emesso è. `openinference.instrumentation.langchain`  
 `requirements.txt`:  

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

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

**Nota**  
La strumentazione è un passo nella configurazione dell'osservabilità. [Per esportare la telemetria per la valutazione, completa la configurazione completa in Imposta l'osservabilità.](supported-frameworks.md#supported-frameworks-setup)

## Come vengono identificati gli intervalli
<a name="langgraph-span-identification"></a>

L'attributo utilizzato per classificare gli intervalli differisce tra le due librerie di strumentazione.

**Example**  
La libreria di OpenTelemetry strumentazione classifica gli intervalli utilizzando l'attributo e vengono impostate anche le versioni recenti. `traceloop.span.kind` `gen_ai.operation.name`  


| Tipo di intervallo | Attributo identificativo | 
| --- | --- | 
| Invoca l'agente |  `traceloop.span.kind`= `workflow` (anche `gen_ai.operation.name` =) `invoke_agent` | 
| Strumento di esecuzione |  `traceloop.span.kind`= `tool` (anche `gen_ai.operation.name` =`execute_tool`) | 
| Inferenza |  `gen_ai.operation.name` = `chat`  | 
La libreria di OpenInference strumentazione classifica gli intervalli utilizzando l'attributo. `openinference.span.kind`  


| Tipo di intervallo | Attributo identificativo | 
| --- | --- | 
| Invoca l'agente |  `openinference.span.kind`= `CHAIN` o `AGENT`  | 
| Strumento di esecuzione |  `openinference.span.kind` = `TOOL`  | 
| Inferenza |  `openinference.span.kind` = `LLM`  | 

## Come vengono estratti i campi di valutazione
<a name="langgraph-extraction"></a>

Per l'invoke agent span, l'input e l'output non contengono un elenco pulito per messaggio. Il contenuto è invece lo stato del ** LangChain grafico serializzato: una stringa JSON che racchiude lo stato** completo. La forma esatta di questo stato serializzato differisce tra le due librerie di strumentazione. In entrambi i casi, il servizio lo analizza per trovare il prompt dell'utente (il messaggio umano) e la risposta dell'agente (il messaggio AI).

LangGraph serializza anche i ruoli dei messaggi in più di un modulo. Un ruolo può apparire come valore minuscolo (`human`,`ai`,`tool`) o come nome di una classe di LangChain messaggi (`HumanMessage`,,). `AIMessage` `ToolMessage` Il servizio riconosce entrambi i moduli.

La posizione di questo contenuto dipende dal modo in cui è stata raccolta la telemetria. L'attributo identificativo (`traceloop.span.kind`o`openinference.span.kind`) è presente nell'intervallo in entrambi i casi. Per ulteriori informazioni, consulta [Intervalli, record di eventi e segnali di telemetria](supported-frameworks-telemetry.md).

### Dai registri degli eventi
<a name="langgraph-extraction-event-records"></a>

Quando la telemetria viene suddivisa, il servizio legge il contenuto del record dell'evento correlato a ciascun intervallo:
+  **Richiesta dell'utente** e **risposta dell'agente**: dal record degli eventi di Invoke Agent Span, in and. `body.input` `body.output`
+  **Chiamata allo strumento**: il nome dello strumento incluso nell'intervallo di esecuzione dello strumento. Gli argomenti e i risultati dello strumento provengono dal record degli eventi di quell'intervallo, in `body.input` and. `body.output`

Per esempi, vedete [Example spans with event records](#langgraph-examples-with).

### Dagli attributi span
<a name="langgraph-extraction-attributes"></a>

Quando la telemetria non viene suddivisa, lo stesso contenuto rimane nell'intervallo degli attributi. Gli attributi dipendono dalla libreria di strumentazione:
+  **OpenTelemetry**:
  +  **Richiesta dell'utente** e **risposta dell'agente**: da `gen_ai.task.input` e `gen_ai.task.output` verso l'intervallo dell'agente di invocazione.
  +  **Richiamata dello strumento**: il nome dello strumento da`gen_ai.tool.name`, gli argomenti e i risultati di `gen_ai.tool.call.arguments` e`gen_ai.tool.call.result`, nell'intervallo dello strumento di esecuzione.
+  **OpenInference**:
  +  **Richiesta dell'utente** e **risposta dell'agente**: da `input.value` e `output.value` sull'intervallo dell'agente di invocazione.
  +  **Richiamata dello strumento**: il nome dello strumento da`tool.name`, gli argomenti e i risultati di `input.value` e`output.value`, nell'intervallo dello strumento di esecuzione.

Ad esempio, vedete [Example spans without event records](#langgraph-examples-without).

## L'esempio si estende ai record degli eventi
<a name="langgraph-examples-with"></a>

Quando la telemetria viene suddivisa, l'intervallo contiene gli attributi identificativi e il contenuto risiede in un record di eventi correlato. I seguenti esempi sono tratti da un agente di LangGraph pianificazione dei viaggi distribuito su Amazon Bedrock Runtime. AgentCore Lo stesso agente è mostrato in ogni libreria di strumentazione.

**Nota**  
Questi esempi non sono intervalli completi. Mostrano dati rappresentativi derivanti da un'interazione con un agente reale, con alcuni campi omessi e valori lunghi troncati per motivi di leggibilità.

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

**Example**  
L'`traceloop.span.kind`attributo (`workflow`) lo identifica come un invoke agent span; le versioni recenti della libreria impostano anche =. `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"
  }
}
```
Il record dell'evento correlato contiene la conversazione. Quello di ogni messaggio `content` è lo stato del LangChain grafico serializzato. L'input racchiude lo stato in una chiave. `inputs` L'output lo avvolge in una `outputs` chiave, con ogni messaggio come oggetto costruttore. LangChain Il prompt dell'utente è il messaggio umano e la risposta dell'agente è il messaggio AI all'interno di quello stato serializzato.  

```
{
  "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"
        }
      ]
    }
  }
}
```
L'`traceloop.span.kind`attributo (`tool`) lo identifica come uno strumento di esecuzione; `gen_ai.tool.name` contiene il nome dello strumento 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"
  }
}
```
Il record dell'evento correlato contiene l'input (argomenti) e l'output (risultato, serializzato come 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>

Con la OpenInference libreria, il tipo span viene inserito nell'`openinference.span.kind`attributo e l'input e l'output dell'agente vengono serializzati nel record dell'evento correlato.

**Example**  
L'`openinference.span.kind`attributo (`CHAIN`o `AGENT` quando il grafico è compilato con un nome) lo identifica come un invoke agent span.  

```
{
  "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"
  }
}
```
Il record dell'evento correlato contiene la conversazione. Il prompt dell'utente è il messaggio relativo al ruolo umano e la risposta dell'agente è il AI-role messaggio contenuto nei messaggi serializzati.  

```
{
  "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"
        }
      ]
    }
  }
}
```
L'`openinference.span.kind`attributo (`TOOL`) lo identifica come uno strumento di esecuzione; contiene il nome dello strumento. `tool.name`  

```
{
  "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"
  }
}
```
Il record dell'evento correlato contiene l'input (argomenti) e l'output (risultato, serializzato come 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"
        }
      ]
    }
  }
}
```

## L'esempio si estende senza record di eventi
<a name="langgraph-examples-without"></a>

Quando la telemetria non viene suddivisa, lo stesso contenuto rimane negli attributi span e non viene prodotto alcun record di eventi separato. Gli esempi seguenti sono tratti da un addetto alla pianificazione dei viaggi. LangGraph Lo stesso agente è mostrato in ogni libreria di strumentazione.

**Nota**  
Questi esempi non sono intervalli completi. Mostrano dati rappresentativi derivanti da un'interazione con un agente reale, con alcuni campi omessi e valori lunghi troncati per motivi di leggibilità.

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

**Example**  
L'`gen_ai.task.input`attributo contiene il prompt dell'utente e l'`gen_ai.task.output`attributo contiene lo stato serializzato con la risposta dell'agente. Entrambi sono lo stato del grafico serializzato LangChain .  

```
{
  "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"
  }
}
```
L'`gen_ai.tool.call.arguments`attributo contiene gli argomenti dello strumento e l'`gen_ai.tool.call.result`attributo contiene il risultato dello strumento, serializzato come 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**  
L'`input.value`attributo contiene il prompt dell'utente e l'`output.value`attributo contiene lo stato serializzato con la risposta dell'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"
  }
}
```
L'`input.value`attributo contiene gli argomenti dello strumento e l'`output.value`attributo contiene il risultato dello strumento, serializzato come 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"
  }
}
```

## Le migliori pratiche per gli agenti LangGraph
<a name="langgraph-best-practices"></a>

Il modo in cui si crea e si richiama un LangGraph agente influisce su ciò che appare nella sua telemetria e quindi sull'affidabilità della valutazione dell'agente. Le seguenti pratiche aiutano a garantire che il prompt dell'utente, la risposta dell'agente e l'attività dello strumento siano ripristinabili.

### 1. Scegli uno schema costruttivo per agenti
<a name="langgraph-bp-construction"></a>

Esistono due modi comuni per creare un LangGraph agente:
+  **Precostruito `create_agent`**: il modo più rapido per iniziare. Produce un singolo intervallo di invoke agent per turno, con la conversazione passata attraverso il ciclo di esecuzione integrato del ciclo LangGraph di esecuzione. Usalo quando desideri un agente Reason-Act standard senza un flusso di controllo personalizzato.

  ```
  from langchain.agents import create_agent
  
  agent = create_agent(model=model, tools=[search_flights, book_flight])
  ```
+  **Personalizzato `StateGraph`**: ti offre il pieno controllo su nodi, bordi e routing condizionale. L'esecuzione di ogni nodo diventa un intervallo a sé stante, quindi le tracce sono più granulari. Usalo quando hai bisogno di un'orchestrazione personalizzata.

  ```
  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()
  ```

Entrambi i modelli vengono valutati allo stesso modo; la differenza è la granularità della traccia.

### 2. Usa `i messaggi` nel tuo stato del grafico (consigliato)
<a name="langgraph-bp-messages"></a>

Il servizio di valutazione ricostruisce la conversazione a partire dai messaggi di input e output dell'agente. L'utilizzo di un `messages` campo non è obbligatorio, ma consente l'estrazione più affidabile. Per una consuetudine`StateGraph`, tenete la conversazione in un `messages` campo del vostro Stato:
+  **Includi `messages` nel tuo Stato (consigliato).** Puoi aggiungere altri campi personalizzati (come i `user_id` metadati). Quando `messages` è presente, l'estrazione standard trova direttamente il prompt dell'utente e la risposta dell'agente. Se `messages` è assente, il servizio torna a ricostruire la conversazione a partire da intervalli di inferenza individuali, il che è meno affidabile.
+  **Aggiungi, non sostituire.** Segui la LangGraph convenzione di aggiungere nuovi messaggi all'elenco anziché sovrascriverlo, in modo da conservare l'intera cronologia delle conversazioni.
+  **Usa tipi di LangChain messaggi canonici** (`HumanMessage`,,,`AIMessage`). `ToolMessage` `SystemMessage` La strumentazione li serializza correttamente e il servizio ne riconosce i ruoli.

### 3. Trasmetti il messaggio utente in un formato supportato
<a name="langgraph-bp-invocation"></a>

Quando richiami un LangGraph agente, aggiungi il messaggio dell'utente `messages` allo stato del grafico. LangGraph accetta il messaggio in tre formati intercambiabili e AgentCore Evaluations li supporta tutti. Ciascuno produce intervalli e record di eventi che il servizio può leggere.
+  **Tuple: una `(role, content)` coppia**:

  ```
  agent.invoke({"messages": [("user", user_message)]}, config=config)
  ```
+  **LangChain oggetto messaggio**: a `HumanMessage` (o altra classe di messaggi):

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

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

Tutti e tre i formati hanno lo stesso `messages` stato, quindi il prompt dell'utente e la risposta dell'agente vengono estratti in modo identico indipendentemente dalla scelta effettuata.