Skip to main content

01 - Agent 的 Trace 长什么样

需要了解分布式追踪的基本概念(trace 是一次请求的完整记录,span 是其中的一段操作)。不需要用过任何具体的可观测平台。

本篇回答:Agent 的一次执行应该被拆成哪些 span、有哪些指标是传统监控里没有的、最少埋哪几个点就能用。

本篇会用到的词

意思
gen_ai.operation.nameOpenTelemetry 用来区分 span 类型的那个属性。它的取值(chat / execute_tool / invoke_agent 等)就是下面要讲的十种操作类型
根 span一棵 trace 最外层的那个 span,代表「一次完整的用户请求」。它的耗时等于用户实际等待的时间
TTFTTime To First Token,首字延迟 —— 从发出请求到吐出第一个 token 的时间,这段时间用户屏幕是空的
TPOTTime Per Output Token,也叫 ITL —— 吐出后续每个 token 之间的间隔,决定「吐字」快不快
prefill / decode模型推理的两个阶段:prefill 一次性处理完整个输入(决定 TTFT),decode 之后逐个吐 token(决定 TPOT)
PIIPersonally Identifiable Information,个人可识别信息。姓名、手机号、身份证号这类,落进 trace 之前要先脱敏

一、一次执行展开成一棵树

用户输入:"帮我查一下我们上周的销售数据,做个总结。"

用户问「帮我查一下上周的销售数据,做个总结」—— 这次执行在 trace 里长这样0s5s10s15sinvoke_agent整棵树的根 · 18.4schat1.2s · 850 token 决定要查数据库execute_tool3.1s query_databasechat1.5s · 2,400 token 决定再查上周做对比execute_tool2.8s query_databaseretrieval0.6s 检索历史报告模板chat9.2s · 5,100 token 生成最终总结传统监控只会记下一条「POST /chat 耗时 18.4s」。这张图能立刻回答:一半的时间花在最后那次生成上,和数据库没关系。
注意六个子 span 是根 span 的孩子,不是彼此的下一步。画成瀑布而不是链条,是因为真实 trace 里它们可能并行 —— 而「有没有并行」本身就是一个要看的结论。

一次用户请求产生六个 span:三次模型调用、两次工具调用、一次检索。

1.1 与传统监控的差别

传统 APMAgent trace
记录内容POST /chat 耗时 18.4s六个 span 的树结构
能回答慢在哪一跳
调用次数代码写死,固定每次执行都可能不同
成本与调用次数无关与 token 用量直接相关

上图中最后一个 span 占了 18.4 秒里的 9.2 秒。没有这棵树,"慢"这个结论无法再往下分解一层。

二、十种操作类型

GenAI 语义约定用 gen_ai.operation.name 区分 span 类型,共十个取值:

取值含义产生时机
create_agent创建 Agent初始化
invoke_agent调用 Agent树根,或子 Agent 调用
invoke_workflow调用工作流编排层
execute_tool执行工具每次工具调用
retrieval检索RAG 召回环节
plan规划Plan-and-Execute 类范式
chat对话补全每次模型调用
text_completion文本补全旧式补全接口
generate_content生成内容多模态
embeddings向量化计算 embedding

2.1 这份清单反映的建模视角

invoke_agentplanexecute_tool 这三个取值的存在,说明规范的心智模型是 Agent 的生命周期,而不是 LLM API 的调用。

对比 2024 年的版本 —— 当时只有 chatembeddings,因为那时的典型用法只是调用模型。取值集合的扩张,直接记录了这两年应用形态的变化。

三、九个指标

比 span 更适合做告警的是指标。GenAI 约定下的 gen_ai.* 指标:

# 客户端侧:单次模型调用的性能与用量
gen_ai.client.operation.duration # 整体耗时
gen_ai.client.operation.time_to_first_chunk # 首字延迟,即 TTFT
gen_ai.client.operation.time_per_output_chunk # 每 token 间隔,即 TPOT
gen_ai.client.token.usage # token 用量

# Agent 侧:一次 Agent 执行的行为特征
gen_ai.invoke_agent.duration # Agent 整体耗时
gen_ai.invoke_agent.inference_calls # 本次执行调用了几次模型
gen_ai.invoke_agent.tool_calls # 本次执行调用了几个工具
gen_ai.invoke_workflow.duration # 工作流耗时
gen_ai.execute_tool.duration # 单个工具耗时

