我用 PAI/Codex 理解 Harness Engineering:Agent 工作环境到底怎么搭

0 阅读12分钟

本文基于七牛云工程师 @Evander 的 PAI / Codex 实践分享整理,以下以第一视角展开。

我一开始也没明白 Harness Engineering 是什么?总觉得和普通的软件工程设计区别不大。直到后来反复遇到同一种交付失败问题,我才逐渐理解 Harness Engineering 到底是什么。

交付失败

明明我在上一轮对话中,刚提醒 Agent 要读上下文。到了下一轮换个项目,它还是可能从当前对话里猜。刚提醒过不要跳验证,它还是可能把“看起来完成了”当结论。不止如此,我对 PRD、安全边界、写作偏好的要求,一旦需要延续到后续对话里,也可能随着上下文变化而逐渐失真。

这些问题看起来都能用一句更严厉的提示词解决。但事实上,它并不 work。

提示词能让 Agent 在这一轮变“乖”一点,但很难让它在十轮以后,或者是换了项目、换了工具,仍然稳定地按同一种方式工作。真正有用的做法,是把这些反复提示从对话里拿出来,放进环境里。

这就是我现在理解的 Harness:它不像一套框架名词,也不像几个 Agent 拼起来的流程。它更像一个工作场。Agent 进来以后,知道从哪里开始,知道该读什么,知道能做什么,知道做到哪了,知道什么不算完成,也知道哪些边界不能越过。

PAI 和 PAI_codex 对我来说,价值就在这里:减少每次重新解释世界的成本,而不是让 Agent 显得更聪明。

这里给不明白 PAI 是什么的人讲下 PAI:它想把 Claude Code 从一个编程助手,改造成一个长期理解你、记得你、能围绕你的人生和工作目标运转的个人 AI 系统。GitHub 地址:github.com/danielmiess…

上下文持久化错觉

我最早做 PAI 时,关注的是身份、记忆、偏好和项目。

这个关注点很容易被误解成是一种“个性化”。比如,让 Agent 知道我的写作风格,知道我在做什么项目,知道我不喜欢什么表达,知道哪些项目已经结束,哪些资料可以用,哪些资料不要默认调取。

但这些东西真正解决的核心问题是任务入口。

一个 Agent 如果不知道我正在做哪个项目,就会把旧材料和新任务混在一起。它如果不知道哪些项目已经结束,就会把历史案例当成当前案例。它如果不知道我的文字偏好,就会把稿子改成一股标准 AI 味。它如果不知道某些路径和凭证不能碰,安全就只能靠临场运气。

所以 PAI 的第一层重点不在“记住我”,而在于让 Agent 不要每次都从空白开始。

后来,我遇到一个很有代表性的教训:文件在磁盘上,并不代表上下文真的进入了工作过程。事情是这样发生的,旧 PAI 迁移时,有些身份文件、偏好文件还在,但却没有被新的 PAI 正确加载。结果就是,系统表面上“有记忆”,实际对话中表现得一无所知。

这个问题击中了我对 Harness 的一个基本理解:上下文更接近运行问题,不能只看有没有记录,更要看它在任务运行时有没有真正生效。

你把规则写进文件,只完成了一半。还要有入口、有加载优先级、有触发条件、有验证方式。否则,那只是一个安静躺在磁盘里的文件。

这也是我后来对 AGENTS.mdCLAUDE.md、PAI_codex README 这些入口文件的理解。它们不应该承担百科全书功能。好的入口更像一张简短地图:先告诉 Agent 现在在哪,去哪找资料,哪些地方不能乱碰。

入口太短,Agent 会猜。入口太长,它会淹没。Harness 的难点就在这个尺度上。

流程即外部状态

PAI 变复杂以后,出现了 Algorithm。

它把这些模块串联了起来:Observe -> Think -> Plan -> Build -> Execute -> Verify -> Learn,其中只有 Think 和 Verify 才和外部状态层相连(上图虚线部分)。

如果只看名字,它很像一套仪式。每个任务都分阶段,写 PRD、列标准、做验证,最后复盘。刚开始,我会觉得它重,甚至有时候重得碍事。

