随着Agent逐步落地生产,Agent可观测性是保障其稳定运行的核心能力,本文结合开发实践梳理了生产级Agent可观测性的完整实现框架。 ## 1. 为什么Agent项目需要补可观测性这一课 随着Agent基础执行能力成熟,大量产品开始落地生产,但多数开发采用「AI Max」思路:换开源模型/框架试错后,就断言AI上限在此,无法量化问题、沉淀优化方法。 作者在开发Mini-Openclaw项目时,遇到写文件工具参数报错问题,仅靠原生日志无法定位,直到补全可观测能力才发现是模型将参数错误塞进了`_raw`字符串,最终通过简单兼容解决问题,验证了可观测性的必要性。 ## 2. 可观测性的基础逻辑:先明确模型能力边界 传统后端系统依靠指标、日志、链路追踪三件套即可满足故障排查需求,因为非Agent程序执行路径固定,可复现问题,但Agent每次执行路径、输出、工具选择都可能不同,可观测设计逻辑完全不同。 AI应用分为两个流派:「AI Max」主张能用AI就全用AI,「AI Min(最小化AI应用)」主张仅在泛化场景用AI,其余用传统工程实现;可观测性仅在AI Min模式下可行,核心是接受模型不可能完美,关键要能知道错在哪、为什么错,形成闭环可重复的优化框架。 ## 3. Agent可观测性的核心组成模块 ### 原始执行数据记录 Mini-Openclaw为每个会话单独保存jsonl原始日志,优先记录模型调用结果、工具调用结果、上下文/状态变化、观测系统自身生成的异常/评估事件,分为模型输入输出和Agent执行流程两部分,可按时间线完整查看Agent思考、调用工具的全流程。 ### 核心运行指标聚合 基于原始数据可计算工具错误率、模型调用耗时、Token消耗、上下文压缩频率、成本评估几类核心指标,这些指标可以提示异常位置,但无法直接定位具体错误原因。 ### Trace调用树结构 Agent执行是树状结构而非线性链路:一次模型调用可能触发多个工具调用,工具结果进入下一轮模型调用,委派工具还会展开子Agent执行流程。通过`model_call_id`关联模型请求响应与后续动作、`tool_call_id`配对工具调用与结果、`delegation_id`把子Agent事件挂回父节点,可清晰呈现完整调用链路,大幅提升问题排查效率。 ### 显式记录决策归因 为了明确「Agent为什么这么选」,通过System prompt要求模型在推理过程中输出固定格式决策块,包含当前目标、候选动作、最终选择、选择原因和预期结果,解析后挂载到对应模型调用节点;不仅方便排查跑偏环节,还能提升模型决策正确率。 ### 把任务状态显式化 复杂多Agent任务中,用户和开发者都需要明确任务流转状态:每个会话创建根任务,委派子Agent时创建子任务,每个任务拥有pending、planning、running、waiting_child、succeeded、failed、cancelled的独立状态机,单独记录任务变化历史和当前状态,把无序对话事件转化为可追踪的任务系统。 ### 执行轨迹异常检测 单次工具调用失败属于正常试错,连续失败无法收敛才是核心风险,常见异常包括重复失败、接近迭代上限、空响应循环、压缩频繁、未知工具;通过预设规则在执行中识别异常,写入异常事件后可在观测页面快速定位。 ### 任务结果评估 要回答「最终任务有没有做对」,需要配套三类评估方式:一是用户主动点赞点踩的用户反馈,二是基于失败信号规则判断的启发式评估,三是用额外大模型做裁判的LLM-as-judge;评估让Agent优化脱离感觉,可量化验证优化效果。 ### 失败Case的回放与对比 抓取失败Case修改配置后,用原用户请求、新配置创建新会话重新执行,对比两次执行的Trace调用树,可结构化对齐节点变化,直观验证修改效果,形成「发现问题-定位问题-修改配置-回放验证」的完整优化闭环。 ## 4. 总结:Agent可观测性的实现框架 目前Mini-Openclaw已搭建完成Agent可观测性的基础能力,核心实现思路覆盖:原始日志记录、核心指标设计、调用链路追踪、异常告警、决策归因、任务状态、结果评估、回放对比八个部分,仍会随着项目开发逐步完善。
2026-05-25 09:11

Agent Harness 可观测性:生产级AI 项目必须补上的一课

本文来自微信公众号: 叶小钗 ,作者:叶小钗,原文标题:《Agent Harness 可观测性:生产级 AI 项目必须补上的一课》


