你有没有过这种经历:

AI帮你写完了一个功能,代码能编译,测试也过了,你看了看合并请求,觉得没问题,就合并了。

几个小时后,你发现不对劲。

新接口是能跑,但AI在实现的时候——绕过了数据访问层、改了一个它不该动的文件、跳过了一个重要的测试、引入了一个安全问题、忽略了一条早就定好的架构规则。

什么都没崩。AI只是做了它认为“对”的事。

而这恰恰是问题所在。

我们一直在想办法让AI变得更聪明。更好的模型、更精的提示词、更大的上下文窗口。

但有没有一种可能:真正的问题,根本不在模型本身,而在我们把模型放进了什么样的环境里?

这就是今天要聊的东西:AI agent 的“马具”(harness)。

一、什么是“马具”?

你可以把AI agent想象成一个能推理、能写代码、能跑命令、能用工具的开发者。

而“马具”,就是这个开发者周围的工程环境。

一个基础的agent是这样的:

提示词 → 模型 → 代码

一个更好的agent是这样的:

任务 → 上下文 → Agent → 工具 → 代码 → 验证 → 反馈 → 回到Agent

区别在哪?

Agent不只是生成代码。它会观察、行动、验证、恢复。

我们来一步步搭一个。

二、从上下文开始

假设你有一个后端项目。

你对AI说:“加一个创建新客户的接口。”

没有额外信息,AI只能猜:接口放哪?用哪个数据库层?项目用什么校验库?错误返回长什么样?测试放哪?命名规范是什么?

而AI非常擅长猜。

这恰恰是我们不想要的。

所以,给AI一份项目专属的说明。比如在项目根目录放一个文件,写清楚:

  • 用TypeScript
  • 控制器不能直接访问数据库
  • 业务逻辑放在服务层
  • 数据库访问放在仓储层
  • 每个新接口都要有测试
  • 用Zod做请求校验
  • 完成前跑lint、类型检查和测试
  • 永远不要改自动生成的文件

这已经好多了。

但还有个问题:这些只是“说明”,AI可以忽略。

所以我们需要从“说明”升级到“强制”。

三、给Agent合适的工具

Agent有多大用处,取决于它能做什么。

不要给它无限制的权限,而是给它明确的工具:

  • 读文件
  • 搜索代码
  • 列出文件
  • 应用补丁
  • 跑测试
  • 跑lint
  • 跑类型检查

这样Agent就能通过已知的能力和代码库交互。

比如一个跑测试的工具,执行完返回:成功还是失败、标准输出、错误输出。

一个搜索代码的工具,能帮Agent先问:“项目里现有的客户接口长什么样?”

而不是上来就盲目创建。

四、上下文要“检索”,不要“倾倒”

一个常见错误:把什么都塞给AI。

“这是500个文件,这是所有日志,这是整个代码库,祝你好运。”

更多上下文,不等于更好的推理。

更好的做法是建一个检索层:根据任务提取关键词,找到相关文件,读取架构文档和规则文件,只给Agent它需要的东西。

任务 → 找到相关上下文 → 只给Agent需要的

这样上下文更聚焦,重要信息不容易被淹没。

五、给Agent记忆

上下文和记忆不是一回事。

上下文回答:“我现在需要知道什么?”

记忆回答:“我们已经学到了什么?”

一个简单的项目可以有这样几个文件:

  • 决策记录
  • 进度记录
  • 失败记录
  • 架构说明

比如在决策记录里写:“客户接口的所有数据库访问都通过仓储类。控制器不能直接调用数据库。原因:保持持久化关注点和业务逻辑分离,让服务更容易测试。”

如果Agent发现了一次失败,不要让它随着任务结束就消失。写进失败记录:“之前的实现试图从控制器直接访问数据库,被拒绝,因为这违反了仓储模式。”

下一次Agent运行,就能从中学到东西。

这比单纯加大上下文窗口有用得多。

六、把规则变成约束

这里有一个重要区别。

“说明”是:永远写测试。

“约束”是:测试不通过,任务就不算完成。

这是两个完全不同的系统。

我们可以用一个验证函数来实现:跑测试、跑类型检查、跑lint,全部通过才算成功。

现在Agent不能简单说一句“完成了”就完事。

马具会问:代码真的通过验证了吗?

七、搭起Agent循环

现在我们有足够的零件来搭一个基本循环了:

  • 获取上下文
  • Agent决定行动
  • 执行
  • 验证
  • 如果失败,把错误反馈给Agent
  • 再试,最多三次

注意变化:不再是“提示词→代码→完成”,而是“提示词→推理→行动→验证→修复→再验证→完成”。

这才是真正的马具的开始。

八、让Agent看到自己的失败

这是Agent系统变得更有意思的地方。

假设Agent写了这样一行代码:直接调用数据库创建客户。

代码能编译。但架构规则说控制器不能直接访问数据库。

马具可以通过lint、架构检查或测试发现这个问题。

然后Agent收到这样的反馈:“验证失败。规则违反:控制器不能直接访问数据库。请把数据库访问移到仓储层。”

这是可操作的反馈。比一句“再试试”强多了。

九、用钩子让马具主动出击

