

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

このページでは、[LangGraph](https://langchain-ai.github.io/langgraph/) エージェントを計測する方法、スパンの識別方法、評価フィールドの抽出方法について説明します。LangGraph エージェントを確実に評価できるように、LangGraph エージェントを構造化するための[ベストプラクティス](#langgraph-best-practices)で終了します。

 **トピック** 
+  [エージェントを計測する](#langgraph-instrument) 
+  [スパンの識別方法](#langgraph-span-identification) 
+  [評価フィールドの抽出方法](#langgraph-extraction) 
  +  [イベントレコードから](#langgraph-extraction-event-records) 
  +  [スパン属性から](#langgraph-extraction-attributes) 
+  [イベントレコードを含むスパンの例](#langgraph-examples-with) 
+  [イベントレコードのないスパンの例](#langgraph-examples-without) 
+  [LangGraph エージェントに関するベストプラクティス](#langgraph-best-practices) 

## エージェントを計測する
<a name="langgraph-instrument"></a>

**OpenTelemetry** (`opentelemetry-instrumentation-langchain`) または **OpenInference** () の 2 つの計測ライブラリのいずれかを使用して、LangGraph エージェントを計測できます`openinference-instrumentation-langchain`。Amazon Bedrock AgentCore Evaluations は両方のライブラリをサポートしています。ライブラリは異なるスコープ名を出力し、異なるスパン属性を使用します。評価サービスは、それぞれから同じ値を抽出します。

Amazon Bedrock AgentCore ランタイムなど、エージェントが AWS Distro for OpenTelemetry (ADOT) で実行されている場合、明示的な計測コードを追加する必要はありません。計測ライブラリをプロジェクトの依存関係に追加するだけで十分です。ADOT は起動時に検出し、自動的にアクティブ化します。

依存関係に必要なパスの計測ライブラリを追加します。次の例では、最小バージョンを固定します。固定する理由がない限り、利用可能な最新バージョンを使用します。

**Example**  
注: バージョン `0.55.0` 以降を使用します。バージョン 0.55.0 では、評価サービスが依存する新しい OpenTelemetry [生成 AI エージェントスパン規則](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md)のサポートが追加されました。  
`opentelemetry-instrumentation-langchain` を依存関係に追加します。出力されるスコープ名は です`opentelemetry.instrumentation.langchain`。  
 `requirements.txt`:  

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

```
[project]
dependencies = [
    "opentelemetry-instrumentation-langchain>=0.55.0",
]
```
`openinference-instrumentation-langchain` を依存関係に追加します。出力されるスコープ名は です`openinference.instrumentation.langchain`。  
 `requirements.txt`:  

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

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

**注記**  
計測は、オブザーバビリティを設定する 1 つのステップです。評価のためにテレメトリをエクスポートするには、[「オブザーバビリティの設定](supported-frameworks.md#supported-frameworks-setup)」で完全なセットアップを完了します。

## スパンの識別方法
<a name="langgraph-span-identification"></a>

スパンの分類に使用される属性は、2 つの計測ライブラリによって異なります。

**Example**  
OpenTelemetry 計測ライブラリは `traceloop.span.kind` 属性を使用してスパンを分類し、最新バージョンでは も設定します`gen_ai.operation.name`。  


| スパンタイプ | 属性の識別 | 
| --- | --- | 
| エージェントを呼び出す |  `traceloop.span.kind` = `workflow` ( も `gen_ai.operation.name` = `invoke_agent`) | 
| 実行ツール |  `traceloop.span.kind` = `tool` ( も `gen_ai.operation.name` = `execute_tool`) | 
| 推測 |  `gen_ai.operation.name` = `chat`  | 
OpenInference 計測ライブラリは、 `openinference.span.kind` 属性を使用してスパンを分類します。  


| スパンタイプ | 属性の識別 | 
| --- | --- | 
| エージェントを呼び出す |  `openinference.span.kind` = `CHAIN`または `AGENT`  | 
| 実行ツール |  `openinference.span.kind` = `TOOL`  | 
| 推測 |  `openinference.span.kind` = `LLM`  | 

## 評価フィールドの抽出方法
<a name="langgraph-extraction"></a>

呼び出しエージェントスパンの場合、入力と出力にはメッセージごとのクリーンリストは含まれません。代わりに、コンテンツは**シリアル化された LangChain グラフ状態**、つまり完全な状態をラップする JSON 文字列です。このシリアル化された状態の正確な形状は、2 つの計測ライブラリ間で異なります。どちらの場合も、サービスはそれを解析してユーザープロンプト (ヒューマンメッセージ) とエージェントのレスポンス (AI メッセージ) を検索します。

LangGraph は、メッセージロールを複数の形式でシリアル化します。ロールは、小文字の値 (`human`、`ai`、`tool`) または LangChain メッセージクラス名 (`HumanMessage`、`AIMessage`、) として表示できます`ToolMessage`。サービスは両方のフォームを認識します。

このコンテンツの場所は、テレメトリの収集方法によって異なります。どちらの場合も、識別属性 (`traceloop.span.kind` または `openinference.span.kind`) はスパン上にあります。詳細については、[「スパン、イベントレコード、テレメトリシグナル](supported-frameworks-telemetry.md)」を参照してください。

### イベントレコードから
<a name="langgraph-extraction-event-records"></a>

テレメトリが分割されると、サービスは各スパンに相関するイベントレコードからコンテンツを読み取ります。
+  **ユーザープロンプト**と**エージェントのレスポンス**: エージェントスパンのイベントレコードの呼び出しから、 `body.input`および 。 `body.output`
+  **ツール呼び出し**: 実行ツールスパンのツール名。ツールの引数と結果は、 `body.input`と のスパンのイベントレコードから取得されます`body.output`。

例については、[「イベントレコードを含むスパンの例](#langgraph-examples-with)」を参照してください。

### スパン属性から
<a name="langgraph-extraction-attributes"></a>

テレメトリが分割されていない場合、同じコンテンツは属性と同じスパンに残ります。属性は、計測ライブラリによって異なります。
+  **OpenTelemetry**:
  +  **ユーザープロンプト**と**エージェントのレスポンス**: `gen_ai.task.input` `gen_ai.task.output` 呼び出しエージェントのスパンとの間で。
  +  **ツール呼び出し**: 実行ツールスパン`gen_ai.tool.call.result`の からのツール名`gen_ai.tool.name`、および `gen_ai.tool.call.arguments`と からの引数と結果。
+  **OpenInference**:
  +  **ユーザープロンプト**と**エージェントのレスポンス**: `input.value` `output.value` 呼び出しエージェントのスパンとの間で。
  +  **ツール呼び出し**: 実行ツールスパン`output.value`の からのツール名`tool.name`、および `input.value`と からの引数と結果。

例については、[「イベントレコードのないスパンの例](#langgraph-examples-without)」を参照してください。

## イベントレコードを含むスパンの例
<a name="langgraph-examples-with"></a>

テレメトリが分割されると、スパンは識別属性を保持し、コンテンツは相関イベントレコードに存在します。次の例は、Amazon Bedrock AgentCore ランタイムにデプロイされた LangGraph の旅行計画エージェントからのものです。各計測ライブラリの下に同じエージェントが表示されます。

**注記**  
これらの例は完全なスパンではありません。実際のエージェントインタラクションからの代表的なデータが表示され、読みやすいように一部のフィールドは省略され、長い値は切り捨てられます。

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

**Example**  
`traceloop.span.kind` 属性 (`workflow`) は、これを呼び出しエージェントのスパンとして識別します。最近のライブラリバージョンも `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"
  }
}
```
相関イベントレコードは会話を保持します。各メッセージの `content`は、シリアル化された LangChain グラフの状態です。入力は 状態を `inputs`キーにラップします。出力は、各メッセージを LangChain コンストラクタオブジェクトとして `outputs`キーにラップします。ユーザープロンプトは人間のメッセージで、エージェントのレスポンスはそのシリアル化された状態内の AI メッセージです。  

```
{
  "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"
        }
      ]
    }
  }
}
```
`traceloop.span.kind` 属性 (`tool`) は、これを実行ツールスパンとして識別します。 はツール名 と `gen_ai.operation.name` = `gen_ai.tool.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"
  }
}
```
相関イベントレコードには、ツールの入力 (引数) と出力 (結果、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>

OpenInference ライブラリでは、スパンタイプは `openinference.span.kind` 属性で実行され、エージェントの入出力は相関イベントレコードでシリアル化されます。

**Example**  
`openinference.span.kind` 属性 (またはグラフが名前でコンパイル`AGENT`されている場合) は`CHAIN`、これを呼び出しエージェントのスパンとして識別します。  

```
{
  "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"
  }
}
```
相関イベントレコードは会話を保持します。ユーザープロンプトはヒューマンロールメッセージで、エージェントのレスポンスはシリアル化されたメッセージの AI ロールメッセージです。  

```
{
  "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"
        }
      ]
    }
  }
}
```
`openinference.span.kind` 属性 (`TOOL`) は、これを実行ツールスパンとして識別します。 はツール名`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"
  }
}
```
相関イベントレコードには、ツールの入力 (引数) と出力 (結果、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"
        }
      ]
    }
  }
}
```

## イベントレコードのないスパンの例
<a name="langgraph-examples-without"></a>

テレメトリが分割されていない場合、同じコンテンツはスパン属性に残り、個別のイベントレコードは生成されません。次の例は、LangGraph の旅行計画エージェントからのものです。各計測ライブラリの下に同じエージェントが表示されます。

**注記**  
これらの例は完全なスパンではありません。実際のエージェントインタラクションからの代表的なデータが表示され、読みやすいように一部のフィールドは省略され、長い値は切り捨てられます。

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

**Example**  
`gen_ai.task.input` 属性はユーザープロンプトを保持し、 `gen_ai.task.output` 属性はエージェントのレスポンスでシリアル化された状態を保持します。どちらもシリアル化された 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"
  }
}
```
`gen_ai.tool.call.arguments` 属性はツール引数を保持し、 `gen_ai.tool.call.result` 属性は 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**  
`input.value` 属性はユーザープロンプトを保持し、 `output.value` 属性はエージェントのレスポンスでシリアル化された状態を保持します。  

```
{
  "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"
  }
}
```
`input.value` 属性はツール引数を保持し、 `output.value` 属性は 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"
  }
}
```

## LangGraph エージェントに関するベストプラクティス
<a name="langgraph-best-practices"></a>

LangGraph エージェントを構築して呼び出す方法は、テレメトリに表示される内容、つまりエージェントの評価の信頼性に影響します。以下のプラクティスは、ユーザープロンプト、エージェントのレスポンス、ツールアクティビティを回復可能にするのに役立ちます。

### 1. エージェント構築パターンを選択する
<a name="langgraph-bp-construction"></a>

LangGraph エージェントを構築するには、次の 2 つの一般的な方法があります。
+  **構築済み `create_agent` **: 最も迅速な開始方法。これにより、1 ターンあたり 1 回の呼び出しエージェントスパンが生成され、会話は LangGraph の組み込み実行ループを通過します。これは、カスタムコントロールフローのない標準の reason-act エージェントが必要な場合に使用します。

  ```
  from langchain.agents import create_agent
  
  agent = create_agent(model=model, tools=[search_flights, book_flight])
  ```
+  **カスタム `StateGraph` **: ノード、エッジ、および条件付きルーティングを完全に制御できます。各ノード実行は独自のスパンになるため、トレースはより詳細になります。カスタムオーケストレーションが必要な場合は、これを使用します。

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

どちらのパターンも同じ方法で評価されます。違いはトレースの粒度です。

### 2. グラフの状態`messages`で を使用する (推奨)
<a name="langgraph-bp-messages"></a>

評価サービスは、エージェントの入力メッセージと出力メッセージから会話を再構築します。`messages` フィールドの使用は必須ではありませんが、最も信頼性の高い抽出が可能になります。カスタム の場合`StateGraph`、会話は 状態の`messages`フィールドに保持します。
+  **を 状態`messages`に含める (推奨）。**他のカスタムフィールド ( `user_id`や メタデータなど) を追加できます。`messages` が存在する場合、標準抽出はユーザープロンプトとエージェントのレスポンスを直接検出します。`messages` が存在しない場合、サービスは個々の推論スパンからの会話の再構築にフォールバックします。これは信頼性が低くなります。
+  **追加します。置き換えないでください。**LangGraph の規則に従って、新しいメッセージを上書きせずにリストに追加すると、会話履歴全体が保持されます。
+  **正規の LangChain メッセージタイプ** (`HumanMessage`、`AIMessage`、`ToolMessage`、) を使用します`SystemMessage`。計測はこれらを正しくシリアル化し、サービスはそれらのロールを認識します。

### 3. サポートされている形式でユーザーメッセージを渡す
<a name="langgraph-bp-invocation"></a>

LangGraph エージェントを呼び出すときは、ユーザーメッセージをグラフ`messages`の状態に追加します。LangGraph はメッセージを 3 つの交換可能な形式で受け入れ、AgentCore Evaluations はそれらのすべてをサポートします。各 は、サービスが読み取ることができるスパンとイベントレコードを生成します。
+  **タプル**: `(role, content)`ペア:

  ```
  agent.invoke({"messages": [("user", user_message)]}, config=config)
  ```
+  **LangChain メッセージオブジェクト**: `HumanMessage` (または他のメッセージクラス):

  ```
  from langchain_core.messages import HumanMessage
  
  agent.invoke({"messages": [HumanMessage(content=user_message)]}, config=config)
  ```
+  ディ**クショナリ**: `{"role", "content"}`ディクショナリ:

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

3 つの形式はすべて同じ`messages`状態になるため、どの形式を選択しても、ユーザープロンプトとエージェントのレスポンスは同じように抽出されます。