1. 为什么 LLM 应用上线后反而更让人睡不着觉做过传统后端服务的同学大概都有个共识服务上线之后只要 CPU、内存、QPS、错误率这几条曲线不飘晚上基本能睡个安稳觉。但换成 LLM 应用和 AI Agent这套经验几乎全部失效。我见过太多团队接口成功率 99.9%平均响应 300ms监控大盘一片绿结果用户投诉不断——回答答非所问、工具调用莫名其妙失败、多轮对话到第三轮就开始胡言乱语、账单一天烧掉几百美金却查不出是哪条链路在漏。这就是 LLM 与 AI Agent 可观测实践要解决的核心问题传统 APM 看得见服务活着但看不见智能体是否在做正确的事。基于观测云搭建 AgentOps 运维体系本质上就是把可观测的边界从基础设施 应用性能扩展到模型行为 智能体决策链路 Token 成本这一整条新维度上。这篇文章适合三类人一是正在把 LLM 能力接入生产系统的后端和平台工程师二是负责 AI Agent 从 0 到 1 搭建、需要为线上稳定性兜底的开发同学三是技术负责人想搞清楚 AgentOps 到底要观测哪些指标、怎么落地、值不值得投入。我会从整体设计思路讲到具体埋点、指标建模、链路追踪、成本归因再到踩过的坑和排查技巧尽量给到可以直接抄作业的方案。先说清楚一个概念边界因为热词里很多人问agent 和 llm 和 ai 模型有什么区别。LLM 是底层的大语言模型负责理解和生成AI Agent 是在 LLM 之上加了一层感知—规划—行动—记忆的循环结构它能调用工具、访问外部数据、做多步决策。所以 LLM 的可观测关注的是单次推理的质量与成本而 Agent 的可观测要复杂得多它要追踪一整条决策链路上每一步的输入输出、工具调用、状态流转。AgentOps 就是把这套运维方法论工程化观测云则是承载这套体系的平台底座。2. AgentOps 观测体系的整体设计与选型思路2.1 传统可观测三支柱为什么不够用传统可观测性建立在 Metrics、Logs、Traces 三支柱上。放到 LLM 场景里这三根柱子都出现了维度缺失。Metrics 层面传统指标是数值型的、低基数的比如请求数、延迟分位。但 LLM 的关键指标很多是语义型的——回答相关性、幻觉率、工具选择准确率这些没法用简单的计数器表达。Logs 层面一次 Agent 调用产生的日志量可能是普通接口的几十倍因为每一步推理的 prompt、completion、工具返回都要记录而且这些内容是非结构化的长文本直接塞进日志系统会爆炸。Traces 层面传统链路追踪假设调用是确定性的、有明确父子关系但 Agent 的决策是动态的它可能循环调用、可能并行调用多个工具、可能中途改变计划链路结构每次都不一样。所以 AgentOps 体系的设计核心是在三支柱之上补一层语义观测层专门处理 LLM 特有的输入输出、Token 计量、工具调用语义、会话上下文这些内容。2.2 观测云作为底座的能力匹配选观测云做这套体系的底座主要看中几个能力。第一是它支持 OpenTelemetry 标准协议这意味着 LLM 生态里主流的埋点方案比如 OpenLLMetry、OpenInference 这类基于 OTel 的 SDK可以无缝接入不用被厂商锁定。第二是它对高基数标签和非结构化数据的处理能力Agent 的 trace 里天然带大量高基数属性比如 session_id、user_id、tool_name、model_name传统时序库扛不住观测云的存储模型更适合。第三是它把指标、日志、链路、事件放在同一个数据平面里做关联分析排查问题时可以从一条异常 trace 直接下钻到对应的日志和指标不用在多个系统之间来回跳。这里要强调一个选型原则AgentOps 平台必须支持自定义语义指标的上报。因为每个业务对好回答的定义不一样客服场景看重解决率代码助手场景看重编译通过率这些指标只能业务自己定义平台要能灵活接收。2.3 分层架构设计我把整套体系分成四层从下往上依次是采集层、传输层、存储计算层、应用层。采集层负责在 LLM 调用和 Agent 执行的关键节点埋点包括模型推理、工具调用、会话管理、成本计量。传输层用 OTel Collector 做统一汇聚和预处理比如脱敏、采样、字段裁剪。存储计算层由观测云承担做指标聚合、链路存储、日志索引。应用层是最终呈现的仪表盘、告警规则、根因分析视图。这个分层的好处是每层职责单一采集层只管采全传输层只管过滤和路由存储层只管存和算应用层只管看和告警。任何一层要换方案不影响其他层。比如后面想把某个模型供应商换成另一个只需要改采集层的适配器上层完全无感。3. 核心观测指标建模与埋点实操3.1 LLM 调用层的关键指标单次 LLM 调用要采集的指标我整理成下面这张表这是整个体系最基础的数据源。指标类别具体指标采集方式用途性能首 Token 延迟 TTFTSDK 埋点衡量用户感知速度性能端到端延迟SDK 埋点衡量整体响应性能输出 Token 速率计算得出衡量生成效率质量输入/输出 Token 数API 返回成本计量基础质量完成原因 finish_reasonAPI 返回判断是否被截断质量重试次数SDK 埋点衡量稳定性成本单次调用费用按 Token 单价计算成本归因异常错误码与错误类型SDK 埋点故障排查TTFT 这个指标特别重要很多人只盯端到端延迟但流式输出场景下用户真正感知的是第一个字什么时候出来。我实测过一个案例端到端延迟 8 秒但 TTFT 只有 400ms用户体感是很快另一个端到端 5 秒但 TTFT 3 秒用户体感是卡死了。所以这两个指标必须分开看。埋点的时候有个细节finish_reason 一定要记录。如果大量请求的 finish_reason 是 length说明输出被 max_tokens 截断了用户拿到的回答是不完整的但接口层面是成功的传统监控完全发现不了。这个坑我踩过线上投诉回答说到一半就没了查了半天才发现是参数配置问题。3.2 Agent 决策链路的关键指标Agent 比 LLM 复杂的地方在于多步决策所以要额外采集这些指标。步数分布一次任务平均走多少步步数突然飙升往往意味着 Agent 陷入循环工具调用成功率按工具名分组统计某个工具失败率上升要立刻告警工具选择准确率需要人工标注或规则校验衡量 Agent 是否选对了工具循环检测相同工具 相同参数连续调用超过阈值就标记异常上下文长度增长曲线多轮对话里上下文膨胀速度直接关系到成本和截断风险任务完成率端到端任务是否达成目标这是最贴近业务的指标工具调用成功率我建议按tool_name做维度拆分因为不同工具的稳定性差异很大。有一次线上问题整体成功率 97% 看着正常但拆开看某个查询工具成功率只有 60%被其他稳定工具的平均值掩盖了。3.3 埋点代码实操以 Python 生态为例用 OTel 的 SDK 做埋点核心是给 LLM 调用和工具调用各包一层 span。下面是我常用的埋点骨架。from opentelemetry import trace from opentelemetry.trace import Status, StatusCode tracer trace.get_tracer(agent.ops) def traced_llm_call(model, messages, **kwargs): with tracer.start_as_current_span(llm.call) as span: span.set_attribute(llm.model, model) span.set_attribute(llm.input_tokens, count_tokens(messages)) span.set_attribute(llm.request.messages, truncate(messages, 2000)) try: resp call_model(model, messages, **kwargs) span.set_attribute(llm.output_tokens, resp.usage.output_tokens) span.set_attribute(llm.finish_reason, resp.finish_reason) span.set_attribute(llm.cost, calc_cost(model, resp.usage)) span.set_attribute(llm.response, truncate(resp.text, 2000)) return resp except Exception as e: span.set_status(Status(StatusCode.ERROR, str(e))) span.record_exception(e) raise工具调用的埋点类似但要额外记录工具名、入参、出参、耗时。def traced_tool_call(tool_name, tool_fn, args): with tracer.start_as_current_span(agent.tool) as span: span.set_attribute(tool.name, tool_name) span.set_attribute(tool.args, truncate(str(args), 1000)) try: result tool_fn(**args) span.set_attribute(tool.success, True) span.set_attribute(tool.result, truncate(str(result), 1000)) return result except Exception as e: span.set_attribute(tool.success, False) span.set_status(Status(StatusCode.ERROR, str(e))) raise注意prompt 和 completion 里极可能包含用户隐私和密钥信息埋点前必须做脱敏。热词里有人问使用 llm 时如何防止密钥等鉴权信息泄露在可观测这一环最直接的做法是在传输层加脱敏规则把疑似密钥、手机号、身份证号的模式统一替换掉而不是指望每个埋点的人都记得手动处理。3.4 会话与上下文追踪Agent 的多轮对话必须用统一的session_id串起来否则你看到的是一堆孤立的 span没法还原完整会话。我的做法是在会话入口生成一个 session_id透传到每一次 LLM 调用和工具调用作为 span 的公共属性。同时要记录turn_index也就是当前是第几轮。这样在仪表盘上可以画出上下文长度随轮次增长的曲线一旦发现某类会话在第 5 轮之后成本陡增就能针对性优化上下文裁剪策略。4. 从采集到告警的完整落地流程4.1 数据采集与传输配置采集端用 OTel SDK传输端用 OTel Collector。Collector 的配置是整个体系的咽喉我一般会配三个 processor脱敏 processor、采样 processor、批处理 processor。脱敏 processor 用正则匹配敏感模式采样 processor 对高流量场景做尾部采样保留错误和慢请求丢弃正常请求批处理 processor 做批量发送降低网络开销。下面是一个简化的 Collector 配置片段。processors: attributes/redact: actions: - key: llm.request.messages action: update value: [REDACTED] tail_sampling: policies: - name: errors type: status_code status_code: {status_codes: [ERROR]} - name: slow type: latency latency: {threshold_ms: 5000} batch: send_batch_size: 512 timeout: 5s提示采样策略要谨慎。LLM 场景下正常请求也很有分析价值如果采样率设得太低做质量分析时样本不够。我的经验是错误和慢请求 100% 保留正常请求按 10% 到 20% 采样既能控制成本又不丢关键信息。4.2 指标聚合与仪表盘搭建数据进到观测云之后要建几块核心仪表盘。我通常分四块健康度大盘、成本大盘、质量大盘、会话分析大盘。健康度大盘放 QPS、错误率、TTFT、端到端延迟分位、工具调用成功率。成本大盘放 Token 消耗趋势、按模型/按业务线/按用户的成本拆分。质量大盘放 finish_reason 分布、重试率、任务完成率。会话分析大盘放步数分布、上下文增长曲线、循环检测命中数。这里有个建模技巧成本一定要做多维归因。只统计总成本没用要能回答哪个业务线最烧钱哪个用户最烧钱哪个模型性价比最低。做法是在埋点时给每次调用打上business_line、user_id、model_name标签聚合时按这些维度下钻。4.3 告警规则设计告警规则不能照搬传统服务那套阈值。LLM 场景的告警要分两类硬性故障和软性劣化。硬性故障包括错误率突增、工具调用连续失败、模型 API 返回鉴权错误这类直接触发高优先级告警。软性劣化包括 TTFT 分位缓慢上升、平均步数逐渐增加、单会话成本异常偏高这类用同比环比和基线偏离来触发优先级低一些但要持续关注。我特别推荐配一条循环检测告警当某个 session 内相同工具 相同参数连续调用超过 5 次立即告警。Agent 陷入死循环是线上最常见也最烧钱的问题早发现早止损。4.4 根因分析视图告警触发之后排查效率取决于数据关联能力。观测云的好处是可以从一条异常 trace 直接下钻。我的排查路径通常是告警指向某个指标异常点进去看是哪些 trace 贡献了异常打开具体 trace 看是哪一步出的问题再关联这一步的日志和当时的系统指标。举个真实例子。有次告警显示某业务线成本突然翻倍从成本大盘下钻到 trace发现是某个工具返回的数据格式变了导致 Agent 反复重试同一个工具步数从平均 3 步涨到 12 步。如果没有链路追踪你只能看到成本涨了根本不知道涨在哪。5. 常见问题与排查技巧实录5.1 高频问题速查表现象可能原因排查方向接口成功但用户投诉答非所问模型幻觉或 prompt 问题看质量指标和实际输入输出成本突然上涨上下文膨胀或循环调用看步数分布和上下文增长曲线工具调用频繁失败工具本身故障或参数错误按 tool_name 拆分成功率响应变慢但错误率为零模型侧限流或 TTFT 上升看 TTFT 分位和重试次数多轮对话后期质量下降上下文超限被截断看 finish_reason 和上下文长度某类请求全部超时特定模型或工具不可用按 model_name 和 tool_name 下钻5.2 几个踩过的坑第一个坑是只监控了 LLM 没监控 Agent。早期我们只埋了模型调用结果 Agent 层面的循环、工具选择错误完全看不见。后来补上 Agent 链路埋点才发现很多问题出在决策层而不是模型层。第二个坑是采样策略太激进。为了省成本把采样率设到 1%结果做质量分析时样本严重不足很多偶发问题根本抓不到。后来改成错误全留、正常采样问题就解决了。第三个坑是脱敏做在采集端。一开始让每个埋点的人自己脱敏结果总有人漏。后来统一挪到 Collector 层做规则集中管理再没出过泄露。第四个坑是告警阈值照搬传统服务。LLM 的延迟天然比普通接口高用传统阈值会疯狂误报。后来改成基于历史基线做动态阈值误报率大幅下降。5.3 独家避坑技巧给每次调用打上 trace_id 并透传到业务日志这样业务侧出问题时能直接关联到可观测数据对 prompt 做版本管理把 prompt 版本号作为标签上报这样能对比不同 prompt 版本的效果差异建立成本预算告警按业务线设日预算超了立即通知避免月底才发现账单爆炸定期做 trace 抽样人工评审机器指标看不出的语义问题靠人工抽查补位工具调用加超时和熔断别让一个慢工具拖垮整个 Agent6. 体系扩展与长期演进的一些个人体会这套体系搭起来之后最明显的变化是排查问题的思路变了。以前遇到 LLM 应用出问题第一反应是重启试试或者换个模型试试现在能精确定位到是 prompt 问题、工具问题还是模型问题处理效率完全不是一个量级。后续可以扩展的方向我自己在实践里试过几个。一是把质量评估自动化用另一个模型做裁判对回答打分把分数作为指标上报这样质量劣化能自动发现。二是做 A/B 实验框架把不同 prompt、不同模型、不同参数的效果差异用数据说话而不是拍脑袋。三是把 AgentOps 和 CI/CD 打通每次 prompt 或工具变更都跑一遍回归测试用可观测数据做发布门禁。我个人在实际操作中的体会是AgentOps 这件事最难的不是技术而是坚持把数据采全、采准。很多团队搭了个架子埋点埋一半指标缺胳膊少腿最后发现排查问题时数据不够用又回头补埋点来回折腾。所以一开始就把指标模型设计清楚比后面反复返工要省事得多。另外别追求一步到位先把 LLM 调用层的核心指标和成本归因做扎实再逐步扩展到 Agent 决策链路这个节奏比较稳。