我们还可以用钩子在提交之前强制执行规则。

比如一个提交前钩子:跑lint、跑类型检查、跑测试,任何一个失败就退出。

现在系统不再依赖Agent“记得”去跑测试。环境自动做了这件事。

这就是“请遵守规则”和“规则不满足就不能继续”的区别。

十、加上恢复机制

Agent会失败。这不是马具的bug,而是马具应该预料到的事。

一个有用的恢复循环是这样的:

尝试执行 → 验证 → 如果成功就返回 → 如果失败,把错误、原因、变化、下一步建议反馈给Agent → 再试。

关键是反馈:什么失败了?为什么失败?发生了什么变化?接下来该试什么?

这给了Agent一条恢复的路径。

十一、别让Agent无限重试

还有一个重要的工程问题:如果Agent一直犯同样的错误怎么办?

试一次,失败。试两次,失败。试三次,失败……

最终你的“自主”Agent变成了一个昂贵的无限循环。

所以要有边界:最多试三次。还可以检测重复失败:如果同样的错误出现过,就停下来。

没有边界的自主,不是可靠性。

十二、加上Git感知

一个写代码的Agent应该清楚自己改了什么。

执行前看状态,执行后看差异。然后马具可以检查结果:如果动了禁止修改的文件,就回滚。

比如允许改客户相关目录和测试,不允许改环境变量文件、自动生成目录、基础设施目录。

Agent可以改代码,但马具决定这些改动能不能接受。

十三、把计划和执行分开

另一个有用的改进:让Agent在改文件之前先做计划。

不是“任务→直接改文件”,而是“任务→计划→审查计划→执行→验证”。

计划里写清楚:要改哪些文件,做哪些变更。

马具可以在Agent动手之前就否掉一个糟糕的计划。 这能省下大量事后清理的功夫。

十四、验证要多层

一套测试不够。

要分层思考:语法层、行为层、架构层。

类型检查、lint、单元测试、集成测试、安全扫描、架构检查——全都要。

构建成功只说明“代码大概能跑”。它不说明“代码属于这个架构”。

这就是为什么马具需要多种验证。

十五、完整的马具2.0

把所有东西拼在一起:

开发者 → 任务 → 马具(上下文、记忆、规则)→ Agent → 工具 → 代码变更 → 验证 → 失败就反馈,成功就完成。

这就是我说的“马具2.0”。

不是更大的提示词,不是又一个系统消息。

是围绕Agent的一整套执行环境。

十六、一个最小可用的马具

你不需要第一天就搭一个巨大的平台。

一个出奇有用的第一版可以是这样:一个类,包含Agent、记忆、最大尝试次数。运行时获取上下文,循环执行、验证、反馈,成功就保存记忆,失败就安全退出。

这不是完整的生产实现。但架构已经在了:

上下文 → 行动 → 执行 → 验证 → 反馈 → 恢复。

从这里开始,你可以一层层加上:工具权限、沙箱、持久记忆、计划、回滚、可观测性、成本控制、安全策略、人工审批、并行Agent。

十七、真正的转变

软件工程正在发生一个微妙但重要的变化。

以前是:开发者 → 代码 → 测试 → 生产。

有了Agent之后是:开发者 → 马具 → Agent → 代码 → 验证 → 反馈 → 回到Agent。

开发者不再只是写代码。他们在设计一个让另一个系统写代码的环境。

这是一个不同的工程问题。需要不同的思维方式。

十八、不要为“最聪明的Agent”做优化

这可能是最重要的一课。

想象两个系统。

系统A:非常强大的模型 + 巨大的上下文窗口 + 最少的工具 + 没有验证 + 没有恢复。

系统B:不错的模型 + 聚焦的上下文 + 专门的工具 + 持久记忆 + 强验证 + 恢复循环 + 护栏。

生产环境我选系统B。

因为可靠性不只来自智能。它来自围绕智能的系统。

十九、最好的Agent,是你能纠正的那个

我们经常问:“这个Agent有多聪明?”

更好的问题是:“这个Agent出错的时候,会发生什么?”

你能发现错误吗?能解释为什么吗?Agent能看到失败吗?能恢复吗?能防止下次再犯吗?能安全回滚吗?

如果答案都是“能”,你就是在建一个工程系统。

如果答案是“不能”,你基本上只是在祈祷模型别出错。

而祈祷,不是部署策略。

最后说几句

AI Agent写代码越来越厉害了。

但给Agent一个代码库权限,然后说“把功能建出来”,是不够的。

真正的工程挑战,是模型周围的一切:

上下文 + 工具 + 记忆 + 约束 + 验证 + 恢复 + 可观测性 = Agent马具

模型提供推理。马具提供纪律。

这改变了我们思考AI辅助开发的方式。

目标不是造一个永远不犯错的Agent。

目标是造一个系统,在这个系统里:错误被快速发现,失败可以恢复,不安全的行为被约束,成功的工作被独立验证。

这才是“能写代码的AI”和“你能真正信任它做工程工作的AI系统”之间的区别。

本文话题 #AI编程 #Agent开发 #软件工程 #AI工作流 #代码质量 #工程效率 #开发者成长 #AI辅助开发