Agent 慢在哪里:用 OpenTelemetry 追踪大模型多轮推理与工具调用
过去,一次大模型调用可以用一行日志说明:调用了什么模型、花了多久、返回了什么。但当模型开始承担 Agent 角色,过程就不再是一次线性请求,而是多轮推理、工具调用、外部服务依赖的连续执行。日志仍然重要,却很难完整表达“哪一步在做什么、哪一步耗时最长、哪个工具由哪次决策触发”。OpenTelemetry 提供了一种更适合 Agent 的记录方式:把一次执行整理成带层级、因果关系和耗时的 Trace / Span 树,让开发团队能够定位问题出在模型、工具,还是某个下游接口。
单次调用靠日志,Agent 需要执行树
单次 LLM 调用的结构相对简单:用户提问,系统调用模型,模型返回答案。在这种场景下,日志可以记录“发生了什么”。但 Agent 的执行过程更接近树状拓扑:一轮推理可能触发多个工具,工具返回结果后,模型又继续下一轮推理。此时,扁平日志难以承载层级关系、时间分布和因果依赖。
OpenTelemetry 的核心思路,是用一套标准数据模型描述运行过程。它有点像 HTTP 协议:HTTP 定义请求和响应如何组织与传输,OpenTelemetry 定义运行数据如何组织与传输。其最小记录单元是 Span。一个 Span 可以包含操作名称、trace_id、span_id、parent_id、开始时间、结束时间、属性、事件、状态和类型等信息。
在这棵树中,trace_id 用来标识一次完整调用,把分散的 Span 归拢到同一棵树下;parent_id 用来标识父子关系,是后端拼接执行树的关键。没有父节点的 Span 被视为根节点。同一进程内,新的 Span 可以自动挂到当前 Span 下;跨进程调用则需要传递上下文。通常,trace_id 和 span_id 会放在 HTTP 请求头中,由 SDK 自动携带和读取。如果缺少这一传递,Agent 和外部服务的记录就会变成两棵互不相关的树。
Trace、Metric、日志分工协作
OpenTelemetry 并不只用于追踪。它将运行数据划分为不同信号,并通过 trace_id 建立关联,形成从粗到细的下钻路径。Trace 用于还原一次完整执行过程,Metric 用于观察聚合趋势,日志用于记录具体事件。三者并不是互相替代,而是共同构成排障链路。
成本差异也很直接。100 万个请求不可能每个都完整保存一棵执行树;Metric 只保存聚合数字,100 万个请求也可以只沉淀为几个数字。日志则可以继续记录详细文本,并通过 trace_id 与 Trace 关联。一条带 trace_id 的日志,可以把散落文本变成执行树上的锚点,让开发者从日志直接跳到对应的 Trace。
文中给出的排障路径可以说明这种协作方式:Metric 先发现 P99 从 80 ms 涨到 210 ms;Trace 进一步定位到 turn -1 中的 tool:query_order 被调了 3 次,每次都 1.5 s+;Log 再给出根因:订单服务接口超时,导致模型被迫反复重试。这个例子说明,Agent 变慢不一定是模型本身慢,也可能是工具链路中的依赖服务超时。
在工程部署上,OpenTelemetry 将 API 与 SDK 分离。库可以只依赖 API;应用安装 SDK 后,埋点生效;如果没有安装,API 调用变成空操作,不会报错。这样,底层库可以低成本内置埋点。生产环境还常使用 OTLP 协议和 Collector。Collector 是独立进程,负责接收、处理、路由和缓冲。调整采样率,例如从 10% 调到 5%,可以修改 Collector 配置,而不必重新部署 Agent。
写对 Span 和属性,才能分析 LLM 过程
对 Agent 来说,Trace 决定能否还原过程,Attributes 决定能否分析过程。Span 本身主要记录操作步骤、时间和父子关系;模型名称、token 用量、轮次、输入输出摘要、失败原因等信息,需要通过 attributes 补充。
Span 的 name 应保持低基数,适合表达操作类别,不适合承载过多业务含义。如果要分析 token 增长曲线,turn.index 和 gen_ai.usage.input_tokens 必须同时存在,并且挂在正确的 Span 上;缺少一个,相关数据就可能变成孤立数字,无法排序分析。字段命名也需要遵循行业约定。例如,应使用 gen_ai.request.model 这类语义约定字段,而不是随意使用 model_name,否则后端面板、成本计算和 LLM 视图可能无法正常工作。
- 有独立耗时的步骤适合建立 Span,如意图识别、query 改写、槽位抽取。
- 步骤产出适合写入 attribute,如识别出的意图、填充的槽位。
- 业务自定义字段可以加自己的前缀,例如 cs.intent、cs.prompt_version,避免与标准字段冲突。
以一个客服 Agent 为例,一次会话可以作为根 Span;前置的意图识别、槽位填充分别建立 Span;每一轮生成、模型调用和工具调用继续作为子 Span。模型 Span 上可以记录 gen_ai.request.model、gen_ai.usage.input_tokens、首 token 时间、成本和截断后的输出内容;工具 Span 上可以记录工具名称和执行状态。这样生成的不是一堆平铺日志,而是一张能看出层级、耗时和依赖关系的执行图。
生产环境的新基础
当 Agent 开始承担客服、订单查询等实际任务,系统问题就不再只是模型回答是否准确,还包括整条执行链路是否可解释、可优化。OpenTelemetry 的意义,是把 Agent 的多轮推理、工具调用和外部依赖纳入统一的数据结构,使执行过程可以被查询、关联和分析。
它不会取代日志。日志回答“发生了什么”,Trace 回答“为什么慢、谁拖累了谁”,Metric 提供聚合层面的异常发现能力。对开发团队而言,真正的门槛在于埋点是否规范:哪些步骤需要 Span,哪些信息应作为属性,字段是否符合语义约定,跨服务上下文是否完整传递。做好这些,Agent 才能从难以定位走向可追踪、可排障、可调优。
原创文章,作者:点点,如若转载,请注明出处:https://www.dian8dian.com/agent-man-zai-na-li-yong-opentelemetry-zhui-zong-da-mo-xing