
# Trace数据上报
Trace数据用于记录智能体的单次请求详情，包括调用链路、节点耗时、模型输入输出等。
下面以Python语言开发的智能体为例，介绍如何将Trace数据上报至AgentArts观测平台。
![](https://support.huaweicloud.com/ops-agentarts/public_sys-resources/note_3.0-zh-cn.png)
第三方智能体上报的Trace数据将直接写入您的华为云应用性能管理APM服务。APM会根据上报的数据量按需计费。为避免在生产环境因大并发测试产生意外费用，请在部署前仔细阅读[APM计费说明](https://support.huaweicloud.com/price-apm2/apm_07_0019.html)。
#### 安装依赖库
安装OpenTelemetry Python SDK及相关依赖库。要求Python 3.9或以上版本。
```
pip install opentelemetry-distro==0.62b1
pip install opentelemetry-api==1.41.1
pip install opentelemetry-exporter-otlp==1.41.1
pip install traceloop-sdk==0.60.0
```
#### 获取上报参数
1. 在AgentArts平台左侧导航栏中选择"运营运维 \> 观测"，并进入"智能体列表"页面。
2. 单击"智能体接入"，填写智能体名称，并选择类型。类型按实际选择。 
   图1智能体接入   
   ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002687916048.png)
   
   
3. 填写完成后，单击"创建"等待平台自动创建接入信息，记录接入地址、鉴权信息、智能体ID等信息。请妥善保管该信息。 
   表1接入信息说明 
   | 参数             | 说明              |
   |:---|:---|
   | agent_id       | 智能体ID。          |
   | trace_endpoint | Trace数据接入地址。    |
   | trace_token    | Trace上报鉴权Token。 |
      
   图2获取接入地址、鉴权信息、智能体ID等信息   
   ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002688075960.png)
   
   
 
