接手的Agent项目,demo阶段表现得像是一位极其能干的高级工程师,代码改得又快又稳,工具切换行云流水,但一旦放到业务现场连着跑几天,问题就全来了。上下文越滚越乱,工具调用开始答非所问,某次操作突然把项目配置文件写坏,甚至因为一个无关紧要的报错反复重试到API配额耗尽。多数人会把这些锅甩给"模型还不够聪明",但干过几年AI工程的人心里都清楚:模型只是大脑,真正决定Agent能不能长期稳定存活下去的,是那套包住它的壳——Harness工程。
我所说的Harness,不是指某项单一技术,而是围绕Agent运行所搭建的一整套控制机制:运行循环、工具合约、上下文管理、错误恢复、权限隔离、可观测性,以及模型接入层。最近这段时间,国内国外都在讨论类似DeepSeek Harness、Claude Code Harness这类项目,也有人把用Rust重写Agent框架当成新风向,背后其实都是同一个诉求:怎么把Agent从"能跑"变成"稳定地跑"。这篇文章我想从Harness工程的核心机制出发,结合我在Linux环境下部署、调优这类系统的实际经验,聊聊那些真正影响Agent稳定性的关键细节,以及踩坑之后的解决方案。
1. 先认清一件事:AI Agent的稳定性问题八成出在"脚手架",而不是大脑
1.1 一个让人头疼的调试场景
我先描述一个非常典型的场景。你写好了一个基于LLM的运维辅助Agent,允许它读取日志、执行脚本、修改配置文件。单轮测试里,它每一步都很有章法,先用grep定位关键错误,再用tail确认时间线,最后给出结论。但你把它放进一个无人值守的任务流里,跑上一天之后再来看,发现它在一次失败的工具调用之后陷入了无限重试:工具返回了一个解析不了的报错,模型不理解这个报错,于是换个参数再试,连续试了十几次都没能把状态拉回来,最终任务超时,整个流程卡死。
这能怪模型吗?从根源看,模型确实不知道如何处理这种异常,但它更根本的问题在于运行环境没有给模型提供"优雅失败"的路径。LLM本质上是一个概率函数,它不会像传统程序那样严格按照逻辑分支执行;它给出的每一步行为都有一个"置信区间",同样一个问题,换一种措辞、换个时间点触发,输出可能完全不同。把这样一个不稳定的核心直接暴露在操作系统、外部API和用户数据面前,稳定地崩溃几乎是一种必然。
1.2 Harness工程到底管什么
Harness这个词,字面意思是"马具"或"挽具",引申到软件工程里就是"约束装置"、"装配框架"。在AI Agent这个词组里,Harness工程指的是介于大模型能力与外部执行环境之间的那一整套控制层。
它管的可不是简单的"调用一下模型API",而是以下几类问题:
- 行为编排:Agent每一步该做什么,以什么顺序做,什么条件下中止。
- 工具边界:模型能调用哪些工具,参数必须满足什么Schema,结果返回后如何被处理。
- 状态维护:对话历史如何组织,上下文何时压缩,关键信息如何保留。
- 错误恢复:调用失败后是重试、跳过、回退,还是上报人工。
- 资源控制:上下文窗口用尽、Token消耗过快、并发冲突时怎么办。
- 权限安全:文件系统操作、网络请求、命令执行分别有什么限制。
这些听起来很像传统后端中间件做的事,但Agent Harness的特殊性在于:它面对的是一个非确定性执行体。传统中间件可以假设所有输入都遵循契约,而Harness必须假设每一次模型输出都可能破坏契约。所以Harness工程的核心方法论,不是去预测模型"想干什么",而是把模型每一次行动的副作用都控制在可回滚、可审计、可恢复的范围内。
1.3 为什么"模型能力最强"不等于"代理系统稳定"
很多人有一个惯性思维:只要把模型版本升级到最新、最强,Agent的幻觉就会变少、稳定性自然提升。这个想法有一半是对的,但另一半被忽略了——Agent系统的稳定性不是模型单项能力决定的,而是整个链路上最短的那块板决定的。
打个比方,一辆车跑得稳不稳,发动机马力只是其中一个因素;悬挂、刹车、转向、轮胎抓地力,哪一项不行都会翻车。Agent系统也一样:模型再聪明,如果工具调用合约定义得模棱两可,它一样会把参数传错;上下文管理机制再不讲究,它照样会在第二十轮对话时把关键信息忘掉;错误恢复策略如果只有"重试三次",它依然会在某个未知异常面前原地打转。
我见过不止一个团队,花了大量精力在提示词上反复打磨,却忽略了Harness层的设计。结果就是:提示词已经写得像法律条文了,Agent仍然会在某些边界场景下把生产数据改坏。真实的生产环境里,稳定的Agent不是"提示出来的",而是"约束出来的"。这就是Harness工程的价值所在。
2. 主流的Agent Harness是如何撑住运行稳定性的
2.1 运行循环:把"模型想怎么办"变成"系统可执行的步骤"
Agent Harness的最底层,是一个标准的运行循环。当前主流架构基本都能归到ReAct框架的变体:模型先观察当前状态,思考下一步行动,然后执行工具调用,再把结果反馈回上下文,如此循环。常见的Agent循环长这样:
循环开始 1. 读取当前任务状态和上下文 2. 将上下文组合成模型输入 3. 请求模型输出:可能是最终答案或一个工具调用 4. 如果是工具调用,则根据合约校验参数、执行工具、记录结果 5. 如果结果有误,则触发错误处理策略 6. 更新上下文,回到第1步这个循环看起来简单,但所有稳定性问题几乎都藏在循环的细节里。我重点说两个最容易出问题的地方:
第一,循环终止条件的制定。Agent任务不是无限对话,它必须有明确的停止条件。很多Harness框架里定义了三种停止情况:模型显式输出"任务完成"、达到最大迭代轮数、某类错误连续出现超过阈值。最大迭代轮数不能设得太小,否则复杂任务会频繁中断;也不能设得太大,否则一个失控的Agent会消耗完你所有Token预算。我在生产环境里一般会把默认上限设在15-25轮,再配合Token数双重保险。
第二,循环中上下文的一致性。每当工具执行完毕,结果文本被拼进对话记录时,模型看到的并不是标准化的JSON,而是散落各处的大段输出。如果这个拼接过程没有清洗和剪裁,Agent很快就会在杂乱的日志里失焦。所以成熟的Harness都会对工具结果做"二次加工":截断超长输出、提取关键字段、折叠重复内容,确保喂回给模型的是经过整理的摘要,而不是原始输出。
2.2 工具调用合约:在模型和外部世界之间设一道安检
如果说运行循环是Agent的心脏,那么工具调用合约就是它的免疫系统。模型是一个自由文本生成器,它输出工具调用的时候本来就可能不守规矩。不是参数类型错了,就是JSON格式不完全合法,甚至可能调用一个并不存在的工具名。
Harness解决这个问题的办法,是把工具定义变成机器可验证的合约。通常做法是用JSON Schema描述每个工具的入参和返回:哪些字段必填、哪些参数类型、取值范围、枚举选项,全部提前写死。模型输出工具调用后,Harness不会直接执行,而是先做一次严格校验:
- 如果参数合法,就执行,并把结果标准化。
- 如果参数不合法,可以尝试根据Schema做纠偏,或把校验错误反馈给模型让它自我修正一次。
- 如果模型连续几次产出非法调用,就终止这条执行链,避免死循环。
这一步至关重要,因为真实场景里,LLM的工具调用格式远不是规规矩矩的。我遇到过模型在函数名后面多加了一个空格、把布尔值写成了字符串"true"、把日期参数传成了"昨天"这种自然语言,甚至在JSON里嵌套了一层多余的数组。如果没有合约校验和纠偏,这些输出通通会变成运行时报错。
合约还有一层作用:它是"最小权限"思想的落地。Harness给模型暴露哪些工具,决定权在工程人员手里,而不是模型自己。一个写代码的Agent,根本不需要暴露删除整个仓库的能力;一个处理客服工单的Agent,不需要能访问财务系统。把工具面收敛得越小,系统能出的乱子就越少。
2.3 上下文管理与自动压缩
先解释一个很多人会困惑的概念,也就是热搜里反复出现的"Agent Token是什么意思"。Token是模型处理文本的基本单位,可以粗略理解为"字词的碎片化表示":英文里一个单词可能被拆成一到两个Token,中文里一个汉字大约对应不到一个Token。模型API按Token计费,而且每次请求能携带的Token总数有上限,这个上限就叫上下文窗口。
Agent运行得越久,对话历史越长,Token消耗越大,上下文窗口迟早会被塞满。如果Harness不做任何处理,等到窗口满了,模型要么直接报错,要么把最前面的历史挤出去——而这部分历史往往恰恰有关键信息。稳定Agent的必修课,就是上下文管理。
我常用的策略是三层:
- 裁剪:超过一定轮数,就把对话历史里那些工具原始输出折叠成一句摘要,只保留"结果状态"和"关键返回值"。
- 摘要:每隔N轮,让模型自己对已完成的子任务做一次总结,把旧的完整对话替换成这份总结,钉在上下文的固定位置。
- 外部记忆:重要的优先级信息、用户目标、代码状态放到一个独立的记忆区(比如向量数据库或JSON文件),每次组装上下文时只按需拉取,而不是把所有内容全部塞给模型。
这套组合拳打下来,即使一个Agent任务持续几十上百轮,它的上下文消耗也能保持稳定增长,而不是线性爆炸。很多开源Harness框架都在做类似的事,DeepSeek Harness这类项目里集成的LLM Wiki插件,本质上就是"外部记忆"的一种形态:把领域知识检索到上下文里,让模型时刻有据可依。领域知识检索和全文灌入相比,既省Token,又不容易被无关信息干扰。
2.4 错误处理:让Agent失败得体面
传统程序里,错误处理是每个函数内部的事;Agent系统里,错误处理必须是Harness层的事。因为模型不会像程序员一样按异常捕获规范写代码,你必须在框架层面建立一个唯一错误出口。
我设计的Agent Harness错误处理分四档:
| 错误等级 | 触发条件 | 处理动作 |
|---|---|---|
| 可自动修复 | 工具参数小范围错误、JSON格式不合法 | 纠偏后重试一次,仍失败则升级 |
| 可重试 | 网络超时、API瞬时限流 | 指数退避重试,最多三次 |
| 需回退 | 操作中途失败、文件被部分修改 | 调用代码回退机制,恢复到操作前快照 |
| 需人类介入 | 权限不足、安全风险、连续多轮同类型失败 | 暂停任务,输出完整失败上下文,等待人工处理 |
关键点是"回退"这一档,它值得单独拿出来说。Agent执行任务时,经常是先写好一个新代码文件,再修改旧文件,然后运行测试。如果某一步出现问题,Agent却还继续往下铺开更多修改,整个状态就会越来越乱。所以Harness应该在每次工具调用前记录一个轻量级的快照,调用失败后能够迅速还原,而不是让Agent带着一身半成品状态继续工作。这也是搜索词里"DeepSeek Harness代码回退"这类讨论的核心价值:回退不是"撤销一次操作",而是"让整个Agent状态回到一个已知良好的检查点"。
3. 从Rust实现到局域网部署:架构选型背后的稳定性逻辑
3.1 为什么有人把Harness搬到Rust上重写
近来的Agent框架有一个明显趋势:用Rust语言重写Harness层。包括"基于Rust语言AI Agent"这个热点,背后不是简单的技术追新,而是实打实的稳定性考量。
Rust在Agent Harness这个场景里最大的优势,一是单二进制部署。Rust编译出来的程序不依赖用户机器上装不装Python环境、有没有Node.js运行时,一个二进制文件拷过去就能跑。这对生产环境的Agent部署来说意义重大,少一层依赖就少一个版本冲突点、少一个环境变量配错的概率。
二是内存安全和并发控制。Agent往往要同时跑多个任务:一个在跟用户对话,一个在后台跑定时任务,一个在处理工具调用的回调。Rust的并发模型保证了这些任务之间的数据和资源隔离问题会在编译期暴露一部分,而不是等线上运行到某个深夜节点才突然崩溃。我跟踪过几个开源Harness项目,从Python生态直接转向Rust重写的并不少见,原因几乎都是同一个:跑得越久、任务越复杂,对系统本身的健壮性要求越高,而Rust的容错底子确实更硬。
当然,Rust不是银弹。Agent的核心逻辑依然是调用LLM,这一部分的稳定性并不会因为换语言自动变好。但Harness层作为一个长时间运行的常驻进程,承载着调度、网络、文件IO、进程管理这么多系统级操作,用Rust底层的稳定性去托住上层的不确定性,这个组合逻辑上是成立的。
3.2 CLI、桌面版与局域网部署各解决什么问题
我看到热搜里有"DeepSeek Harness Linux"、"DeepSeek Harness桌面版"、"离线局域网"这些关键词,把它们连起来看,正好是Harness部署形态的演进路径。
CLI形态是Harness的第一选择。只保留一个终端入口,Agent的输入输出全走文本,工具调用也以命令行为主。CLI的好处是脚本友好、自动化方便、可组合性强,适合跟现有CI/CD流程集成。一个运维Agent如果用CLI跑在Linux服务器上,它可以直接被cron调用、被监控系统探测状态,还能输出结构化日志。
桌面版解决的是交互体验问题。很多人不想对着黑底白字的终端用Agent,那就横向套一层GUI:左边是对话面板,右边是文件树,底部是工具调用实时日志。这层GUI本质上只是CLI的"浏览器",稳定性核心仍然在底层Harness里,所以架构上不建议把业务逻辑写进界面层。
局域网/离线部署,这个是稳定性的进阶玩法。Agent如果不能联网,或者只能在局域网内访问模型推理服务,很多外部依赖和网络故障就被直接隔离掉了。离线部署意味着你不再受模型API服务商限流、宕机、接口升级的影响;局域网部署意味着你可以对模型服务做统一治理,比如集中配置API Key、统一限流策略、把敏感数据留在内网。对一个生产级Agent来说,可控的网络边界就是可控的稳定性边界。
我自己的经验是,先以CLI形态搭建核心Harness,跑通之后再决定要不要套桌面壳、要不要迁移到局域网模型服务。别一开始就奔着"全家桶式平台"去,那样只会让不稳定因素多一个维度。
3.3 Token机制:精确控制每次调用的开销
刚才讲了Token是什么,这里补一个更工程化的视角:Token机制直接决定了Agent的运行成本和上下文预算。
每个模型的上下文窗口是有限的,当前主流模型普遍在128K到200K Token之间,听起来很大,但Agent跑起来才知道什么是"吞Token巨兽":一次工具调用返回的目录列表可能几千Token、日志文件的尾部输出可能上万Token,上下文预算消耗速度远超想象。Harness层如果不对Token做精细管理,很快就会遇到两个尴尬局面:要么超长输入导致API直接报错,要么上下文成本高到业务方拒绝买单。
在实际项目里,我习惯在Harness的日志系统中埋一个Token计数器:每轮请求前后各记录一次Token用量,同时累计整个任务的消耗。这样就能明确回答三个问题:这个Agent任务平均烧多少Token、哪个环节最耗Token、上下文窗口还有多少余量。有了这些数据,上下文压缩策略的触发门槛就不再是靠感觉,而是量化配置。
4. 插件、提示词与代码回退:我踩过的几个稳定性的坑
4.1 插件系统是一把双刃剑
插件生态是Agent Harness迅速普及的最大推手之一。像"DeepSeek Harness如何安装插件"、"实用插件"这些热搜,说明大家已经不满足于框架自带的基础能力,想通过插件扩展出知识库检索、提示词优化、定时任务、告警通知等能力。
但把插件装进去之前,必须想清楚一个问题:插件和插件之间、插件和框架之间的兼容性,到底由谁来负责?
我踩过的很典型的一个坑是:装了一个"提示词优化"插件,它会自动改写用户的输入之后再发给模型,本意是提升回答质量。但它没有考虑到我的Harness已经在系统提示词里定义了一套严格的工具调用格式。插件改写后的用户输入混入了一些系统层的指令词,直接把模型的工具调用格式搞乱了,连续好几轮输出都产生了带多余字段的工具调用,合约校验次次失败、来回重试,任务进度被拖垮了一半。
插件可以装,但要遵循两个原则。第一,插件的能力边界必须被Harness约束住:读取上下文的插件不能改上下文,执行工具的插件不能绕过工具合约。第二,每条插件都应该有自己的独立配置空间,不能和主线配置混在一起。这个教训在后面我会展开说。
4.2 提示词优化插件的真实作用半径
提示词优化插件,本质上是在"让模型更容易遵循指令"这件事上做文章。它的常见做法是:把用户提问的重心提取出来、补充行业术语、把模糊范围量化、给模型更多可操作的背景。这类插件在简单问答场景下确实是好的,一两轮对话里,模型确实能给出更精准的答案。
但到了Agent这种多轮工具调用场景,提示词优化能做的就很有限了。Agent的稳定性更多取决于模型能不能稳定地按合约输出工具调用,而不是"回答得有没有文采"。我后来甚至发现,某些过于精细的提示词模板反而会引入约束:模板里写了一些"你应该考虑成本"、"你应该优先效率"这样的原则性句子,模型听了之后反而在自己拿不准的时候表现得更犹豫、更爱解释,而不是果断地调工具。
所以我现在的建议是:提示词优化的重心放在系统提示词与任务目标声明上,不要用插件去干预每一轮用户输入的改写。真正想把Agent变稳,靠的是把工具调用格式示例写进提示词、每一步操作前强制输出"计划"、模型决策过程可被日志复现。这些,插件能帮忙的不是没有,但作用半径比宣传的窄很多。
4.3 把"代码回退"作为Agent操作的保险丝
代码回退机制,我愿称之为Agent Harness体系里最值得做扎实、却最容易被忽视的部件。理由很简单:Agent一旦具备写文件、改代码能力,它就是生产系统里的一个高权限操作者。高权限操作者一旦犯错,如果没有回退能力,一个小错误会被它自己的后续操作放大成一场灾难。
回退机制不应该只是一个"撤销"按钮,而应该是一个完整的流程:
操作前:Harness截获调用,计算涉及文件和变更内容,创建内存快照或临时备份 操作中:记录每一步修改的diff,追加到审计日志 操作后:Agent主动声明"任务完成"后,先运行验证脚本 验证失败:定位最近一个通过验证的检查点,自动回滚到该状态我落地过的一个案例:让Agent批量重构一个服务里的几个模块,它在改完第三个文件之后,突然把之前一个公共函数也顺手改了,结果回归测试失败。如果没有回退机制,就要靠人肉去Git记录里翻差异;有了回退机制,Harness直接基于测试结果回滚那一步错误修改,并保留了Agent现场执行时的一切上下文供人工分析。这个过程的体验,才让我意识到操作可回滚本身就是一种稳定性保障,它能鼓励Agent放手去执行,又能在出错时兜住底。
4.4 配置文件版本管理:一个容易被忽略的暗坑
插件装多了、配置项堆起来,Agent Harness的本地配置就变成了一个"类编程工程"。YAML或JSON配置文件里字段的嵌套关系越复杂,越容易出问题。我前面提到的配置冲突陷阱,通常就发生在这个阶段。
比如DeepSeek Harness安装插件的时候,插件A定义一个plugin_options字段,插件B也定义同名plugin_options字段,但两处值的Schema完全不一样。一些实现不完善的框架会直接把后读取的配置覆盖掉先读取的,或者直接抛出无法解析的报错。更隐蔽的是,某段配置里的model.temperature被写成了一个字符串"0.7",如果不是框架恰好做了强转,模型行为会在某个版本升级之后突然变得"不可解释地随机"。
我现在会在Harness的配置层做三件事:
- 配置解析时做严格Schema校验,发现非法字段立即报错并标明来源文件。
- 配置变更纳入Diff审计,每次修改都留着前后对比记录,方便回退。
- 插件配置和核心配置分开存放,核心配置只允许受控渠道修改,插件配置则限制在各自的命名空间内。
这几层防护看上去很简单,却能在实际运行中消灭掉一大类"莫名奇妙变了个行为"的疑难杂症。
5. 模型无关的Harness设计:从Claude Code到免费/本地模型的接入
5.1 不登录、换模型,这为什么是一个工程问题
热搜里有一条很有意思:"Claude Code Harness可以不登录用其他模型吗"。这反映出一个真实需求:很多Agent用户不希望被绑定在某一个模型服务商的账号体系里,或者想用其他厂商的模型、本地模型、甚至免费模型来跑同一个Harness框架。
这个需求在工程上完全合理。模型无关的Harness才是高稳定性的Harness,理由很简单:任何一个外部模型服务商都可能发生限流、故障、价格调整、甚至接口停用。如果你的Harness和某个模型服务的SDK、鉴权方式、消息格式深度耦合,那你的Agent稳定性就被另一家公司攥在手心里。
不登录、换模型这件事,难点不在于"调用一个API",而在于不同模型服务的接口能力有差异。有的模型原生支持工具调用(Function Calling / Tool Use),有的模型不支持,只能靠提示词"诱导"它输出JSON格式的工具调用;有的模型对上下文窗口上限设得很低,有的模型系统提示词还有特殊规则。Harness要稳定的适配所有这些模型,就必须在模型接入层做一个统一的抽象。
5.2 模型抽象层长什么样
我建议Harness里至少要有一层模型适配器(Model Adapter),粒度不要放在"某个具体厂商"上,而放在"某一类接口能力"上。常见的抽象维度有三个。
消息格式统一。不管底层是OpenAI兼容接口、Claude Messages接口,还是DeepSeek的自有格式,对上统一转成同一个内部消息结构。内部结构里只保留角色、内容、工具调用记录这几个字段,底层的事情交给适配器去转换。
工具调用能力的降级与模拟。底层模型如果原生支持工具调用,就直接走它的专用参数;如果不支持,适配器会把它降级成"提示词约定+输出解析"模式:在系统提示词里加入工具格式说明,然后在模型输出里用正则或JSON解析器提取工具调用。这个降级路径写起来不复杂,但真正做的时候要注意一点:提示词约定模式和原生模式下的工具调用成功率有差距,所以Harness的合约校验和纠偏逻辑要在两条路径下都起效,这样模型换成哪一种都能稳定运行。
参数映射与默认值。不同模型对temperature、top_p这类采样参数的处理规则不一致,有些模型的终版回答生成阶段还会受到特殊参数影响。适配器应该把这些差异吃掉,对外暴露统一的参数面。
5.3 接入免费模型和本地模型后我的实测观察
我自己在Harness里接过免费模型,也接过局域网内的本地推理服务,先放结论:接入免费模型意味着可以低成本跑通全链路,但必须接受它带来的额外波动;接入本地模型则意味着你真正控制了稳定性的大头。
免费模型常见的问题有三个:上下文窗口往往比较小,几十轮对话之后挤压感就来了;并发限制和限流额度比较紧,高峰时段动不动就429;工具调用的可靠性、指令遵循能力会比收费模型差一档,经常需要对工具调用结果做多次纠偏。我的做法是,让Agent的关键路径默认走更强、更稳定的模型,而那些低风险的子任务、摘要生成、格式清洗才交给免费模型或小模型。这个分层策略用起来之后,成本降下来了,稳定性也没塌。
本地模型(局域网部署)的优势则是低延迟和数据可控,但它同样需要Harness多做一项事:模型版本更新时,行为变化可能比外部API更剧烈。因为外部API通常有明确的版本兼容承诺,而本地模型换个权重包、换一次量化精度,表现就可能完全不同。所以我的Harness会专门记录每次任务的"模型指纹"(版本号+量化类型+采样参数),这样万一行为出现回归,能够立刻定位是不是模型升级引起的。
6. 落地Harness工程时的一些实践心得
6.1 先建观测,再谈护栏
如果只能给一条Harness落地的建议,我会说:先把日志和可观测性做到位,再去叠各种护栏。
没有观测数据支撑的稳定性建设,基本靠猜。Agent每轮到底在想什么、调用了什么工具、工具返回了什么、上下文截断时丢掉了哪段信息、Token消耗在哪一步暴涨——这些数据如果不完整,你的任何优化都找不到靶点。我现在做Harness的第一件事,就是在运行循环的每个关键点埋上结构化日志,并保留完整的历史快照。排查问题的时候,第一件事永远是翻日志看现场,而不是凭感觉改提示词。
建议日志至少包含:请求时间、模型名称、本轮Token数、上下文截断计数、工具名、工具调用参数、工具返回码、处理耗时、重试次数、错误等级和原始错误文本。
6.2 把提示词当代码来测试
很多人维护Agent的时候,提示词改来改去非常随意,今天加一句"你要谨慎",明天删一句"不要解释过程",然后直接在线上验证。这其实是把提示词当"玄学"在维护,任何稳定性都无从谈起。
提示词应该被当成代码一样对待:有版本号、有变更记录、有回归测试。我给Harness配了一套提示词回归集,里面放了几十条"高频任务+期望行为"对:比如"用户要求修改配置时,模型必须先输出修改计划"、"工具调用失败时,模型必须直接报告而不是编造成功"。每次改完提示词,先跑一遍回归集,确认老行为没有被改崩,再跑到线上灰度。这套习惯坚持下来,提示词相关的"灵异事件"明显少了很多。
6.3 做约束而不是做限制:几个我反复强调的注意点
最后梳理几个我在实战中反反复复对人强调的注意点:
- 尽量给Agent留出"拒绝执行"的出口。Agent碰到权限不足或指令含糊的任务时,宁可停下来问人,也不要硬猜着执行。Harness里应该明确定义"触发人工介入"的条件,而不是把所有异常都交给重试。
- 对模型输出永远保持怀疑。工具执行之前,Harness要自己再校验一次参数和副作用,别因为模型说"我只改动一个字段"就真的只相信它改了那一个字段。
- 回退机制不要只做一层,要能逐层扩大。文件快照是一层回退,Git仓库是一层,配置备份是一层,数据库事务是一层。层越多,Agent的试错成本越低。
- 警惕超长任务的累积误差。任务轮数越长,上下文压缩和摘要带来的信息损耗就越多。如果业务允许,把长任务拆成多个短任务,分别跑、分别验。
- 升级模型或框架之前先跑回归。无论是底层Harness版本升级,还是把模型从一种换成另一种,都要先跑一遍前面说的回归集,确认稳定性没有后退再放行。
以上这些经验,大部分都不是从框架文档里看来的,而是把一个又一个线上事故翻出来复盘后攒下的。稳定的AI Agent确实不是靠某一个"神奇框架"白捡的,它是一场围绕不确定性、反复做对抗的过程。Harness工程的价值,就是让你在对抗模型不确定性的时候,手里有足够多的牌可打。能用好这套约束机制,Agent的稳定运行才不是靠运气,而是靠设计。