Agent 效果差,先别怪模型:一份从 Harness 到引擎的排障顺序
Agent 效果变差时,大多数人的第一反应是"模型不行,换一个"。
但在排查顺序里,模型应该排在最后:先查 Harness,再查引擎配置,最后才怀疑权重。
这个顺序不是拍脑袋定的,是从三层的职责推出来的——模型能力由权重给,权重能不能被发挥,环境有否决权。
一、能力由权重给,发挥被环境卡
同一份权重,放进不同的环境,表现可以差很多。
这不是新结论:模型不动,只改系统提示、上下文注入和验证钩子,表现就能差出一截。模型没变,架子变了。
所以"效果差"要先分成两种:一种是能力不够,一种是能力没用上。前者才需要换模型,后者换模型只是把问题换了个地方藏。
换模型还有一个隐性代价:变量变多了。
原来的问题还没定位,你就同时改了权重、改了对话模板、改了工具解析的行为。哪怕新模型表现变好了,你也不知道是哪一项起了作用;如果变差了,你更不知道从哪查起。
补一句成本账:换模型要重新跑一遍评测集,重新调提示,重新做工具调用(tool call)格式的兼容。这三件事加起来,通常比查一遍配置贵得多。
有一条判断可以先立住:如果同一个模型在干净环境里能过这条任务,问题就不在模型。
干净环境指的是:最小上下文、明确的工具描述、没有历史包袱、权限全开的一次单轮请求。这一步能过,后面要查的都是环境。
图 1 排查顺序:先 Harness,再引擎配置,最后才怀疑模型。同一层不通过,就停在该层修。
二、第一层:提示、上下文、工具定义、权限
Harness 是模型外面那一整圈环境——主循环、工具层、上下文管理、记忆、权限与沙箱、验证与可观测。这一层出问题,表现和内层几乎一样:答得不对。
四个高频项按顺序看。
系统提示有没有被改过。 现象通常是行为风格突然变了,或者原本遵守的输出格式开始不守。验证方法很土但有效:把当前提示和上一次表现正常的版本做 diff,拿旧提示跑同一批任务做回归。很多"模型变笨"最后查出来是一次顺手改的提示没进版本库。
上下文是不是被塞爆了。 现象是长会话跑到后面开始忘事,前面说过的约束不再遵守,或者答非所问。验证办法是看每轮实际注入的 token 用量,以及有没有触发截断或压缩。上下文工程做得再好,注入顺序一变、旧约束被压到很后面,效果也会掉。
工具描述是不是含糊。 现象是参数填错位置、该调的工具没调、调了个语义相近但不对的工具。验证办法是拿单个工具做定向测试:只给它一个工具,描述改成两版,看调用成功率差多少。工具描述越含糊,模型越是在猜。
权限有没有把该放行的操作拦住。 这一项最容易被误判成模型能力问题。现象是模型说要执行、但什么也没发生,或者同一操作反复重试。验证办法是看宿主侧的拒绝记录——拒绝发生在宿主,不在模型,模型通常不知道自己的动作被挡了。
合成案例一(非特定项目,数字示意)
现象:一个处理售后的 Agent 上线两周后开始跳过订单核验,直接发起退款,偶尔还会把两个订单号混在一起。团队第一反应是模型退化了。
排查:先按 Harness 四项过一遍。提示做 diff,发现两周前有人为了"回答更简洁"删掉了"先核验再操作"的约束;工具描述没动;上下文没有触发截断;权限规则也没变。
定位:问题在提示和校验钩子两处。约束被删之后,模型不再把核验当成必经步骤;同时校验钩子被挪到了最终回复前,等于错误已经发生才被检查。
修复前后:把约束写回提示,把钩子移回工具执行前。同一批回放任务里(200 条,示意),未核验就退款的比例从 12% 降到 1% 以下。
这一层还有一个结构性难点:四类问题的表现彼此重合。
所以不能从表现反推层,只能按顺序排除。你先假定是 Harness,把四项过一遍;四项都干净,再往下走。跳步的代价是把两层的问题混在一起,最后得出"模型不行"这个错误结论。
三、第二层:量化、硬上限、缓存、解析器
Harness 干净之后,问题常常还在模型外面——在推理引擎的配置里。
这一层的特殊性在于:它不在你的提示词控制范围内,但它对结果有否决权。
量化精度。 同一份权重,Q4 和 FP16 在长链推理上的差距有时很明显,本地跑小模型时尤其明显。受影响最大的是需要精确格式输出和长步骤推理的任务:格式错一位、步骤漏一环,链路就断了。要注意分寸:这是"有时明显",不是"一定崩",具体差异要用自己的任务集测。
上下文硬上限。 引擎侧有一个 max_model_len 之类的硬闸。它先于 Harness 的上下文工程生效:你在上层做了压缩、做了裁剪、做了分层记忆,只要总长度还是超过这个闸,多余部分照样被截掉。
现象很典型:明明做了上下文管理,模型还是"没看到"某段内容。这时候要看的是引擎实际收到的长度,而不是你拼好的长度。
tool parser 的差异。 同一个模型换一个引擎,工具调用的解析成功率可能变。模型输出的文本形式差不多,但不同引擎对边界情况(多余字段、缺字段、多个调用并列、带解释文字)的处理不一样。
现象是:同一段输出,这个引擎能解析成结构化调用,那个引擎解析成空,然后宿主拿到空调用,模型被迫用自然语言硬答。
prefix caching 有没有命中。 它影响成本和延迟,也影响一致性。现象是两边的:命中时多轮对话明显变便宜;不命中时,改前面一句会让后面的行为整体漂移。
合成案例二(非特定项目,数字示意)
现象:同一套 Harness、同一份权重,迁到另一台机器后工具调用成功率明显下降,长任务跑到后半段开始重复调用同一个工具。
排查:Harness 四项都干净。转查引擎,发现部署时把精度换成了 Q4 量化档、max_model_len 被下调、推理后端也换了,新后端的 tool parser 对带解释文字的输出解析失败。
定位:两件事叠加。上下文硬上限先于 Harness 的裁剪生效,长任务在中途被截断,模型丢了之前的步骤记录,于是重复调用;解析器返回空的 tool_call,宿主把空结果当成自然语言继续走。
修复前后:精度调回 FP16 档、max_model_len 与上下文预算对齐、换回兼容的解析器。同一批评测里(数字示意),工具调用成功率从 71% 回到 94%,重复调用从平均 3 次降到 1 次以内。
这一层判断归属,可以用一条标准:这件事需不需要知道"任务是什么"?
需要知道任务的,归 Harness。比如这轮该不该压缩历史、这段结果要不要回灌。只需要知道模型结构的,归引擎。比如 KV cache 怎么分页、一次前向怎么批处理。这条标准比"它看起来像不像外部服务"可靠得多。
四、第三层:什么时候才该换模型
只有前两层都排除之后,才轮到模型。
而且到这一步,还要再分一次:是能力不足,还是能力没用对。
能力不足的判定标准是:同一任务,在干净环境、最小上下文、明确工具描述下,仍然稳定不达标。注意"稳定"两个字——偶尔错一次可能是采样或解析问题,稳定错才是能力问题。
能力没用对的判定标准是:换一种问法、换一种工具描述、换一种步骤拆法就能过,但换个模型也能过。这种情况换模型属于运气,不是定位。
真到要换的时候,把账算全:评测集要不要重跑、提示要不要重调、工具调用格式要不要重新适配、上下文长度要不要重新评估。这四项里任何一项没做,你都无法确认新模型真的更好。
还有一个容易忽略的点:不同模型对同一份 Harness 的敏感度不同。
一个在厚 Harness 下表现很好的模型,换到一个薄 Harness 里可能掉得厉害;反过来也一样。所以"换模型"实际上换的是"模型 + Harness"这组搭配,不是单独换一个零件。
五、按顺序打勾,不要跳步
排查的价值在顺序,不在清单长度。
- 先确认现象可复现:同一输入、同一配置,能稳定重现
- 系统提示与上次正常版本做 diff
- 检查本轮实际注入的 token 用量与截断/压缩记录
- 拿单个工具做定向测试,对比两版工具描述
- 查宿主侧的权限拒绝与执行失败记录
- 查引擎实际收到的长度,对照
max_model_len - 换一次引擎配置或解析器,看工具调用成功率
- 最后才在干净环境里单独评测模型本身
清单只有八行,但每一行都要能回答"通过还是没通过"。答不出来的,说明这一项还没查。
结尾
排障的核心不是"哪个模型更强",而是"这次到底是哪一层没让它发挥"。
顺序的价值在于:每排除一层,你就少一个变量;等排到模型那一层,剩下的问题才是真的属于它。
层搞混是排查里最常见的弯路:先分清哪一层,再决定查什么。