今年开始,Agent的基础执行环境从能力上已经OK,所以逐渐开始有很多产品真正的走向生产,这个时候如何让Agent长期稳定的运行,如何正确的执行长链路复杂任务就变得很重要了;


现阶段所有围绕Agent工程架构的技术被称为Harness,关于什么是Harness我们之前已经做过概括介绍,而今天我们将话题缩小,重点关注课题:Agent的执行可观测性。



该课题产生的原因来源于某产品负责人学员的感叹:


我终于知道,为什么搞不懂公司那批程序员在做什么了,他们在做技术架构的时候采用的是AI Max思路:


一个开源技术不行就换一个,单智能体不行就换多智能体,全部试过以后就说AI的上限就是这样,没有优化空间了,等新的技术开源了就再来一遍。


我有时候确实好奇,忍不住要问一他们怎么量化上限、有没有过程方法论?这批程序员就说量化不了、沉淀不了,都是别人的东西跑一下就好了。


我总觉得哪里不对,但因为不懂也说不出个所以然,只能听之任之,现在好了,确实不行,老子来给他们设计技术路径!


Agent的执行日志


最近我一直在开发Mini-Openclaw这个Agent项目,


目前基本的骨架已经搭建起来了,模型,工具,技能,记忆管理,会话压缩,多Agent协作等。


接下来准备做一些工具和skills来跑一跑案例,看看的Agent到底怎么样,能不能正常完成任务。


我先选择了一个简单的任务


让Agent帮我写一篇关于AI手机的文章,非常简单就是调用一个write_file的工具,把内容写到指定文件里。


然后Agent一直告诉我路径参数错误


Error:缺少'path'参数


文件一直没有写成功。


看到这个提示,感觉是路径问题,是不是目录不存在还是我的工具参数描述定义不清楚,


我仔细检查了一下这些代码,没有发现明显的问题。


按照我之前软件开发的经验,我需要去打印日志输出,看看模型返回了什么,工具为什么会出错。于是我接着去开发了,Agent执行日志和模型日志这两个模块的记录和显示,方便查看模型输入和输出,工具的执行结果等。


功能开发完成后,再执行一次我们写文章的任务,一下就看到了真正的原因:模型连续几次把工具参数包成了错误的_raw结构。



工具期待的是结构化参数,比如path和content。模型却把它们塞进了_raw字符串里。工具拿不到字段,自然失败。


这个问题挺简单的,模型返回的参数格式不对,程序需要做一下兼容就好了。


到这里,大家可能会认为以后遇到问题是不是就看刚刚开发的2个日志面板就可以了。


真实情况是还远远不够,Agent有没有按照我们的想法去完成任务,它的耗时,成本这些是怎么样的,所以给我们Agent做一个可观察的面板就非常有必要了:



什么是可观测性


可观察性这个说起来挺简单的,就是系统在运行的时候,我们可不可以在外面看出它里里面发生了什么。


我们开发其他软件的时候,常见三件套是指标、日志、链路追踪:


  1. 指标告诉你服务有多快,花费了多少钱,错误率多少等等


  2. 日志记录具体发生了什么事情


  3. 链路追踪记录调用关系,谁调用了谁,可以看出瓶颈在哪里


这三者结合起来基本就覆盖了大部分后端系统的故障排查需求:



非Agent程序有一个特性,就是它们的执行路径是固定,出错了我们还可以重跑复现问题,排查问题使用我们上面的3件套就可以了。


但是Agent不一样,同样的问题,每一次的执行路径都可能不一样,每一次输出的内容都不一样,甚至工具选择都不一样。


所以到底怎么来设计Agent的可观察性呢?在开始这个话题前,我们先探讨下模型的能力边界问题。


模型的能力边界


首先,大家要注意的是,可观测性并不是Agent所特有的,只要是AI项目,就都会有可观测的难题,这里就包括最传统的知识库RAG项目,但无论那一套的底层逻辑都是前面说的三件套。


在给学员上课的时候,最常说的一句话是:做AI应用一定要了解模型边界!这里所谓模型边界涉及了AI应用的两个流派:


  1. AI Max:能用AI就用AI;


  2. AI Min:能不用AI就不用AI;


所谓的可观测性,只在能不用AI就不用AI的模式下可行,他的背后体现的是模型的边界认知:追求完美准确率不现实,关键是要知道错在哪、为什么错、怎么改!并且能证明技术框架是闭环可重复的!