但后来我发现,它真正要解决的,是让“认真”这件事变成外部状态,而不是让 Agent 看起来认真。

人对 Agent 说“仔细一点”,通常没什么用。Agent 会转头就答应,而且说自己“已经检查了”“已经理解了”“已经完成了”。问题在于,这些 AI 承诺太廉价了。没有记录,没有证据,没有可检查的状态,它说完也就过去了。

而 PRD、ISC、Progress、Decision Log、Verification 这些东西,本质上都是为了让 Agent 的“我做了”变得可追踪。

踩过的坑

这里面有几个坑,我印象很深。

一个是空壳 PRD。Agent 只写 frontmatter、时间戳和 slug,看起来它创建了工作记录,但事实上并没有 Context,没有 Criteria,没有 Decisions,也没有 Verification。后来,我才把这件事写成明确规则:PRD 不能只有壳,必须有实质内容。

另一个是阶段跳跃。Algorithm 看似启动了,但 Observe 没真正拆需求,Think 没写风险,Verify 没有证据,Learn 只写一句空话。流程外观看起来完整,但里面却是空的。这比不用流程还糟,因为它会给人一种“已经系统化了”的错觉。

还有一个是假闸门。一些 Agent 做检查时,会用关键词来判断质量。只要文档里出现某些词,就认为对应检查做过。后来,我发现这几乎等于没检查,因为正常内容里总会出现这些词。真正有效的闸门要检查结构,比如 Section 是否存在,内容是否达到最低长度,是否有具体证据。

这些坑让我意识到,Harness 的重点不在多设计几个阶段。真正要看的,是每个阶段能不能留下别人可以检查的东西:Agent 自己说完成,只能当线索;文件改了,也只是线索;测试跑过,才开始有说服力。等测试、日志、截图、diff、PRD、工作记录能互相对上,才接近“可交付”。

这也是我现在越来越不相信 Agent “自我评价”的原因。Agent 很容易给自己的输出打高分。尤其是写作、产品判断、架构方案这种没有唯一答案的任务,它会把顺滑当成正确,把完整当成可靠。Harness 要做的事情,就是把判断的一部分移到外部。

Skill 不是能力列表

PAI 里有很多 SKILL,从写作到排错,TDD 到深挖,红队、交接、格式化、知识库整理没有不覆盖的。

如果把 SKILL 看成能力列表,就会很容易走偏:任务复杂,就多开几个 SKILL;不放心,就再开几个;最后像在堆 buff。这样不一定更好,反而可能让 Agent 更散。

我现在更愿意把 SKILL 看成工作姿势。

排错、写文章、做计划、交付前审查,其实都需要不同的姿势。排错要先复现,再定位,再验证;写文章要先读材料,搞清楚论证依赖;做计划要先问边界和成功标准;交付前要换成审查视角,把自己的产物当成别人写的东西来挑刺。

SKILL 的价值是把这些姿势固定下来。

使用 SKILL 的正确姿势

这次写 Harness 文章就是一个很好的反例和修正。

第一版 Agent 写得太快。外部参考资料没吃透,只是把几组观点并排摆出来,文章看起来完整,实际没有合成一个清晰的判断。我指出来以后,Agent 才重新补读、重新分层、重新给每组材料找到它在论证里的位置。

之后,文章整体感觉提升了点,但还是太像资料整合。后来,我又指出,参考链接和并列句太多,写得不好看,也没抓住 Harness 的精髓。

这几轮我和 Agent 之间的反馈过程,本身就是一种直观的 Harness,甚至比引用别人的 Harness 文章更能说明它是什么。

这也侧面说明一件事:如果没有外部反馈,Agent 很容易停在第一版。它会觉得自己完成了,而且写得还挺完整。真正推动文章变好的,不是某个更复杂的提示词。关键是任务环境里出现了纠偏机制:你指出问题,我重新读材料,生成计划,落文件,再检查风格。

SKILL Routing 应该服务的也是这个方向:不把任务变复杂,只让 Agent 在合适的时候进入合适的工作状态。

迁移中的有效性检验

