20889
阅读时间 70 分钟

从 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 也不够,真正缺的是整套执行壳”这件事讲清楚。

这篇文章的核心命题

PromptContextAgent 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,以及承载它的 SpecsSkills,再往后接上 CLIMCPCloud 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 写成项目宪法#

OpenAI 在 Introducing Codex 里明确提到,Codex 可以通过仓库内的 AGENTS.md 学会如何导航代码库、运行测试和遵循项目实践;Anthropic 官方文档里,CLAUDE.md project memory 也被定位成承载项目架构、代码规范和常用命令的长期记忆。

这些东西当然有用,但我现在越来越警惕一种做法:把所有经验、禁令、命令、风格、注意事项全堆到一个几千字文件里,然后默认 agent 会永远准确执行。

问题在于:

  • 过期文档会带着“官方口吻”误导模型
  • 和源码冲突时,模型不一定总能分清谁更新
  • 太长的全局规则会把真正高频、关键的信息淹没

长期有效的项目级 Context 需要的是:短、准、可维护、经常更新,而不是像部门制度一样越写越厚。

我现在很认同的一句工程直觉

过期的 Context,很多时候比没有 Context 还危险。

第三种:什么都继续写回 Prompt#

如果一个约束会在几十个任务里重复出现,那它就不该继续靠人肉复制粘贴活着。

这时候更合理的做法,通常是把它升级成:

  • 项目级记忆:AGENTS.mdCLAUDE.md
  • 任务级规格:specs、issue、PRD、设计稿
  • 可复用模块:Skills、subagents、playbooks
  • 运行级信号:测试失败、日志、trace、截图对比

否则你做的不是 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 Styles161 Reasoning Rules99 UX Guidelines 这类结构化资料库。

这类 skill 最适合干的一件事,就是先帮 agent 把“这次页面到底该走什么风格路线”定下来。

比如你已经知道自己这次要做的是:

  • 金融后台,那就更偏稳、清晰、可信,不要乱上 AI 紫粉渐变
  • 美业落地页,那就可能更适合柔和、轻奢、强调情绪价值的路线
  • AI 产品控制台,那就可以考虑更偏 AI-Native UIBento 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 明确标 archiveddeprecatedsuperseded by
  • 给迁移中的旧目录写清楚“只读参考,不要继续新增逻辑”
  • 把最权威的实现路径、schema、checklist 放到更容易被 agent 命中的位置
  • 能删掉的过期样例就删掉,别把噪声永久留在仓库里

这一点很重要,因为 Context Engineering 不是纯写作文,它很多时候就是信息架构治理,甚至是仓库卫生治理。

我现在更愿意从四个维度设计 Context#

生命周期#

  • 项目级:AGENTS.mdCLAUDE.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-promax skill,里面放 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 真正干的事,大概是这样的:

  1. agent 在独立 worktree 里启动这次任务的本地环境
  2. gh、specs、设计稿和相关 Skill 拿到任务背景
  3. 改代码,但不只停在 diff 上
  4. 启动应用,用浏览器或 Playwright 把“成员邀请”主流程点一遍
  5. 读取截图、DOM、日志、可能的话再看 trace 或 network
  6. 跑 lint、tests、结构检查,确认没有把边界打穿
  7. 如果失败,根据这些运行时信号继续修,而不是重新瞎蒙一轮
  8. 通过后开 PR,拉 agent review 或 cloud review 继续迭代
  9. 如果发现某类问题反复出现,再把它升级进 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 EngineeringAI 在什么信息约束下干AGENTS.mdSpecsSkills、设计稿、日志、检索结果AI 会乱猜、乱引用、乱实现
Agent HarnessAI 怎么稳定地干并验证结果CLI、MCP、hooks、Actions、cloud tasks、CI、sandbox、observabilityAI 能说不能稳,能跑不能收敛

如果要把这张表压缩成一句话,那就是:

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 在排队,而是三层控制面在逐步补齐前一层做不到的部分。

现在回头看前两篇文章,线其实就串起来了#

如果这篇文章写到这里读者还只是记住了 PromptContextHarness 三个词,那这篇文章其实还没写成功。

因为这篇文章真正想完成的,不是再塞三个新名词,而是让人突然意识到:

原来我前面写的那些模型、那些开发方式、那些工具形态、那些生态位,不是在铺陈信息量,而是在铺这条控制面的主线。

第 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 工具,很多时候是在提前生产高质量 Context
  • Skills,很多时候是在把长期经验结构化、模块化、按需注入
  • 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 编程不再只是补全
  • 工具生态位的分化,解释了为什么工程上不能继续迷信单工具神话
  • PromptContextHarness 的分层,解释了为什么这些能力必须被组织成控制面
  • 第 4 篇文章先把主线项目亮出来,则是因为控制面必须落到真实战场里

到这里,读者再回头看 SkillsMCPCLISpecsCloud tasks,就不会再把它们当一堆散装名词,而会知道:

  • 哪些是在帮自己定义目标
  • 哪些是在帮自己治理信息
  • 哪些是在帮自己稳定执行
  • 哪些又会在下一部分里变成调试成本、护栏设计和失败兜底的问题来源

这时候,Part 1 才算真的从“破局”走到了“收束”。

延伸阅读
从 Prompt 到 Context 再到 Agent Harness:先把控制面的轮廓看见
更新于
2026-04-02
© 2026 AI 原生工程(AI Native Engineering)
内容版权归对应作者与贡献者所有;项目汇编与品牌归项目维护方所有。
文稿默认采用 CC BY-NC-SA 4.0,示例代码采用 MIT License。
Powered by Next.js & Fumadocs
Theme inspired by Fuwari