从 Prompt 到 Context 再到 Agent Harness:先把控制面的轮廓看见
看清任务入口、材料供给与执行闭环如何组合成 AI 编程控制面
这篇文章不再叫 Context Engineering,因为我自己中途改主意了#
最开始这第 3 篇文章,其实不是这么定的。
当时我是先根据自己的经验,和 AI 一起把 outline 过了一遍,初步定下来写 Context Engineering。因为按我原来的直觉,这篇文章讲清楚上下文、规则、污染、约束,差不多也就够了。
结果中途群友突然提了一嘴 Harness,我一下子就警觉了:这个东西可能不能不写。
更有意思的是,OpenAI 那篇讲 100% AI 写代码、做出 100 万行项目 的文章,我之前其实看过。只是我当时第一反应比较直男——大概是觉得:嗯,他们这个工作流看起来和我自己平时搞的那套,也没有差到天上去,好像没什么新鲜感,所以我也就没太当回事。
但后来仔细一想,事情可能真没那么简单。
因为如果只是“我平时也这么干”,那顶多说明大家都在同一条路上;可如果 OpenAI 已经把这套东西系统化地命名、拆层、工程化了,那就说明这里面不是只有 Context 这么简单,而是已经长出了一层更完整的控制面。
这也是我为什么会中途改主意:这篇文章如果还只是写成狭义的 Context Engineering 教程,就有点低估问题了。
因为今天真正困住很多人的,已经不只是“Context 没喂好”,而是:
- Prompt 说不清
- Context 供给混乱
- Agent 能跑,但跑不稳
- 工具很多,但没有控制面
- 验证链路、边界、反馈闭环都没搭起来
所以这篇文章不该再写成狭义的 Context Engineering 教程。
这篇文章真正要讲清楚的是:AI 编程的控制面,正在从 Prompt 扩到 Context,再扩到 Agent Harness。
说明:Harness 是个很新的词
Harness Engineering在 AI 编程语境里,不是什么用了很多年的老概念。至少在工程圈里,它是 2026 年 2 月 被 OpenAI 通过Harness engineering: leveraging Codex in an agent-first world系统化带火的。所以这篇文章不会装成它是一个早就行业统一定义好的经典术语。我这里采用这个词,是因为它确实很有解释力,能把“Prompt 不够、Context 也不够,真正缺的是整套执行壳”这件事讲清楚。
这篇文章的核心命题
Prompt、Context、Agent Harness不是替代关系,而是 AI 编程控制面的分层进化。
Prompt决定这次要干什么Context决定 AI 在什么信息约束下干Agent Harness决定它怎么稳定执行、验证、收敛
先纠正一个误区:Prompt 没死,死的是“盲打式 prompting”#
很多人现在一提 Prompt Engineering,语气就像在说什么上古遗迹。
我觉得这个判断挺草率的。
真正过时的,不是 Prompt,而是那种在聊天框里反复试错、试到哪算哪、没有验证、没有结构、没有边界的盲打式 prompting。Mitchell Hashimoto 早在 2023 年就专门写过 Prompt Engineering vs. Blind Prompting,他想说的其实很直接:不是所有“对模型说话”都配叫 engineering。
Prompt 到底解决什么#
Prompt Engineering 解决的是一个非常基础、但永远绕不过去的问题:
这次,到底要 AI 干什么。
也就是说,它负责定义:
- 目标是什么
- 边界是什么
- 成功标准是什么
- 输出应该长什么样
如果这一步说不清,后面一切都是空中楼阁。
一个很简单,但更符合现阶段 CodeAgent 的例子#
烂 Prompt#
帮我给这个项目加一个用户接口过渡时期常见、但已经不太像现在主流 CodeAgent 风格的 Prompt#
请在现有 Next.js + Prisma 项目里新增一个“获取单个用户信息”的 API。
要求:
- 复用现有路由风格,不要自己另起框架
- 禁止直接拼接 SQL
- 必须使用 Prisma Client
- 需要处理用户不存在的情况
- 返回结构与项目现有 API 保持一致
- 最后告诉我你改了哪些文件,以及如何验证这段 Prompt 我保留着,因为它很适合说明“任务表达比一句废话强太多”。
但如果放到今天的主流 CodeAgent 语境里,它其实已经有点“过度展开”了。不是说这些要求错了,而是其中不少内容,已经从“需要你亲口教模型”的东西,变成了“强 agent 理应默认做到”的基线。
比如:
需要处理用户不存在的情况,这类正常边界分支,现阶段大多数像样模型本来就会补复用现有路由风格、不要自己另起框架,很多 agent 也会先靠读仓库自己判断- 真正更容易被偷懒糊弄过去的,反而常常是
不要顺手做无关重构、发现多个入口先说明选择、不要自己编一套返回协议
所以问题不在于 Prompt 要不要详细,而在于:你到底是在补模型的基础理解,还是在卡它最容易擅自发挥的决策点。
更符合现阶段 CodeAgent 风格的任务指令#
在现有项目里新增“获取单个用户信息”的 API。
重点:
- 不要改现有架构,只沿用仓库里已经存在的实现路径
- 如果发现有多个可接入入口,先说明你选哪一个,以及为什么
- 不要顺手做无关重构
- 完成后按项目已有方式验证,并告诉我改了哪些文件、怎么验证的这一版更像我现在真的会给 CodeAgent 的任务指令。
它和前一版最关键的区别不在于“更短”,而在于:它不再把篇幅浪费在那些优秀 agent 本来就该通过读仓库学会的东西上,而是把重点放在那些模型最容易擅自发挥、最容易偷懒、最容易越界的地方。
比如我前面举的这个历史版本里,有一句是:
需要处理用户不存在的情况
放到今天看,这句很多时候其实已经不算重点了。因为对现阶段大多数强 CodeAgent 来说,用户不存在 这种边界,本来就是它应该自己补上的基本功。
更值得看情况补一句的,通常反而是这种:
沿用项目现有错误语义,不要自创一套返回格式
但这里我也不想把话说死。因为即便是这句,也不是任何时候都非写不可。像 Codex 这种典型的 repo-first agent,很多时候属于“不把相关文件翻一圈就不干活”的类型。它会先去看现有 handler、service、schema、tests,再决定用户不存在时到底该怎么返。所以如果仓库风格本来就清晰,它往往自己就能跟上,不一定需要人再额外提醒。
真正需要额外强调这类约束的情况,通常是:
- 你已经观察到这个 agent 有偷懒习惯
- 你不想让它为了省事,自己发明错误码、状态码或者返回结构
- 当前仓库里存在多套风格并存,容易让模型选错参考对象
- 这是一个对外 API、SDK 或公共契约,语义偏差的代价很高
- 你用的不是那种 repo-first、会主动翻很多文件再动手的 agent
所以这两段对比真正说明的不是“Prompt 要写得越长越好”,而是:
- 早期更多是在补模型的基础理解
- 现在更多是在约束模型的判断边界、执行优先级和偷懒空间
- 而且这些约束写到什么程度,还要看你在用的是哪一类 CodeAgent,以及这个仓库本身清不清楚
- 如果仓库本身是 monorepo、多栈并存,或者正处在迁移期,那像“只改
apps/admin,不要碰legacy-bff”这种边界,依然很值得明确写进 Prompt
为什么 Prompt 永远不会消失#
因为只要你还在和模型协作,你就不可能跳过“定义当前任务”这一步。
哪怕后面引入了 Context,以及承载它的 Specs、Skills,再往后接上 CLI、MCP、Cloud tasks,也只是把控制面往外扩,不是把 Prompt 消灭掉。
所以我更愿意把 Prompt Engineering 放在第一层:
它不是全部,但它永远是入口。
这一层的边界
Prompt Engineering最容易被神化,也最容易被踩。神化它的人,会把它说成万能钥匙;否定它的人,又会把它说成过时垃圾。两边都太极端了。更准确的理解是:Prompt 是入口层,没有它不行,但只有它也不行。
为什么只靠 Prompt 很快就会撞墙#
真正开始做工程任务之后,你很快就会发现:Prompt 再认真写,也只能覆盖一部分问题。
因为单次 Prompt 很难天然装下这些东西:
- 项目的长期规范
- 历史架构决策
- 目录和命名习惯
- 设计稿与验收标准
- 运行时的动态信号
- 执行时允许调用什么工具
- 出错后该怎么收口和回退
这也是为什么很多人会出现一种很熟悉的幻觉:
明明我 Prompt 已经写得比以前认真很多了,为什么 AI 还是会乱猜?
因为问题已经不再是“这次任务说没说清”,而是:
模型理解这个任务时,手里到底拿到了什么材料。
一个很典型的翻车场景#
比如你想让 AI 在现有仓库里补一个列表页。
Prompt 已经写清楚了:
- 要支持搜索
- 要支持分页
- 要走现有组件体系
- 要复用已有接口风格
结果 AI 依然可能会:
- 自己发明一个新的表格组件
- 用旧目录里的废弃写法
- 把测试辅助函数当正式业务模式参考
- 乱用相对路径
- 忽略你项目里已经有的状态管理方案
这时候问题不是 Prompt 失效,而是 Prompt 已经碰到了它的边界。很多原本靠人肉反复写在 Prompt 里的约束,到了这一步,其实就该往 AGENTS.md、specs、Skills 这些更稳定的载体里迁了。
一句很现实的话很多人嘴上说“AI 很笨”,本质上是在让模型裸奔:只给目标,不给上下文;只给任务,不给约束;只给命令,不给边界。
Context Engineering 解决的不是“多喂一点”,而是“控制信息分发”#
当 Prompt 开始撞墙,下一步通常不是把 Prompt 再写长 500 字,而是开始做 Context Engineering。
但如果把这件事理解成“把更多东西塞进上下文”,那很容易从工程进步走成 token 自杀。
更准确地说,我现在更愿意把 Context Engineering 理解成:
模型在什么时刻、以什么形式、拿到哪一组材料来理解当前任务,以及哪一组噪声应该被屏蔽。
Thoughtworks 在 Context engineering 里给出的方向我很认同:它关注的不是 prompt wording,而是整个 inference context 的系统设计与优化。翻译成人话就是:不是继续往上下文里猛塞材料,而是把真正影响当前决策的材料,以更合适的方式分发进去。
我现在更警惕三种“伪 Context Engineering”#
第一种:把整个仓库都喂进去#
这招看上去很豪横,实际上经常只是把噪声、过期样例和主线代码一起喂给模型。
放到今天尤其如此。因为很多强一点的 CodeAgent,本来就会自己搜仓库、看相邻实现、顺着调用链往上翻。你真正该操心的,往往不是“它能不能看到更多”,而是“哪些材料会被它当成 source of truth、哪些旧材料会因为出现太多而混进来、哪些迁移中的实现应该被排除”。
如果 legacy/、__mocks__/、实验目录、废弃示例和正式实现摆在一个权重上,模型当然会学歪。
第二种:把 AGENTS.md 写成项目宪法#
AGENTS.md 写成项目宪法#OpenAI 在 Introducing Codex 里明确提到,Codex 可以通过仓库内的 AGENTS.md 学会如何导航代码库、运行测试和遵循项目实践;Anthropic 官方文档里,CLAUDE.md project memory 也被定位成承载项目架构、代码规范和常用命令的长期记忆。
这些东西当然有用,但我现在越来越警惕一种做法:把所有经验、禁令、命令、风格、注意事项全堆到一个几千字文件里,然后默认 agent 会永远准确执行。
问题在于:
- 过期文档会带着“官方口吻”误导模型
- 和源码冲突时,模型不一定总能分清谁更新
- 太长的全局规则会把真正高频、关键的信息淹没
长期有效的项目级 Context 需要的是:短、准、可维护、经常更新,而不是像部门制度一样越写越厚。
我现在很认同的一句工程直觉过期的 Context,很多时候比没有 Context 还危险。
第三种:什么都继续写回 Prompt#
如果一个约束会在几十个任务里重复出现,那它就不该继续靠人肉复制粘贴活着。
这时候更合理的做法,通常是把它升级成:
- 项目级记忆:
AGENTS.md、CLAUDE.md - 任务级规格:specs、issue、PRD、设计稿
- 可复用模块:
Skills、subagents、playbooks - 运行级信号:测试失败、日志、trace、截图对比
否则你做的不是 Context Engineering,只是把“记忆系统”外包给自己的耐心。
Skills 是最容易被低估的 Context Engineering#
Skills 是最容易被低估的 Context Engineering#我前面专门补了 Skills,不是为了凑名词,而是因为它确实很典型。
不同产品对这类东西的叫法不一样:有的叫 Skills,有的叫 project memory,有的叫 subagents。但从工程视角看,它们很多时候都在做同一件事:把长期有效、可复用、按需加载的上下文结构化。
Anthropic 官方文档里,subagents 的一个关键设计就是独立 context window:把某类任务需要的指令、工具和专门上下文隔离开,不要污染主线程。这个思路我觉得特别有代表性,因为它说明今天的 Context Engineering,已经不只是“写规则”,而是开始考虑怎么按需加载、怎么减少污染、怎么把高价值经验模块化复用。
举个更像现在真实工作流的例子。
如果我要让 agent 去改一个后台页面,涉及设计稿对齐、组件选型、响应式适配和基础可访问性,我当然可以每次都在 Prompt 里重写一遍:
- 用现有 design system
- 间距遵循 4/8px token
- 优先复用现有卡片和表格组件
- 移动端注意 safe area
- 表单要有基本 a11y
- 最后截个图给我看
但这种做法说白了就是人肉复制粘贴。
更像 Context Engineering 的做法,是把这些长期有效的 UI 规则、Figma 交付习惯、组件优先级、检查清单收进一个 Skill 里,需要时再触发。
这里就可以举一个很具体的公开例子:UI UX Pro Max。这个 skill 的 README 里写得很直白:它不只是给几个审美建议,而是会基于项目需求去生成一整套 design system,里面包含 pattern、style、colors、typography、key effects、anti-patterns 和 pre-delivery checklist;它还内置了 67 UI Styles、161 Reasoning Rules、99 UX Guidelines 这类结构化资料库。
这类 skill 最适合干的一件事,就是先帮 agent 把“这次页面到底该走什么风格路线”定下来。
比如你已经知道自己这次要做的是:
- 金融后台,那就更偏稳、清晰、可信,不要乱上 AI 紫粉渐变
- 美业落地页,那就可能更适合柔和、轻奢、强调情绪价值的路线
- AI 产品控制台,那就可以考虑更偏
AI-Native UI、Bento Grid、高信息密度的表达
这时候 skill 给出的东西,本质上不是“代替设计师拍脑袋”,而是把一套可复用的风格判断、行业 anti-pattern 和交付 checklist 结构化成可以按需注入的 Context。
这样做有几个直接好处:
- 不用每次都重复讲同一套废话
- 只在相关任务里加载,噪声更低
- 团队能复用,不用靠个人记忆维持
- 规范更新时改一处就行,不用改几十个 Prompt
- 在“先确定路线,再出页面”这一步上,比临场口嗨稳定得多
GitHub 高度相关的项目也是一样。把 label 语义、PR checklist、commit scope、review 习惯写进一个 GitHub workflow skill 或 repo memory,本质上也是在做 Context Engineering。真正到了用 gh 去发评论、建 PR、改 issue 的那一步,才开始逐渐踩到 Harness 的边界。
这也是我现在一个很重要的判断:
Skills 不是外挂插件那么简单,它们很多时候就是“结构化、可复用、按需注入的 Context”。
今天更常见的问题,不是没 Context,而是权重错了#
早期大家经常遇到的问题,确实是“什么都没给,模型只能瞎猜”。
但到了现在,尤其是你开始用强一点的 CodeAgent 之后,更常见的问题反而变成了:
不是没有 Context,而是给了很多 Context,但模型对这些材料的权重分配错了。
这里的“权重错了”,不只是“先看到谁就把谁当权威”。顺序当然有影响,但远远不是唯一因素。
按我的真实体验,模型还很容易被这些东西带偏:
- 某类写法在仓库里出现次数更多,于是它把“出现最多的”错当成“现在的标准”
- 旧文档虽然过期了,但因为被复制、归档、引用了很多次,反而显得更像权威
- 仓库正在做架构迁移,新旧实现并存,模型把“还没迁完的旧路径”当成主线
- 同一个概念在 specs、issue、代码注释、归档文档里说法不一致,模型会自己挑一个最像答案的版本
我自己在用 OpenSpec 的时候,就真踩过这种坑。
有些任务做完之后会归档,归档目录里多个 spec 混在一起。如果这时候又刚好经历过几轮 refactor,AI 就很容易把旧 spec 当成新 spec,或者因为某个旧约束在多个地方重复出现,就误以为那才是当前标准。
代码里也是一样。比如某块业务正在往新架构迁,新的目录和旧的目录会并存一段时间。对人来说,这叫“迁移中”;对模型来说,如果没有明确告诉它哪边才是 source of truth,它就很可能把“看起来更多”“更熟悉”“出现更频繁”的那一边当成标准。
还是拿路径别名这个例子说。项目明明统一要求用:
import Button from "@/components/Button";结果 AI 还是给你写成:
import Button from "../../components/Button";这时候问题未必是“它没看到规则”,更可能是:
- 旧目录里的相对路径写法在仓库里出现得更多
- 示例代码、测试夹具、废弃实现重复出现,污染了模型判断
- 项目级规则存在,但没有被明确标成当前 source of truth
- 当前任务没有指出“这次必须优先参考哪几个文件、哪一套目录”
这就是我现在越来越在意的一点:Context Engineering 不只是补材料,还要管理权威顺序、出现频率、时效性和排除顺序。
该屏蔽的旧样例要屏蔽,该标明 source of truth 的文件要标明,该说明“这是迁移中的旧实现,不要继续模仿”的地方要说明,该告诉 agent “优先参考这一页,不要参考那一页”的地方也要直说。
更进一步说,有些 Context 问题的解法根本不是“再补一份说明文档”,而是直接做仓库治理:
- 给归档 spec 明确标
archived、deprecated、superseded by - 给迁移中的旧目录写清楚“只读参考,不要继续新增逻辑”
- 把最权威的实现路径、schema、checklist 放到更容易被 agent 命中的位置
- 能删掉的过期样例就删掉,别把噪声永久留在仓库里
这一点很重要,因为 Context Engineering 不是纯写作文,它很多时候就是信息架构治理,甚至是仓库卫生治理。
我现在更愿意从四个维度设计 Context#
生命周期#
- 项目级:
AGENTS.md、CLAUDE.md、架构规则、命名规范、常用命令 - 任务级:specs、issue、PRD、设计稿、截图、验收标准
- 运行级:当前 diff、终端输出、测试结果、浏览器状态、trace、观测数据
形态#
- 规则:约束、禁令、风格要求
- 样例:golden path、参考实现、模板文件
- 流程:
Skills、playbooks、subagents、检查清单 - 信号:日志、失败测试、截图对比、线上报错
加载方式#
- 常驻加载:长期有效的项目规则
- 按需检索:只在任务相关时拉取 specs、设计稿、外部文档
- 隔离加载:subagent / 子代理使用独立 context window,避免主线程被污染
- 反馈回注:把执行过程中产生的测试结果、trace、diff 再回送给模型
质量#
- 权威性:源码、测试、正式 specs 往往比旧 wiki 更可信
- 新鲜度:过期文档要么更新,要么别喂
- 一致性:冲突规则不解决,模型一定会乱选
- 成本:每一段额外 context 都应该解释自己为什么值得占 token
一个更符合当下的例子#
还是拿一个很实际的任务说。
假设我要让 agent 给现有 Next.js 管理后台补一个“团队成员管理”页面。
如果我只做“堆料式 Context”,很容易变成这样:
- 一个 3000 字的
AGENTS.md - 一整份 PRD 全贴进去
- 十几张设计图一起塞
- 整个仓库开放搜索,但不告诉它优先参考哪条实现路径
- 最后再补一句“按现有风格来”
看上去信息很多,实际上很容易把模型喂晕。
我现在更愿意这么配:
- 项目级 Context:
AGENTS.md里只保留稳定、长期有效的架构规则、命名规范、常用验证命令 - 任务级 Context:这次页面对应的 issue、目标路由、Figma frame、现有成员 API、验收标准
- 技能型 Context:一个
ui-ux-promaxskill,里面放 design system、响应式和 a11y checklist;如果项目和 GitHub 工作流强相关,再加一个 GitHub workflow skill - 运行级 Context:当前 diff、Playwright 截图对比、失败测试、lint 输出
这样 agent 不需要“知道一切”,但它会更容易在这一次任务里知道足够对的东西。
我现在对 Context Engineering 的一句话理解它不是让 AI “什么都知道”,而是让 AI 在当前时刻知道足够对、足够新、足够权威的东西。
做到这一步,agent 至少不会再赤手空拳地瞎猜了。
但它能不能稳定执行、验证、失败后继续收敛,那就已经不是 Context 一层能单独解决的事了。这也是为什么下一层必须是 Harness。
Agent Harness 解决的是“怎么把 agent 放进一个可控的 how loop”#
如果说:
Prompt负责说清楚这次要干什么Context负责给够信息、控制权重和减少噪声
那 Agent Harness 解决的就是下一层问题:
这件事到底要怎么跑起来、怎么验证、怎么收口,出了问题又怎么继续迭代。
我觉得这里最容易把人带偏的一点是:很多文章一写 Harness,就开始列一堆名词:CLI、MCP、hooks、CI、browser use、cloud tasks……看上去很高级,但读完之后你还是不知道自己到底该做什么。
所以这一节我不想再按“工具大全”写。
我更想把它写成一个很朴素、但更符合当下工作流的问题:
你到底有没有为 agent 设计一条可重复、可观察、可验证、可纠偏的 how loop。
我现在更愿意把 Harness 理解成“how loop”#
Thoughtworks 在 Humans and Agents in Software Engineering Loops 里有个说法我很喜欢:human 不只是 in the loop,更应该学会 on the loop。
翻译成人话就是:
in the loop是每次 agent 做错了,人就下场补代码、补 Prompt、补一句说明on the loop是 agent 一旦反复做错,人就去改产生结果的那条流程本身
这其实就是我现在理解的 Harness。
它不是单个工具,也不是一份配置文件,而是:
让 agent 能独立跑,又不至于脱缰的整套 how loop。
OpenAI 在 Harness engineering: leveraging Codex in an agent-first world 里真正有价值的部分,我觉得也不是“100% AI 写了 100 万行代码”这个标题党数字,而是它把工程师的工作重心明确地从“亲手写代码”挪到了“设计环境、指定意图、搭建反馈闭环”。
这个视角一旦转过来,很多事情就突然顺了:
- 为什么光有 Prompt 不够
- 为什么光有 Context 也不够
- 为什么 agent 明明能写代码,却还是经常跑不稳
因为“会写”不等于“会在一个工程系统里稳定交付”。
真正值得关心的,不是装了什么工具,而是 loop 能不能闭环#
我现在看一个团队的 Harness 成不成熟,不太先看它装了多少工具,而是先看这四个问题。
第一件事:agent 在哪里跑#
这是很多人最容易忽略的。
如果 agent 直接在一个脏乱共享环境里乱跑:
- 多个任务共用一个工作目录
- 本地 dev server 状态互相污染
- 浏览器缓存和登录态串来串去
- 日志全混在一起
那它就算模型再强,也很容易出玄学问题。
OpenAI 在官方文章里提到的一个特别关键的点,就是per git worktree 启动应用:每个任务有自己的 worktree、自己的 app 实例、自己的日志和观测数据。这不是花活,这是稳定性的前提。
因为只有这样,你才能让 agent:
- 长时间跑一个任务而不污染别的任务
- 并行多个任务而不互相打架
- 把截图、日志、trace、diff 和这次改动稳定对应起来
如果放到个人开发者的工作流里,我觉得最小可用版本至少要做到:
- 一个任务一个 worktree 或独立工作目录
- 能稳定重启项目,而不是复用一坨不知道什么状态的 dev server
- 危险命令有 sandbox、approval 或最起码的 guardrail
第二件事:agent 能不能看懂“正在发生什么”#
很多人以为 Harness 就是“让 agent 能执行命令”。
我现在越来越觉得,这只是很小的一部分。
真正拉开差距的,往往是:agent 能不能看懂运行时世界。
OpenAI 那篇文章里最有启发的一段,就是他们不是只给 Codex 看代码和文档,而是把这些东西也做成 agent 可读:
- 应用 UI
- DOM snapshot 和截图
- 浏览器导航结果
- logs
- metrics
- traces
这件事的意义非常大。
因为一旦这些信号能进 agent 的 loop,很多以前只能靠人盯着做的任务,才第一次真正变得可执行。
比如下面这种需求,在没有运行时可观测性的情况下几乎就是一句空话:
- 启动时间压到 800ms 以内
- 四条关键用户路径里,不允许有 span 超过 2 秒
- 邀请成员成功后,页面状态、toast 和审计日志必须一致
为什么以前 agent 很难做这类事?
因为它只能“猜自己写得对不对”。
而一旦你给它浏览器、截图、日志、指标、trace,它就开始不只是写代码,而是在对照现实信号迭代。
这一层最值钱的,不是多会写代码真正强的
Harness,不是让 agent 更会“说”,而是让 agent 更会观察、验证和自证。
第三件事:agent 怎么证明自己做对了#
这里也是我觉得很多文章最容易写虚的地方。
很多人写“让 agent 自测一下”,这句话说了跟没说差不多。
真正的问题是:
它到底拿什么证明自己做对了?
如果答案还是“模型自己觉得差不多”,那这根本不叫验证。
在我看来,Harness 这一层最核心的价值之一,就是把“感觉对了”换成尽量多的机械检查:
- unit / integration / e2e tests
- lint
- type check
- contract check
- structural test
- architecture lint
- screenshot diff
- PR review checklist
Martin Fowler 在 Harness Engineering 里也专门抓住了这一点:OpenAI 那套东西真正重要的,不只是 context,而是把 architecture constraints、deterministic checks 和 garbage collection 都放进了系统里。
我自己现在的判断很直接:
Prompt负责表达目标Context负责减少误解Harness则要尽量把“是否做对”变成可机械判定的问题
因为只要这一步没建立起来,人就永远还是那个最后兜底的肉身 QA。
第四件事:agent 失败以后,系统会不会越跑越聪明#
这可能是 Harness 最像工程、也最不像“聊天技巧”的地方。
很多人现在其实已经有一点 harness 雏形了:
- 能跑命令
- 能看文件
- 能开 PR
- 能跑测试
但一旦失败,后续动作还是非常原始:
- 人看一眼
- 人改一下
- 人再告诉 agent“你这里错了,重来”
这样当然也能做事,但它很难复利。
我越来越认同 OpenAI 那个思路:agent 挣扎,不先怪模型,先问系统缺了什么。
缺的是:
- 文档?那就补文档
- 校验?那就补 lint / test / structural check
- 运行时信号?那就补日志、trace、截图采集
- 评审流程?那就补 review playbook、PR checklist、agent review
- 容易重复犯错?那就把这条经验升级成
Skill、hook 或仓库规则
这才是 Harness Engineering 最有含金量的地方:
不是一次次纠正输出,而是持续改造那条生产输出的 loop。
一个很实用的判断标准如果同一类错误已经出现了三次,团队还在靠人肉提醒,而不是把它升级成 rule、lint、skill、checklist 或 hook,那多半还没真正进入
Harness Engineering。
我现在更愿意把 Harness 拆成四层能力#
为了别把这件事重新写成“概念大杂烩”,我现在更愿意这样理解 Harness。
1. 执行环境层#
让 agent 有一个稳定、可隔离、可恢复的工作现场。
例如:
- worktree / container / sandbox
- permissions / approvals
- session state
- long-running tasks
2. 运行时可见性层#
让 agent 不只是看见代码,还能看见运行后的世界。
例如:
- browser / CDP
- screenshots / video
- logs / metrics / traces
- runtime observations
3. 机械验证层#
把“做对了没有”尽量交给确定性检查,而不是情绪判断。
例如:
- tests
- CI
- linters
- structural checks
- contract / schema validation
4. 收敛与抗熵层#
让系统在失败、漂移、重复犯错之后,不是越来越烂,而是越来越稳。
例如:
- review loop
- background cleanup agents
- doc gardening
- golden rules
- recurring refactor tasks
你会发现,这四层里真正不可替代的,不是某个具体工具名,而是这些能力本身。
工具当然重要,但工具只是实现手段,不是学习重点。
用同一个任务看,Harness 到底多做了什么#
还是沿用前面的例子:
给现有 Next.js 项目新增“团队成员管理”页面,要求带权限校验、列表查询、成员邀请和基础审计日志。
如果只有 Prompt + Context,agent 当然已经能写出不少代码了。
但真正到了落地时,最容易卡住的往往不是“不会写”,而是这些问题:
- 它写出来的 UI 到底和设计稿差了多少
- 邀请流程跑起来之后,toast、表格刷新和审计日志是否一致
- 某个 403 到底是权限逻辑错了,还是请求头没带对
- 这次改动有没有悄悄破坏别的成员管理路径
- 失败之后,它有没有足够信号继续修,而不是站在原地瞎猜
这时候 Harness 真正干的事,大概是这样的:
- agent 在独立 worktree 里启动这次任务的本地环境
- 用
gh、specs、设计稿和相关Skill拿到任务背景 - 改代码,但不只停在 diff 上
- 启动应用,用浏览器或 Playwright 把“成员邀请”主流程点一遍
- 读取截图、DOM、日志、可能的话再看 trace 或 network
- 跑 lint、tests、结构检查,确认没有把边界打穿
- 如果失败,根据这些运行时信号继续修,而不是重新瞎蒙一轮
- 通过后开 PR,拉 agent review 或 cloud review 继续迭代
- 如果发现某类问题反复出现,再把它升级进
Skill、rule、lint 或 cleanup 任务
你会发现,到了这一步,agent 做的已经不是“写代码”这么简单,而是在一个可控 loop 里执行、验证、收敛。
这也是为什么我现在越来越不愿意把 Harness 写成“工具集合介绍”。
因为那样读者最后学到的,往往只是:
- 去装几个 MCP
- 去接几个 CLI
- 去开个 cloud task
但真正该学会的是:
- 怎么隔离环境
- 怎么让应用对 agent 可见
- 怎么把验证变成机械检查
- 怎么把重复失败升级成系统改进
这里还要补一个边界:不是所有东西都只属于某一层#
前面我已经把 Skills 更多放在了 Context 那一层,因为大多数 Skills 的本质是结构化、可复用、按需注入的上下文。
但放到真实工程里,层和层之间也不是绝对绝缘的。
比如:
- 一个 UI skill,大多数时候更像
Context - 但如果这个 skill 里还包含了固定的验证步骤、截图检查清单、review playbook,那它就已经开始摸到
Harness的边界了
所以我的建议不是死抠“这个词到底只属于哪一层”,而是先问:
它主要是在解决“表达目标”“分发信息”,还是“稳定执行与收敛”里的哪一个问题。
这一节最重要的一句话
Agent Harness不是“我给 agent 接了多少工具”,而是“我有没有把 agent 放进一条可重复、可观察、可验证、可纠偏的 how loop”。
三层关系不是替代,而是控制面逐层外扩#
到这里,其实就能把三层关系说得很清楚了。
| 层级 | 它回答的问题 | 典型载体 | 没有它会怎样 |
|---|---|---|---|
Prompt Engineering | 这次要 AI 干什么 | Prompt、任务描述、验收要求 | AI 连目标都说不清 |
Context Engineering | AI 在什么信息约束下干 | AGENTS.md、Specs、Skills、设计稿、日志、检索结果 | AI 会乱猜、乱引用、乱实现 |
Agent Harness | AI 怎么稳定地干并验证结果 | CLI、MCP、hooks、Actions、cloud tasks、CI、sandbox、observability | AI 能说不能稳,能跑不能收敛 |
如果要把这张表压缩成一句话,那就是:
Prompt 决定方向,Context 决定理解,Harness 决定交付质量。
这也是我觉得第 3 篇文章必须重写命题的原因。
因为如果还把它写成“精准投喂 Context 的艺术”,那读者最后只会记住:
哦,所以我应该多写点 rules。
但真正该学会的,是:
我需要搭建的是分层控制面,而不是继续在聊天框里修修补补。
一个贯穿案例:同一个任务,三层控制面分别起什么作用#
这一节我建议用一个统一任务贯穿,不然这篇文章很容易飘成概念体操。
任务就用这个:
给现有 Next.js 项目新增一个“团队成员管理”页面,要求带权限校验、列表查询、成员邀请和基础审计日志。
只有 Prompt 时会发生什么#
你可以把需求说出来,AI 也能开始写。
但大概率会出现这些问题:
- 自己猜目录结构
- 自己猜状态管理方式
- 自己猜权限模型
- 自己猜 API 返回结构
- 写完也不一定知道怎么验证
这时它像一个“愿意干活但刚入职的信息不足实习生”。
加上 Context 后会怎样#
这时你补上:
- 项目技术栈和当前要改的那一段实现边界
- 组件规范和 design system
- API 风格与 source of truth 实现
- 设计稿和验收标准
- 现有 auth 方案
AGENTS.md- 相关
Skill与“哪些旧目录不要参考”这类排除信息
AI 的实现会明显更贴项目。
它不再只是“写点看起来像代码的东西”,而是在对齐项目上下文之后写代码。
再加上 Agent Harness 后会怎样#
这时候它不仅知道该怎么写,还知道该怎么执行:
- 用 CLI 搜仓库
- 用 MCP 读设计稿或 issue
- 跑测试和 lint
- 通过 hooks 控危险命令
- 用 GitHub Actions 或 cloud tasks 跑异步任务
- 失败时根据日志和测试结果继续迭代
这时候,AI 才真正从“会回答的模型”变成“能稳定做事的 agent system”。
这也是为什么我现在越来越不爱听那种单点神话#
比如:
- “只要 Prompt 写得好就够了”
- “只要 Context 配好了就无敌了”
- “只要装上某个 agent 工具就自动 AI Native 了”
这些说法都太像单点神话。
真实工程从来不是靠一个点赢,而是靠一整层控制面慢慢搭出来。
这节真正想让读者看懂的同一个任务,从 Prompt 到 Context 再到 Harness,不是三个 buzzword 在排队,而是三层控制面在逐步补齐前一层做不到的部分。
现在回头看前两篇文章,线其实就串起来了#
如果这篇文章写到这里读者还只是记住了 Prompt、Context、Harness 三个词,那这篇文章其实还没写成功。
因为这篇文章真正想完成的,不是再塞三个新名词,而是让人突然意识到:
原来我前面写的那些模型、那些开发方式、那些工具形态、那些生态位,不是在铺陈信息量,而是在铺这条控制面的主线。
第 1 篇文章为什么要先写那么多模型、交互方式和开发模式#
现在回头看第 1 篇文章《从"你写 AI 补"到"你说 AI 做"的范式转移》,应该就会更清楚。
我前面花很多篇幅去写模型能力演进,不是为了做一版 AI 圈编年史。
我真正想说明的是:如果没有模型能力的跃迁,后面这些控制面根本长不出来。
- 没有更稳的 tool calling,agent 很难真正执行
- 没有更长的上下文和更稳的长任务能力,
Context很难发挥价值 - 没有更好的多模态和运行时理解,
Harness里的浏览器、截图、日志、trace 就会沦为摆设
所以第 1 篇文章里为什么要写那么多模型?因为我想先把“为什么今天的问题已经不再只是补全”这件事钉死。
同理,我写那么多交互方式、开发模式和工具形态,也不是为了把历史阶段背给读者听,而是为了说明:
当 AI 从补全走到执行,人的工作重点就一定会从“自己写实现”慢慢转向“定义目标、分发信息、设计执行壳”。
换句话说,第 1 篇文章讲的是:为什么这条控制面会出现。
第 2 篇文章为什么要写那么多不同生态位的工具#
第 2 篇文章《兵器谱:Vibe Coding 工具版图与组合策略》也一样。
那篇如果只当成工具测评来看,当然会觉得我怎么一会儿讲 GitHub Copilot,一会儿讲 Codex,一会儿讲 Claude Code、OpenCode、OpenSpec、CodeRabbit、Skills、MCP,好像什么都讲了一遍。
但第 3 篇文章写到这里,应该就能看出来了:
第 2 篇文章真正想做的,不是给工具排个高低,而是把它们放回各自的生态位。
因为不同工具,本来就在控制面的不同位置上发力:
SpecDriven工具,很多时候是在提前生产高质量ContextSkills,很多时候是在把长期经验结构化、模块化、按需注入- CLI agent,很多时候更贴近
Harness,因为它最容易接上执行、验证和收敛 loop - Web / 云端 agent,更适合异步委派、后台执行和 review 协作
- GitHub Copilot 这种平台型工具,强在能把 IDE、GitHub、CLI、review、agent 委派串成一条链
所以第 2 篇文章为什么要写“岗位分工”?因为如果没有岗位分工,读者最后就会把所有东西都混成一句话:
找个最强的工具,然后希望它包打天下。
但真实工程从来不是这么赢的。
第 3 篇文章真正做的,是把前两篇的线收成一张图#
如果硬要把前三篇文章压成一句话,那大概就是:
- 第 1 篇文章回答:为什么范式变了
- 第 2 篇文章回答:现在有哪些岗位和武器
- 第 3 篇文章回答:这些东西到底该怎么在脑子里串成一个控制面
到了这里,前两篇文章那些看上去分散的内容,其实才真正闭环:
- 模型能力演进,解释了为什么 agent 会从补全走向执行
- 工具形态分化,解释了为什么不会存在一个包打天下的“完美单品”
- 控制面分层,则解释了这些能力和工具为什么必须被重新组织,而不是继续散着用
这也是我最想让读者产生的那个“哦,原来如此”的瞬间。
不是“我又学了三个新概念”,而是:
原来前两篇文章写的不是散装知识,而是在铺今天这一张控制面总图。
这也是为什么下一篇文章不再继续聊“选什么”,而是先把主线项目摆上桌面#
如果读者走到这里,应该已经不会再只问:
- 哪个模型最强?
- 哪个工具最好?
- 哪个 agent 最能打?
因为这些问题到了真实工程里,很快都会变成更扎心的版本:
- 为什么 AI 写得越来越快,但 debug 越来越痛苦?
- 为什么它明明改对了局部,却总在边缘条件翻车?
- 为什么一个任务越长,代码越像黑盒面条?
- 为什么工具越多,失控感反而越强?
这时候,为什么还要先有一篇主线项目亮相,其实就很自然了。
因为如果控制面只停在脑子里,它依然很容易重新变成概念体操。
所以紧接着这篇文章之后,我不想立刻跳进“暗礁”,而是要先把 GraphSpec 这条主线项目摆上桌面,让读者先看清楚:后面这些工具、约束、护栏和自动化能力,到底是要拿来打什么仗。
一旦项目本身先亮出来,后面真正要面对的问题才会变得具体:
Prompt没立住,任务目标就会漂Context没治理好,模型就会乱引用、乱跟风、乱学旧实现Harness没搭好,agent 就会能跑但不稳、能改但不会验证、出错也不会收口
而再往下一部分走,才会自然进入《暗礁》:
- 调试成本为什么会激增
- 护栏为什么不是“保守”,而是 AI Native 工程的基础设施
- 熔断、回滚、审计这些听上去很“重”的词,为什么最后反而是在帮人把速度保住
换句话说,这篇文章不是为了把 Part 1 封死,而是为了先把主线项目递到读者手里,再把读者送进下一部分真正的工程问题里。
如果这篇文章真的讲明白了,读者应该开始这样想我现在缺的,可能已经不是“再换一个更强的模型”,而是:
- 任务到底有没有说清楚
- 上下文到底有没有治理好
- 执行 loop 到底有没有闭环
- 失败之后到底有没有 guardrail 和反馈系统
到这里,第 3 篇文章才真正闭环#
这篇文章如果最后只留下四句话,我希望是:
- 模型能力的跃迁,解释了为什么 AI 编程不再只是补全
- 工具生态位的分化,解释了为什么工程上不能继续迷信单工具神话
Prompt、Context、Harness的分层,解释了为什么这些能力必须被组织成控制面- 第 4 篇文章先把主线项目亮出来,则是因为控制面必须落到真实战场里
到这里,读者再回头看 Skills、MCP、CLI、Specs、Cloud tasks,就不会再把它们当一堆散装名词,而会知道:
- 哪些是在帮自己定义目标
- 哪些是在帮自己治理信息
- 哪些是在帮自己稳定执行
- 哪些又会在下一部分里变成调试成本、护栏设计和失败兜底的问题来源
这时候,Part 1 才算真的从“破局”走到了“收束”。
延伸阅读
- OpenAI:
Harness engineering: leveraging Codex in an agent-first world- OpenAI:
Unlocking the Codex harness: how we built the App Server- OpenAI:
Unrolling the Codex agent loop- OpenAI:
Introducing Codex- Thoughtworks:
Context engineering- Thoughtworks:
Context engineering: How to give AI exactly what it needs- Martin Fowler:
Humans and Agents in Software Engineering Loops- Martin Fowler:
Harness Engineering- Mitchell Hashimoto:
My AI Adoption Journey