从 Claude PAI 到 PAI_codex,是我理解 Harness 的另一个关键节点。

因为一些原因,我需要从 Claude PAI 迁移到 Codex PAI。但是问题也随之来了:旧 PAI 很重,它有 Algorithm、Memory,还有 Hook、SKILL 和 Agents。不止如此,它还有语音通知,以及 Session Lifecycle。它在 Claude Code 里像一套完整的个人 AI 基础设施。

但现在,我要切到 Codex,就不能原样照搬了。

Claude-only Hook 不能直接用。旧的 Runtime 行为不能直接复制,还有凭证、Provider 配置、历史状态,都不能拿来就用。哪怕目录里有很多有用东西,也要先判断哪些是历史证据,哪些是当前事实,哪些能迁移,哪些必须隔离。

所以,我要做 PAI_codex 时,“Absorb, do not copy” 就变得很关键了。它说的是 Harness 迁移的基本原则,不只是文件管理。PAI 迁移真正要继承的,是旧系统里的工作逻辑:项目要能路由,背景要能吸收,工作要能记录,验证要有门槛,风险要有边界。

因此,PAI_codex 保留下来的东西就变得很朴素了。它会根据模糊语言判断项目和意图。给每个项目做 absorption,让 Agent 不必每次从原始仓库和旧聊天里重新“挖矿”。它用 Work Records 保存重要任务。它有 Validate 和 Absorb Validate,防止系统自己悄悄腐烂。

它还明确说,Claude 侧 PAI 是历史材料,不是 Codex 的 Runtime。

这里面有一个很重要的转变:我开始把 Harness 理解成一组可迁移的工作关系,而不是某套具体工具。

一套工作关系里,总要有人或系统负责入口、状态、反馈和边界;失败发生以后,还要有人把它变成下次的默认行为。工具可以换,只要这些关系还在,Agent 就有工作场。

工作场的核心是沉淀

如果只让我用一句话说 Harness 的精髓,我会说:把每一次对 Agent 的临时提醒,尽量沉淀成下一次默认生效的环境。

每一次临时提醒背后,通常都有一个可以固化的位置。项目背景应该进入入口和路由;旧资料误用要靠 Context Map 和项目隔离;跳验证要靠完成前检查;空口说完成要靠证据来约束;危险文件要靠工具和规则里的安全边界;过度润色这种风格问题,也应该沉到写作偏好里。

这里的重点不在自动化一切。很多判断仍然需要人来做,尤其是文章好不好、方案稳不稳、某个边界能不能破,都不是 Agent 自己说了算。

Harness 要做的,是把人反复做的低层提醒减少掉,让人的注意力留给更高层的判断。

所以我现在不太愿意把 Harness 讲成“模型之外的工程系统”这么宽泛的话。那句话没错,但容易变成概念。对我来说,它更具体:Harness 是一个让 Agent 不必每次从零开始,也不能随便宣布完成的工作场

它既给自由,也给限制。没有工具,Agent 只能说,不能做;没有限制,Agent 会乱做;没有状态,Agent 会断片;没有反馈,Agent 会自我感觉良好;没有沉淀,同一个错误会一遍遍出现。

这几个东西合在一起,才像一个真正能工作的环境。

最后

我现在看 PAI / Codex,不太把它当“个人 AI 配置”了。

它更像一个长期实验:我能不能把自己和 Agent 协作中反复出现的问题,逐步变成环境里的结构?

一开始是记忆和身份。后来是 Algorithm 和 PRD。再后来是 SKILL Routing、Work Records、项目 absorption、验证门槛。到 Codex 这里,又多了一层迁移:哪些东西能带走,哪些东西只能作为历史证据。

这些东西单独看都不神秘。真正有意义的是,当入口、上下文、工具、状态、反馈和边界连起来,Agent 的工作就不再只靠当前这一轮对话;它犯错以后,错误也有机会变成下一次的结构。

这就是我现在理解的 Harness Engineering。

Agent 不缺一张更长的提示词。它缺一张桌子,一套工具,一份进度表,一些不能越过的边界,以及一个会说“不算完成”的反馈系统。