LlamaIndex
本页说明了如何对LlamaIndex代理进行仪器测量、如何识别跨度以及如何提取评估字段。最后,它提供了构建 LlamaIndex 代理的最佳实践,以便对其进行可靠评估。
主题
对你的代理进行仪器
您可以使用两个仪器库中的任何一个来检测 LlamaIndex 代理:OpenTelemetry(opentelemetry-instrumentation-llamaindex) 或 OpenInference(openinference-instrumentation-llama-index)。Amazon Bedrock AgentCore 评估支持这两个库。这些库发出不同的作用域名称并使用不同的跨度属性。评估服务从每个值中提取相同的值。
当您的代理与 AWS Distro for OpenTelemetry (ADOT) 一起 AgentCore 运行时,例如在 Amazon Bedrock Runtime 上,您无需添加显式的检测代码。将仪器库添加到项目的依赖项中就足够了。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",
]
仪器化是设置可观测性的一个步骤。要导出遥测以进行评估,请在设置可观测性中完成完整设置。
如何识别跨度
用于对跨度进行分类的属性在两个仪器库中有所不同。
例
- OpenTelemetry
-
OpenTelemetry 仪器库使用属性对跨度进行分类。traceloop.span.kind由于将推理和工具操作都 LlamaIndex 标记为task, AgentCore 因此 Avaluations 会通过traceloop.entity.name属性来消除它们的歧义:实体名称以结尾的 a 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 发射CHAINLLM、和TOOL跨度;它不发射AGENT跨度。根工作流跨度 (aCHAIN) 充当调用代理跨度。
| 跨度类型 |
识别属性 |
|
调用代理
|
openinference.span.kind=CHAIN(根工作流程跨度)
|
|
执行工具
|
openinference.span.kind = TOOL
|
|
推理
|
openinference.span.kind = LLM
|
LlamaIndex 发出几个中间CHAIN跨度(例如,用于输出解析和工具布线)。 AgentCore 评估仅将根工作流跨度视为调用代理跨度,并根据跟踪中的推理 (LLM) 跨度重建用户提示和代理响应。
如何提取评估字段
LlamaIndex 代理是一个工作流程,其顶层跨度在其子跨度之前发出。该工作流程跨度本身没有可用的对话内容,因此 AgentCore 评估会从子跨度(推断和工具跨度)重建用户提示和代理响应,并将它们附加到调用代理跨度。
LlamaIndex 还将内容序列化为嵌套的 JSON。工具参数封装为{"kwargs": {…}},工具结果封装为{"blocks": [{"text": "…"}], …}。 AgentCore 评估揭开了这些表格的包装。当 LlamaIndex ReAct 代理以表单生成输出时Thought: … Answer: <response>, AgentCore 评估会提取后面的文本Answer:作为代理响应。
这些内容的位置取决于遥测数据的收集方式。在这两种情况下,标识属性(traceloop.span.kind或openinference.span.kind)都在跨度上。有关更多信息,请参阅跨度、事件记录和遥测信号。
来自事件记录
拆分遥测时, AgentCore 评估会从与每个跨度相关的事件记录中读取内容:
-
用户提示和代理响应:根据推理跨度的事件记录重建而成,在。body.output在 OpenTelemetry 库中,用户提示来自聊天历史记录内容,代理响应来自模型结果内容。在 OpenInference 库中,用户提示是纯文本输入消息,代理响应是模型输出(后面的文本Answer:用于 ReAct 代理)。
-
工具调用:执行工具跨度中的工具名称。工具参数和结果来自该跨度的事件记录,在body.input(解包自{"kwargs": {…}})和body.output(解包自{"blocks": […]})中。
有关示例,请参阅包含事件记录的跨度示例。
来自跨度属性
如果未拆分遥测,则相同的内容将作为属性保留在跨度上。这些属性取决于仪器库:
-
OpenTelemetry: 内容位于每个跨度的traceloop.entity.input和traceloop.entity.output属性上。 AgentCore 评估将相同的聊天历史记录、结果和工具解包应用于这些值。
-
OpenInference:推理内容位于已编入索引的消息属性(llm.input_messages.
和llm.output_messages.)上。工具参数来自input.value(解包自{"kwargs": {…}}),工具的结果来自output.value(解包自{"blocks": […]})。
有关示例,请参阅没有事件记录的跨度示例。
包含事件记录的示例
拆分遥测时,跨度带有识别属性,内容存在于相关的事件记录中。以下示例来自部署在 Amazon Bedro LlamaIndex ReAct AgentCore ck Runtime 上的旅行计划代理。每个仪器库下都显示相同的代理。
这些示例不是完整的跨度。它们显示来自真实代理互动的代表性数据,为了便于阅读,省略了一些字段,长值被截断。
OpenTelemetry
例
- Invoke agent span
-
traceloop.span.kind属性 (workflow) 将其标识为调用代理跨度。工作流程跨度不包含对话内容; AgentCore 评估会根据子跨度重建用户提示和代理响应。
{
"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.entity.name结尾为的traceloop.span.kind属性 (task) 将其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 评估在第一个推理跨度上从聊天历史字符串({"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中的-role 文本。
{
"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-role 文本。
{
"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 评估会根据推理跨度重建用户提示和代理响应。
{
"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 评估使用最后一条纯文本输入消息作为用户提示。 LlamaIndex 发出重复的带assistant:前缀的输出消息, AgentCore 评估会跳过该消息,转而使用干净的副本。
{
"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 评估从中读取用户提示。响应来自上次推理跨度的模型结果。
{
"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 评估会根据这些子跨度重建调用代理跨度。
-
将工具注册为FunctionTool对象。将每个工具定义为 LlamaIndex FunctionTool(或使用生成工具的@tool样式助手)。工具跨度由其实体名称标识,其参数和结果在 AgentCore 评估展开的kwargs和blocks结构中序列化。
-
保持工具结果的文本可序列化。以字符串或 JSON-serializable 值的形式返回工具结果。 LlamaIndex 将它们包装在文本块中;保持它们可序列化可确保清晰地捕获工具结果。
-
对于 ReAct 代理,请使用标准输出格式。 AgentCore 评估从 ReAct 代理输出Answer:部分提取最终答案。使用标准 ReAct 提示符( LlamaIndex 默认)可保持代理响应可恢复。