最近这半年,我越来越清晰地感觉到一个趋势:大家讨论 AI 智能体的时候,注意力正在从“模型选哪个、参数怎么调”转移到“模型外面那层壳怎么搭”。这层壳,在圈子里逐渐有了一个名字,叫 Harness Engineering。说白了,就是围绕大模型构建提示词、工具、状态、控制流程、评估机制的一整套工程。很多项目一开始跑得挺欢,一上真实流量就崩,问题根本不在模型智商,而是 Harness 太单薄。我自已也有一段被客服智能体“折腾到怀疑人生”的经历,把它修好之后,对智能体的稳定性有了完全不一样的理解。这篇就把我的认知和整个排查、改造的过程整理出来,希望能给正在做智能体开发的人省一点弯路。
1. 先搞清楚什么叫“智能体崩溃”
很多人一听到崩溃,第一反应就是程序报错、服务器 500、进程退出了。但做了智能体开发之后你会发现,真正的“崩溃”远比这隐蔽,它是智能体还在回复,但回复的内容已经脱离了你原本的设计目标。
1.1 崩溃不止是报错:三类最常见的翻车现场
我习惯把智能体崩溃分成三类。
第一类是“死循环型”。智能体调了一个查询订单接口,接口返回数据格式不符合预期,它不返回给用户,而是继续调用另一个工具尝试“修复”。第二个工具也失败,它又尝试第三个,最后在十几个工具调用之间来回横跳,像钻进了一个迷宫出不来。用户看不到过程,只看到页面一直转圈,最后超时。这类崩溃占了我遇到的情况大头。
第二类是“幻觉叠加型”。单次生成的大模型幻觉大家都能理解,但智能体场景里,幻觉会被工具调用结果持续放大。比如智能体读不到用户订单,就“合理推断”出一个订单号去查库,查不到就开始道歉并编造退款规则。表面上它在正常对话,实际上已经走上了错误逻辑链。这一类最危险,因为它不报错,日志里全是正常记录,业务方却接到大量投诉。
第三类是“规则漂移型”。早期你会给智能体写很长的系统提示词,规定它只能做订单查询,其他一律拒绝。结果它在长对话里逐渐“忘记”了这个限制,用户连续问了几次“你能帮我改地址吗”,它就从“很抱歉我不能”变成“好的,我来帮你尝试”,然后去调根本没有权限的接口。模型能力越强,这种模仿人类“妥协”的倾向就越明显。
三类的共同点,是问题都出在模型的外围,而不是模型本身。你换更强的模型,死循环还是会死循环,只是换一种姿势。
1.2 为什么模型越来越强,“崩溃”却越来越常见
这里有一个很反直觉的观察:模型本身越聪明,智能体越容易在不该发挥的地方“自由发挥”。传统软件系统的崩溃是可预期的,输入输出边界清晰;而智能体本质上是一段概率性文本生成过程参与的系统控制,同样的输入,两次生成可能走完全不同的路径。
模型变强带来的是更流畅的自然语言能力和更复杂的工具调用意图,但如果你没有一个强约束的外围框架,这些能力就会变成不可控变量。打个比方,一台发动机马力再大,底盘、转向、刹车没跟上,上路还是翻车。Harness 就是那个底盘。底盘不牢光换发动机,只会让翻车翻得更快。
这也是为什么这两年智能体领域的新趋势,不再是单纯比谁的模型好,而是比谁的外围工程能力强:谁能在模型之外把这个“壳”设计得足够鲁棒,谁家智能体就不容易翻车。
2. Harness Engineering 是什么:一句话版本和完整版本
这个概念还没有特别统一的严格定义,不同团队叫法也不完全一样。有人叫工程护栏,有人叫编排框架,有人干脆就叫“系统提示词工程”。我的理解很简单:Harness 是让大模型在特定任务里稳定完成任务的所有外围机制的总和。
2.1 一句话理解
如果把大模型想象成一个知识渊博但容易走神的新员工,Harness 就是你给他安排的工作台、作业指导书、审批流程和质检机制。工作台决定他能接触到什么工具,作业指导书决定他说话的边界,审批流程决定哪些动作必须停下来有人确认,质检机制决定他的产出是否达标。模型本身是“大脑”,Harness 是“工作环境”。
一开始我只把重心放在系统提示词上,觉得把提示词写得足够细,智能体就不会乱来。后来发现提示词只是 Harness 的一小块,甚至不是最重要的一块。一个设计良好的 Harness,可以达到用较小的模型加简单提示词,就能跑赢大模型加复杂提示词的稳定性。这不是我一家之言,圈子里很多团队实测都有类似结论。
2.2 Harness 五层拆解
我在实际项目中,通常把 Harness 拆成五层,每一层都有自己独立的关注点。
第一层是上下文层。系统和用户内容怎么组织,历史对话怎么保留,怎么截断,需要把哪些关键业务规则固定住。这一层最容易被低估,因为测试时特别短,上下文一长就暴露问题。比如智能体只保存最近 10 轮对话,用户在第 11 轮提到“刚才说的那个订单”,智能体已经完全不记得了,就会开始猜测,猜测就会出错。
第二层是工具层。工具的描述、参数定义、调用超时、异常返回格式,全部要单独设计。我见过太多项目把工具描述写得太含糊,结果模型根本不知道什么时候该用哪个工具,明明有查询接口,它偏要自己算一个答案出来。工具层理想状态是:每个工具都有明确的触发条件、完整的参数 schema、稳定的失败返回,并且失败返回里要包含可读的错误原因。
第三层是状态层。多轮任务里智能体执行到哪一步了,哪些信息已经拿到,哪些还没拿到,需要怎样流转,这些状态不能靠模型自己“记忆”,因为记忆就是幻觉的温床。正确做法是维护一个结构化的任务状态对象,每一轮依据状态决定下一步动作。可以把它理解为智能体的“记事本”,模型的每次思考都基于这个记事本,而不是基于缥缈的“我记得”。
第四层是控制层。这是我和团队改造重点。包括工具调用的次数上限、单步超时、循环检测、连续失败熔断、危险动作的人工审批闸口。控制层原则是:所有可能无限循环或产生副作用的行为,都必须在代码层面强制终止,而不是寄希望于模型“自觉”。你永远不能在大模型提示词里写“请勿循环调用”,你要在循环外面套一个“超过五次强制结束”的守卫,这才是工程。
第五层是评估与可观测层。系统能跑还不够,你要能随时回答三个问题:它现在做什么?它做得好不好?它是否比上周更稳定?这三个问题需要 trace 日志、成功率统计、回归测试集来回答。没有这一层,Harness 改善就成了摸黑走路。
2.3 关键结论:Harness 不是“工程美化”,是决定成败的成本项
很多团队规划智能体项目时,预算大部分花在模型 API 和算法人力上,Harness 设计的时间和人力常常被压缩到“顺便做一下”。这是一个战略判断错误。从我自己的体感来说,模型能力大家都能买到,差距真的不在模型,而在于谁能把 Harness 做深做透。
你可以用开源模型和商业模型对比,单轮问答差距确实存在,但放到智能体场景,把所有决策和工具调用都收敛到固定流程上之后,差距会被大幅抹平。这说明模型能力之上的 Harness,才是稳定性的主要贡献者。早意识到这个,可以少走很多弯路。
3. 实战案例:一个客服智能体从“70% 成功率”到“99% 稳定运行”
理论说多了容易虚,我拿一个真实搞过的模拟项目来拆解吧。背景是一个电商场景的订单查询客服智能体,我代称它为“某客服助手”。上线第一周,各项监控数据触目惊心:成功率只有 70% 左右,大量会话中途中断,人工介入率特别高,投诉关键词里全是“机器人听不懂人话”。
3.1 项目背景和病态现象
这个智能体的功能并不复杂:用户登录后,智能体读取订单接口、物流接口、售后规则,回答用户的问题,必要时发起退款申请。模型用的是当时主流的大模型,提示词写了将近两千字,几乎把能想到的边界都写进去了。
病态现象非常有代表性。第一,用户问“我的快递到哪了”时,智能体经常返回“您有多个订单,请问哪一个”,哪怕用户当前只有一个进行中的订单。第二,用户报出订单号后,智能体查完物流,还会“顺手”推荐一些毫不相关的商品,把客服对话搞成了营销。第三,一旦用户情绪激动,它会一反常态地道歉、承诺补偿,甚至直接说要给用户退款 500 元,这在业务上完全不合规。
这几类现象放在一起,基本可以判断:提示词里写的规则,模型在长对话和多工具场景里并没有稳定遵守。我们最开始以为加大模型规模能解决,试了一版更大更强的,结果成功率没怎么升,反而因为模型更强,生成文本更长,响应延迟更高,用户体感更加糟糕。
3.2 根因定位:trace 数据不会说谎
果断把重心从调模型转到修 Harness。第一步是搭 trace。我们没有额外买复杂的观测平台,就是把每一步的用户输入、系统状态、模型输出、工具调用参数和结果都记录成结构化日志,拼出一个完整的调用链。
trace 一出来,问题清清楚楚。
“快递到哪了”这个问题的链路是:智能体先调订单列表接口,接口返回了两个历史订单,模型一看有复数订单,就按预设逻辑让用户选。但其中一单半年前就完成了,另一单才是进行中的。模型没有能力判断“只有进行中的订单才需要提供给用户”,于是把两个订单都抛出去,制造了无意义的选择。
“推荐商品”问题则出在一个历史上为了提升活跃度加入的商品推荐工具。这个工具在系统提示词里写了“仅在用户询问商品时使用”,但在一次会话中,模型判断用户情绪不错,就主动调用推荐工具,而控制层没有任何拦截。它会“过度服务”。
“虚假承诺退款”更致命,根因是售后规则工具的返回内容太长了,一次塞进上下文的长文本里包含了很多种情况。模型在处理实际对话时引用了其中一条不适用于当前订单的规则,因为它根本区分不了规则适用的前提条件,它只是“看起来很像”地选择了最近的文本。
3.3 我给 Harness 动的手术:状态、工具、控制三层齐改
定位到根因之后,我做了几个关键改造。
第一处改造是在状态层。我在会话状态里增加了一个“当前订单快照”字段。第一步先把订单列表接口的返回结果做过滤和归一化,只保留“进行中”的订单,然后存储为结构化状态,并在工具说明里要求:所有涉及订单的问题,一律从状态快照里取数据,不许模型自己从冗长的工具响应里挑。这一步直接干掉了“多个订单让你选”的问题。
第二处改造在工具层。商品推荐工具被直接下架。短期营收可能受影响,但稳定优先,推荐功能应该由独立的营销智能体来承担,而不是塞在一个客服智能体里。工具层还补了一个失败回退:凡是读取物流信息失败,统一返回“暂时无法查询,请稍后重试”,不提供给模型任何发挥的余地。模型一旦没有模糊的数据可引用,自然不会编造。
第三处改造在控制层。我设计了一个带硬限制的调用循环,类似下面这种思路:
MAX_TOOL_CALLS = 5 for step in range(MAX_TOOL_CALLS): response = llm.generate(messages, tools=tools, current_state=state) if response.tool_calls: state.last_action = "tool_call" result = execute_tool(response.tool_calls, state) messages.append(result) if result.is_error: state.consecutive_failures += 1 else: state.consecutive_failures = 0 if state.consecutive_failures >= 2: return "抱歉,系统暂时无法完成这个操作,请稍后再试。" else: return response.text return "抱歉,这个问题比较复杂,我会转给人工客服处理。"这套逻辑的核心思路是:工具调用成功与否,不交给模型判断,而是由代码检测。连续失败两次,直接熔断,让用户走人工,不要再浪费用户时间。达到最大调用次数,也不再让模型继续“思考”,而是直接兜底回复。这样的做法损失了一些“智能感”,但换来了硬性的稳定。
控制层还加了一个行为审批闸口。凡是模型输出里出现“退款”“补偿”“改地址”这类高风险意图,不直接执行,而是先返回一个确认话术,要求用户明确点击或复述确认。这等于在关键副作用发生前加了一个人工确认位。这里是模拟项目,没有接真实审批系统,但机制和真实场景是一致的。
提示词也做了精简,从两千字精简到六百字左右,只保留核心身份、工具使用原则、拒绝边界三条。之前以为提示词越全越好,实际操作后发现,提示词越长,模型越容易在长上下文中忽略某些约束,精简之后反而规则更突出,遵守率更高。
3.4 修复后的数据验证
改造上线后,我观察了两周。成功率从 70% 爬到了 99% 左右,这是一个非常直观的数据变化。具体来说,原来每天有 30% 的会话最终走到人工兜底,现在降到 1% 上下;原来平均每个会话要调用 4 到 7 次工具,现在控制在 2 到 3 次;用户反馈里“机器人乱说话”的投诉直接归零。
这里有一个值得注意的细节:模型本身没有换,提示词还变短了,唯一的变量是 Harness。我不否认模型能力的重要性,但在智能体场景,稳定性确实更多来自外围工程。很多团队在遇到智能体不稳定时,第一反应是换更强模型,而不是检查自己的 Harness,在我看来,这就是舍本逐末。
4. 平时怎么发现“即将崩溃”的信号:可观测性与回归测试
智能体崩溃不可怕,可怕的是崩完之后你根本不知道它怎么崩的。很多团队连基础的 trace 都没有,靠用户投诉反馈,再打开后台看聊天记录,一条条人工分析,效率低得让人抓狂。这块我有几个很实用的建议。
4.1 让每次智能体运行都有“黑匣子”
那套客服智能体改造前后的对比让我彻底明白了一个道理:没有 trace 就没有排查权。每个会话我都建议至少记录以下内容。
- 会话的唯一 request_id,用来串联整条链路
- 每轮的用户输入和最终的模型输出
- 每次工具调用的名称、参数、耗时、返回码
- 状态对象的每次变更
- 控制层的每个终止或兜底点的触发原因
把这些记录成 JSON 日志之后,搭建一个简单的检索界面就行。排查时可以按 request_id 调出整条链路,一眼可以看出模型哪一步开始走偏,是工具返回异常还是提示词没有约束住。
不要嫌这个工作琐碎。很多崩溃是间歇性的,没有黑匣子,你只能靠猜。你也不会愿意在生产环境为了查一个 bug 去打印一堆临时代码。
4.2 建立智能体回归测试集:不能只测 happy path
传统软件开发里会做单元测试,智能体领域同样可以做,而且必须做。我习惯把测试用例分成几类。
第一类是正常路径,用户正常下单、正常查询,测试智能体能不能顺利走到正确工具并给出答案。第二类是异常输入,用户乱说、骂人、发语音转文字的错误文本、发空消息,测试智能体会不会失态。第三类是工具故障,模拟接口超时、返回空数据、返回非法格式,测试智能体会不会死循环或编造数据。第四类是越权试探,用户问客服能不能改价格、能不能绕过退款限制,测试智能体会不会“灵活处理”。
每一类都跑一遍,全都通过才允许发布。这在实践中有一些难度,因为大模型生成有随机性,同样的用例十次可能九次通过一次失败。我的做法是在每个用例上设定一个通过阈值,比如工具故障类用例要求“10 次里至少 9 次符合预期”。这样既容忍大模型的概率性,又确保稳定性在可控区间。
4.3 用成本不高的方式做持续监控
上线之后,还需要监控。不用一开始就上重型平台,一个简单的定时任务就可以:每天随机抽取 30 到 50 个真实会话,用规则筛查几个关键事件,比如是否有连续三个相同动作的工具调用、是否有超过五步的循环、是否出现退款等高风险关键词。如果有,自动报警。
这套机制成本很低,但非常有效。它可以在用户大规模投诉之前,先让你自己发现问题。我和团队现在保持一个习惯:每周开一次稳定性复盘会,数据都是从这个监控里来。你会发现,稳定不是一次性工程,而是一个不断被打破又重新建立平衡的过程。
5. 给想做 Harness 工程的人:避坑清单和几条反直觉心得
最后聊聊经验教训。这些东西不是教科书上写的,全是自己踩坑踩出来的。
5.1 常见崩溃诱因对照表
为了便于快速定位问题,我整理了一张对照表,基本覆盖了我见过的大部分翻车场景。
| 崩溃现象 | 最可能的诱因 | 优先排查方向 |
|---|---|---|
| 工具调用死循环 | 控制层缺少次数上限和失败熔断 | 在代码里加硬性循环限制 |
| 模型编造工具返回数据 | 工具返回格式不稳定,模型只能靠猜 | 统一工具返回结构,失败时给兜底文案 |
| 长对话后忘记规则 | 上下文过长,提示词被淹没 | 精简系统提示词,规则放到关键节点重复强调 |
| 对敏感操作“过度服务” | 工具层权限过大,没有审批闸口 | 高风险操作转为显式人工确认 |
| 回答前后矛盾 | 状态没有统一维护,靠模型记忆 | 用结构化状态对象记录关键信息 |
| 间歇性失败,无法复现 | 缺少 trace 日志 | 部署结构化 logging,全链路串联 |
这张表不能覆盖所有情况,但它能告诉你一个基本方向:遇到智能体异常,先想 Harness 哪一层没有堵住,而不是先怀疑模型智商。
5.2 几条反直觉但很有用的心得
第一,给模型留“退路”,反而会减少出错。早期我总想把所有边界都堵死,让模型只能走我规定的路。结果模型遇到边界情况时会强行找一条路走,往往就走错了。后来我在提示词里明确加了一句:如果信息不足,直接告诉用户“我无法确认,请稍后再试或联系人工”。加了这句之后,模型在未知场景下的胡编乱造大幅下降。让模型敢说“不知道”,是稳定性的一个重要开关。
第二,工具不是越多越好。工具越多,模型选择成本越高,选错的概率越大。客服项目里我把十几个工具砍到五个,稳定性明显上升。每加一个工具都要问自己:这个工具不模型调用直接硬编码行不行?很多看似需要模型决策的点,其实用代码判断更可靠。
第三,提示词要“分布式”放置而不是全部堆在系统提示词里。我发现把关键规则分散到对应的工具说明和状态描述中,比集中在系统提示词里更有效。比如订单查询规则写在订单工具的 description 里,退款权限写在退款工具里,模型执行特定任务时才看到强相关约束,遵守率比在开头写一万字高得多。
第四,小型开源模型加完善 Harness,很多时候比商业大模型裸奔更稳。这不一定准确,但可以作为选型参考。当你的系统已经把大部分决策收敛到固定判断流程,模型需要“自由发挥”的空间很小,那么大模型带来的额外优势就不明显了。
5.3 我个人的最后提醒
做了大半年 Harness Engineering,我最大的体会是:你别把智能体当成一个“超级会说话的人”,你要把它当成一个“需要严格管理的新员工”。员工越聪明,越容易自作主张,你需要给他明确的工作职责、决策边界和审批流程。没有一套好的 Harness,再强的模型也只是个高学历的定时炸弹。
还有一个小建议,所有工具调用日志里从第一天就带上 request_id,这个不起眼的字段会在你排查问题时救你无数次。别等到智能体已经崩得不可开交,再回头补日志,那真的太难了。
希望这篇拆解能给你一点启发。如果你正在做智能体开发,遇到模型“好像不太行”的时候,先别急着换模型,去看看你的 Harness,大概率会有奇效。我自己的项目就是这样,换了一整套外围控制设计之后,同样的模型跑出了完全不一样的稳定性。这条经验,值得你花时间验证一下。