这里给大家举个例子,之前AI课的时候学员过多,需要一个排班系统,大概的需求是:


学员在微信群打出自己每天的空余时间,AI会主动统计大家都有空的时间,如果满足条件就预约会议,学员在群里的聊天信息如下:


A:20.00-22.00有空


B:18-20点没空,其他都可以


C:二十点后可以;


D:下午4点前没空;


E:我随便了,都行;


非常简单的需求,但就是这么一个简单的系统就能聊清楚什么是模型边界。


能用AI就AI


全部用AI就很简单了,直接一股脑丢给模型加一句“请问今天我该安排什么时间上课”就行,比如:



在简单场景下,AI Max是最优解,包括很多智能体如Manus在简单任务里面的表现是非常不错的。


随后就是,能不用AI就不用AI:


最小化AI应用


所谓最小化AI应用,就是只在不得不使用AI的地方使用,比如这里不得不使用的地方就是提取关键词,也就是语义识别每个学员的空闲时间:


A:空闲时间段为20:00-22:00(即晚上8点到10点)。


B:18:00-20:00没空,其他时间空闲(即00:00-18:00和20:00-24:00)。


C:二十点后可以,即20:00-24:00空闲。


D:下午4点前没空,即16:00-24:00空闲(下午4点为16:00)。


E:所有时间都空闲(即00:00-24:00)。


拿到空闲时间后,再自己用算法去做实现,这里马上就涉及了另一个问题了:在最小化AI应用的场景里,什么时候需要用AI?


答案很简单,在充满泛化场景的时候需要,比如上面ABCDE的回答,你很难用正则的方法给他匹配出来,类似这种关键词(关键知识)的提取只能依靠AI;


类似的场景是,我要求学员的昵称必须是学号-昵称-城市的格式,但学员一定会做得五花八门,比如就有学号_昵称_城市、城市_学号_昵称、学号昵称@城市等等莫名其妙的排布方式。


这种在学员自己设置后,也只有AI能快速帮他们做更正。


所有类似这种泛化要求较高的往往都必须AI出场,并且AI在这个领域做得挺好的!


那么,在这个基础之下,就可以讨论可观测性了:


可观测性


现阶段的AI项目其实有个巨大不确定性因素,因为大模型本身就是个巨大黑盒(还是概率输出)。


还是以上面排班系统为例,可观测性的价值在于:如果出现了AI识别不了的情况,能很快识别并解决!


比如现在出现一个F,他给的答案比较另类:


戌亥之时,余有暇。


类似于这种回答,模型很可能识别不了,那么排班系统就会出问题,这个在能不用AI就不用AI的模式下就可以被识别并优化。


这里的可以被识别且优化就是我们所谓的模型能力可观测。



上述是比较泛的模型可观测性介绍,理解他们后,我们再回归主题,进入Agent可观测性的讨论:


Agent可观察性


我们参考了其他系统的可观察性加上Agent的特性,Agent的可观察性大概包含以下几个部分:


原始日志数据,记录会话历史,模型的输入和输出,记录思考过程,工具的输入和输出


指标聚合,设计对应的指标,回答服务有多快,花费了多少钱,错误率多少等等


Trace调用树,回答谁调谁,调用链是什么样的


决策归因,这一步为什么要这么做?考虑过别的吗


任务状态流转,目标拆成了什么?哪一步在哪个状态?计划改了几次?


异常检测,Agent走了哪条路径?有没有打转/反复重试/死循环?


评估,这次到底成功了吗?输出对不对?


回放与对比,改一行prompt,重跑这个case,看会不会更好?


接下来我们逐步展开讨论:


原始数据的记录


我们开发的Mini-OpenClaw是单机、自托管、文件存储的项目,每一个会话保存一份jsonl包含用户请求消息,模型请求和响应,工具输入和输出,异常,会话压缩,评估结果这些原始内容。


这些都是原始数据,没有经过任何加工,只是记录了Agent的执行过程发生的所有动作


以下几类事件优先保留下来


  • model_call和model_result,记录模型输入输出、token、耗时、模型名。


  • tool_call和tool_result,记录工具名、参数、结果、错误。


  • 上下文和状态变化,比如压缩、任务状态迁移。


  • 观测系统自己生成的事件,比如anomaly、evaluation。


这类基础数据我们分成了2个部分一个模型的输入和输出,方便查看提示词是否按照我们设计的格式提供给模型



