1. 模型换新反而变笨:一次让我改观的内部事故1.1 事故复盘:离线评估涨了,线上通过率却崩了我们团队长期维护一个面向内部员工的知识库问答 Agent,场景不复杂:员工提问,系统从文档库检索片段,再调用几个简单工具做汇总和跳转。立项那会儿,大家的共识是“瓶颈一定在模型侧”,所以整整两个多月都在折腾模型能力:换更强的基础模型、改写提示词、堆更复杂的思维链示例。离线测试集上指标确实在涨,从 70% 出头一路爬到 80% 多,我们还挺满意,觉得离上线就差一步。结果那一步差点把项目踩翻。把新模型切到预发环境跑真实流量后,任务通过率不但没涨,反而比旧版本跌了将近 15 个百分点。最诡异的是,人工抽查时新模型的回答质量明显更高,语言更自然,推理链条也更清晰,可一旦落到系统里,大量请求在中途就“报废”了。翻了一下午日志才定位到根因:旧版模型每次调用工具都老老实实返回固定结构的 JSON,新模型更强了,开始在自由文本里混入工具参数,或者把参数顺序、嵌套层级按自己的习惯调整——而调用层的解析器依然只认老结构,于是一条条请求全部卡死在解析环节。这件事给我的冲击很大。我们花了大量精力在模型侧追求更高的“纸面智商”,却忽略了外围那套工程框架:谁来定义工具调用协议,谁来校验和兜底,谁来管理上下文,谁来观测每一轮决策。新模型明明更聪明,系统却因为外包壳没有跟上而整体变笨。那之后我基本认同一个判断:Agent 能力的决定因素,大头不在模型本身,而在围绕模型构建的 Harness。1.2 模型是纸面上限,Harness 是最终下限先说清楚我这里的“Harness”指什么。它不是一个神秘的新技术名词,而是软件工程里早就有的概念,原意是“测试脚手架、支撑装置”。放在 Agent 场景里,就是围绕大语言模型搭起来的那整套工程骨架:上下文如何组装、工具如何被调用和校验、循环何时终止、失败怎么处理、每一步怎么被观测、操作边界在哪里。模型能力决定的是系统的“纸面上限”——理论上它能解决多难的问题,推理多复杂。这个上限很重要,但用户感受到的永远不是纸面上限,而是实际下限:一百个请求里有多少个被正确、稳定、及时地处理完。而真正决定这个下限的,不是模型智商,而是 Harness 的质量。模型再聪明,只要上下文被塞爆、工具参数解析不了、失败后没有重试、出错后没人知道,用户体验就一定垮。举一个不那么技术圈的例子:一台车能跑多快,确实取决于发动机;但一辆车能不能安全地把人从 A 送到 B,取决于底盘、转向、刹车、轮胎、仪表盘这些“外围系统”。发动机天天换代,底盘散架了照样出事故。Agent 也一样:模型进步的速度肉眼可见,但如果 Harness 只停留在“能跑通一个 demo”的水平,那系统就永远停留在 demo 的可靠性上。这也是这篇文章想说的核心:Agent 很强,但 Harness 才是那个决定成败的东西。2. 给 Harness 画个像:一次 Agent 调用完整链路里到底谁在兜底2.1 从用户输入到最终回答,七个必须被工程化的节点很多人理解 Agent 就是把请求发给模型,然后拿结果。一旦开始搭真实系统就会发现,一次普通调用背后至少要经过七个节点,而每个节点都有大量的工程决策:接收用户输入:先做意图分类、敏感词过滤、身份与权限识别。这一步做不好,后面全白搭。上下文组装:从长期记忆、检索系统里拉取相关资料,在 token 预算内拼装成模型真正看到的 prompt。这里决定了“模型有没有足够且干净的信息”。模型决策:模型根据上下文决定是直接作答,还是调用某个工具。这一步是模型的“主场”,但也最容易跑偏。参数校验:模型说要调用工具,参数是否合法、枚举值是否正确、有没有越权访问?服务端必须二次把关。工具执行:真正去查数据库、调接口、执行操作,拿到结构化结果。结果回填:把工具返回的内容拼回上下文,让模型判断“是不是已经够了,还是需要再调用一次”。输出生成与审计:生成最终回答,做内容过滤、格式修复,写入日志和 trace。不难发现,真正属于模型发挥的只有第 3 步和部分第 7 步,其余全部是 Harness 的职责。如果第 2 步上下文组装混乱,模型再聪明也答不到点子上;如果第 4 步参数校验形同虚设,工具调用就会变成一场灾难。我见过太多失败的 Agent 项目,问题都出在第 3 步之外。提示:排查 Agent 问题时,不要只盯着“模型这次答得对不对”。先看请求在七个节点里走到哪一步断掉的,80% 的故障都在模型前后,而不是模型本身。2.2 Harness 的五个核心模块:上下文、契约、循环、观测、边界如果把七个节点往上抽象一层,Harness 可以拆成五个核心模块,每个模块都有明确职责。第一是上下文总线。它负责信息编排,包括对话历史的存取、长文本的摘要压缩、检索片段的选择与排序、系统提示词的固定与保护。上下文总线是 Agent 的“短期工作记忆”,管理不好它,模型就会表现出一副“什么都记不住”的样子。很多长会话场景里的失忆问题,本质都是上下文预算策略出了问题,而不是模型笨。第二是工具契约。模型不是一个稳定的程序调用者,它天然会“自由发挥”。工具契约就是在这里做硬约束:定义清楚每个工具有什么参数、参数类型是什么、哪些必填、哪些枚举可选,然后用服务端校验器强制检查。工具契约越严谨,模型的输出越容易被约束在安全区域内。我在下一章会专门讲,这个模块可以救回大量“模型乱输出”导致的问题。第三是控制循环。Agent 的核心特性是“可以反复决策、调用工具、再决策”,那循环就必须有控制:最多允许几轮、单轮超时多久、什么条件可以提前终止、要不要设置 token 总预算上限。如果没有这套控制,一个稍微复杂的任务就可能让模型陷入自我对话,既不收敛,还白烧 token。第四是可观测体系。每一个请求都应该能追踪完整决策链:模型中间输出了什么、选了什么工具、工具返回了什么、发生了多少次上下文压缩、有没有触发重试。没有观测,Agent 就是一个黑盒,出问题只能靠猜。观测体系是 Harness 里最容易被砍掉、但后期最值得投入的部分。第五是边界与权限。模型能触达哪些工具、哪些数据,敏感操作要不要人工确认,执行环境是否隔离,所有操作有没有审计日志。边界模块不是用来限制功能的,而是保证系统在出错时不至于造成真实损失。权限设计得越清楚,越敢让 Agent 去碰更高价值的任务。五个模块之间不是独立存在的。工具契约错了会被可观测体系记录下来,控制循环能根据失败率决定要不要熔断,上下文总线决定工具返回结果怎么被底层模型接收。它们共同构成了一个 Agent 系统的稳定底盘,也就是标题里说的 Harness。3. 我踩过的三个 Harness 坑,以及后来落地的解法3.1 上下文管理失控:长会话聊到一半直接“失忆”第一个让我印象深刻的问题,来自一个长会话客服机器人。用户和系统连续对话十几轮之后,模型开始反复问“你刚才说什么来着”,或者完全忽略最开始的诉求。起初我们怀疑是模型窗口太小,后来一查日志才明白:Harness 策略太粗暴,直接把全部聊天记录和检索片段一股脑拼进上下文,token 一超就由模型“自行取舍”。问题就出在这个“自行取舍”上。基础模型看到超长上下文时,注意力会被前后部分吃掉,系统提示词里的规则也容易被淹没,用户早期的关键信息反而被挤掉了。模型不是失忆,是整个上下文已经被无意义的信息污染了。后来我们改成四段式预算管理:系统指令区占用固定预算、对话历史区采用滚动摘要、检索结果区每次只保留分数最高的片段、中间推理过程单独控制长度。当历史超过预算时,不是直接截断,而是把更早的内容交给一个小模型做分层摘要,保留关键实体和未完成事项。这个改动上线后,长会话的满意度明显回升。3.2 工具调用缺少约束:模型自由发挥,解析全线崩溃这就是开头那次事故的核心问题。模型升级之后,输出格式开始变得“灵活”,旧的解析器完全跟不上。后来我们梳理了一遍,发现典型失败有三种:参数顺序和旧 schema 不一致、多工具调用混在一条回复里、嵌套对象少了层级。我们的解法分三层。第一层是约束层:启用结构化输出能力,把工具契约写进系统提示词,并同时提供 JSON Schema 作为强制校验依据。第二层是校验层:服务端对所有工具参数做二次校验,类型不对就拒绝,枚举值不在范围内就拒绝,校验失败不直接抛错,而是把结构化错误信息返回给模型,让它“修改自己的调用”。第三层是修复层:允许模型针对校验失败做一次自我修正,最多重试一到两次。这套机制跑下来,工具调用的解析成功率从 80% 上下拉到 98% 以上。关键变化是:不再把“模型输出什么”当作理所当然,而是默认它有乱写的可能,然后用 Harness 去纠正它。3.3 评测和观测滞后:上线靠感觉,回滚靠猜我们早期的评测基本等于“离线样例 + 人工抽测”。离线样例就几十条,变化一多就失效;人工抽测样本量小,还赶上谁心情好谁打分。结果就是每次改动都不知道是变好了还是变坏了,线上一旦出问题,连回滚的勇气都没有。后来我们建立了三层评测观测体系。第一层是离线回归集:除了基础问答,还专门准备了一批“坏样本”,覆盖上下文超长、参数错误、工具失败、意图模糊等情况,每次改动 Harness 或模型都先跑一遍。第二层是真流回放:把线上匿名化请求录制下来,在离线环境重放,对比新旧版本的成功率、延迟和 token 消耗差异,这一层能抓出大量离线样例发现不了的回归。第三层是线上 trace 指标:每个请求绑定唯一标识,记录完整决策链。从这里开始,我们才真正做到了“改什么都敢上线”,因为判断依据从“感觉”变成了回归报告。这套体系后来成为团队内部的底线要求。4. 把 Harness 从“能用”调到“好用”的几个关键取舍4.1 在工具协议层,稳定永远优先于灵活做 Harness 的过程中,我反复遇到同一个问题:要不要给模型更多自由发挥空间?比如允许它自由输出一段文字再附带一个模糊的“动作意图”,或者允许没有任何格式约束的自然语言调用。直觉上,灵活性意味着更强的表达力;但工程上,灵活性往往意味着更低的稳定性。我们最后的原则是:协议层宁可“笨”一点,也要稳定。工具调用必须落到严格的结构化 schema 上,必填字段必须有,枚举值必须限定,类型错误必须拦截。模型的创造力应该发挥在任务理解和推理过程上,而不是发挥在“怎么描述工具参数”上。想通这一点后,很多纠结立刻消失了。当然,完全死板也有副作用。有的场景下模型确实需要用自然语言来表达模糊诉求,比如“帮我查一下最近类似的工单”——这里我们不会逼迫它选一个固定参数,而是提供意图识别工具,先把自然语言转成一个待确认的结构化参数,再做后续调用。这个折中保留了必要的灵活性,却没有破坏协议层的稳定性。4.2 上下文预算管理:给每类信息固定配额,超出就压缩而不是硬塞上下文预算管理是我认为 Harness 里最值得精细化投入的部分。很多问题表面是“模型变笨了”,实际是“信息配比失衡了”。一条指令、一大段历史、六七个检索片段、工具返回的长表格全部挤在一起,模型根本不知道该重点看哪块。我们后来把上下文拆成四个预算区,每个区单独设上限。下面是一份示例配置,实际数值按业务调整:区域预算占比超出策略系统指令与工具说明15%固定不变,绝不压缩对话历史摘要25%旧内容滚入摘要,保留关键实体与未完成任务检索结果与工具结果40%按相关性阈值截断,低分片段直接丢弃模型中间推理预留20%为思维链和最终生成留出空间这套配置背后有一个核心原则:检索必须在组装上下文之前完成,先筛选再拼接,而不是把所有内容一股脑塞进去。超出预算时,优先压缩历史、保留最新;牺牲检索片段时,优先保留与当前问题相关性高的部分;系统指令永远不动。实践下来,同样一个模型,只靠调整预算配比就能让效果出现可感知的提升。4.3 可观测指标:定位问题是出在模型还是 Harness可观测体系最大的价值,是把模糊的“系统不行”变成具体的“某个模块不行”。我们内部长期追踪一组关键指标,每次发布都拿它们说话:指标含义我常用的阈值参考任务成功率完整跑完一次用户请求的比例越高越好,低于 90% 立即告警工具调用失败率工具执行返回错误的占比超过 5% 就要排查工具侧解析重试率模型输出未通过校验,需要自我修正的占比超过 10% 说明约束或提示词有问题平均循环数一次请求中模型决策的轮数超过 5 轮通常说明上下文信息不足单任务 token 消耗包含重试在内的总消耗环比突增 20% 以上要查上下文预算端到端延迟从用户输入到最终输出超过哨兵阈值多数是工具调用拖慢配套的是 trace 记录:每次请求一个 trace id,每一轮都记录模型返回原文、工具返回结果、上下文压缩事件、重试原因。这样前端反馈“不好用”时,我们拿到 trace id 就能直接看到是模型答错、工具挂掉、还是检索没召回。没有这套体系时,排查一个线上问题平均要半天;有了以后,大多数问题在十分钟内就能定位到具体模块。5. Harness 的兜底设计:当模型犯错,系统怎么保持体面5.1 失败分类是兜底的第一步模型一定会犯错,Harness 要考虑的不是“怎么让模型不犯错”,而是“错误发生后系统怎么表现”。我们内部把失败分成几类,每一类对应不同的处理策略。失败类型常见原因典型表现解析失败模型输出不符合工具契约参数缺失、类型不对、嵌套结构错误工具异常底层接口报错、数据源超时工具返回错误码或异常消息上下文污染历史摘要失真、检索片段冲突模型答非所问、重要信息被忽略逻辑失误模型理解错了目标、工具选错调用了无关工具、结果与问题不匹配权限冲突操作超出用户或系统边界模型试图执行被禁止的动作分类最大的意义,是为了不“一刀切”。解析失败适合自修复重试,工具异常适合等待或降级,权限冲突绝对不能自动重试,逻辑失误则可能需要重新检索并重新生成。把失败分类写进 Harness,兜底逻辑才有的放矢。5.2 重试、降级与熔断,处理工具故障的三种姿势工具调用不会永远稳定,外层 Harness 必须给它们设计故障处理策略。重试要克制。大部分工具报错属于瞬时问题,比如网络抖动、数据库连接超时,指数退避重试一到三次就能解决。但重试不是越多越好,一个已经稳定报错的接口,重试十次只会加剧负载。所以我们的规则是:每次重试间隔翻倍,累计超过三次就停止,不再白耗资源。降级要提前设计。某个核心工具不可用时,Harness 要有预案:是走简化流程、换一个近似工具,还是直接告知用户“暂时无法完成该操作”。降级方案要在工具层定义好,不能等事故发生后临时商量。熔断要果断。当工具连续失败率达到阈值,比如 30 秒内超过三成请求失败,Harness 会自动熔断该工具调用链,后续请求直接跳过它,转人工或转备选路径,过一段时间再半开试探恢复。因为熔断一旦启动,目的就是保护下游系统和产品体验,哪怕暂时牺牲部分功能,也比全链路雪崩强。5.3 权限与人工确认:宁可慢一点,也不能让模型拿着钥匙随便开门最后一个兜底是边界。Agent 能调用的工具,权限必须显式配置:能查什么数据、不能查什么数据、能执行什么操作、不能执行什么操作。敏感动作,比如发消息、删除数据、修改配置,不能“模型说做就做”,必须由用户显式确认,或者至少设置二次校验。我在实践中把 Harness 视为“交警”而不是“代办”:它负责判断这辆车能不能上路、要在哪个车道、什么时候该停,而不是替驾驶者全权决定一切。有一次我们放开了某个 Agent 的自动执行权限,结果模型因为理解错了用户句子的指代,差一点执行一条实际不该执行的删除操作。从那以后,凡是高影响动作,默认都加人工确认节点。用户端多一步确认,换来的是整个系统的安全余量。这种“慢一点但稳一点”的设计,才是 Agent 能放心交给真实用户使用的前提。模型可以很强,但只有 Harness 把门守住了,强才有意义。
1. 模型换新反而变笨:一次让我改观的内部事故1.1 事故复盘:离线评估涨了,线上通过率却崩了我们团队长期维护一个面向内部员工的知识库问答 Agent,场景不复杂:员工提问,系统从文档库检索片段,再调用几个简单工具做汇总和跳转。立项那会儿,大家的共识是“瓶颈一定在模型侧”,所以整整两个多月都在折腾模型能力:换更强的基础模型、改写提示词、堆更复杂的思维链示例。离线测试集上指标确实在涨,从 70% 出头一路爬到 80% 多,我们还挺满意,觉得离上线就差一步。结果那一步差点把项目踩翻。把新模型切到预发环境跑真实流量后,任务通过率不但没涨,反而比旧版本跌了将近 15 个百分点。最诡异的是,人工抽查时新模型的回答质量明显更高,语言更自然,推理链条也更清晰,可一旦落到系统里,大量请求在中途就“报废”了。翻了一下午日志才定位到根因:旧版模型每次调用工具都老老实实返回固定结构的 JSON,新模型更强了,开始在自由文本里混入工具参数,或者把参数顺序、嵌套层级按自己的习惯调整——而调用层的解析器依然只认老结构,于是一条条请求全部卡死在解析环节。这件事给我的冲击很大。我们花了大量精力在模型侧追求更高的“纸面智商”,却忽略了外围那套工程框架:谁来定义工具调用协议,谁来校验和兜底,谁来管理上下文,谁来观测每一轮决策。新模型明明更聪明,系统却因为外包壳没有跟上而整体变笨。那之后我基本认同一个判断:Agent 能力的决定因素,大头不在模型本身,而在围绕模型构建的 Harness。1.2 模型是纸面上限,Harness 是最终下限先说清楚我这里的“Harness”指什么。它不是一个神秘的新技术名词,而是软件工程里早就有的概念,原意是“测试脚手架、支撑装置”。放在 Agent 场景里,就是围绕大语言模型搭起来的那整套工程骨架:上下文如何组装、工具如何被调用和校验、循环何时终止、失败怎么处理、每一步怎么被观测、操作边界在哪里。模型能力决定的是系统的“纸面上限”——理论上它能解决多难的问题,推理多复杂。这个上限很重要,但用户感受到的永远不是纸面上限,而是实际下限:一百个请求里有多少个被正确、稳定、及时地处理完。而真正决定这个下限的,不是模型智商,而是 Harness 的质量。模型再聪明,只要上下文被塞爆、工具参数解析不了、失败后没有重试、出错后没人知道,用户体验就一定垮。举一个不那么技术圈的例子:一台车能跑多快,确实取决于发动机;但一辆车能不能安全地把人从 A 送到 B,取决于底盘、转向、刹车、轮胎、仪表盘这些“外围系统”。发动机天天换代,底盘散架了照样出事故。Agent 也一样:模型进步的速度肉眼可见,但如果 Harness 只停留在“能跑通一个 demo”的水平,那系统就永远停留在 demo 的可靠性上。这也是这篇文章想说的核心:Agent 很强,但 Harness 才是那个决定成败的东西。2. 给 Harness 画个像:一次 Agent 调用完整链路里到底谁在兜底2.1 从用户输入到最终回答,七个必须被工程化的节点很多人理解 Agent 就是把请求发给模型,然后拿结果。一旦开始搭真实系统就会发现,一次普通调用背后至少要经过七个节点,而每个节点都有大量的工程决策:接收用户输入:先做意图分类、敏感词过滤、身份与权限识别。这一步做不好,后面全白搭。上下文组装:从长期记忆、检索系统里拉取相关资料,在 token 预算内拼装成模型真正看到的 prompt。这里决定了“模型有没有足够且干净的信息”。模型决策:模型根据上下文决定是直接作答,还是调用某个工具。这一步是模型的“主场”,但也最容易跑偏。参数校验:模型说要调用工具,参数是否合法、枚举值是否正确、有没有越权访问?服务端必须二次把关。工具执行:真正去查数据库、调接口、执行操作,拿到结构化结果。结果回填:把工具返回的内容拼回上下文,让模型判断“是不是已经够了,还是需要再调用一次”。输出生成与审计:生成最终回答,做内容过滤、格式修复,写入日志和 trace。不难发现,真正属于模型发挥的只有第 3 步和部分第 7 步,其余全部是 Harness 的职责。如果第 2 步上下文组装混乱,模型再聪明也答不到点子上;如果第 4 步参数校验形同虚设,工具调用就会变成一场灾难。我见过太多失败的 Agent 项目,问题都出在第 3 步之外。提示:排查 Agent 问题时,不要只盯着“模型这次答得对不对”。先看请求在七个节点里走到哪一步断掉的,80% 的故障都在模型前后,而不是模型本身。2.2 Harness 的五个核心模块:上下文、契约、循环、观测、边界如果把七个节点往上抽象一层,Harness 可以拆成五个核心模块,每个模块都有明确职责。第一是上下文总线。它负责信息编排,包括对话历史的存取、长文本的摘要压缩、检索片段的选择与排序、系统提示词的固定与保护。上下文总线是 Agent 的“短期工作记忆”,管理不好它,模型就会表现出一副“什么都记不住”的样子。很多长会话场景里的失忆问题,本质都是上下文预算策略出了问题,而不是模型笨。第二是工具契约。模型不是一个稳定的程序调用者,它天然会“自由发挥”。工具契约就是在这里做硬约束:定义清楚每个工具有什么参数、参数类型是什么、哪些必填、哪些枚举可选,然后用服务端校验器强制检查。工具契约越严谨,模型的输出越容易被约束在安全区域内。我在下一章会专门讲,这个模块可以救回大量“模型乱输出”导致的问题。第三是控制循环。Agent 的核心特性是“可以反复决策、调用工具、再决策”,那循环就必须有控制:最多允许几轮、单轮超时多久、什么条件可以提前终止、要不要设置 token 总预算上限。如果没有这套控制,一个稍微复杂的任务就可能让模型陷入自我对话,既不收敛,还白烧 token。第四是可观测体系。每一个请求都应该能追踪完整决策链:模型中间输出了什么、选了什么工具、工具返回了什么、发生了多少次上下文压缩、有没有触发重试。没有观测,Agent 就是一个黑盒,出问题只能靠猜。观测体系是 Harness 里最容易被砍掉、但后期最值得投入的部分。第五是边界与权限。模型能触达哪些工具、哪些数据,敏感操作要不要人工确认,执行环境是否隔离,所有操作有没有审计日志。边界模块不是用来限制功能的,而是保证系统在出错时不至于造成真实损失。权限设计得越清楚,越敢让 Agent 去碰更高价值的任务。五个模块之间不是独立存在的。工具契约错了会被可观测体系记录下来,控制循环能根据失败率决定要不要熔断,上下文总线决定工具返回结果怎么被底层模型接收。它们共同构成了一个 Agent 系统的稳定底盘,也就是标题里说的 Harness。3. 我踩过的三个 Harness 坑,以及后来落地的解法3.1 上下文管理失控:长会话聊到一半直接“失忆”第一个让我印象深刻的问题,来自一个长会话客服机器人。用户和系统连续对话十几轮之后,模型开始反复问“你刚才说什么来着”,或者完全忽略最开始的诉求。起初我们怀疑是模型窗口太小,后来一查日志才明白:Harness 策略太粗暴,直接把全部聊天记录和检索片段一股脑拼进上下文,token 一超就由模型“自行取舍”。问题就出在这个“自行取舍”上。基础模型看到超长上下文时,注意力会被前后部分吃掉,系统提示词里的规则也容易被淹没,用户早期的关键信息反而被挤掉了。模型不是失忆,是整个上下文已经被无意义的信息污染了。后来我们改成四段式预算管理:系统指令区占用固定预算、对话历史区采用滚动摘要、检索结果区每次只保留分数最高的片段、中间推理过程单独控制长度。当历史超过预算时,不是直接截断,而是把更早的内容交给一个小模型做分层摘要,保留关键实体和未完成事项。这个改动上线后,长会话的满意度明显回升。3.2 工具调用缺少约束:模型自由发挥,解析全线崩溃这就是开头那次事故的核心问题。模型升级之后,输出格式开始变得“灵活”,旧的解析器完全跟不上。后来我们梳理了一遍,发现典型失败有三种:参数顺序和旧 schema 不一致、多工具调用混在一条回复里、嵌套对象少了层级。我们的解法分三层。第一层是约束层:启用结构化输出能力,把工具契约写进系统提示词,并同时提供 JSON Schema 作为强制校验依据。第二层是校验层:服务端对所有工具参数做二次校验,类型不对就拒绝,枚举值不在范围内就拒绝,校验失败不直接抛错,而是把结构化错误信息返回给模型,让它“修改自己的调用”。第三层是修复层:允许模型针对校验失败做一次自我修正,最多重试一到两次。这套机制跑下来,工具调用的解析成功率从 80% 上下拉到 98% 以上。关键变化是:不再把“模型输出什么”当作理所当然,而是默认它有乱写的可能,然后用 Harness 去纠正它。3.3 评测和观测滞后:上线靠感觉,回滚靠猜我们早期的评测基本等于“离线样例 + 人工抽测”。离线样例就几十条,变化一多就失效;人工抽测样本量小,还赶上谁心情好谁打分。结果就是每次改动都不知道是变好了还是变坏了,线上一旦出问题,连回滚的勇气都没有。后来我们建立了三层评测观测体系。第一层是离线回归集:除了基础问答,还专门准备了一批“坏样本”,覆盖上下文超长、参数错误、工具失败、意图模糊等情况,每次改动 Harness 或模型都先跑一遍。第二层是真流回放:把线上匿名化请求录制下来,在离线环境重放,对比新旧版本的成功率、延迟和 token 消耗差异,这一层能抓出大量离线样例发现不了的回归。第三层是线上 trace 指标:每个请求绑定唯一标识,记录完整决策链。从这里开始,我们才真正做到了“改什么都敢上线”,因为判断依据从“感觉”变成了回归报告。这套体系后来成为团队内部的底线要求。4. 把 Harness 从“能用”调到“好用”的几个关键取舍4.1 在工具协议层,稳定永远优先于灵活做 Harness 的过程中,我反复遇到同一个问题:要不要给模型更多自由发挥空间?比如允许它自由输出一段文字再附带一个模糊的“动作意图”,或者允许没有任何格式约束的自然语言调用。直觉上,灵活性意味着更强的表达力;但工程上,灵活性往往意味着更低的稳定性。我们最后的原则是:协议层宁可“笨”一点,也要稳定。工具调用必须落到严格的结构化 schema 上,必填字段必须有,枚举值必须限定,类型错误必须拦截。模型的创造力应该发挥在任务理解和推理过程上,而不是发挥在“怎么描述工具参数”上。想通这一点后,很多纠结立刻消失了。当然,完全死板也有副作用。有的场景下模型确实需要用自然语言来表达模糊诉求,比如“帮我查一下最近类似的工单”——这里我们不会逼迫它选一个固定参数,而是提供意图识别工具,先把自然语言转成一个待确认的结构化参数,再做后续调用。这个折中保留了必要的灵活性,却没有破坏协议层的稳定性。4.2 上下文预算管理:给每类信息固定配额,超出就压缩而不是硬塞上下文预算管理是我认为 Harness 里最值得精细化投入的部分。很多问题表面是“模型变笨了”,实际是“信息配比失衡了”。一条指令、一大段历史、六七个检索片段、工具返回的长表格全部挤在一起,模型根本不知道该重点看哪块。我们后来把上下文拆成四个预算区,每个区单独设上限。下面是一份示例配置,实际数值按业务调整:区域预算占比超出策略系统指令与工具说明15%固定不变,绝不压缩对话历史摘要25%旧内容滚入摘要,保留关键实体与未完成任务检索结果与工具结果40%按相关性阈值截断,低分片段直接丢弃模型中间推理预留20%为思维链和最终生成留出空间这套配置背后有一个核心原则:检索必须在组装上下文之前完成,先筛选再拼接,而不是把所有内容一股脑塞进去。超出预算时,优先压缩历史、保留最新;牺牲检索片段时,优先保留与当前问题相关性高的部分;系统指令永远不动。实践下来,同样一个模型,只靠调整预算配比就能让效果出现可感知的提升。4.3 可观测指标:定位问题是出在模型还是 Harness可观测体系最大的价值,是把模糊的“系统不行”变成具体的“某个模块不行”。我们内部长期追踪一组关键指标,每次发布都拿它们说话:指标含义我常用的阈值参考任务成功率完整跑完一次用户请求的比例越高越好,低于 90% 立即告警工具调用失败率工具执行返回错误的占比超过 5% 就要排查工具侧解析重试率模型输出未通过校验,需要自我修正的占比超过 10% 说明约束或提示词有问题平均循环数一次请求中模型决策的轮数超过 5 轮通常说明上下文信息不足单任务 token 消耗包含重试在内的总消耗环比突增 20% 以上要查上下文预算端到端延迟从用户输入到最终输出超过哨兵阈值多数是工具调用拖慢配套的是 trace 记录:每次请求一个 trace id,每一轮都记录模型返回原文、工具返回结果、上下文压缩事件、重试原因。这样前端反馈“不好用”时,我们拿到 trace id 就能直接看到是模型答错、工具挂掉、还是检索没召回。没有这套体系时,排查一个线上问题平均要半天;有了以后,大多数问题在十分钟内就能定位到具体模块。5. Harness 的兜底设计:当模型犯错,系统怎么保持体面5.1 失败分类是兜底的第一步模型一定会犯错,Harness 要考虑的不是“怎么让模型不犯错”,而是“错误发生后系统怎么表现”。我们内部把失败分成几类,每一类对应不同的处理策略。失败类型常见原因典型表现解析失败模型输出不符合工具契约参数缺失、类型不对、嵌套结构错误工具异常底层接口报错、数据源超时工具返回错误码或异常消息上下文污染历史摘要失真、检索片段冲突模型答非所问、重要信息被忽略逻辑失误模型理解错了目标、工具选错调用了无关工具、结果与问题不匹配权限冲突操作超出用户或系统边界模型试图执行被禁止的动作分类最大的意义,是为了不“一刀切”。解析失败适合自修复重试,工具异常适合等待或降级,权限冲突绝对不能自动重试,逻辑失误则可能需要重新检索并重新生成。把失败分类写进 Harness,兜底逻辑才有的放矢。5.2 重试、降级与熔断,处理工具故障的三种姿势工具调用不会永远稳定,外层 Harness 必须给它们设计故障处理策略。重试要克制。大部分工具报错属于瞬时问题,比如网络抖动、数据库连接超时,指数退避重试一到三次就能解决。但重试不是越多越好,一个已经稳定报错的接口,重试十次只会加剧负载。所以我们的规则是:每次重试间隔翻倍,累计超过三次就停止,不再白耗资源。降级要提前设计。某个核心工具不可用时,Harness 要有预案:是走简化流程、换一个近似工具,还是直接告知用户“暂时无法完成该操作”。降级方案要在工具层定义好,不能等事故发生后临时商量。熔断要果断。当工具连续失败率达到阈值,比如 30 秒内超过三成请求失败,Harness 会自动熔断该工具调用链,后续请求直接跳过它,转人工或转备选路径,过一段时间再半开试探恢复。因为熔断一旦启动,目的就是保护下游系统和产品体验,哪怕暂时牺牲部分功能,也比全链路雪崩强。5.3 权限与人工确认:宁可慢一点,也不能让模型拿着钥匙随便开门最后一个兜底是边界。Agent 能调用的工具,权限必须显式配置:能查什么数据、不能查什么数据、能执行什么操作、不能执行什么操作。敏感动作,比如发消息、删除数据、修改配置,不能“模型说做就做”,必须由用户显式确认,或者至少设置二次校验。我在实践中把 Harness 视为“交警”而不是“代办”:它负责判断这辆车能不能上路、要在哪个车道、什么时候该停,而不是替驾驶者全权决定一切。有一次我们放开了某个 Agent 的自动执行权限,结果模型因为理解错了用户句子的指代,差一点执行一条实际不该执行的删除操作。从那以后,凡是高影响动作,默认都加人工确认节点。用户端多一步确认,换来的是整个系统的安全余量。这种“慢一点但稳一点”的设计,才是 Agent 能放心交给真实用户使用的前提。模型可以很强,但只有 Harness 把门守住了,强才有意义。