前阵子我让一个 coding agent 帮我修一个不大的 bug。
问题其实很具体:
- 一个接口 500
- 只在某个 feature flag 打开时出现
- 复现路径明确
- 影响范围也不大
按理说,这种活儿很适合交给 AI。结果它上来先读了 8 个文件,跑了 5 次测试,顺手改了两个无关组件,又把 lint 配置动了,最后还非常自信地告诉我:
“问题已经修复,建议你跑一下验证。”
我一看 git diff,差点笑出声。
真正的 bug 还在,倒是 eslint 配置被它改松了,console.log 多了两个,README 还被顺手润色了一段。
如果你用过一阵 AI 编程工具,对这种场面应该不陌生。
很多人会把这类问题理解成:
- 模型还不够聪明
- 提示词没写好
- 这家模型最近变笨了
我现在越来越不这么看。
我更愿意把问题说得更直一点:
AI 编程真正难的,往往不是模型本身,而是你有没有给它搭一套像样的工作环境。
这个“工作环境”,就是我今天想聊的:Harness 工程。
它听上去很像一个会把读者劝退的词,但你要是真开始做 AI 编程系统,就会发现它根本绕不过去。
因为你很快就会撞上这些问题:
- 工具应该给到什么粒度?
- 哪些规范应该长期生效,哪些应该按需加载?
- 复杂任务要不要先规划?
- 长时间会话怎么避免上下文烂掉?
- 多个 agent 并行改代码时怎么不互相踩死?
- MCP 是不是越多越好?
- 怎么防止 agent 把“我觉得差不多了”当成“真的验证通过了”?
这些问题,靠“更强的 prompt”都解决不了。
它们是纯工程问题。
而所谓 harness 工程,说白了就是一句话:
给模型搭一个能长期稳定干活的工作环境。
不是让它看起来更像人。
而是让它真的更像一个靠谱的同事。
一、先别把 Agent 想得太玄,它的心脏通常只有一条循环
我现在看各种 AI Agent 产品,第一反应已经不是“哇,太智能了”,而是“来,我看看你这层壳子到底是怎么接的”。
因为你把外壳剥开以后,内核经常朴素得让人不好意思:
while True:
response = model(messages, tools)
if response asks for tools:
execute tools
append results
else:
return
就这。
模型看上下文,决定下一步。
你负责把它要做的动作真的做掉。
再把结果喂回去。
如果你愿意,可以把这套东西想象成一个特别能说会道、脑子也不错,但手脚全靠外包的实习生:
- 它知道“下一步应该查日志”
- 但它自己不会真的去查
- 你得给它一个
read_file - 或者给它一个
bash
所以一个 AI 编程系统最核心的第一步,不是“怎么让模型变聪明”,而是:
怎么让模型有手、有脚、有眼睛。
这就是 tools。
但事情到这里才刚开始。
因为光有手脚,不代表它会有条理地干活。
我见过太多 agent 一旦开始工作,就进入一种非常熟悉的人类状态:
- 明明要修 bug,先去整理目录
- 明明要加鉴权,先改按钮颜色
- 明明要跑测试,先写文档
- 明明是修一个接口,最后把半个项目重构了
这个时候你就会意识到,AI 编程最可怕的问题,从来不是“不会写”,而是:
它太会动手了,但不一定知道自己在干什么。
所以真正有效的 harness,不会停在 loop + tools,而是会继续补三样东西:
- planning
- context management
- verification
这三样,缺哪个都迟早翻车。
二、我最看重的一条原则:复杂任务先规划,再执行
这件事对人类程序员成立,对 AI 更成立。
一个很现实的例子:
假设我要加一套“市场结算后自动通知用户”的功能。
这听起来很直白,但实际上至少会牵出这些东西:
- 数据表是不是要加通知记录
- 用户偏好要不要建模
- 邮件和站内信要不要一起发
- 市场结算的触发点在后端哪个事件上
- 前端要不要加未读消息入口
- 大量用户同时通知时会不会打爆
如果我只是丢一句:
“帮我把通知功能做了。”
那很容易出现一种 AI 经典事故:
- 它先从最容易写的 UI 入手
- 再绕回后端
- 中途发现缺表
- 然后边写边改方案
- 最后产出一堆“看起来很忙”的 diff
但你很难说它真的在解决问题。
我现在更倾向于强制让 AI 先做一件事:
先把任务重新说清楚,再拆计划,再列风险,再等确认。
这一步的意义非常大,因为它做了三件事:
- 把模糊需求变成共享认知
- 把风险提前暴露,而不是埋进代码里
- 给后续执行建立一条“别跑偏”的轨道
很多人觉得 planning 很浪费 token。
我刚开始也这么想。
后来我发现,真正浪费 token 的从来不是 planning,而是:
- 没计划直接写
- 写了半天方向错了
- 再回来重做
- 再解释一次自己为什么改了这些东西
那才是真正的 token 黑洞。
所以如果你让我只给一条最先落地的 harness 建议,我会说:
复杂任务先规划,这不是礼貌,这是系统稳定性的门槛。
三、别把所有东西都塞进一份总提示词,规则、技能、命令必须分层
这是我后来踩坑踩出来的一个血泪教训。
很多人刚开始搭 agent 配置时,最自然的做法是:
- 把团队规范塞进去
- 把技术栈注意事项塞进去
- 把 TDD 原则塞进去
- 把安全要求塞进去
- 把代码风格塞进去
- 把自己不喜欢的写法也塞进去
最后得到一个 3000 行的“神级系统提示词”。
然后你每次开会话,都在拿一辆满载的卡车去买瓶水。
问题不是“信息不够”,问题是:
什么都常驻,就等于什么都不重要。
后来我越来越喜欢把东西拆成三层:
1. Rules:长期生效的硬约束
比如:
- 不准硬编码 secret
- 提交前必须验证
- 代码风格底线
- 目录结构约束
- 审批红线
这层像法律。
它回答的是:
“无论你现在在做什么,有哪些事情就是不能越线。”
2. Skills:按需加载的方法论
比如:
- 怎么做安全审查
- 怎么做 TDD
- 怎么做上下文压缩
- 怎么做 context budget 审计
- 怎么做某个框架下的实现
这层像 SOP。
它回答的是:
“遇到这种任务时,应该按什么套路做。”
3. Commands:高频工作流入口
比如:
/plan/tdd/verify/code-review/learn
这层像快捷操作台。
它回答的是:
“哪些流程值得我以后别再每次重讲,直接一键触发。”
这套分层对开发者特别有用,因为它能帮你避免一种很经典的配置病:
什么都想放进去,结果系统越来越重,越来越难维护。
我现在的判断很明确:
- 永远有效的,放规则
- 某类任务才需要的,放技能
- 高频动作,做成命令
只要这层分不清,后面上下文和工作流一定会乱。
四、别让 AI 靠记忆做人,能自动化的都尽量自动化
这应该是我最近一年对 AI 编程系统最大的观念变化。
我以前总觉得:
“没事,模型够聪明,它会记得的。”
后来我发现这句话和“我以后会记得健身”一样不靠谱。
什么东西最容易被忘?
- git push 前再看一眼 diff
- 改完文件记得删
console.log - 长时间跑 dev server 最好别堵在主会话里
- compact 前把当前状态写下来
- 编辑 TS 文件后顺手 typecheck 一下
这些事对不对?
对。
重要不重要?
重要。
但它们都太机械、太高频、太容易漏。
所以对这类动作,我现在越来越倾向一个简单粗暴的标准:
如果它又高频、又机械、又重要,那就别再指望模型或者人类“记得做”,直接做成 hook。
举几个非常典型的开发场景:
场景 1:dev server 把主会话堵死
你让 agent 跑 npm run dev,它就真的在前台傻跑。
然后你眼睁睁看着主会话被日志淹没。
更好的做法是:
- 识别 dev server 命令
- 自动放进 tmux 或独立窗口
- 主会话继续工作
- 日志可追踪
场景 2:agent 改完一堆代码,末尾留了 4 个 console.log
这类问题特别适合做 stop hook。
每次响应后扫一遍改动文件,发现就提醒。
场景 3:你写着写着上下文爆了
最糟糕的不是 compact,而是:
- 在错误时机 compact
- 刚好把还没落盘的状态压没了
所以 compact 前自动记一笔当前状态,这类 hook 非常值。
我对 hook 现在的理解不是“增强项”,而是:
它是把工作习惯从“靠记忆”变成“靠系统”的关键层。
而真正成熟的 hook 系统,还得满足两件事:
- 能区分“提醒”和“阻断”
- 能分级,不是只有开和关
研究探索阶段和生产交付阶段,治理强度当然不一样。
把这两种状态混成一套固定规则,只会让人越用越烦。
五、上下文不是聊天记录,它更像一根内存条
这个比喻虽然土,但特别准。
很多人嘴上知道“上下文有限”,但行动上还是把 Claude Code 当微信聊天。
今天塞:
- 团队规范
- 框架指南
- 历史 bug
- API 文档
- 架构说明
- PR diff
明天再塞:
- 一堆 MCP
- 一堆 rules
- 一堆 skills
- 一堆 agent 描述
最后开始抱怨:
“怎么越用越钝?”
这事儿我现在看得很明白:
不是模型突然失忆了,是你的上下文预算被你自己干烂了。
我现在特别认同一个观点:
上下文不是自然资源,是预算。
你必须知道预算被谁花掉了。
比如:
- 常驻规则吃多少
- 已加载 skills 吃多少
- MCP tools schema 吃多少
- agent 描述吃多少
- 当前会话历史吃多少
一旦你不拆这个账本,就会陷入一种非常熟悉的错觉:
“最近对话有点长,compact 一下应该就好了。”
其实不一定。
可能真正的问题是:
- 你同时开了 12 个 MCP
- 一堆技能常驻了
- 你把项目说明写成了一本小书
- 你给每个 agent 都写了八百字人物小传
所以对上下文,我现在有三条硬习惯:
1. Always-on 内容必须短
凡是常驻加载的,都要克制。
2. 重知识一律按需加载
不是所有会话都要带着一整本操作手册。
3. Compact 要在人类能看懂的阶段边界发生
最适合 compact 的时候通常是:
- 调研结束,准备执行前
- 一个阶段做完,切到下一阶段前
- 一条死胡同走完,准备换方向前
最糟糕的 compact,是正在改到一半时突然压缩。
那种感觉就像你写代码写到一半,脑子被人拔电源。
六、Subagent、后台任务、Worktree,这三种“分出去做”根本不是一回事
这是我觉得开发者最容易搞混的一组概念。
表面上看,它们都像是在“把事情分出去做”。
但分出去的,其实不是同一种东西。
1. Subagent:把“思考和探索”分出去
比如我要回答一个问题:
“这个仓库的测试框架到底怎么接起来的?”
这时候我不一定要让主 agent 带着几十轮读文件记录去查。
更好的做法是:
- 派一个 subagent
- 让它自己读文件、自己搜
- 最后只带摘要回来
这解决的是:
上下文污染。
2. Background task:把“等待”分出去
比如:
npm installpytestdocker build
这些命令本身不需要另一个脑子,它们只是慢。
这种时候你真正想分出去的不是“思考”,而是:
等待时间。
3. Worktree:把“工作空间”分出去
这又是第三种完全不同的分离。
假设一个 agent 在改登录流程,另一个 agent 在改通知系统。
如果两个人都在同一个目录里改,你迟早会看到:
- 脏 diff 互相污染
- 回滚边界失控
- 一堆“这个文件到底是谁改的”事故
这时候要分出去的不是思考,也不是等待,而是:
执行空间。
所以对这三者,我现在会这么记:
subagent:分出去的是脑力background task:分出去的是等待worktree:分出去的是工位
这个区分一旦分清,很多 agent 系统设计问题会突然变得非常清楚。
七、多 agent 真正难的,从来不是“多”,而是“乱”
很多人一说到 AI agent 并行,就很兴奋:
- 多开几个窗口
- 多起几个 agent
- 一起干活
听起来很美。
但只要你真的试过,很快就会进入一种熟悉的项目管理地狱:
- 谁在做什么?
- 谁已经做完了?
- 谁改了哪几个文件?
- 谁的结果可信?
- 哪个任务被谁卡住了?
- 哪个 worktree 现在还能删,哪个不能动?
也就是说,多 agent 系统一旦往前走,真正的瓶颈根本不是“会不会并行”,而是:
有没有控制平面。
我现在对这件事的理解越来越像管理一个小团队。
一个靠谱的多 agent harness,至少得有这些东西:
1. 任务系统
不是 TodoList,而是:
- 有状态
- 有依赖
- 可认领
- 可并行
2. 角色边界
谁负责:
- 规划
- 实施
- 审查
- 安全
- 验证
3. handoff 机制
不是“我把上下文全丢给下一个人”,而是:
- 当前结论是什么
- 哪些文件动了
- 风险是什么
- 下一个 agent 只需要知道什么
4. 工作区隔离
并行改代码,不隔离目录,就是在等事故。
所以我现在越来越相信一件事:
AI 多 agent 的成熟度,不取决于你能同时开几个实例,而取决于你有没有把控制平面搭出来。
八、MCP 很重要,但越用越觉得:它不是越多越好
我对 MCP 的态度这两年变化挺大。
刚开始会觉得:
“太爽了,什么都能接。”
后来用久了发现,MCP 和公司里开 SaaS 账号有点像:
- 开的时候都觉得必要
- 过一阵发现一半根本没在用
- 但成本和复杂度一直在那儿
MCP 当然有价值,尤其是:
- 跨系统检索
- 浏览器自动化
- 一些平台交互
- 外部能力接入
但它的问题也很真实:
- tool schema 占上下文
- server 多了会拖慢体验
- 健康状态得管
- 认证、限流、异常恢复得管
我现在更赞同一种比较现实的策略:
1. 不是所有能力都要常开
2. 高频、边界清楚的能力,很多时候可以退回 CLI + commands
3. 真正复杂、动态、需要探索的外部系统,再优先上 MCP
4. MCP 一旦多起来,就必须进入治理
比如:
- 数量控制
- 健康检查
- backoff
- reconnect
- fail-open / fail-close 策略
说白了:
MCP 不是装饰品,而是基础设施。
基础设施一旦不治理,迟早会反噬你。
九、我现在最信的一条:Harness 本身必须进入测试
这条以前我真没那么重视。
总觉得:
- hooks 反正能跑
- rules 反正是 Markdown
- commands 反正只是入口
- manifests 反正配置一次就好了
后来越写越发现,这种想法非常危险。
因为真正长期使用后,最容易坏掉的往往不是业务代码,而是这些“外围基础设施”:
- command 指向了一个早就不存在的 skill
- agent frontmatter 写错,结果整个委托链失效
- hook JSON 格式漂了
- 一条路径写成了个人电脑绝对路径
- 一个安装 manifest 跟 README 里的数量对不上
这些问题单看都不大,但它们会持续破坏整个工作系统的可信度。
所以我现在很认同一个很硬的结论:
如果你的 harness 是长期资产,那它就必须像代码一样被测试。
不是“顺手测一下”,而是:
- 有 CI
- 有校验链
- 有单元测试
- 有不变量
什么时候我会觉得一套 AI 工程系统开始像样了?
不是它能不能写出一段漂亮代码。
而是它能不能证明:
- 自己的规则没漂
- 自己的 hooks 没坏
- 自己的命令没失效
- 自己的配置没泄漏私人垃圾
这件事听上去一点也不性感。
但恰恰是这种“不性感”的地方,决定了一套 harness 能不能活久。
十、最后说一句我自己的感受
我现在越来越不相信“AI 编程的未来,拼的是谁家模型更像一个程序员”这套说法。
我反而越来越相信另一件事:
未来真正拉开差距的,是谁更会给模型搭工作环境。
同一个模型,放进不同的 harness 里,表现差异会大得离谱。
有的像实习生第一天上班:
- 找不到文件
- 改代码没计划
- 没验证就说完成
- 多开几个实例就互相打架
有的则越来越像一个成熟团队里的靠谱同事:
- 有规则边界
- 有任务系统
- 有自动化提醒
- 有长期记忆
- 有并行机制
- 有恢复能力
- 有验证闭环
这两者拼的根本不是“智商”,而是外面那层工程。
所以如果今天有人问我:
“AI 编程真正值得研究的是什么?”
我现在大概率会回答:
不是怎么写一句更神的 prompt。 而是怎么把 loop、tools、rules、skills、hooks、memory、tasks、worktrees、verification 这些东西,组合成一套长期稳定工作的 harness。
这件事听上去没那么炫。
但真做进去以后,你会发现它比“提示词工程”要硬核得多,也值钱得多。