还有另外一部分是用来记录Agent的执行日志,可以按照时间线查看Agent的执行流程,我们可以按照时间的先后顺序完整的查看Agent是怎么一步一步思考,调用工具来完成任务的



指标设计


有了原始数据,指标很容易就能计算出来,我们需要哪些指标呢,我们简单设计了下面这几个指标


  • 工具错误率


  • 模型调用耗时


  • token消耗


  • 上下文压缩是不是过于频繁


  • 成本评估


这些指标很有用,它们能告诉哪里可能不正常,比如工具错误率很高,我们就需要去排查工具错误的原因,上下文压缩过于频繁,我们就要考虑上下文窗口设置是否合理,或者压缩算法有问题。


指标能提示我们哪里出问题了,但是不能告诉到底是什么错误


工具错误率30%,只能说明工具调用经常失败,它不能解释失败是工具实现坏了,还是模型传错参数,还是工具描述让模型误解了schema。


平均迭代次数变高,也不能直接说明Agent为什么打转。可能是任务本来变难了,也可能是它一直在重复同一个错误。


Trace调用树结构


到这里我们就不再满足于一个简单的事件列表日志,我们需要看到一次Agent的执行的调用树


Agent的执行不是一条线。它更像一棵树,一次模型调用产生一个或多个工具调用,工具结果进入下一轮模型调用,某个工具如果触发委派,下面还会展开一个子Agent的完整执行过程。


我们在设计原始日志保存的时候记录几个关键的字段


  • model_call_id


  • tool_call_id


  • delegation_id


model_call_id用来把一次模型请求、响应、决策记录和后续动作关联起来。tool_call_id用来把工具调用和工具结果配对。delegation_id用来把子Agent的事件挂回父Agent的委派节点。


有了这些字段,Trace调用树就不需要靠时间顺序来猜。


比如我们上次写文件失败的问题,如果放在Trace里看,会清楚很多。你可以展开某一次model call,看到它选择了write_file。再展开tool call,看到参数里出现_raw。再看tool result,发现工具返回字段缺失或参数解析失败。接着看下一轮model call,检查它有没有把上一轮失败纳入上下文。然后你会发现,它又生成了一次几乎同样的_raw。


这个时候,我们几可以很清楚的看到模型在重复错误参数结构。



如果没有Trace,我们还需要在众多的日志记录里面去翻看,查找对应的数据。有了Trace我们可以很清楚看到调用链路是怎么样的,排查问题的效率会有很大的提升。


子Agent也是同理。没有delegation_id,子Agent的事件会像一段插进来的噪声,而且这个是并行执行,只看时间线就会很乱了。你知道它做了什么事情,但很难知道它属于父任务的哪一次委派。挂成树以后,父子关系才稳定。


决策归因,为什么要这么做


通过Trace我们可以看到Agent的执行树,可以看到它不停的选择工具执行,这个时候我们自然就想知道模型选择这个工具的原因,它下次执行还会不会选择这个工具,还有没有其他的选择呢,特别是Agent如果把任务跑偏了要如何排查它在哪一步跑偏,它为什么会这样选择。


我们知道Agent做了什么,但不知道它为什么这么做。


对传统程序来说,行为来自代码。对Agent来说,很多行为来自模型当时的判断。


为了把为什么做记录下来,我们的做法是在system prompt里加入一个决策记录规范,让模型在需要选择动作时,在reasoning中输出一个固定格式的决策块。里面包括当前目标、候选动作、最终选择、选择原因和预期结果。



后端拿到模型响应后,会解析这个决策块,生成decision事件,再挂到对应的模型调用节点上。


这样看Trace时,就不只是看到它调用了write_file,还可以看到它当时认为自己的目标是什么,为什么选择写文件,而不是继续搜索或者询问用户。


我觉得这个设计是有价值的,它可以显示的告诉我们模型做出选择的原因。


我们把这个决策放到了reasoning里面。reasoning模型通常更容易输出这类结构,普通chat模型,系统只能退回启发式:从实际tool_call里拿到选择动作,再从reasoning或文本里截取一段理由。


当然我们不能完全相信这个决策,但对调试Agent来说,这已经比纯日志强很多。事实上在输出这个决策依据的时候,等同于大模型在自己反思,决策的正确率也会变高。



把任务状态显式化


对于简单一点的任务通过Trace面板就能看出问题所在,但是复杂任务光有Trace还不够。


