

# LlamaIndex
<a name="supported-frameworks-llamaindex"></a>

本页说明了如何对[LlamaIndex](https://docs.llamaindex.ai/)代理进行仪器测量、如何识别跨度以及如何提取评估字段。最后，它提供了构建 LlamaIndex 代理[的最佳实践](#llamaindex-best-practices)，以便对其进行可靠评估。

 **主题** 
+  [对你的代理进行仪器](#llamaindex-instrument) 
+  [如何识别跨度](#llamaindex-span-identification) 
+  [如何提取评估字段](#llamaindex-extraction) 
  +  [来自事件记录](#llamaindex-extraction-event-records) 
  +  [来自跨度属性](#llamaindex-extraction-attributes) 
+  [包含事件记录的示例](#llamaindex-examples-with) 
+  [没有事件记录的示例跨度](#llamaindex-examples-without) 
+  [ LlamaIndex 代理的最佳实践](#llamaindex-best-practices) 

## 对你的代理进行仪器
<a name="llamaindex-instrument"></a>

您可以使用两个仪器库中的任何一个来检测 LlamaIndex 代理：**OpenTelemetry**(`opentelemetry-instrumentation-llamaindex`) 或 **OpenInference**(`openinference-instrumentation-llama-index`)。Amazon Bedrock AgentCore 评估支持这两个库。这些库发出不同的作用域名称并使用不同的跨度属性。评估服务从每个值中提取相同的值。

当您的代理与 AWS Distro for OpenTelemetry (ADOT) 一起 AgentCore 运行时，例如在 Amazon Bedrock Runtime 上，您无需添加显式的检测代码。将仪器库添加到项目的依赖项中就足够了。ADOT 会在启动时发现它并自动将其激活。

为你想要的依赖关系路径添加仪器库。除非有理由固定，否则请使用最新的可用版本。

**Example**  
注意：使用版本`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",
]
```
注意：使用版本`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",
]
```

**注意**  
仪器化是设置可观测性的一个步骤。要导出遥测以进行评估，请在设置[可观](supported-frameworks.md#supported-frameworks-setup)测性中完成完整设置。

## 如何识别跨度
<a name="llamaindex-span-identification"></a>

用于对跨度进行分类的属性在两个仪器库中有所不同。

**Example**  
 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.span.kind` LlamaIndex 发射`CHAIN``LLM`、和`TOOL`跨度；它不发射`AGENT`跨度。根工作流跨度 (a`CHAIN`) 充当调用代理跨度。  


| 跨度类型 | 识别属性 | 
| --- | --- | 
| 调用代理 |  `openinference.span.kind`=`CHAIN`（根工作流程跨度） | 
| 执行工具 |  `openinference.span.kind` = `TOOL`  | 
| 推理 |  `openinference.span.kind` = `LLM`  | 
LlamaIndex 发出几个中间`CHAIN`跨度（例如，用于输出解析和工具布线）。 AgentCore 评估仅将根工作流跨度视为调用代理跨度，并根据跟踪中的推理 (`LLM`) 跨度重建用户提示和代理响应。

## 如何提取评估字段
<a name="llamaindex-extraction"></a>

 LlamaIndex 代理是一个**工作流程**，其顶层跨度在其子跨度之前发出。该工作流程跨度本身没有可用的对话内容，因此 AgentCore 评估会从子跨度（推断和工具跨度）重建用户提示和代理响应，并将它们附加到调用代理跨度。

LlamaIndex 还将内容序列化为嵌套的 JSON。工具参数封装为`{"kwargs": {…​}}`，工具结果封装为`{"blocks": [{"text": "…​"}], …​}`。 AgentCore 评估揭开了这些表格的包装。当 LlamaIndex ReAct 代理以表单生成输出时`Thought: …​ Answer: <response>`， AgentCore 评估会提取后面的文本`Answer:`作为代理响应。

这些内容的位置取决于遥测数据的收集方式。在这两种情况下，标识属性（`traceloop.span.kind`或`openinference.span.kind`）都在跨度上。有关更多信息，请参阅[跨度、事件记录和遥测信](supported-frameworks-telemetry.md)号。

### 来自事件记录
<a name="llamaindex-extraction-event-records"></a>

拆分遥测时， AgentCore 评估会从与每个跨度相关的事件记录中读取内容：
+  **用户提示**和**代理响应：根据**推理跨度的事件记录重建而成，在。`body.output`在 OpenTelemetry 库中，用户提示来自聊天历史记录内容，代理响应来自模型结果内容。在 OpenInference 库中，用户提示是纯文本输入消息，代理响应是模型输出（后面的文本`Answer:`用于 ReAct 代理）。
+  **工具调用**：执行工具跨度中的工具名称。工具参数和结果来自该跨度的事件记录，在`body.input`（解包自`{"kwargs": {…​}}`）和`body.output`（解包自`{"blocks": […​]}`）中。

有关示例，请参阅[包含事件记录的跨度示](#llamaindex-examples-with)例。

### 来自跨度属性
<a name="llamaindex-extraction-attributes"></a>

如果未拆分遥测，则相同的内容将作为属性保留在跨度上。这些属性取决于仪器库：
+  **OpenTelemetry**: 内容位于每个跨度的`traceloop.entity.input`和`traceloop.entity.output`属性上。 AgentCore 评估将相同的聊天历史记录、结果和工具解包应用于这些值。
+  **OpenInference**：推理内容位于已编入索引的消息属性（`llm.input_messages. `和`llm.output_messages.`）上。工具参数来自`input.value`（解包自`{"kwargs": {…​}}`），工具的结果来自`output.value`（解包自`{"blocks": […​]}`）。

有关示例，请参阅[没有事件记录的跨度示](#llamaindex-examples-without)例。

## 包含事件记录的示例
<a name="llamaindex-examples-with"></a>

拆分遥测时，跨度带有识别属性，内容存在于相关的事件记录中。以下示例来自部署在 Amazon Bedro LlamaIndex ReAct AgentCore ck Runtime 上的旅行计划代理。每个仪器库下都显示相同的代理。

**注意**  
这些示例不是完整的跨度。它们显示来自真实代理互动的代表性数据，为了便于阅读，省略了一些字段，长值被截断。

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

**Example**  
`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"
  }
}
```
`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\"}" }
      ]
    }
  }
}
```
`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
<a name="llamaindex-examples-with-openinference"></a>

**Example**  
根工作流跨度上的`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"
  }
}
```
`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\"}" }
      ]
    }
  }
}
```
`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 ..." }
      ]
    }
  }
}
```

## 没有事件记录的示例跨度
<a name="llamaindex-examples-without"></a>

如果不拆分遥测，则相同的内容将保留在跨度属性上，并且不会生成单独的事件记录。以下示例来自 LlamaIndex ReAct 旅行计划代理商。每个仪器库下都显示相同的代理。

**注意**  
这些示例不是完整的跨度。它们显示来自真实代理互动的代表性数据，为了便于阅读，省略了一些字段，长值被截断。

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

**Example**  
该`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"
  }
}
```
该`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
<a name="llamaindex-examples-without-openinference"></a>

**Example**  
该`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"
  }
}
```
消息内容在已编入索引的属性上是内联的。这些`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 代理的最佳实践
<a name="llamaindex-best-practices"></a>

构建和调用 LlamaIndex 代理的方式会影响其遥测中显示的内容，从而影响对代理进行评估的可靠性。以下做法有助于确保用户提示、代理响应和工具活动可恢复。
+  **使用 LlamaIndex 代理工作流程。**将您的代理构建为 LlamaIndex 代理工作流程（例如，`ReActAgent`或`FunctionAgent`），以便框架发出包含推理和工具子跨度的顶级工作流程跨度。 AgentCore 评估会根据这些子跨度重建调用代理跨度。
+  **将工具注册为`FunctionTool`对象。**将每个工具定义为 LlamaIndex `FunctionTool`（或使用生成工具的`@tool`样式助手）。工具跨度由其实体名称标识，其参数和结果在 AgentCore 评估展开的`kwargs`和`blocks`结构中序列化。
+  **保持工具结果的文本可序列化。**以字符串或 JSON-serializable 值的形式返回工具结果。 LlamaIndex 将它们包装在文本块中；保持它们可序列化可确保清晰地捕获工具结果。
+  **对于 ReAct 代理，请使用标准输出格式。** AgentCore 评估从 ReAct 代理输出`Answer:`部分提取最终答案。使用标准 ReAct 提示符（ LlamaIndex 默认）可保持代理响应可恢复。