#### 上报Trace数据
**配置参数信息：**
在上报Trace数据前，需配置环境变量。服务名称（OTEL_SERVICE_NAME）必须遵循AgentArts.{{智能体ID}}.{{版本号}} 的格式（版本号默认填写default）。
```
OTEL_SERVICE_NAME=AgentArts.{智能体ID}.default
OTEL_EXPORTER_OTLP_TRACES_HEADERS=Authentication={trace_token}
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT={trace_endpoint}
OTEL_EXPORTER_OTLP_TRACES_INSECURE=true
```
**上报Trace数据示例代码：**
本示例为连通性测试示例，用于首次接入AgentArts时验证上报地址、Token和智能体ID是否匹配正确，并确认平台能否正常接收数据。**此阶段使用手动构造的静态数据。**
```
import os
import time
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# 1. 替换为您的真实接入凭证
AGENT_ID = "您的智能体ID"
AGENT_NAME = "您的智能体名称"
TRACE_ENDPOINT = "您的Trace接入地址"
TRACE_TOKEN = "您的Trace鉴权Token"
# 2. 配置 OTel 环境变量
os.environ["OTEL_SERVICE_NAME"] = f"AgentArts.{AGENT_ID}.default"
os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = f"Authentication={TRACE_TOKEN}"
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = TRACE_ENDPOINT
os.environ["OTEL_EXPORTER_OTLP_TRACES_INSECURE"] = "true"
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(tracer_provider)
tracer = trace.get_tracer(__name__)
def test_connection():
    # 模拟数据专用的会话 ID 与用户 ID
    mock_session_id = "test_session_12345"
    mock_user_id = "test_user"
    # 初始化 Token 累加器，用于汇总所有 Model Span 的 Token 消耗
    total_input_tokens = 0
    total_output_tokens = 0
    total_tokens = 0
    # 创建 Root Span (根节点)
    with tracer.start_as_current_span("test_user_request") as root:
        root.set_attribute("gen_ai.span.type", "root")
        root.set_attribute("gen_ai.resource.id", AGENT_ID)
        root.set_attribute("gen_ai.agent.name", AGENT_NAME)
        root.set_attribute("gen_ai.resource.type", "agent")
        root.set_attribute("gen_ai.application_name", "default")
        root.set_attribute("gen_ai.environment", "default")
        root.set_attribute("gen_ai.call.type", "API")
        root.set_attribute("gen_ai.conversation.id", mock_session_id)
        root.set_attribute("gen_ai.user.id", mock_user_id)
        root.set_attribute("input.value", "测试输入")
        # 创建 Model Span (大模型子节点)
        with tracer.start_as_current_span("test_llm_call") as model_span:
            model_span.set_attribute("gen_ai.span.type", "LLM")
            model_span.set_attribute("gen_ai.resource.id", AGENT_ID)
            model_span.set_attribute("gen_ai.resource.type", "agent")
            model_span.set_attribute("gen_ai.agent.name", AGENT_NAME)
            model_span.set_attribute("gen_ai.conversation.id", mock_session_id)
            model_span.set_attribute("gen_ai.user.id", mock_user_id)
            model_span.set_attribute("traceloop.workflow.type", "LLM")
            model_span.set_attribute("gen_ai.request.model", "deepseek-v4-pro")
            # 【注意】此处为模拟数据，仅供测试连通性，实际场景需要从真实的响应中提取参数
            time.sleep(0.5)
            model_span.set_attribute("gen_ai.usage.input_tokens", "100")
            model_span.set_attribute("gen_ai.usage.output_tokens", "200")
            model_span.set_attribute("gen_ai.usage.total_tokens", "300")
            model_span.set_attribute("gen_ai.client.operation.duration", "0.5")
            model_span.set_attribute("input.value", "测试输入")
            model_span.set_attribute("output.value", "测试输出")
            # 将本次 Model Span 的 Token 消耗累加至总计
            total_input_tokens += 100
            total_output_tokens += 200
            total_tokens += 300
        root.set_attribute("output.value", "测试输出")
        # 将所有 Model Span 的 Token 消耗累加后统一写入 Root Span
        # 若请求中存在多个 Model Span，Root Span 上的值为所有节点的 Token 消耗总和
        root.set_attribute("gen_ai.usage.input_tokens", total_input_tokens)
        root.set_attribute("gen_ai.usage.output_tokens", total_output_tokens)
        root.set_attribute("gen_ai.usage.total_tokens", total_tokens)
if __name__ == "__main__":
    test_connection()
    tracer_provider.shutdown() # 刷新数据至服务端
    print("测试 Trace 数据已发送，请前往 AgentArts 控制台查看。")
```
为了保证您的第三方Trace数据能够被AgentArts观测控制台正确识别、解析并展示在各种分析图表中，您在手动埋点上报时，必须严格遵守以下字段命名与数据类型规范。关于所有可设置的Attribute字段及含义，请参考[OpenTelemetry字段映射](https://support.huaweicloud.com/ops-agentarts/agentarts_14_0127.html)。
表2Attribute说明 
| Attribute                        | 是否必填 | 说明                                                                                                                                                  |
|:---|:---|:---|
| gen_ai.span.type                 | 是    | 区分节点类型。Root Span节点填写"root"，Model Span 节点填写"LLM"，Tool Span节点填写"PLUGIN"。                                                                              |
| gen_ai.resource.id               | 是    | 智能体ID，直接作为字符串写入。                                                                                                                                    |
| gen_ai.resource.type             | 是    | 资源类型，默认填写"agent"。                                                                                                                                   |
| gen_ai.conversation.id           | 是    | 用户本次对话的唯一会话ID。用于在平台"会话分析"中串联并还原上下文。                                                                                                                 |
| gen_ai.agent.name                | 是    | 智能体名称。                                                                                                                                              |
| gen_ai.call.type                 | 是    | 触发类型固定填写"API"。                                                                                                                                      |
| gen_ai.request.model             | 否    | 调用的模型名称（如"deepseek-v4-pro"）。                                                                                                                        |
| gen_ai.usage.input_tokens        | 否    | 输入Token消耗量。需在Model Span和Root Span上同时设置，否则平台"会话分析"和"调用链分析"中的Tokens统计将显示为0。Root Span上的值应为本次请求中所有Model Span输入Token消耗的累加总和；若只有一个Model Span，则直接取该节点的值。   |
| gen_ai.usage.output_tokens       | 否    | 输出Token消耗量。需在Model Span和Root Span上同时设置，否则平台"会话分析"和"调用链分析"中的Tokens统计将显示为0。Root Span上的值应为本次请求中所有Model Span输出Token消耗的累加总和；若只有一个Model Span，则直接取该节点的值。   |
| gen_ai.usage.total_tokens        | 否    | Token总消耗量。需在Model Span和Root Span上同时设置，否则平台"会话分析"和"调用链分析"中的Tokens统计将显示为0。Root Span上的值应为本次请求中所有Model Span输入和输出Token消耗的累加总和；若只有一个Model Span，则直接取该节点的值。 |
| gen_ai.client.operation.duration | 否    | 模型调用真实耗时。                                                                                                                                           |
| traceloop.workflow.type          | 否    | 系统协议标识。对Model Span节点必须填充 "LLM" 字符串。用于在平台"调用链分析"过滤"Model span"时，精确将其检索出来。                                                                            |
| input.value                      | 是    | 当前节点的原始输入文本（对Root节点为用户提问，对Model节点为模型输入）。                                                                                                            |
| output.value                     | 是    | 当前节点的最终输出文本（对Root节点为智能体回答，对Model节点为模型生成文本）。                                                                                                         |
   
#### 查看上报数据
数据上报后，在"运营运维 \> 观测 \> 智能体列表"页面，单击对应的智能体名称，在"调用链分析"中可以看到调用链数据。
图3查看上报数据   
![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002688075958.png)
#### 示例：真实对话中的Trace（调用链）数据上报
本示例中的脚本会启动一个本地交互式终端，您可以像聊天一样在终端输入问题跟智能体对话。在对话过程中，代码会自动创建Root Span和Model Span两层Span，并在调用模型成功后，动态提取真实的提问、回复、Token消耗以及网络耗时上报给AgentArts。
**本地环境准备与依赖安装：**
请在你的电脑终端（Windows的CMD或macOS/Linux的Terminal）中执行以下命令，安装所需的Python依赖库：
```
pip install opentelemetry-api==1.41.1
pip install opentelemetry-sdk==1.41.1
pip install opentelemetry-exporter-otlp==1.41.1
pip install openai==1.14.0
pip install python-dotenv==1.0.0
```
**配置环境变量：**
安装完成后，在您的代码文件夹下创建一个名为.env的文本文件。填写华为云MaaS服务的模型API Key和AgentArts平台上获取的真实凭证：
```
# ==========================================
# 1. 智能体大模型的 API 凭证（以接入 MaaS 的 OpenAI 兼容接口为例）
# ==========================================
MODEL_NAME=deepseek-v4-pro
MODEL_URL=https://api.modelarts-maas.com/openai/v1
MODEL_API_KEY=换成在MaaS上申请的模型API_Key
# ==========================================
# 2. 华为云 AgentArts 观测接入凭证
# ==========================================
AGENT_NAME=换成智能体名称
AGENT_ID=换成智能体ID
DOMAIN_ID=换成华为云账号ID（在控制台右上角“我的凭证”中复制，不要填假数据，否则会被平台隔离过滤）
USER_ID=换成华为云IAM用户ID（在控制台右上角“我的凭证”中复制，不要填假数据，否则会被平台隔离过滤）
# Trace 上报通道配置
TRACE_ENDPOINT=换成Trace数据接入地址（示例：https://apm-access.cn-southwest-2.myhuaweicloud.com）
TRACE_TOKEN=换成Trace上报鉴权Token
```
表3环境变量说明 
| 参数                                                                                                                                                        | 说明                                                                                                                                                                                                                                                                                      |
|:---|:---|
| MODEL_NAME                                                                                                                                                | 华为云[MaaS服务](https://console.huaweicloud.com/modelarts/#/model-studio/homepage)的模型名称。取值为OpenAI兼容接口中的model参数。 图4模型名称 ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002687916102.png)                                              |
| MODEL_URL                                                                                                                                                 | 华为云MaaS服务的模型URL，采用OpenAI兼容接口。取值为：https://api.modelarts-maas.com/openai/v1。                                                                                                                                                                                                              |
| MODEL_API_KEY                                                                                                                                             | 华为云MaaS服务的模型API Key，请登录[MaaS服务](https://console.huaweicloud.com/modelarts/#/model-studio/homepage)获取。 图5模型API Key ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002717835577.png)                                               |
| TRACE_ENDPOINT TRACE_TOKEN AGENT_ID AGENT_NAME | Trace数据接入地址、Trace上报鉴权Token、智能体ID、智能体名称，从接入指南中获取。 图6获取接入地址、鉴权信息、智能体ID等信息 ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002717675717.png)                                                                                          |
| DOMAIN_ID USER_ID                                                                                                     | 华为云账号ID、华为云IAM用户ID， 请登录"[我的凭证 \> API凭证](https://console.huaweicloud.com/iam/#/mine/apiCredential)"页面获取。 图7获取domain id、user id ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002717675715.png) |
   
**编写智能体调用及数据上报脚本：**
创建一个名为agent_trace.py的代码文件，并填写如下内容：
```
import os
import time
import uuid
from openai import OpenAI
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor
# 自动加载同目录下的 .env 文件
load_dotenv()
# 读取配置参数
AGENT_ID = os.getenv("AGENT_ID")
AGENT_NAME = os.getenv("AGENT_NAME")
TRACE_ENDPOINT = os.getenv("TRACE_ENDPOINT")
TRACE_TOKEN = os.getenv("TRACE_TOKEN")
USER_ID = os.getenv("USER_ID")
# 配置标准 OTel 环境变量
os.environ["OTEL_SERVICE_NAME"] = f"AgentArts.{AGENT_ID}.default"
os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = f"Authentication={TRACE_TOKEN}"
os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = TRACE_ENDPOINT
os.environ["OTEL_EXPORTER_OTLP_TRACES_INSECURE"] = "true"
# 初始化 OTel Tracer 提供者
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
trace.set_tracer_provider(tracer_provider)
tracer = trace.get_tracer(__name__)
def chat_with_agent(user_query: str, session_id: str):
    """模拟与智能体对话，并在执行过程中自动上报 Trace 链路数据"""
    client = OpenAI(
        api_key=os.getenv("MODEL_API_KEY"),
        base_url=os.getenv("MODEL_URL")
    )
    # 初始化 Token 累加器，用于汇总本次请求中所有 Model Span 的 Token 消耗
    total_input_tokens = 0
    total_output_tokens = 0
    total_tokens = 0
    # 1. 启动最外层 Root Span，记录整个交互会话的生命周期
    with tracer.start_as_current_span("agent_dialogue_session") as root_span:
        root_span.set_attribute("gen_ai.span.type", "root")
        root_span.set_attribute("gen_ai.resource.id", AGENT_ID)
        root_span.set_attribute("gen_ai.agent.name", AGENT_NAME)
        root_span.set_attribute("gen_ai.resource.type", "agent")
        root_span.set_attribute("gen_ai.call.type", "API")
        root_span.set_attribute("gen_ai.conversation.id", session_id)
        root_span.set_attribute("gen_ai.user.id", USER_ID)
        root_span.set_attribute("input.value", user_query)        # 记录Root节点的原始输入
        # 2. 启动大模型子 Span，专门记录 LLM 推理过程
        with tracer.start_as_current_span("llm_inference_call") as model_span:
            # 作用说明：标识当前节点类型为模型调用节点，用于控制台解析
            model_span.set_attribute("gen_ai.span.type", "LLM")
            # 作用说明：模型节点上也必须携带资源 ID 与类型，防止 URN 路径拼接错乱
            model_span.set_attribute("gen_ai.resource.id", AGENT_ID)
            model_span.set_attribute("gen_ai.resource.type", "agent")
            model_span.set_attribute("gen_ai.agent.name", AGENT_NAME)
            model_span.set_attribute("gen_ai.conversation.id", session_id)
            model_span.set_attribute("gen_ai.user.id", USER_ID)
            model_span.set_attribute("traceloop.workflow.type", "LLM")
            # 作用说明：记录实际请求调用的模型名称
            model_span.set_attribute("gen_ai.request.model", os.getenv("MODEL_NAME"))
            # 记录大模型 API 网络调用开始时间
            start_time = time.time()
            # 发起真实的大模型对话调用
            completion = client.chat.completions.create(
                model=os.getenv("MODEL_NAME"),
                messages=[{"role": "user", "content": user_query}]
            )
            # 计算大模型请求真实时延
            duration = time.time() - start_time
            # 动态捕获模型返回的真实响应数据与 Token 消耗
            usage = completion.usage
            response_content = completion.choices[0].message.content
            # 3. 将真实捕获的运行时参数动态注入 Model Span 属性中
            model_span.set_attribute("gen_ai.usage.input_tokens", usage.prompt_tokens)      # 作用说明：记录输入 Token
            model_span.set_attribute("gen_ai.usage.output_tokens", usage.completion_tokens) # 作用说明：记录输出 Token
            model_span.set_attribute("gen_ai.usage.total_tokens", usage.total_tokens)       # 作用说明：记录总 Token 消耗
            model_span.set_attribute("gen_ai.client.operation.duration", str(duration))     # 作用说明：记录大模型调用耗时
            model_span.set_attribute("input.value", user_query)                             # 作用说明：记录真实提问
            model_span.set_attribute("output.value", response_content)                      # 作用说明：记录模型真实回复
            # 将本次 Model Span 的 Token 消耗累加至总计
            total_input_tokens += usage.prompt_tokens
            total_output_tokens += usage.completion_tokens
            total_tokens += usage.total_tokens
        # 在 Root Span 上记录最终输出答案，保证调用链树根节点的输入/输出展示完整
        root_span.set_attribute("output.value", response_content)
        # 将所有 Model Span 的 Token 消耗累加后统一写入 Root Span
        # 若请求中存在多个 Model Span，Root Span 上的值为所有节点的 Token 消耗总和
        root_span.set_attribute("gen_ai.usage.input_tokens", total_input_tokens)
        root_span.set_attribute("gen_ai.usage.output_tokens", total_output_tokens)
        root_span.set_attribute("gen_ai.usage.total_tokens", total_tokens)
        return response_content
if __name__ == "__main__":
    # 动态生成本轮对话的唯一会话 ID，保证在平台“会话分析”中能聚合在一起
    current_session_id = f"sess-{uuid.uuid4().hex[:12]}"
    print(f"==================================================")
    print(f" 智能体运行时已启动！会话 ID: {current_session_id}")
    print(f"==================================================")
    while True:
        user_input = input("\nUser: ")
        if user_input.strip().lower() in ["exit", "quit", "q"]:
            print("正在退出并刷新数据上报...")
            break
        print("智能体正在思考并上报调用链...")
        reply = chat_with_agent(user_input, current_session_id)
        print(f"Agent: {reply}")
    # 刷新 Trace 缓冲并一键上传
    tracer_provider.shutdown()
    print("数据刷新上报完成！")
```
**执行测试，验证上报数据：**
在您的代码文件夹下，打开终端并运行：
```
python agent_trace.py
```
运行后，可与智能体进行会话，可通过Ctrl+C命令退出会话。退出后，登录AgentArts平台，在"运营运维 \> 观测 \> 智能体列表"页面，单击对应的智能体名称。在"调用链分析"中可以看到调用链数据。
图8运行示例   
![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002717675713.png)
图9数据上报示例   
![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002688075958.png)
#### 常见问题
- **运行代码后，观测页面看不到Trace数据怎么办？**
  请按以下顺序排查：
  1. **检查接入参数**：确认agent_id、trace_endpoint、trace_token是否与数据上报准备中获取的信息一致。
  
  2. **检查服务名称格式**：确认OTEL_SERVICE_NAME遵循AgentArts.{智能体ID}.default格式。
  
  3. **检查网络连通性**：确认网络是否能连通Trace接入地址。
  
  4. **等待数据同步**：数据上报后通常需要几分钟才能在观测页面展示，请稍后再查看。
   
- **为什么在平台"调用链分析"中，单击模型节点的"指标"** **页签时报错，** **或者F12抓包发现后端API路径中出现了双斜杠（如** **/agent//span/...）**
  原因：出现该报错是由于您只在最外层的根节点（Root Span）上设置了智能体URN关联属性，而**漏掉了在模型节点（Model Span）上设置gen_ai.resource.id和gen_ai.resource.type属性**。
  在AgentArts观测功能中，当您单击不同的节点查看调用链的Span详情时，页面会实时读取该节点上的属性来拼接查询API路径。如果模型节点缺少了这两个属性，路径就会因为缺省而拼错（出现双斜杠），导致页面请求报错、数据无法展示。
  解决方案：在您的代码中，不仅要给最外层的Root Span设参，**每一个内部创建的子Span（如大模型调用）也必须强制上报这两个对齐标签** ：
  ```
  with tracer.start_as_current_span("test_llm_call") as model_span:
      # 必须给子节点也绑定智能体ID和资源类型，保证页面路由拼接正常
      model_span.set_attribute("gen_ai.resource.id", AGENT_ID)
      model_span.set_attribute("gen_ai.resource.type", "agent")
      model_span.set_attribute("gen_ai.span.type", "LLM")
      # ... 后续属性
  ```
  图10报错样例
  ![](https://support.huaweicloud.com/ops-agentarts/zh-cn_image_0000002687916104.png)
  
- **为什么在平台"会话分析"或"调用链分析"中，Tokens列显示为0？**
  原因：Token相关字段（gen_ai.usage.input_tokens、gen_ai.usage.output_tokens、gen_ai.usage.total_tokens）仅在Model Span上设置，而未在Root Span上同步设置。平台在统计会话/Trace维度的Token消耗时，读取的是Root Span上的Token字段，若Root Span缺少这些字段，则统计结果将显示为0。
  解决方案：需在Root Span关闭前，将本次请求中所有Model Span的Token消耗累加后，统一写入Root Span。若请求中只有一个Model Span，直接取该节点的值；若存在多个Model Span，则需逐一累加后再写入：
  ```
  # 在 Root Span 外层初始化 Token 累加器
  total_input_tokens = 0
  total_output_tokens = 0
  total_tokens = 0
  # 每个 Model Span 结束后累加
  total_input_tokens += usage.prompt_tokens
  total_output_tokens += usage.completion_tokens
  total_tokens += usage.total_tokens
  # Root Span 关闭前，将累加结果统一写入
  root_span.set_attribute("gen_ai.usage.input_tokens", total_input_tokens)
  root_span.set_attribute("gen_ai.usage.output_tokens", total_output_tokens)
  root_span.set_attribute("gen_ai.usage.total_tokens", total_tokens)
  ```
  
- **Trace数据上报失败：Transient error StatusCode.UNAVAILABLE encountered while exporting...**
  原因：替换**TRACE_ENDPOINT** 环境变量时，接入地址缺少**https://**协议前缀，系统无法识别目标服务地址格式，导致连接失败。
  解决方案：确保TRACE_ENDPOINT配置值包含完整协议前缀，例如TRACE_ENDPOINT=https://apm-access.cn-southwest-2.myhuaweicloud.com，修改后重新上报。
  
 
