
如果你跟我一样天天跟AI Agent打交道你大概率会遇到一个尴尬的场面Demo里跑得好好的智能体一塞进真实业务流里就原地打转要么在某个工具调用上反复横跳要么干脆忘了自己最初要干嘛。去年我开始认真琢磨这个问题最后沉淀下来一套专门用来衡量Agent“到底能走多远”的评估体系起名就叫Agent-Reach。简单说Agent-Reach不是又一个Agent框架而是一套面向长程任务的触达能力评估方案。它不关心你在单轮问答里答得多漂亮只关心一个Agent在多步骤、多工具、多约束的真实任务里能推进到哪一步卡在哪里为什么卡住。这篇文章我会把Agent-Reach的内部设计、评分算法、实操接入流程和踩坑记录完整写出来适合正在做Agent应用开发、AI评测平台搭建、或者想把自己那个“演示无敌、落地翻车”的Agent好好治一治的同学。1. 核心思路为什么要单独定义“触达能力”在动手拆Agent-Reach之前先得说清楚一个很现实的问题现有指标不够用了。1.1 传统评测指标到底漏了什么过去我们评测AI能力最喜欢看的是准确率、BLEU、ROUGE这类指标。它们本质上在回答一个问题“模型输出的东西对不对”。但你拿这些指标去衡量Agent会发现一个致命错位——Agent的任务不是“输出一个答案”而是“完成一连串动作”。举个我实际遇到的例子。做一个内部工单处理Agent任务是把用户报障工单自动分派给对应技术组。传统评测看什么看最终分类对不对。可实际运行中这个Agent干了一件很离谱的事它识别出是网络故障后先调用工单系统接口创建工单然后又调用了一个不存在的“外网诊断服务”报错后重试了8次最后才分派成功。最终结果是“对的”中间过程完全是灾难。如果只看准确率这个Agent得分满分实际上它浪费了大量token还拖慢了响应时间。Agent-Reach的出发点就是补这块空白。它考察的不是“结果对不对”而是“Agent在正确轨道上推进了多深”我们把这条推进路径叫作触达链Reach Chain从起点到终点的每一跳都是一次触达。1.2 把它拆成三个可量化的问题设计Agent-Reach时我把评测目标强行收敛成三个问题这三个问题也对应后面整个指标体系的骨架第一Agent有没有按照预定的任务拓扑执行到终点如果没有在第几层偏离的第二Agent在执行过程中有没有做无意义的动作或者说它的路径纯净度有多高第三Agent碰到障碍时是主动绕行还是卡死重试绕行和卡死的比例直接反映它的真实鲁棒性。这三个问题分别对应触达深度Reach Depth、路径纯度Path Purity和障碍消化率Obstacle Digestion。这套体系本身不绑定任何具体框架理论上只要你的Agent具备可观测的中间动作流就能接入。2. 整体设计与分层指标拆解这一节是Agent-Reach最核心的部分。我把它拆成分层的指标体系每一层解决一类问题层与层之间有明确的计算依赖关系。2.1 任务拓扑把真实任务变成有向无环图Agent-Reach不是拿一个prompt就让Agent随便跑。它会事先把目标任务建模成一个有向无环图DAG每个节点代表一个必须完成的子目标每条边代表子目标之间的依赖关系。拿电商售后Agent举例一个“退货退款”任务可以建模成验证订单合法性→确认商品状态→审核退货原因→生成退货单→推送退款指令→同步财务系统。这6个节点形成一个串行链路任何一个节点失败后面的节点就没办法正常触达。这里有个当时设计时很关键的决策为什么用DAG而不用线性清单因为真实任务往往有分支。比如“确认商品状态”失败后有的流程会跳到“人工介入”节点而不是直接终止。用DAG可以把这种分支路径也纳入评测范围触达深度就能区分“主线触达”和“分支兜底触达”不会出现“Agent走了兜底分支但主线没走完”被一刀切判0分的情况。在Agent-Reach里每个节点还会打上三个标签必达节点、可选节点、兜底节点。必达节点就是主线核心没走通就等于任务失败可选节点走通可以加分兜底节点是异常处理逻辑走通说明Agent具备应变能力但它不能用来替代必达节点。2.2 四个核心指标的计算逻辑指标设计上Agent-Reach一共包含四个核心指标这里逐个拆解。触达深度是基础指标。它计算的是Agent实际触达的节点数除以必达节点总数但注意不是简单除法而是按拓扑层级加权。越靠近终点的节点权重越高因为Agent如果能在长程任务中保持方向感走到最后它的价值远高于只会在开头做几个简单动作。假设一个任务有5个必达节点权重从1到5递增Agent完成了前3个那触达深度就是(123)/(12345)6/150.4。这个设计会惩罚那种“开局猛如虎后面原地杵”的Agent。路径纯度用来识别无效动作。统计Agent执行过程中所有与任务拓扑无关的工具调用、消息往返、重复查询。路径纯度 有效动作数 / 总动作数。假设Agent完成一次退单用了12次工具调用其中3次是在查询一个没用到的物流接口那路径纯度就是9/120.75。这个指标非常灵敏很多Agent在benchmark里结果全对但过程稀碎查路径纯度一眼就能暴露。障碍消化率衡量的是Agent面对错误和拦路时的表现。我们把失败重试次数、异常分支跳转次数、外部兜底调用次数统称为“障碍事件”。消化率 成功绕行障碍数 / 总障碍数。重点在于判定什么算“绕行成功”Agent遇到A接口超时后主动切换B接口并完成同一目标成功Agent遇到A接口超时后连续重试5次A接口直到超时上限失败。这个指标能看出Agent是真有策略还是在用蛮力。最后的综合评分是一个加权合成综合分 触达深度×0.4 路径纯度×0.3 障碍消化率×0.3。权重比例我调过好几轮最终确定这个配比是因为在实际评测中发现触达深度是最难提升的指标而路径纯度和障碍消化率更像是“过程卫生”给它们过高的权重会导致Agent为了刷纯度而拒绝尝试复杂动作。2.3 评测沙箱的轻量设计指标再好没有可控的评测环境就是空中楼阁。Agent-Reach配套了一套轻量评测沙箱它不是重型的仿真平台而是一个拦截层加状态记录器。拦截层部署在Agent工具调用的必经之路上。如果你的Agent用的是LangChain可以直接在ToolNode外面包一层wrapper如果是自研框架只要在工具路由层做拦截就行。拦截层负责三件事记录每次工具调用的入参和出参、实时比对目标拓扑上的节点完成状态、在特定节点注入预设故障。状态记录器则把每一次“状态转移”都存成结构化日志。比如Agent从节点2“确认订单状态”进入节点3“审核退货原因”会记一条带时间戳的边日志。这些日志后期可以回放成完整的触达路径出问题时用来做“事故回放”非常有用。3. 实操过程从零搭建Agent-Reach评测概念说完了直接进入实操。这里我把Agent-Reach从构建到跑通一套完整评测的全过程写出来你能照着搭出一套自己的版本。3.1 第一步定义你的任务拓扑图任务拓扑是整个评测的地图所以第一步也是最容易出错的一步。我当时做的第一个评测任务“跨系统数据同步”一开始贪大求全把任务图设计成了200多个节点的庞然大物结果标注成本极高跑出来的数据也稀疏得没法看。后面总结出一套比较健康的任务拆法单任务控制在10到15个子目标其中必达节点占60%-70%可选节点占20%-30%兜底节点留10%-20%。每个节点必须有可验证的完成判定条件不能写“分析数据合理”这种模糊句子必须写“调用check_consistency接口返回success且差异计数为0”。任务图数据结构可以用JSON描述每个节点包含id、type、depends_on、 verify。我记得第一个版本顺手用Python写了个简单校验函数用来检查XML格式对不对这里给出一个简化的验证逻辑示例import json def check_graph_validity(graph_data): node_ids set() must_nodes [] for node in graph_data[nodes]: node_ids.add(node[id]) if node[type] must: must_nodes.append(node[id]) if not must_nodes: raise ValueError(must have at least one must-type node) for node in graph_data[nodes]: for dep in node.get(depends_on, []): if dep not in node_ids: raise ValueError(fdependency {dep} not found) if not _has_cycle(graph_data): print(graph is a valid DAG) return graph_data def _has_cycle(graph_data): visited {} for node in graph_data[nodes]: if node[id] not in visited and _dfs_cycle(node[id], graph_data, visited): return True return False def _dfs_cycle(node_id, graph_data, visited): if visited.get(node_id) 1: return True visited[node_id] 1 node next(n for n in graph_data[nodes] if n[id] node_id) for dep in node.get(depends_on, []): if _dfs_cycle(dep, graph_data, visited): return True visited[node_id] 2 return False这个check_graph_validity函数主要做三件事检查有没有必达节点、检查依赖引用是否有效、检查成环。第一次写评测任务时我在依赖检查上栽过跟头有一个节点依赖了三个上游节点结果上游节点在某种分支下不会执行导致Agent永远没法触发这个节点评测分数一片飘绿但其实是图本身有bug。3.2 第二步注入扰动与故障的节奏Agent-Reach评测和普通跑测最大的区别在于它有主动的故障注入机制。但这玩意儿不是乱来的注入故障的时机和位置直接影响评测结果的有效性。我总结出来的原则是故障注入要围绕“关键依赖边”展开而不是随机炸一个节点。所谓关键依赖边就是从拓扑图里算出来的必经路径比如串行链路中间的那条边一旦断掉后面所有节点都失去意义。在这种边上注入故障最能检验Agent的替代路径规划能力。注入方式有三种。第一是接口延迟注入把正常40毫秒的响应拉到3秒看Agent会不会超时放弃第二是返回错误码注入让某个工具接口直接返回500看Agent有没有备选工具第三是数据异常注入让接口返回格式错误的数据比如本该返回JSON却返回了纯文本这种情况下非常考验Agent的解析容错能力。实操中比较推荐做“分段注入”把任务执行过程分成前、中、后三个阶段每阶段只注入一个故障。如果一上来就同时注入三个故障Agent基本必挂评测结果只能说明它不抗压但说不清它是怎么死的。分段注入则可以看清Agent在不同任务阶段对故障的敏感度差异。实际跑的时候我发现大部分Agent在后段故障面前的崩溃率是前段的两倍以上原因大概率是前段执行消耗了大量上下文窗口留给后段处理的推理空间被压缩了。3.3 第三步执行评测并记录原始轨迹任务拓扑配好、故障计划定好就可以正式跑了。Agent-Reach评测执行时不需要改Agent本身的代码只需要在工具层挂上拦截钩子。我推荐以标准Agent框架加上自定义回调的方式来记录轨迹这样侵入性最小。以LangChain为例可以在AgentExecutor的callbacks里挂一个自定义Handlerfrom langchain_core.callbacks import BaseCallbackHandler class ReachTracker(BaseCallbackHandler): def __init__(self): self.steps [] self.current_action {} def on_tool_start(self, serialized, input_str, **kwargs): self.current_action { type: tool_call, tool: serialized.get(name, unknown), input: input_str, timestamp: _now() } def on_tool_end(self, output, **kwargs): self.current_action[output] str(output) self.steps.append(self.current_action) def on_agent_action(self, action, **kwargs): self.steps.append({ type: thought, content: action.log, timestamp: _now() })这套追踪逻辑跑下来每个Agent的动作序列全都在ReachTracker.steps里。之后评测计算脚本就是遍历这些steps对照任务拓扑节点判断触达状态。有一个容易忽略的坑一定要在on_tool_start和on_tool_end两个钩子里同时记录时间戳和输入输出只记录输出不记录输入排查问题时根本看不出Agent是为了什么发起这次工具调用。评测执行时建议每个任务跑至少5次取平均因为大语言模型本身有随机性单次结果很容易被采样噪声带偏。我试过同一任务同参数连跑10次触达深度的波动范围能达到0.15左右路径纯度的波动小一些大概在0.08以内。3.4 第四步输出评测报告和触达热力图数据回收后Agent-Reach最后会生成一份标准评测报告。报告分两部分数值汇总和轨迹可视化。数值汇总就是四个核心指标加上每个节点的独立触达率。独立触达率是每一层节点的完成比例这个数比综合分更能定位问题。比如某个Agent综合分0.65一眼看还行但节点触达率热力图会显示它有3个中间节点触达率只有20%就会清楚地暴露瓶颈区在任务的中后段转换处。轨迹可视化方面我不建议上来就搞复杂UI先用一张最朴素的节点表做排序就够了。列出每个节点的完成率、失败原因分布、平均尝试次数基本90%的Agent问题都能定位。真需要可视化再考虑把轨迹导出成DOT格式用Graphviz生成触达热力图。4. 关键参数与计算示例指标不能只在概念上说得通必须有明确的数学表达和可复现的计算过程。这一节我把Agent-Reach涉及的核心公式和参数默认值完整列出来你可以直接用。4.1 触达深度的权重公式细节触达深度Reach Depth的完整公式是这样的RD Σ(w_i × d_i) / Σ(w_i × m_i)其中d_i是第i个层级实际完成的必达节点数m_i是第i层级的必达节点总数w_i是第i层级的权重。默认权重从1开始线性递增第n层权重等于n。这样设计的原因是任务执行到后期Agent承受的干扰和上下文压力都更大完成后期节点需要的能力水平高于完成早期节点。举一个具体例子。假设你的任务图谱有三个层级每层必达节点分别是3、2、2权重分别是1、2、3。Agent在每层完成了3、1、0个节点那触达深度就是RD (1×3 2×1 3×0) / (1×3 2×2 3×2) 5/13 ≈ 0.385这个分数直观地反映出Agent在前层全部完成、中层完成一半、后层完全失败的状态。如果按普通节点完成率算它完成了4/7≈0.57看上去还过得去但加权后就知道它根本没能力推进到远程目标这就是触达深度指标的区分力所在。4.2 路径纯度与障碍消化率的边界处理规则路径纯度PP 有效动作数 / 总动作数。这里有一个重要的边界问题什么算有效动作Agent-Reach里有一个预定义的有效动作名单名单里是任务拓扑图上所有节点对应的工具调用。不在名单上的动作一律算无效动作。这个设计的目的是避免把“Agent闲聊时调用了一个翻译工具”这种无关动作也算进有效动作里。障碍消化率OD 绕过成功的障碍事件数 / 总障碍事件数。判定绕过成功有两个严格条件第一Agent在遇到障碍后没有再调用同一个故障工具超过2次超过2次视为卡死重试第二Agent最终完成了障碍点之后的下一个必达节点。这两个条件同时满足才算一次成功消化。这样做是为了防止Agent“假装绕行”它试了另一个工具但也失败了只不过报错信息变了这种不算成功。4.3 综合评分默认参数表综合评分SC 0.4×RD 0.3×PP 0.3×OD。这是一组默认参数也可以根据业务特性调整。比如客服机器人更看重路径纯度因为无效动作直接对应调用成本自动化运维Agent更看重障碍消化率因为线上环境故障是常态长程研究类Agent则更看重触达深度。下面这组默认参数建议在初次跑评测时保持不动方便横向对比不同Agent的能力基线参数默认值说明触达深度权重0.4任务推进能力路径纯度权重0.3动作有效性障碍消化率权重0.3异常应对能力层级权重增长步长1每加深一层权重1重试上限2次超过算卡死最低评测次数5次取均值这个重试上限2次是我反复试出来的平衡点。设成1次有些Agent因为轻微抖动就被误判为失败设成3次就会放过那些“撞了南墙也不回头”的笨Agent。5. 常见问题与排查技巧实录这块是最有实战价值的部分。Agent-Reach搭建和使用过程中我踩了不少坑挑几个有代表性的写出来。5.1 卡死重试判定失效第一次跑评测时有一个Agent在同一个工具上连续重试了9次但障碍消化率还是给了1.0分。排查后发现是因为我用的故障注入方式是“延迟注入”也就是接口没有立刻返回错误只是变慢。Agent调这个工具时因为还没到超时阈值所以没有触发异常记录但Agent已经在这个工具上消耗了大量时间后面的必达节点全都没做。处理办法是把障碍判定从“异常发生”改成“时间消耗异常发生”双条件。现在Agent-Reach对延迟注入的定义是单次工具调用用时超过基准耗时三倍以上算一次障碍事件。这样Agent在慢接口上反复磨蹭就会被如实记入失败重试。5.2 任务拓扑依赖边设计错误还有一个很隐蔽的问题我设计过一个任务有两个可选节点依赖同一个必达节点但必达节点在不同分支下可能以不同的工具调用完成。Agent用分支A完成了这个必达节点然后评测脚本却只认分支B的工具名导致必达节点被判断为未完成。这个问题的根源是把“节点完成判定”绑定到了具体工具名而正确的做法是绑定到“任务效果”。从那以后我们改用验证函数来做节点判定不再匹配工具名。验证函数只检查业务状态是否达成不管用什么工具达成的。5.3 汇总分数的“森林错觉”刚开始用Agent-Reach时我习惯只看综合分吃过一次大亏。有一个Agent综合分0.71看起来挺不错我差点就放它上线。后来去看节点触达率才发现它的高层级节点触达率惨不忍睹0.71的分纯粹是靠低层级节点的完成率硬拉上来的。这种分数掩盖问题的情况一定要重视。建议每次跑完评测除了看综合分强制看一眼“高层级节点触达率”也就是权重最高的那一层节点的完成情况。如果这个数小于0.5综合分再高也不能上线。后来我在评测报告里直接加了一个警告逻辑最高层级触达率低于0.5时报告中综合分旁边显示一个“高风险”标记。5.4 评测数据的横向对比价值Agent-Reach除了单次评测更大的价值在于横向对比。我在一个项目里同时评测了三个Agent方案纯Prompt工程方案、ReAct框架方案、带自反思机制的方案。纯Prompt方案触达深度0.42路径纯度0.88障碍消化率0.31典型的“短跑稳定、长跑崩溃”型选手ReAct框架方案触达深度0.68路径纯度0.71障碍消化率0.58中规中矩自反思机制方案触达深度0.79路径纯度0.65障碍消化率0.74虽然路径纯度不高但明显更能扛长程任务、更有“带回弹能力”。这个对比结果非常有说服力。它不是笼统地说哪个方案好而是精确指出每个方案的优劣维度。最后客户选择自反思机制方案因为业务场景是多轮跨系统操作长程稳定比短期效率更重要。6. 后续扩展方向Agent-Reach目前已经有能力支撑常规Agent评测但我觉得还有三个很值得扩展的方向。第一是多Agent协作评测。现在的指标体系主要针对单Agent任务链路但真实业务里经常是多个Agent协作干活一个Agent做分析另一个Agent做执行中间还有交接。可以扩展出“协作触达”指标衡量Agent之间交接信息的完整性和时效性。第二是动态拓扑。目前评测任务拓扑是预先定义好的Agent没有能力在任务中途发现新的子目标并扩展现有拓扑。下一版想加入“开放节点”机制允许Agent在特定条件下扩展任务图扩展出来的节点被视为一条额外触达路径。第三是成本约束评测。现在Agent跑任务很贵多两步调用就是多不少token费用。希望在评分里加入“触达成本效率”综合分除以总token消耗看看这个Agent花多少钱才能触达一个必达节点。低成本长触达的Agent在实际选型里往往比高触达高成本的Agent更实用毕竟老板们最后看的还是划算不划算。我自己跑了这么多轮Agent-Reach之后最大的感受是评测不是给Agent找麻烦而是给Agent画地图。你连一个Agent在哪条路上能走多远都没量过就别指望它在生产环境里替你开车。把Agent-Reach当成一把尺子先把自家Agent的“脚力”量清楚再谈怎么优化这条路绝对比拍脑袋调prompt靠谱得多。以后你们团队引入新Agent方案的时候不妨也试试这套触达评估逻辑先用数据说话再决定让不让人家上线。