

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

Auf dieser Seite wird erklärt, wie ein [LangGraph](https://langchain-ai.github.io/langgraph/)Agent instrumentiert wird, wie Spans identifiziert werden und wie Bewertungsfelder extrahiert werden. Abschließend werden [bewährte Verfahren](#langgraph-best-practices) zur Strukturierung eines LangGraph Agenten beschrieben, sodass er zuverlässig bewertet werden kann.

 **Topics** 
+  [Instrumentieren Sie Ihren Agenten](#langgraph-instrument) 
+  [Wie werden Spannweiten identifiziert](#langgraph-span-identification) 
+  [Wie werden Bewertungsfelder extrahiert](#langgraph-extraction) 
  +  [Aus Ereignisaufzeichnungen](#langgraph-extraction-event-records) 
  +  [Aus Span-Attributen](#langgraph-extraction-attributes) 
+  [Beispiel für Spans mit Ereignisdatensätzen](#langgraph-examples-with) 
+  [Beispiel für Spans ohne Ereignisdatensätze](#langgraph-examples-without) 
+  [Bewährte Methoden für Agenten LangGraph ](#langgraph-best-practices) 

## Instrumentieren Sie Ihren Agenten
<a name="langgraph-instrument"></a>

Sie können einen LangGraph Agenten mit einer von zwei Instrumentierungsbibliotheken instrumentieren: **OpenTelemetry**(`opentelemetry-instrumentation-langchain`) oder **OpenInference**(`openinference-instrumentation-langchain`). Amazon Bedrock AgentCore Evaluations unterstützt beide Bibliotheken. Die Bibliotheken geben unterschiedliche Bereichsnamen aus und verwenden unterschiedliche Span-Attribute. Der Bewertungsservice extrahiert aus jedem die gleichen Werte.

Wenn Ihr Agent mit AWS Distro for OpenTelemetry (ADOT) ausgeführt wird, z. B. auf Amazon Bedrock AgentCore Runtime, müssen Sie keinen expliziten Instrumentierungscode hinzufügen. Es reicht aus, die Instrumentierungsbibliothek zu den Abhängigkeiten Ihres Projekts hinzuzufügen. ADOT erkennt es beim Start und aktiviert es automatisch.

Fügen Sie die Instrumentierungsbibliothek für den gewünschten Pfad zu Ihren Abhängigkeiten hinzu. In den folgenden Beispielen wird eine Mindestversion angehängt. Verwenden Sie die neueste verfügbare Version, sofern Sie keinen Grund dafür haben.

**Example**  
HINWEIS: Verwenden Sie Version `0.55.0` oder höher. Version 0.55.0 fügte Unterstützung für die neueren OpenTelemetry [Generative-AI-Agent-Span-Konventionen](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md) hinzu, auf denen sich der Evaluierungsservice stützt.  
Fügen Sie Ihre Abhängigkeiten hinzu`opentelemetry-instrumentation-langchain`. Der ausgegebene Bereichsname lautet`opentelemetry.instrumentation.langchain`.  
 `requirements.txt`:  

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

```
[project]
dependencies = [
    "opentelemetry-instrumentation-langchain>=0.55.0",
]
```
Fügen `openinference-instrumentation-langchain` Sie Ihre Abhängigkeiten hinzu. Der ausgegebene Bereichsname lautet`openinference.instrumentation.langchain`.  
 `requirements.txt`:  

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

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

**Anmerkung**  
Die Instrumentierung ist ein Schritt bei der Einrichtung der Beobachtbarkeit. Um Telemetrie zur Auswertung zu exportieren, schließen Sie die vollständigen Einstellungen unter Beobachtbarkeit [einrichten](supported-frameworks.md#supported-frameworks-setup) ab.

## Wie werden Spannweiten identifiziert
<a name="langgraph-span-identification"></a>

Das zur Klassifizierung von Spans verwendete Attribut unterscheidet sich zwischen den beiden Instrumentierungsbibliotheken.

**Example**  
In der OpenTelemetry Instrumentierungsbibliothek werden Spans anhand des `traceloop.span.kind` Attributs klassifiziert. Neuere Versionen werden ebenfalls festgelegt. `gen_ai.operation.name`  


| Typ der Spanne | Identifizierendes Attribut | 
| --- | --- | 
| Agent aufrufen |  `traceloop.span.kind`= `workflow` (auch `gen_ai.operation.name` =`invoke_agent`) | 
| Tool ausführen |  `traceloop.span.kind`= `tool` (auch `gen_ai.operation.name` =`execute_tool`) | 
| Inferenz |  `gen_ai.operation.name` = `chat`  | 
Die OpenInference Instrumentierungsbibliothek klassifiziert Spannweiten anhand des `openinference.span.kind` Attributs.  


| Typ der Spannweite | Identifizierendes Attribut | 
| --- | --- | 
| Agent aufrufen |  `openinference.span.kind`= oder `CHAIN` `AGENT`  | 
| Tool ausführen |  `openinference.span.kind` = `TOOL`  | 
| Inferenz |  `openinference.span.kind` = `LLM`  | 

## Wie werden Bewertungsfelder extrahiert
<a name="langgraph-extraction"></a>

Beim Invoke Agent Span enthalten Eingabe und Ausgabe keine saubere Liste pro Nachricht. Stattdessen ist der Inhalt der **serialisierte LangChain Graphstatus**: eine JSON-Zeichenfolge, die den vollständigen Status umschließt. Die genaue Form dieses serialisierten Zustands unterscheidet sich zwischen den beiden Instrumentierungsbibliotheken. In beiden Fällen analysiert der Dienst ihn, um die Benutzeraufforderung (die menschliche Nachricht) und die Antwort des Agenten (die KI-Nachricht) zu finden.

LangGraph serialisiert auch Nachrichtenrollen in mehr als einer Form. Eine Rolle kann als kleingeschriebener Wert (`human`,`ai`,`tool`) oder als LangChain Nachrichtenklassenname (`HumanMessage`,,`AIMessage`) erscheinen. `ToolMessage` Der Dienst erkennt beide Formen.

Der Speicherort dieser Inhalte hängt davon ab, wie Telemetriedaten erfasst wurden. Das identifizierende Attribut (`traceloop.span.kind`oder`openinference.span.kind`) befindet sich in beiden Fällen auf der Spanne. Weitere Informationen finden Sie unter [Spans, Ereignisdatensätze und Telemetriesignale](supported-frameworks-telemetry.md).

### Aus Ereignisaufzeichnungen
<a name="langgraph-extraction-event-records"></a>

Wenn die Telemetrie aufgeteilt wird, liest der Dienst Inhalte aus dem Ereignisdatensatz, der jeder Spanne zugeordnet ist:
+  **Benutzeraufforderung** und **Antwort des Agenten**: aus dem Ereignisdatensatz des Invoke Agent Span, in und. `body.input` `body.output`
+  **Werkzeugaufruf**: Der Werkzeugname aus dem Bereich „Tool ausführen“. Die Werkzeugargumente und das Ergebnis stammen aus dem Ereignisdatensatz dieser Spanne, in `body.input` und`body.output`.

Beispiele finden Sie unter [Beispiel für Spans mit Ereignisdatensätzen](#langgraph-examples-with).

### Aus Span-Attributen
<a name="langgraph-extraction-attributes"></a>

Wenn die Telemetrie nicht aufgeteilt wird, verbleibt derselbe Inhalt als Attribute im Bereich. Die Attribute hängen von der Instrumentierungsbibliothek ab:
+  **OpenTelemetry**:
  +  **Benutzeraufforderung** und **Agentenantwort**: von `gen_ai.task.input` und nach `gen_ai.task.output` dem Invoke Agent Span.
  +  **Werkzeugaufruf**: der Werkzeugname von `gen_ai.tool.name` und die Argumente und das Ergebnis von `gen_ai.tool.call.arguments` und `gen_ai.tool.call.result` im Bereich des Ausführungswerkzeugs.
+  **OpenInference**:
  +  **Benutzereingabe** und **Agentenantwort**: von `input.value` und nach `output.value` dem Invoke-Agent-Span.
  +  **Werkzeugaufruf**: der Werkzeugname von `tool.name` und die Argumente und das Ergebnis von `input.value` und `output.value` im Bereich des Ausführungswerkzeugs.

Beispiele finden Sie unter [Beispielbereiche ohne Ereignisdatensätze](#langgraph-examples-without).

## Beispiel für Zeitspannen mit Ereignisdatensätzen
<a name="langgraph-examples-with"></a>

Wenn die Telemetrie aufgeteilt wird, enthält die Spanne die identifizierenden Attribute und der Inhalt befindet sich in einem korrelierten Ereignisdatensatz. Die folgenden Beispiele stammen von einem LangGraph Reiseplanungsagenten, der auf Amazon AgentCore Bedrock Runtime eingesetzt wurde. Derselbe Agent wird unter jeder Instrumentierungsbibliothek angezeigt.

**Anmerkung**  
Bei diesen Beispielen handelt es sich nicht um vollständige Datenreihen. Sie zeigen repräsentative Daten aus einer echten Agenteninteraktion, wobei einige Felder weggelassen und lange Werte aus Gründen der Lesbarkeit gekürzt wurden.

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

**Example**  
Das `traceloop.span.kind` Attribut (`workflow`) identifiziert dies als Span für den Aufruf-Agenten. Neuere Bibliotheksversionen haben auch den Wert = gesetzt. `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"
  }
}
```
Der korrelierte Ereignisdatensatz enthält die Konversation. Bei jeder Nachricht `content` handelt es sich um den serialisierten LangChain Graphstatus. Die Eingabe umschließt den Status unter einem `inputs` Schlüssel. Die Ausgabe umschließt ihn unter einen `outputs` Schlüssel, wobei jede Nachricht ein LangChain Konstruktorobjekt ist. Die Benutzeraufforderung ist die menschliche Nachricht und die Antwort des Agenten ist die KI-Nachricht innerhalb dieses serialisierten Zustands.  

```
{
  "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"
        }
      ]
    }
  }
}
```
Das `traceloop.span.kind` Attribut (`tool`) identifiziert dies als einen Bereich für das Ausführungswerkzeug. Es `gen_ai.tool.name` enthält den Namen des Tools und `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"
  }
}
```
Der korrelierte Ereignisdatensatz enthält die Werkzeugeingabe (Argumente) und die Ausgabe (Ergebnis, serialisiert als 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>

In der OpenInference Bibliothek ist der Span-Typ im `openinference.span.kind` Attribut enthalten, und die Eingabe und Ausgabe des Agenten werden im korrelierten Ereignisdatensatz serialisiert.

**Example**  
Das `openinference.span.kind` Attribut (oder `AGENT` wenn das Diagramm mit einem Namen kompiliert wird) identifiziert`CHAIN`, dass es sich um einen Span für den Aufruf-Agenten handelt.  

```
{
  "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"
  }
}
```
Der korrelierte Ereignisdatensatz enthält die Konversation. Bei der Benutzeraufforderung handelt es sich um die Nachricht in der menschlichen Rolle und die Antwort des Agenten um die AI-role Nachricht in den serialisierten Nachrichten.  

```
{
  "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"
        }
      ]
    }
  }
}
```
Das `openinference.span.kind` Attribut (`TOOL`) identifiziert dies als einen Bereich für das Ausführungstool; es `tool.name` enthält den Namen des Tools.  

```
{
  "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"
  }
}
```
Der korrelierte Ereignisdatensatz enthält die Werkzeugeingabe (Argumente) und die Ausgabe (Ergebnis, serialisiert als 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"
        }
      ]
    }
  }
}
```

## Beispiel: Spans ohne Ereignisdatensätze
<a name="langgraph-examples-without"></a>

Wenn die Telemetrie nicht aufgeteilt wird, verbleibt derselbe Inhalt in den Span-Attributen und es wird kein separater Ereignisdatensatz erstellt. Die folgenden Beispiele stammen von einem LangGraph Reiseplanungsbüro. Derselbe Agent wird unter jeder Instrumentenbibliothek angezeigt.

**Anmerkung**  
Bei diesen Beispielen handelt es sich nicht um vollständige Datenreihen. Sie zeigen repräsentative Daten aus einer echten Agenteninteraktion, wobei einige Felder weggelassen und lange Werte aus Gründen der Lesbarkeit gekürzt wurden.

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

**Example**  
Das `gen_ai.task.input` Attribut enthält die Benutzeraufforderung, und das `gen_ai.task.output` Attribut enthält den serialisierten Status der Agentenantwort. Bei beiden handelt es sich um den serialisierten LangChain Graphstatus.  

```
{
  "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"
  }
}
```
Das `gen_ai.tool.call.arguments` Attribut enthält die Werkzeugargumente und das `gen_ai.tool.call.result` Attribut enthält das Werkzeugergebnis, serialisiert als. 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**  
Das `input.value` Attribut enthält die Benutzeraufforderung, und das `output.value` Attribut enthält den serialisierten Status der Agentenantwort.  

```
{
  "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"
  }
}
```
Das `input.value` Attribut enthält die Werkzeug-Argumente und das `output.value` Attribut enthält das Werkzeugergebnis, serialisiert als. 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"
  }
}
```

## Bewährte Methoden für Agenten LangGraph
<a name="langgraph-best-practices"></a>

Die Art und Weise, wie Sie einen LangGraph Agenten erstellen und aufrufen, wirkt sich darauf aus, was in seiner Telemetrie angezeigt wird und wie zuverlässig der Agent bewertet werden kann. Mit den folgenden Methoden wird sichergestellt, dass die Benutzeraufforderung, die Antwort des Agenten und die Aktivität des Tools wiederhergestellt werden können.

### 1. Wählen Sie ein Konstruktionsmuster für Agenten
<a name="langgraph-bp-construction"></a>

Es gibt zwei gängige Methoden, einen LangGraph Agenten zu erstellen:
+  **Vorkonfiguriert `create_agent`**: der schnellste Weg, um loszulegen. Pro Runde wird ein einziger Agent-Aufruf-Span erzeugt, wobei die Konversation die integrierte Ausführungsschleife LangGraph durchläuft. Verwenden Sie diese Option, wenn Sie einen Standard-Reason-Act-Agenten ohne benutzerdefinierten Kontrollfluss benötigen.

  ```
  from langchain.agents import create_agent
  
  agent = create_agent(model=model, tools=[search_flights, book_flight])
  ```
+  **Benutzerdefiniert `StateGraph`**: gibt Ihnen die volle Kontrolle über Knoten, Kanten und bedingtes Routing. Die Ausführung jedes Knotens erhält eine eigene Spanne, sodass die Traces detaillierter sind. Verwenden Sie dies, wenn Sie eine benutzerdefinierte Orchestrierung benötigen.

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

Beide Muster werden auf die gleiche Weise ausgewertet. Der Unterschied besteht in der Granularität der Ablaufverfolgung.

### 2. Verwenden Sie `Nachrichten` in Ihrem Graphenstatus (empfohlen)
<a name="langgraph-bp-messages"></a>

Der Bewertungsservice rekonstruiert die Konversation anhand der Eingabe- und Ausgabenachrichten des Agenten. Die Verwendung eines `messages` Felds ist nicht verpflichtend, ermöglicht aber die zuverlässigste Extraktion. Für ein benutzerdefiniertes `StateGraph` Feld sollten Sie die Konversation in einem `messages` Feld in Ihrem Bundesstaat speichern:
+  **`messages`In Ihrem Bundesland angeben (empfohlen).** Sie können weitere benutzerdefinierte Felder hinzufügen (z. `user_id` B. Metadaten). Wenn `messages` vorhanden, findet die Standardextraktion die Benutzeraufforderung und die Antwort des Agenten direkt. Wenn sie nicht vorhanden `messages` ist, rekonstruiert der Service die Konversation anhand einzelner Inferenzspannen, was weniger zuverlässig ist.
+  **Anfügen, nicht ersetzen.** Halten Sie sich an die LangGraph Konvention, neue Nachrichten an die Liste anzuhängen, anstatt sie zu überschreiben, sodass der gesamte Konversationsverlauf erhalten bleibt.
+  **Verwenden Sie kanonische LangChain Nachrichtentypen** (`HumanMessage`,,,`AIMessage`). `ToolMessage` `SystemMessage` Die Instrumentierung serialisiert diese korrekt und der Dienst erkennt ihre Rollen.

### 3. Übergeben Sie die Benutzernachricht in einem unterstützten Format
<a name="langgraph-bp-invocation"></a>

Wenn Sie einen LangGraph Agenten aufrufen, fügen Sie die Benutzernachricht zum `messages` Status des Diagramms hinzu. LangGraph akzeptiert die Nachricht in drei austauschbaren Formaten, und AgentCore Evaluations unterstützt alle Formate. Jedes erzeugt Zeitspannen und Ereignisdatensätze, die der Service lesen kann.
+  **Tupel**: ein `(role, content)` Paar:

  ```
  agent.invoke({"messages": [("user", user_message)]}, config=config)
  ```
+  **LangChain Nachrichtenobjekt**: a `HumanMessage` (oder eine andere Nachrichtenklasse):

  ```
  from langchain_core.messages import HumanMessage
  
  agent.invoke({"messages": [HumanMessage(content=user_message)]}, config=config)
  ```
+  **Wörterbuch**: ein `{"role", "content"}` Wörterbuch:

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

Alle drei Formate führen zu demselben `messages` Status, sodass die Benutzeraufforderung und die Antwort des Agenten unabhängig davon, welches Sie wählen, identisch extrahiert werden.