[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fF-Biu8HkeSSDnBBRKxftdxPhht-s8PANLOeiMl5TVKE":3},{"item":4,"related":44},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":35,"sourceName":36,"sourceUrl":36,"status":37,"seoTitle":36,"seoDescription":36,"canonicalUrl":36,"isFeatured":38,"sno":39,"sortOrder":40,"publishedAt":41,"updatedAt":42,"createdAt":43},"525e9d4d-50ba-48c4-be55-4810590d714b","article","AI Agent 可观测性：如何知道它到底在哪一步出错","genai-agent-observability-with-opentelemetry","Agent 的一次回答可能经过多次模型调用、检索、工具执行和重试。本文从日志、指标与 Trace 的分工讲起，介绍 OpenTelemetry 的 GenAI 语义约定、失败排查方法、敏感内容采集边界，以及如何把 AI 运行变成可解释的执行链路。","## 当 Agent 答错时，先别急着换模型\n\n一个 Agent 花了 45 秒才回答一个简单问题，原因可能完全不同：模型本身慢、检索服务慢、工具重试了三次、上下文被塞得太长，或者多个步骤串行执行导致整体延迟被放大。\n\n如果系统只有一条“请求失败”日志，你无法知道问题发生在哪里。AI 应用的可观测性，不能只记录最终答案，而要记录一次 Agent 运行中发生过的模型调用、工具调用、检索、重试和输出。\n\n![OpenTelemetry 标志](https:\u002F\u002Fopentelemetry.io\u002Fimg\u002Flogos\u002Fopentelemetry-horizontal-color.png)\n\nOpenTelemetry（简称 OTel）正在为 GenAI 场景补充语义约定（Semantic Conventions），把“模型名称”“输入输出 Token”“工具调用”和“Agent 工作流”等信息用统一字段记录。OpenTelemetry 的[官方实践文章](https:\u002F\u002Fopentelemetry.io\u002Fblog\u002F2026\u002Fgenai-observability\u002F)展示了如何把一次 LLM 调用放进普通服务的 Trace 中。\n\n## 日志、指标和 Trace 各自回答什么\n\n三种信号不是互相替代的：\n\n- **日志**回答“某一刻发生了什么”，适合记录错误详情和业务事件。\n- **指标**回答“整体趋势怎样”，适合看延迟、Token 消耗、错误率和调用量。\n- **Trace**回答“一次请求经过了哪些步骤”，适合定位 Agent 的链路瓶颈。\n\n对传统 Web 请求来说，一条 Trace 可能是“网关 → API → 数据库”。对 Agent 来说，它更像：\n\n```text\n用户请求\n  └─ Agent 工作流\n      ├─ LLM：判断是否需要检索\n      ├─ Retriever：查询知识库\n      ├─ LLM：生成工具参数\n      ├─ Tool：调用订单 API\n      ├─ LLM：整理结果\n      └─ 最终回答\n```\n\n没有这条树状链路，工程师只能靠猜。\n\n## GenAI 语义约定记录了什么\n\n具体字段仍处于演进中，但常见信息包括：\n\n- 请求使用的模型与服务商。\n- 输入 Token、输出 Token 和调用持续时间。\n- 模型停止原因，例如正常结束或发起工具调用。\n- Agent、Workflow、Session 和工具的标识。\n- 检索、工具执行和模型调用之间的父子关系。\n\n例如，一次慢请求可以被拆成：模型调用 1.2 秒，向量检索 0.4 秒，订单 API 8 秒，模型总结 1.1 秒。你不必猜“是不是模型变慢了”，因为 Trace 会直接显示大部分时间花在订单 API 上。\n\n```mermaid\nflowchart TD\n    Q[\"用户请求\"] --> T[\"Agent Trace\"]\n    T --> L1[\"LLM：理解意图\"]\n    L1 --> R[\"检索或工具调用\"]\n    R --> L2[\"LLM：生成下一步\"]\n    L2 --> C{\"成功完成?\"}\n    C -->|否| E[\"记录错误与重试原因\"]\n    C -->|是| M[\"记录结果、Token 与耗时\"]\n    E --> F[\"返回或进入受限重试\"]\n    M --> F\n```\n\n## 一次失败应该怎样排查\n\n假设用户投诉：“客服 Agent 这次答非所问。”可以按下面顺序看 Trace：\n\n### 先看输入是否正确\n\n检查系统指令、用户问题、历史摘要和检索片段是否真的进入了模型上下文。很多所谓“模型幻觉”，根源是检索为空、字段被截断，或者把旧版本政策混进了当前请求。\n\n### 再看工具是否返回正确\n\n工具调用成功不代表业务结果正确。HTTP 状态码是 200，不等于订单查询返回了正确用户的数据。Trace 里应记录工具名称、版本、参数摘要、耗时和错误类型；对于敏感值，只记录哈希、字段名或脱敏后的摘要。\n\n### 最后看模型是否正确使用上下文\n\n如果上下文里有正确资料，模型仍然选错工具或忽略约束，才更像提示设计、模型能力或路由策略的问题。此时可以把同一个 Trace 送进离线评测，比较不同模型、提示模板和工具描述。\n\n## 一条 Agent Trace 应该长什么样\n\n不要把所有信息都塞到一个巨大的 Span 里。更容易排查的结构，是为一次用户任务建立根 Span，再按执行层级嵌套：\n\n```text\nagent.run\n├── retrieval.query\n├── gen_ai.chat\n│   └── tool.call\n├── tool.execute\n└── gen_ai.chat\n```\n\n每个 Span 记录“这个步骤做了什么”和“花了多少时间”，而不是默认保存全部内容。模型 Span 可以记录模型名、响应状态、输入输出 Token 和结束原因；检索 Span 可以记录索引名、Top-K、过滤条件摘要和命中文档 ID；工具 Span 可以记录工具版本、参数校验结果、外部响应码和重试次数。\n\n把字段分成低基数和高基数也很重要。模型名、操作类型和错误类别适合做指标标签；完整用户问题、订单号和工具参数不适合直接作为指标标签，否则时间序列数量会爆炸。高基数信息应该放在受控的日志或事件里，并设置访问权限。\n\n## 从代码到 Trace：先包住边界，再追求完整\n\n第一版 instrumentation 不需要覆盖整个 Agent 框架。可以先包住三个边界：\n\n```python\nwith tracer.start_as_current_span(\"agent.run\") as run:\n    result = call_model(messages)\n    record_model_usage(run, result.usage)\n\n    with tracer.start_as_current_span(\"tool.execute\") as tool_span:\n        tool_span.set_attribute(\"tool.name\", tool_name)\n        tool_result = execute_tool(args)\n\n    final = call_model(messages + [tool_result])\n```\n\n关键不是这段代码本身，而是让每次模型调用和工具调用都继承同一个 Trace 上下文。否则你会得到一堆互相孤立的请求记录，仍然无法回答“这次回答经过了哪个工具”。\n\n接下来再补齐重试、检索和人工接管。每加一类信号，都应该配一个排查问题：它能不能帮助定位慢、错、贵或不安全？如果不能，就不要为了“字段齐全”增加采集复杂度。\n\n## 内容采集是双刃剑\n\n记录完整 Prompt 和模型输出，对调试非常有帮助；但这些内容也可能包含个人信息、商业机密、访问令牌和用户输入的恶意指令。\n\nOpenTelemetry 的 GenAI 指南特别强调，默认可以只记录模型名、Token 和耗时，只有明确开启内容采集时才保存完整消息、工具参数和工具结果。生产环境建议分层：\n\n- 默认记录元数据，不记录原文。\n- 调试租户或抽样请求才采集内容。\n- 对邮箱、手机号、订单号和密钥做脱敏。\n- 限制 Trace 的保存时间和访问角色。\n- 严禁把完整 Prompt 直接打进普通应用日志。\n\n可观测性本身也必须经过威胁建模，否则为了排查 AI 问题，反而建立了一个更大的数据泄露面。\n\n一种实用的内容策略是“默认摘要、按需取原文”：Trace 默认只保存消息长度、哈希、敏感字段数量和版本号；当用户授权调试时，再从加密的短期存储中关联原文。这样既能判断“上下文是否变长、是否发生了重试”，也不会让每个监控面板都暴露完整对话。\n\n如果确实需要记录工具结果，应优先保存经过裁剪的结构化摘要。例如只保存 HTTP 状态、返回字段集合和结果条数，不保存完整客户资料。对于安全事件，还可以保存触发规则和脱敏后的攻击片段，让安全团队能复盘，不让普通业务角色看到原始隐私数据。\n\n## 指标应该如何设计\n\n至少需要四类指标：\n\n1. **延迟**：首 Token 延迟、完整响应延迟、工具调用延迟。\n2. **消耗**：输入输出 Token、缓存命中、模型调用次数。\n3. **可靠性**：超时、解析失败、工具失败、重试次数和人工接管率。\n4. **质量代理指标**：引用覆盖率、结构化输出校验率、拒答率和离线评测分数。\n\n不要把“Token 越少越好”当成唯一目标。压缩上下文可能降低成本，却也可能删掉回答所需的证据。正确的做法是同时看质量、延迟和成本，按用户任务分组，而不是只看全局平均数。\n\n这些指标还需要和“请求类型”绑定。客服问答、代码生成、文档摘要和事务执行的正常范围不同，混在一起看会把异常平均掉。建议至少按 Agent、任务类型、模型版本和租户分组，并同时看 P50 与 P95。平均延迟正常，不代表最慢的那 5% 用户没有一直卡住。\n\n成本归因也不要只用一个总金额。可以把一次任务的成本拆成模型成本、检索成本、工具调用成本和重试成本。这样当账单上升时，你才能判断应该缩短上下文、调整模型路由、修复工具超时，还是限制某一类 Agent 的最大步数。\n\n## 与传统 OTel 的关系\n\nGenAI 语义约定不是一套新的监控后端，也不是要求你换掉现有的 Jaeger、Prometheus 或 OTLP Collector。它更像是一组让不同厂商“说同一种字段语言”的约定。\n\n因此，落地可以从现有链路开始：给每次 Agent 运行创建一个根 Span，把模型调用和工具调用作为子 Span，再把 Token、模型版本和错误原因写入标准属性。这样未来更换可观测性后端时，数据仍然能迁移。\n\n不过要注意，语义约定仍在快速发展，字段的稳定级别可能变化。建议把属性名集中封装在自己的 instrumentation 层，不要在几十个业务文件里散落字符串。\n\n## 从观测到自动修复\n\n可观测性最终不只是给人看，还可以成为控制回路：\n\n- 工具连续超时，自动降低该工具的并发并切换备用路径。\n- 输入 Token 接近预算，先压缩历史，再决定是否升级模型。\n- 结构化输出连续校验失败，暂停自动执行，转人工处理。\n- 某个模型版本的错误率显著上升，按流量比例回滚到上一版本。\n\n但自动修复必须有边界。不要让 Agent 根据自己记录的 Trace 无限调整权限、提示词或工具列表。观测数据应该进入经过审核的策略层，由明确的阈值、审批和回滚机制控制变更。\n\n## 结语：从“答案错了”走向“哪一步错了”\n\nAI Agent 的可观测性不是给日志加几个 Token 字段，而是把一次非确定性运行还原成可解释的执行链路。工程团队真正需要的不是知道“模型很慢”，而是知道“哪一个模型调用、哪一次检索、哪一个工具、哪一次重试造成了这次慢”。\n\n建议先选一个高价值流程，建立最小 Trace：请求 ID、Agent ID、模型名、输入输出 Token、工具名、耗时和错误类型。等链路稳定后，再逐步加入内容采集、评测结果和成本归因。\n\n**落地清单：**\n\n- 是否能看到一次 Agent 运行的完整步骤树？\n- 是否能区分模型慢、工具慢和重试造成的慢？\n- 是否记录了模型版本、提示版本和工具版本？\n- 是否默认关闭敏感内容采集？\n- 是否把 Trace 与离线评测样本关联起来？\n\n## 一手资料\n\n- [OpenTelemetry GenAI 可观测性实践](https:\u002F\u002Fopentelemetry.io\u002Fblog\u002F2026\u002Fgenai-observability\u002F)\n- [OpenTelemetry GenAI 属性与语义约定](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fsemconv\u002Fregistry\u002Fattributes\u002Fgen-ai\u002F)\n- [OpenTelemetry 语义约定总览](https:\u002F\u002Fopentelemetry.io\u002Fdocs\u002Fspecs\u002Fsemconv\u002F)","\u002Fuploads\u002F2026-08-05\u002F19586c04-7c5c-483a-8cdf-0860e7a03918.jpg",[],[],"Foundit AI","https:\u002F\u002Ffoundit.cn","f39339b1-aaa6-4e86-b0c2-a6e6a21113b5",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31],{"id":24,"name":25,"slug":26},"0848beb4-db26-4fb8-b391-f852a11be192","AI编程","ai-coding",{"id":28,"name":29,"slug":30},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug",{"id":32,"name":33,"slug":34},"4c2bbea6-eab7-40a8-8447-1de478ff7749","分析","analyse","资料来源",null,"published",false,64,0,"2026-07-31T00:00:00.000Z","2026-08-05T04:11:43.185Z","2026-08-05T02:13:45.344Z",[45,54,64],{"id":46,"type":6,"title":47,"slug":48,"summary":49,"coverUrl":50,"authorName":14,"sno":51,"publishedAt":52,"createdAt":53},"a3c11b62-9668-40cf-822d-25787f994c75","A2A：当 Agent 开始互相「递名片」","a2a-agent-to-agent-protocol","MCP 让 AI 统一接上工具，却没解决 Agent 之间怎么分工。A2A（Agent-to-Agent 协议）用「Agent Card 名片」让智能体互相发现、委派任务、协作交付。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-19\u002F7819028f-dd6f-4988-9964-56134773dc53.jpg",75,"2026-07-17T00:00:00.000Z","2026-07-19T16:17:09.511Z",{"id":55,"type":6,"title":56,"slug":57,"summary":58,"coverUrl":59,"authorName":60,"sno":61,"publishedAt":62,"createdAt":63},"7cc644a5-e0de-4d7b-802e-9e8b69677e12","AI 生成的代码会不会复制开源项目","ai-code-open-source-reference-license","AI 生成代码不等于天然没有来源。本文区分常见写法与高相似片段，解释代码引用、许可证、依赖供应链和轻量来源检查，帮助团队把合规当成代码质量的一部分。","\u002Fuploads\u002F2026-09-13\u002F920327ad-de7f-4caa-a2f4-816d467c9f9c.jpg","Foundit",40,"2026-09-13T00:00:00.000Z","2026-09-13T11:55:49.911Z",{"id":65,"type":6,"title":66,"slug":67,"summary":68,"coverUrl":69,"authorName":60,"sno":70,"publishedAt":71,"createdAt":72},"c85be666-a2ac-481a-a233-1d9aa7c5bfa1","AI 为什么会推荐不存在的 npm 包？","ai-hallucinated-dependencies-supply-chain","AI 可能把不存在或过时的依赖说得很像真的，甚至让开发者把陌生包安装进项目。本文解释依赖幻觉、恶意抢注、版本风险和安装前的供应链检查。","\u002Fuploads\u002F2026-09-14\u002F21c507cf-18e5-4b18-b71a-a501f6fb85c0.jpg",41,"2026-09-14T00:00:00.000Z","2026-09-14T11:00:01.589Z"]