LlamaIndex
このページでは、LlamaIndex エージェントを計測する方法、スパンの識別方法、評価フィールドの抽出方法について説明します。LlamaIndex エージェントを確実に評価できるように、LlamaIndex エージェントを構造化するためのベストプラクティスで終了します。
トピック
エージェントを計測する
OpenTelemetry (opentelemetry-instrumentation-llamaindex) または OpenInference () の 2 つの計測ライブラリのいずれかを使用して、LlamaIndex エージェントを計測できますopeninference-instrumentation-llama-index。Amazon Bedrock AgentCore Evaluations は両方のライブラリをサポートしています。ライブラリは異なるスコープ名を出力し、異なるスパン属性を使用します。評価サービスは、それぞれから同じ値を抽出します。
Amazon Bedrock AgentCore ランタイムなど、エージェントが AWS Distro for OpenTelemetry (ADOT) で実行されている場合、明示的な計測コードを追加する必要はありません。計測ライブラリをプロジェクトの依存関係に追加するだけで十分です。ADOT は起動時に検出し、自動的にアクティブ化します。
依存関係に必要なパスの計測ライブラリを追加します。ピン留めする理由がない限り、利用可能な最新バージョンを使用してください。
例
- OpenTelemetry
-
注: バージョン 0.61.0 以降を使用します。これは、評価サービスでテストされた最も古いバージョンです。
opentelemetry-instrumentation-llamaindex を依存関係に追加します。出力されるスコープ名は ですopentelemetry.instrumentation.llamaindex。
requirements.txt:
opentelemetry-instrumentation-llamaindex>=0.61.0
pyproject.toml:
[project]
dependencies = [
"opentelemetry-instrumentation-llamaindex>=0.61.0",
]
- OpenInference
-
注: バージョン 4.4.1 以降を使用します。これは、評価サービスでテストされた最も古いバージョンです。
openinference-instrumentation-llama-index を依存関係に追加します。出力されるスコープ名は ですopeninference.instrumentation.llama_index。
requirements.txt:
openinference-instrumentation-llama-index>=4.4.1
pyproject.toml:
[project]
dependencies = [
"openinference-instrumentation-llama-index>=4.4.1",
]
計測は、オブザーバビリティを設定する 1 つのステップです。評価のためにテレメトリをエクスポートするには、「オブザーバビリティの設定」で完全なセットアップを完了します。
スパンの識別方法
スパンの分類に使用される属性は、2 つの計測ライブラリによって異なります。
例
- OpenTelemetry
-
OpenTelemetry 計測ライブラリは、 traceloop.span.kind 属性を使用してスパンを分類します。LlamaIndex は推論オペレーションとツールオペレーションの両方を としてタグ付けするためtask、AgentCore Evaluations はtraceloop.entity.nameそれらを 属性で曖昧さを解消します。taskエンティティ名が で終わる Tool.taskは実行ツールスパンで、その他のものは推論スパンtaskです。
| スパンタイプ |
属性の識別 |
|
エージェントを呼び出す
|
traceloop.span.kind = workflow
|
|
実行ツール
|
traceloop.span.kind = tool、または traceloop.span.kind = task traceloop.entity.name で終わる Tool.task
|
|
推測
|
traceloop.span.kind = task (ツールタスクではない)
|
- OpenInference
-
OpenInference 計測ライブラリは、 openinference.span.kind 属性を使用してスパンを分類します。LlamaIndex は CHAIN、LLM、および TOOLスパンを出力します。AGENTスパンは出力しません。ルートワークフロースパン (CHAIN) は、呼び出しエージェントのスパンとして機能します。
| スパンタイプ |
属性の識別 |
|
エージェントを呼び出す
|
openinference.span.kind = CHAIN (ルートワークフロースパン)
|
|
実行ツール
|
openinference.span.kind = TOOL
|
|
推測
|
openinference.span.kind = LLM
|
LlamaIndex は、複数の中間CHAINスパン (出力解析やツールルーティングなど) を出力します。AgentCore Evaluations は、ルートワークフロースパンのみを呼び出しエージェントスパンとして扱い、トレースの推論 (LLM) スパンからユーザープロンプトとエージェントレスポンスを再構築します。
評価フィールドの抽出方法
LlamaIndex エージェントはワークフローであり、最上位のスパンは子スパンの前に出力されます。このワークフロースパンには独自の使用可能な会話コンテンツがないため、AgentCore Evaluations は子スパン (推論とツールスパン) からユーザープロンプトとエージェントレスポンスを再構築し、呼び出しエージェントスパンにアタッチします。
LlamaIndex は、ネストされた JSON としてコンテンツをシリアル化します。ツール引数は としてラップされ{"kwargs": {…}}、ツールの結果は としてラップされます{"blocks": [{"text": "…"}], …}。AgentCore Evaluations は、これらのフォームをラップ解除します。LlamaIndex ReAct エージェントが 形式で出力を生成するとThought: … Answer: <response>、AgentCore Evaluations はエージェントのレスポンスAnswer:として の後にテキストを抽出します。
このコンテンツの場所は、テレメトリの収集方法によって異なります。どちらの場合も、識別属性 (traceloop.span.kind または openinference.span.kind) はスパン上にあります。詳細については、「スパン、イベントレコード、テレメトリシグナル」を参照してください。
イベントレコードから
テレメトリが分割されると、AgentCore Evaluations は各スパンに相関するイベントレコードからコンテンツを読み取ります。
-
ユーザープロンプトとエージェントのレスポンス: の推論スパンのイベントレコードから再構築されましたbody.output。OpenTelemetry ライブラリでは、ユーザープロンプトはチャット履歴コンテンツから、エージェントレスポンスはモデル結果コンテンツから取得されます。OpenInference ライブラリでは、ユーザープロンプトはプレーンテキストの入力メッセージで、エージェントのレスポンスはモデル出力 (ReAct エージェントAnswer:に使用した後のテキストを含む) です。 ReAct
-
ツール呼び出し: 実行ツールスパンのツール名。ツールの引数と結果は、 ( からラップ解除) と body.input ( からラップbody.output解除{"kwargs": {…}}) で、そのスパンのイベントレコードから取得されます{"blocks": […]}。
例については、「イベントレコードを含むスパンの例」を参照してください。
スパン属性から
テレメトリが分割されていない場合、同じコンテンツは属性と同じスパンに残ります。属性は、計測ライブラリによって異なります。
-
OpenTelemetry: コンテンツは各スパンの traceloop.entity.inputおよび traceloop.entity.output 属性にあります。AgentCore Evaluations は、同じチャット履歴、結果、ツールのラップ解除をこれらの値に適用します。
-
OpenInference: 推論コンテンツは、インデックス付きメッセージ属性 (llm.input_messages. および ) にありますllm.output_messages.。ツール引数は から取得され input.value ( からラップ解除{"kwargs": {…}})、ツールの結果は から取得されます output.value ( からラップ解除){"blocks": […]}。
例については、「イベントレコードのないスパンの例」を参照してください。
イベントレコードを含むスパンの例
テレメトリが分割されると、スパンは識別属性を保持し、コンテンツは相関イベントレコードに存在します。次の例は、Amazon Bedrock AgentCore ランタイムにデプロイされた LlamaIndex ReAct の旅行計画エージェントからのものです。各計測ライブラリの下に同じエージェントが表示されます。
これらの例は完全なスパンではありません。実際のエージェントインタラクションからの代表的なデータが表示され、読みやすいように一部のフィールドは省略され、長い値は切り捨てられます。
OpenTelemetry
例
- Invoke agent span
-
traceloop.span.kind 属性 (workflow) は、これを呼び出しエージェントのスパンとして識別します。ワークフロースパンには会話コンテンツはありません。AgentCore Evaluations は、子スパンからユーザープロンプトとエージェントレスポンスを再構築します。
{
"traceId": "6a01eef11066751d68f90def0da1f80a",
"spanId": "ba1833fa7f097041",
"name": "ReActAgent.workflow",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex",
"version": "0.61.0"
},
"attributes": {
"traceloop.span.kind": "workflow",
"traceloop.entity.name": "ReActAgent.workflow",
"session.id": "sea-nyc-trip-2-turns-llamaindex-otel"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
末尾が のtraceloop.span.kind属性 (task) traceloop.entity.name は、これを実行ツールスパンとしてTool.task識別します。相関イベントレコードには、ツールの引数 ( でラップkwargs) とツールの結果 ( でラップblocks) が、ツール名とともに保持されます。
{
"traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
"spanId": "5b332f3cd15ace04",
"name": "FunctionTool.task",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex",
"version": "0.61.0"
},
"attributes": {
"traceloop.span.kind": "task",
"traceloop.entity.name": "FunctionTool.task",
"session.id": "sea-nyc-trip-2-turns-llamaindex-otel"
},
"status": {
"code": "OK"
}
}
{
"spanId": "5b332f3cd15ace04",
"traceId": "6a01eefa5c52f3d86a35038f35f5ba30",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex"
},
"body": {
"input": {
"messages": [
{ "role": "user", "content": "{\"kwargs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}}" }
]
},
"output": {
"messages": [
{ "content": "{\"blocks\": [{\"block_type\": \"text\", \"text\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\"}], \"tool_name\": \"search_flights\"}" }
]
}
}
}
- Inference span
-
traceloop.span.kind 属性 (task) traceloop.entity.nameは、 で終わることのない でTool.task、これを推論スパンとして識別します。LlamaIndex エージェントは、ターンごとにこれらのスパンのいくつかを生成します。各コンテンツは、シリアル化された JSON 文字列として にまとめられます body.output ( はありませんbody.input)。AgentCore Evaluations は、最初の推論スパンの chat-history 文字列 ({"input": […]}オブジェクト) からユーザープロンプトを読み取り、最後の推論スパンのモデル結果文字列 ({"result": {"response": …}}オブジェクト) からエージェントレスポンスを読み取ります。
以下は、推論スパン自体です。
{
"traceId": "6a01eef11066751d68f90def0da1f80a",
"spanId": "d9a1f0c7b3e64a20",
"name": "BaseWorkflowAgent.task",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex",
"version": "0.61.0"
},
"attributes": {
"traceloop.span.kind": "task",
"traceloop.entity.name": "BaseWorkflowAgent.task",
"session.id": "sea-nyc-trip-2-turns-llamaindex-otel"
},
"status": {
"code": "OK"
}
}
最初の推論スパンでは、イベントレコードのbody.outputコンテンツはチャット履歴です。ユーザープロンプトは、ネストされたinput配列内の userロールテキストです。
{
"spanId": "d9a1f0c7b3e64a20",
"traceId": "6a01eef11066751d68f90def0da1f80a",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex"
},
"body": {
"output": {
"messages": [
{
"content": "{\"input\": [{\"role\": \"user\", \"blocks\": [{\"block_type\": \"text\", \"text\": \"Hey, how can you help me\"}]}], \"current_agent_name\": \"Agent\"}"
}
]
}
}
}
最後の推論スパンでは、イベントレコードのbody.outputコンテンツがモデル結果になります。エージェントレスポンスは、ネストされたresult.responseオブジェクト内の assistantロールテキストです。
{
"spanId": "826bc829697a9610",
"traceId": "6a01eef11066751d68f90def0da1f80a",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex"
},
"body": {
"output": {
"messages": [
{
"content": "{\"result\": {\"response\": {\"role\": \"assistant\", \"blocks\": [{\"block_type\": \"text\", \"text\": \"Here are the available flights from Seattle to New York City ...\"}]}}, \"current_agent_name\": \"Agent\"}"
}
]
}
}
}
OpenInference
例
- Invoke agent span
-
ルートワークフロースパンのopeninference.span.kind属性 (CHAIN) は、これを呼び出しエージェントのスパンとして識別します。スパンには使用可能な会話コンテンツはありません。AgentCore Evaluations は、推論スパンからユーザープロンプトとエージェントレスポンスを再構築します。
{
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"spanId": "0a7990d804132a9b",
"name": "ReActAgent.run",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.llama_index",
"version": "4.4.1"
},
"attributes": {
"openinference.span.kind": "CHAIN",
"input.mime_type": "application/json",
"output.mime_type": "text/plain",
"session.id": "sea-nyc-trip-2-turns-llamaindex-oi"
},
"status": {
"code": "OK"
}
}
- Execute tool span
-
openinference.span.kind 属性 (TOOL) は、これを実行ツールスパンとして識別します。 はツール名tool.nameを保持します。ツール引数と結果は、相関イベントレコードにblocksそれぞれ kwargsと でラップされます。
{
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"spanId": "ab105c12cc40048f",
"name": "FunctionTool.acall",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.llama_index",
"version": "4.4.1"
},
"attributes": {
"openinference.span.kind": "TOOL",
"tool.name": "search_flights",
"tool.description": "search_flights(origin: str, destination: str, date: str) -> str ...",
"session.id": "sea-nyc-trip-2-turns-llamaindex-oi"
},
"status": {
"code": "OK"
}
}
{
"spanId": "ab105c12cc40048f",
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"scope": {
"name": "openinference.instrumentation.llama_index"
},
"body": {
"input": {
"messages": [
{ "content": "{\"kwargs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}}" }
]
},
"output": {
"messages": [
{ "content": "{\"blocks\": [{\"text\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"destination\\\": \\\"NYC\\\", \\\"flights\\\": [ ... ]}\"}], \"tool_name\": \"search_flights\"}" }
]
}
}
}
- Inference span
-
openinference.span.kind 属性 (LLM) は、これを推論スパンとして識別します。メッセージロールはスパン属性にあり、コンテンツは相関イベントレコードに存在します。ADOT は入力ロールを にフラット化するためuser、AgentCore Evaluations はユーザープロンプトとして最後のプレーンテキストの入力メッセージを使用します。LlamaIndex は、重複するassistant:プレフィックス付きの出力メッセージを発行します。このメッセージは AgentCore Evaluations がスキップし、クリーンコピーを優先します。
{
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"spanId": "1221a062c7f90a8e",
"name": "OpenAI.astream_chat",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.llama_index",
"version": "4.4.1"
},
"attributes": {
"openinference.span.kind": "LLM",
"llm.system": "openai",
"llm.model_name": "gpt-4o-mini",
"llm.input_messages.0.message.role": "system",
"llm.input_messages.1.message.role": "user",
"llm.output_messages.0.message.role": "assistant",
"session.id": "sea-nyc-trip-2-turns-llamaindex-oi"
},
"status": {
"code": "OK"
}
}
{
"spanId": "1221a062c7f90a8e",
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"scope": {
"name": "openinference.instrumentation.llama_index"
},
"body": {
"input": {
"messages": [
{ "role": "user", "content": "{\"messages\": [ ... ]}" },
{ "role": "user", "content": "You are designed to help with a variety of tasks ..." },
{ "role": "user", "content": "Hey, how can you help me" }
]
},
"output": {
"messages": [
{ "role": "assistant", "content": "assistant: Thought: ... Answer: I can help you plan your trip ..." },
{ "role": "assistant", "content": "Thought: ... Answer: I can help you plan your trip ..." }
]
}
}
}
イベントレコードのないスパンの例
テレメトリが分割されていない場合、同じコンテンツはスパン属性に残り、個別のイベントレコードは生成されません。次の例は、LlamaIndex ReAct の旅行計画エージェントからのものです。各計測ライブラリの下に同じエージェントが表示されます。
これらの例は完全なスパンではありません。実際のエージェントインタラクションからの代表的なデータが表示され、読みやすいように一部のフィールドは省略され、長い値は切り捨てられます。
OpenTelemetry
例
- Execute tool span
-
traceloop.entity.input 属性はツール引数を保持し ( でラップkwargs)、 traceloop.entity.output 属性はツールの結果を保持します ( でラップ)blocks。
{
"traceId": "6a4de7c376913db82e6f0f336a16731d",
"spanId": "b64c37adefae74f0",
"name": "FunctionTool.task",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex",
"version": "0.61.0"
},
"attributes": {
"traceloop.span.kind": "task",
"traceloop.entity.name": "FunctionTool.task",
"traceloop.entity.input": "{\"kwargs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}}",
"traceloop.entity.output": "{\"blocks\": [{\"block_type\": \"text\", \"text\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"flights\\\": [ ... ]}\"}], \"tool_name\": \"search_flights\"}",
"session.id": "sea-nyc-trip-2-turns-unified"
},
"status": {
"code": "OK"
}
}
- Inference span
-
traceloop.entity.output 属性には、AgentCore Evaluations がユーザープロンプトを読み取るチャット履歴が保持されます。レスポンスは、最後の推論スパンのモデル結果から取得されます。
{
"traceId": "6a4de7b85e61747e6b568a1f4768e89d",
"spanId": "31ea3d5882dac680",
"name": "BaseWorkflowAgent.task",
"kind": "INTERNAL",
"scope": {
"name": "opentelemetry.instrumentation.llamaindex",
"version": "0.61.0"
},
"attributes": {
"traceloop.span.kind": "task",
"traceloop.entity.name": "BaseWorkflowAgent.task",
"traceloop.entity.output": "{\"input\": [{\"role\": \"user\", \"blocks\": [{\"block_type\": \"text\", \"text\": \"Hey, how can you help me\"}]}], \"current_agent_name\": \"Agent\"}",
"session.id": "sea-nyc-trip-2-turns-unified"
},
"status": {
"code": "OK"
}
}
OpenInference
例
- Execute tool span
-
input.value 属性はツール引数を保持し ( でラップkwargs)、 output.value 属性はツールの結果を保持します ( でラップ)blocks。
{
"traceId": "6a387ef07b8f4f3732fab45d3c0b51ff",
"spanId": "d5a1c9e70b46f312",
"name": "FunctionTool.acall",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.llama_index",
"version": "4.4.2"
},
"attributes": {
"openinference.span.kind": "TOOL",
"tool.name": "search_flights",
"input.value": "{\"kwargs\": {\"origin\": \"SEA\", \"destination\": \"NYC\", \"date\": \"2025-03-15\"}}",
"output.value": "{\"blocks\": [{\"text\": \"{\\\"origin\\\": \\\"SEA\\\", \\\"flights\\\": [ ... ]}\"}], \"tool_name\": \"search_flights\"}",
"session.id": "sea-nyc-trip-2-turns-oi"
},
"status": {
"code": "OK"
}
}
- Inference span
-
メッセージの内容は、インデックス付き属性でインラインです。llm.input_messages. 属性はシステムプロンプトとユーザープロンプトを保持し、llm.output_messages.属性はモデル出力を保持し、AgentCore評価はエージェントのレスポンスAnswer:として の後にテキストを抽出します。
{
"traceId": "6a387ee61078243c1cc455ed45c6c313",
"spanId": "c9f0a2b41d773e88",
"name": "OpenAI.astream_chat",
"kind": "INTERNAL",
"scope": {
"name": "openinference.instrumentation.llama_index",
"version": "4.4.2"
},
"attributes": {
"openinference.span.kind": "LLM",
"llm.model_name": "gpt-4o-mini",
"llm.input_messages.0.message.role": "system",
"llm.input_messages.0.message.content": "You are designed to help with a variety of tasks ...",
"llm.input_messages.1.message.role": "user",
"llm.input_messages.1.message.content": "Hey, how can you help me",
"llm.output_messages.0.message.role": "assistant",
"llm.output_messages.0.message.content": "Thought: ... Answer: I can help you plan your trip ...",
"session.id": "sea-nyc-trip-2-turns-oi"
},
"status": {
"code": "OK"
}
}
LlamaIndex エージェントのベストプラクティス
LlamaIndex エージェントを構築して呼び出す方法は、テレメトリに表示される内容、つまりエージェントの評価の信頼性に影響します。以下のプラクティスは、ユーザープロンプト、エージェントのレスポンス、ツールアクティビティを回復可能にするのに役立ちます。
-
LlamaIndex エージェントワークフローを使用します。エージェントを LlamaIndex エージェントワークフロー ( ReActAgentや などFunctionAgent) として構築し、フレームワークが推論とツールの子スパンを含む最上位ワークフロースパンを出力できるようにします。AgentCore Evaluations は、これらの子スパンから呼び出しエージェントスパンを再構築します。
-
ツールをFunctionToolオブジェクトとして登録します。各ツールを LlamaIndex として定義します (または、LlamaIndex を生成する @toolスタイルのヘルパーを使用します)。 FunctionToolツールスパンはエンティティ名で識別され、引数と結果は でシリアル化kwargsされ、 blocks構造 AgentCore Evaluations がラップ解除します。
-
ツールの結果をテキストシリアル化可能に保ちます。ツールの結果を文字列または JSON シリアル化可能な値として返します。LlamaIndex はそれらをテキストブロックにラップします。シリアル化可能な状態にしておくと、ツールの結果がクリーンにキャプチャされます。
-
ReAct エージェントの場合は、標準の出力形式を使用します。AgentCore Evaluations は、ReAct エージェントの出力の Answer:セクションから最終的な回答を抽出します。標準の ReAct プロンプト (LlamaIndex のデフォルト) を使用すると、エージェントのレスポンスは回復可能になります。