比如我让Agent去搜索热点新闻,主Agent理解需求后,可能委派几个子Agent来完成任务,这时候用户真正关心的是任务状态:任务有没有完成?哪个卡住了?当前进行到了哪一步?


我们在系统中单独设计了任务状态。


每个会话开始时会创建一个root task。调用delegate_task时,会创建子task。任务有自己的状态机,从pending、planning、running,到waiting_child、succeeded、failed、cancelled。


PS delegate_task这个是我们Agent自带的一个工具,用来创建子Agent


这让Agent的过程从一串对话事件,变成了一个可以查看状态的任务系统。


同时项目里多了2个基础日志记录tasks.jsonl和tasks.json。前者记录任务变化历史信息,后者保存当前任务状态。


在主流程里,会话开始时创建root task,并在会话结束时把它转为succeeded。创建子Agent的时候同时创建子task,并根据子Agent的执行结果转为succeeded或failed。



异常检测


Agent一次工具调用失败很正常。工具schema没写清楚,模型第一次试错,或者环境里缺文件,都可能发生。真正危险的是它连续失败,不能收敛,还在不停的执行。


它可能同一个工具连续失败。也可能连续两轮模型都没有响应。也可能token突然暴涨。还有一种很常见的情况:它一直说自己在调整,但实际上只是换一种说法重复失败。


为了判断Agent有没有在正常执行任务,我们需要一个执行轨迹异常检测。


我们在项目里先实现了一组规则,比如重复失败、接近迭代上限、空响应循环、压缩频繁、未知工具。


这些规则会在执行过程中或者会话结束后触发。一旦命中,就写入anomaly事件。前端可以在可观察性页面展示,也可以在日志和Trace里定位。



评估


前面这些更多是在看过程如何。当我们看清楚过程后,还要回答一个更简单的问题:这次到底做对没有?


比如写文章这个任务,文件有没有写成功,内容是不是符合要求,中间有很多异常的话,最后结果还能不能接受。


所以我又做了评估体系,我设置3种评估方式


  • 第一类是用户反馈。用户可以对模型的的回复点赞或者点踩


  • 第二类是启发式评估。会话结束以后,系统会看有没有明显失败信号。比如没有最终回复,有高严重度异常,模型调用失败,迭代次数接近上限,工具错误率太高。


  • 第三类是LLM-as-judge,让另一个模型来评估Agent输出


有了评估以后,优化才不只是凭感觉。


否则我改了prompt,只能说好像顺了一点,但不知道错误率有没有下降,打转有没有减少,最终成功率有没有提高。



回放和对比


真实调试Agent时,最常见的动作是:抓到一个失败case,改prompt,改工具描述,改Agent配置,然后再跑一次。


问题是,怎么判断改得有效?


严格复现基本不现实。模型有随机性,工具结果也可能不同,外部环境也在变化。


我们只能用同一个case,在相似条件下再跑一次。


具体做法很很简单:拿原来的user message,带上新的prompt、工具描述或Agent配置,创建一个新会话重新跑。跑完以后,对比两棵Trace调用树。


比如原来写文件失败了4次,新会话只失败1次,或者没有失败。


原来触发了高风险异常告警,新会话没有触发。


原来的评估是失败,新会话变成成功。


这样我们就能更清楚地判断,改prompt或工具描述到底有没有改善轨迹。


两个会话的迭代、模型调用、工具调用、委派节点会被结构化对齐。哪些节点相同,哪些新增,哪些消失,哪些状态或耗时发生变化,都可以展示出来。


这就让优化有了一个闭环:


从发现问题,定位轨迹,再修改配置,最后回放对比。


这里的回放更像是用同一个case做相似条件下的再次验证。它存在可控的偏差,不过已足够帮我们判断优化方向。



总结


这就是我在开发Mini-Openclaw这个Agent时候,对Agent可观察性的一些思考,目前开发的功能看起来都还比较粗糙,随着后续开发还会逐步的完善,目前实现的思路就是这些


  • 日志记录


  • 指标设计


  • 链路追踪


  • 异常告警


  • 决策归因


  • 任务状态


  • 结果评估


  • 回放对比


大家有什么好的建议可以评论区留言。

AI创投日报频道: 前沿科技
本内容来源于网络 原文链接,观点仅代表作者本人,不代表虎嗅立场。
如涉及版权问题请联系 hezuo@huxiu.com,我们将及时核实并处理。
正在改变与想要改变世界的人,都在 虎嗅APP
赞赏
关闭赞赏 开启赞赏

支持一下   修改

确定