智能体可观测与调用链路追踪落地

日期:2026-07-22

一、项目背景

我们当时接手的是一批已经跑在生产环境的多智能体系统,链路长、工具调用多,单个会话背后往往串起检索、生成、外部 API 十余类工具。某个 Agent 排障时,运维只看到最终返回"任务失败",但到底失败在哪一步、调了哪个工具、花了多久、消耗多少 token,全靠猜。这个项目里,我们采用自研的 AI 网关(接入层 Gateway-In 与可观测 Observability 层)作为统一埋点底座,目标是让每一个 Agent 调用和工具调用都能被 trace_id 串联、被回放、被下钻。在此之前,日志分散在模型服务、工具服务和业务服务三套体系里,格式各异、时区不一,跨服务排查一次要拉三个人,平均耗时难以忍受。我们立项的第一原则就是:先把可观测做厚,再谈任何性能优化。

二、落地场景

落地场景主要有四块。第一是 trace 注入,每个进入 AI 网关的请求在 Gateway-In 拿到全局 trace_id,并向下游模型服务与工具调用透传,做到一次会话一个身份,哪怕中途换模型、换工具也不丢上下文。第二是统一采集,每个 Agent 节点和工具调用的输入/输出做脱敏摘要、耗时、token 数统一上报到可观测层,不再各写各的日志格式,采集协议统一走 OpenTelemetry,存储落到同一套后端。第三是调用链串联与回放,把一次多轮对话里几十次模型调用和工具调用拼成完整链路,支持按 trace_id 回放任意历史会话,复盘线上问题不必再找用户要截图。第四是瓶颈定位,长链路里哪一步拖慢整体、哪个工具是长尾,用可观测层的分位线视图直接标红,排障从翻日志变成看图,新人也能在十分钟内定位异常节点。

三、关键技术挑战与解决思路

挑战一:跨 Agent / 工具 trace 串联。智能体的调用不是简单树形,而是带循环、带分支的有向图,比如 Agent 调工具、工具又触发子 Agent。最初我们用 parent_span_id 做父子链,遇到 Agent 调 Agent 再回调的场景就断了。解决思路是引入「逻辑会话 id + 节点序号」双标识,trace_id 代表一次用户会话,span 内记录 node_seq 和 prev_node,重放时按图重建而非按树遍历。OpenTelemetry 的 span 属性里我们额外塞了 agent_name、tool_name、model_id 三个业务标签,让链路天然带业务语义。

挑战二:输入输出脱敏与留痕。trace 里必须留痕才能回放,但 prompt 可能含客户姓名、电话、地址等敏感字段。我们采用网关层的统一脱敏算子,在 Gateway-In 出口做模板替换:正则命中手机号、身份证、邮箱后打成 [PHONE]、[ID]、[EMAIL] 占位符,原始值不落库。这里踩的坑是脱敏放在采样之后,导致部分被采样的链路丢了留痕、无法复现,后来调整为"先脱敏再采样",保证任何被采样的 trace 都有可回放内容,原始敏感值永不进存储。

挑战三:长链路耗时与瓶颈定位。一个复杂 Agent 任务可能有 40 次以上模型调用,总耗时由多个环节叠加。我们把每次调用的耗时拆成 queue_time(网关排队)、infer_time(模型推理)、tool_time(工具执行)三段分别打点。压测时发现某向量检索工具在高峰期 tool_time 抖动到约 8 秒,通过 P99 分位线对比快速定位是底座向量数据库层连接池打满,而非模型本身慢,从而把优化精力从模型侧转到连接池扩容上,避免误判。

挑战四:回放与根因下钻。光有链路图还不够,排障要能点开任意一个 span 看脱敏输入输出来复现。我们在可观测层做 span 详情页,点击展开即可看到该节点的脱敏 prompt、返回摘要、token 明细,甚至能把同一 trace_id 在测试环境原样重放一遍验证修复。根因下钻上,我们把"失败 span 向上聚合到首个异常父节点"作为默认视图,避免运维在一堆成功 span 里翻找,一眼就能看到是哪一层最先报错。我们还给每个异常类型打了错误码标签,同类故障第二次出现时能直接关联到历史处理记录,平均定位时间进一步缩短。

四、效果数据

上线后我们统计了三个月脱敏示意数据,可观测能力带来的收益清晰:

指标改造前改造后说明
排障耗时约 45 分钟/次降至约 8 分钟/次trace 串联替代日志翻找
调用链覆盖率约 40%提升至约 95%网关统一埋点全量接入
长尾链路占比约 18%降至约 6%P99 瓶颈定位后优化
token 成本归因不可见可归因至部门/应用计量层 Metering 打通

以上为脱敏示意值,用于说明能力建设方向,非审计级数字,实际收益取决于链路复杂度与调用量。

五、可复用经验总结

两条核心经验。第一,可观测先于优化。很多团队一上来就调模型、加缓存,但连"慢在哪"都说不清,优化是盲人摸象。我们当时先把 trace 全量接上,性能瓶颈和长尾工具自己就浮出来了,后续每轮优化都有数据对照,不会再出现"改了半天不知道有没有用"的尴尬。第二,trace 串联比日志堆叠更值钱。日志堆得再多,跨 Agent 一断就废;把 trace_id 当成血液在网关层统一管理,回放和下钻才真正可落地。这套思路在我们采用的 AI 网关底座上复用成本很低,建议任何多智能体系统从第一天就把可观测接上,而不是等线上出问题再补。顺便提一句,计量层 Metering 的 token 数据打通后,成本也能按部门归因,这反过来又倒逼各业务线主动优化自己的长尾链路,形成正向循环。

案例片段(已脱敏): trace 注入与采样配置(简化):yaml observability:  trace:    propagate_header: "x-trace-id"    inject_at: gateway_in    span_tags: [agent_name, tool_name, model_id]    sampling:      strategy: "parent_based"      rate: 0.2      mask_before_sample: true   # 先脱敏再采样  mask:    rules:      - pattern: "1[3-9]\\d{9}"        replace: "[PHONE]"      - pattern: "\\d{17}[\\dxX]"        replace: "[ID]"      - pattern: "[\\w.]+@[^\\s]+"        replace: "[EMAIL]"