3.1 耗时被拆成三个独立指标

operation.durationtime_to_first_chunktime_per_output_chunk —— 规范用三个指标表达"快慢",而不是一个。

原因在于三者的关系:

规范用三个指标表达「快慢」,因为它们的优化方向不同总耗时operation.durationTTFT · 首字延迟time_to_first_chunkTPOT · 每 token 间隔time_per_output_chunk×输出长度受排队、prefill、缓存命中率影响受批次大小、decode 吞吐影响只记总耗时,等于把两个成因完全不同的量加在一起看 —— 数字变大了,你却不知道该去调队列还是调批次。
这也是为什么输出长度不同的两次请求不能直接比总耗时:一次 50 token 的回答和一次 5,000 token 的回答,即使 TTFT 和 TPOT 完全一样,总耗时也会差两个数量级。

只记总耗时,则输出长度不同的两次请求无法比较 —— 一次输出 100 token 用 3 秒和一次输出 2000 token 用 20 秒,后者其实更快。

这与 Agent 网关 · Token 速率与 QoS 从工程实践得出的结论一致:time_to_first_chunk 即 TTFT,time_per_output_chunk 即 TPOT。

3.2 两个传统监控里没有的指标

gen_ai.invoke_agent.inference_calls
gen_ai.invoke_agent.tool_calls

传统服务的下游调用次数由代码写死,因此"调了几次"不是一个需要监控的量。Agent 不同:同一个问题,模型今天可能两步解决,明天可能绕十步。

这两个指标是发现"模型开始绕远路"的唯一手段

观察到的现象可能原因
inference_calls 的 P99 翻倍换了模型版本,或改了提示词导致模型反复试探
tool_calls 均值上升而 inference_calls 不变工具返回质量下降,模型需要多次调用才能拿到可用结果
两者都上升、成本上升、成功率不变净损失,应当告警

成本失控通常不是单价上涨,而是步数增加。 步数只有这两个指标能观测到。

四、MCP 使用同一套词汇

规范仓库中有一份 docs/gen-ai/mcp.md(1,332 行):MCP 的工具调用与发起它的 Agent 共用同一套 trace 词汇。

这意味着一棵 trace 树可以同时覆盖 Agent 编排层和 MCP 工具层,不需要在两套体系间做转换 —— 对 Agent 网关 · MCP 网关描述的工具聚合场景尤其重要,因为网关本身就处在两层之间。

五、规范尚未稳定

截至 2026-08,没有任何一个 gen_ai.* 属性、span 或指标被标记为 Stable。

规范中标记为稳定的 128 个属性,全部是从核心语义约定继承的通用项(server.addresserror.type 这类),与 GenAI 无关。

此外它在 2026 年发生过一次仓库迁移:v1.42.0(2026-06-12)将全部 gen_ai.* 从主仓库拆出,成立独立的 semantic-conventions-genai 仓库(创建于 2026-05-05)。

5.1 应对方式

不稳定不等于不能用,但需要隔离变更影响:

# ❌ 直接在业务代码里写属性名
# 规范一改,所有调用点都要跟着改
span.set_attribute("gen_ai.usage.input_tokens", n)

# ✅ 收敛到一个薄封装层
# 规范变更时只改这一处;也便于同时输出两套约定(见 02 篇)
class AgentSpan:
"""对埋点属性的唯一出口。业务代码不直接接触属性名。"""

def set_input_tokens(self, n: int) -> None:
# 规范未稳定,属性名可能变化 —— 变更只影响这一行
self._span.set_attribute("gen_ai.usage.input_tokens", n)

具体的选型策略见 02 篇

六、最小可用埋点清单

从零开始时,下面这组覆盖大部分排查与计费需求:

优先级埋什么解决什么问题
1invoke_agent 根 span,含 inference_calls / tool_calls发现步数异常
2每次 chat span,含 token 用量成本归因的原料
3time_to_first_chunktime_per_output_chunk回答"为什么用户说慢"
4每次 execute_tool span,含工具名与耗时定位工具侧瓶颈
5租户 / 团队标识(在网关侧注入,见 03 篇账单可拆解

前四项在应用侧埋,第五项必须在网关侧注入 —— 应用侧传入的身份标识可被伪造,不能作为计费依据。

下一篇02 - 两套语义约定

← 回到 专题索引  ·  Agent Infra 板块总览