2026 年 2 月,OpenAI 发布了一篇文章《Harness engineering: leveraging Codex in an agent-first world》。文章里有一个很抓人的细节:他们内部有一个 beta 产品,从零开始,五个月后代码库接近百万行,而这些代码全部由 Codex agents 生成。
第一次读这篇文章时,很容易把后来的开源项目 Symphony 和这个“百万行内部项目”联系到一起。但深入看源码后,需要先澄清一个重要事实:公开的 openai/symphony 仓库并不是那篇 Harness Engineering 文章里的内部产品。
更准确的关系是:
Harness Engineering 文章讲的是 OpenAI 内部如何把一个产品代码库改造成 agent-first 的工程环境。 Symphony 是 OpenAI 后来公开的 Codex orchestration spec 和参考实现,用来解决另一个问题:当单个 Codex session 已经能可靠工作后,如何把一批 issue 自动分配给多个 Codex workers。 Symphony 不是那篇文章里的百万行项目,但它明显继承了 Harness Engineering 的方法论:把上下文、规则、验证、工作流、工具、安全边界和观测能力都写进工程系统。
所以,读 Symphony 源码的价值,不在于找到那个“百万行项目”的实现,而在于看到 Harness Engineering 如何从一套理念落到可执行的软件结构里。
Harness Engineering 不是写更长的 Prompt
很多人谈 agent 编程时,会本能地把注意力放在 prompt 上:怎么写提示词,怎么让模型听话,怎么让模型少犯错。
但 Harness Engineering 的核心恰恰不是 prompt。
它真正关心的是:当一个 coding agent 进入你的仓库时,能不能独立回答这些问题:
这个项目怎么启动? 这个任务什么算完成? 要跑哪些测试? 失败日志在哪里? 哪些目录可以改,哪些不能改? 代码架构边界是什么? 如何开 PR? 如何处理 review feedback? 如果执行中断,下一次如何恢复?
如果这些问题都靠人临时解释,那 agent 再强也只是一个需要持续看护的助手。反过来,如果这些问题都能在仓库中找到答案,并且大部分答案可以通过命令、测试、lint、日志和工具自动验证,那么 agent 才可能真正自主工作。
这就是 Harness Engineering 的实质:为 agent 建一套可读、可运行、可验证、可恢复、可约束、可观测的工程轨道。
Symphony 解决的是下一阶段问题
OpenAI 后来发布 Symphony 时,问题已经变了。
当一个 repo 已经通过 harness engineering 变得适合 Codex 工作后,人类工程师会遇到新的瓶颈:不是单个 agent 不会写代码,而是同时管理多个 agent session 的成本太高。
你要打开多个终端,看每个 Codex 在做什么,判断哪个卡住了,哪个需要 review,哪个 CI 失败,哪个可以继续推进。这个过程本身会变成新的 context switching 地狱。
Symphony 的定位就是把这种“人盯 session”的模式升级为“系统管 work item”:
从 Linear 读取候选 issue。 为每个 issue 创建独立 workspace。 在 workspace 中启动 Codex app-server。 把 issue 内容和 repo workflow 渲染成 prompt。 持续让 Codex 工作,直到 issue 状态变化。 记录日志、token、session、retry、dashboard。
这就是为什么 Symphony 源码虽然不大,但非常值得读。它展示的是 agent 工程成熟后的编排层。
Symphony 源码里最重要的三个文件
读 Symphony 时,我建议先看三个文件,而不是直接冲进 Elixir 模块。
第一个是 SPEC.md。
它不是普通 README,而是一份语言无关的服务规范。里面定义了 Symphony 的组件边界、配置 schema、issue 模型、workspace 模型、orchestrator 状态机、retry 语义、observability 要求等。
这件事本身就很 Harness Engineering:先把系统行为写成可读、可实现、可验证的规范,再让实现去对齐规范。
第二个是 elixir/AGENTS.md。
它是给 agent 的仓库入口,告诉 agent:
当前 Elixir/OTP 环境是什么。 如何安装依赖。 主质量门是 make all。runtime config 来自 WORKFLOW.md。workspace safety 是硬要求。 public functions 要有 @spec。PR body 必须符合模板。 行为变更要同步文档。
这份文件不长,但它把 agent 进入项目最需要知道的规则讲清楚了。它不是百科全书,而是地图。
第三个是 elixir/WORKFLOW.md。
这是 Symphony 最值得借鉴的设计。它既是配置文件,也是 agent 执行任务时的工作流说明。
上半部分 YAML front matter 定义机器可读配置:
Linear project slug。 active states 和 terminal states。 polling interval。 workspace root。 workspace hooks。 agent 并发数。 Codex app-server 命令。 sandbox policy。
下半部分 Markdown body 是渲染给 Codex 的 per-issue prompt。它详细规定:
不同 Linear 状态怎么处理。 如何维护一个持久的 ## Codex Workpad评论。为什么要先复现,再修改。 如何同步 origin/main。如何处理 PR feedback。 如何进入 Human Review。 如何在 Merging 状态执行 land flow。 什么情况下才算 blocked。
这正是 Harness Engineering 的关键动作:把资深工程师脑子里的隐性流程,变成 repo-owned、versioned、agent-readable 的执行合同。
AGENTS.md 应该是地图,不是小说
OpenAI 的 Harness Engineering 文章有一个很实用的观点:不要把所有知识塞进一个巨大的 AGENTS.md。
这点在 Symphony 里也能看到。
elixir/AGENTS.md 很短,只放入口信息和硬规则。更复杂的内容被拆到:
SPEC.mdWORKFLOW.mdelixir/docs/logging.mdelixir/docs/token_accounting.md.codex/skills/*/SKILL.md
这对新项目非常重要。
很多团队第一次给 agent 写规则,会写一个几千行的 AGENTS.md。短期看似完整,长期会失控:重复、过期、冲突、难维护,agent 也很难从中提取重点。
更好的做法是:
AGENTS.md只做入口和索引。 架构放 docs/architecture.md。验证策略放 docs/validation.md。日志规范放 docs/logging.md。产品规则放 docs/product/。复杂执行计划放 docs/execution-plans/。高频操作放 .codex/skills/或scripts/。
换句话说,repo 要成为 agent 的系统记录,而不是把所有上下文临时塞进 prompt。
Prompt 也应该可测试
Symphony 的 PromptBuilder 模块有一个细节很值得学:它用 Solid 模板渲染 WORKFLOW.md 的 prompt,并开启严格变量和严格 filter。
这意味着:
模板里写错变量名会失败。 使用不存在的 filter 会失败。 不会静默渲染成空字符串。
这很重要。对于无人值守 agent 系统来说,prompt 模板错误不是小问题。如果 issue title、description、attempt、labels 之类的变量渲染错了,agent 得到的任务上下文就会缺失。静默失败会让问题延迟到执行阶段才暴露。
所以新项目如果开始使用 workflow prompt,至少应该做三件事:
prompt 模板要放在 repo 里。 prompt 模板要有测试。 unknown variable 要 fail fast。
不要把 prompt 当成随手写的字符串。它是系统的一部分。
Workspace 隔离是 agent 安全的底线
Symphony 的 Workspace 模块做了非常务实的路径安全处理:
每个 issue 对应一个独立 workspace。 issue identifier 会被转成安全目录名。 workspace 必须位于配置的 workspace root 下。 workspace 不能等于 root。 通过 canonical path 检测 symlink escape。 hook 执行有 timeout。 删除 workspace 前可以执行 before_removehook。
这背后有一个朴素原则:不要相信 agent 会永远在正确目录工作。要用系统边界保护它。
新项目如果想让 agent 稳定工作,最小做法是给每个任务一个独立 worktree:
git worktree add ../workspaces/ISSUE-123 -b ISSUE-123或者 fresh clone:
git clone git@github.com:org/repo.git ../workspaces/ISSUE-123不要让多个任务共用一个开发目录。不要让 agent 直接在你的主工作区里执行长任务。workspace 隔离不是锦上添花,是多 agent 和无人值守执行的基础设施。
Orchestrator 把“会话”升级成“工作项”
Symphony 最核心的模块是 Orchestrator。
它负责:
定时 poll issue tracker。 根据 active states 选择候选 issue。 跟踪 claimed、running、retrying 状态。 控制全局并发。 控制不同状态的并发。 支持 SSH worker 容量。 issue 进入 terminal state 时停止 worker。 agent 崩溃后指数退避重试。 agent 正常结束但 issue 仍 active 时继续下一轮。 汇总 session id、token、rate limit、last event。 提供 dashboard snapshot。
这里最重要的思想是:不要把一次 Codex turn 结束等同于任务完成。
任务是否完成,应该由外部工作流决定:issue 状态、acceptance criteria、validation、PR checks、review feedback。agent 可以说“我完成了”,但系统要看状态机和质量门。
这也是 Symphony 比简单脚本更进一步的地方。脚本只会“启动一个 agent”。Orchestrator 管的是任务生命周期。
Workpad 是被低估的关键设计
WORKFLOW.md 里要求 agent 为每个 issue 维护一个 ## Codex Workpad 评论。
这个设计非常实用。
一个好的 workpad 会包含:
当前 workspace 和 commit。 执行计划。 acceptance criteria。 validation checklist。 已完成事项。 当前 blocker。 关键命令输出。 混淆点和假设。
它的价值在于持久化 agent 的中间状态。没有 workpad,长任务一旦中断,下一次 agent 很可能重新调查、重复执行、遗漏上下文。多人 review 时,也很难知道 agent 为什么这么改。
对新项目来说,即使你暂时不接 Symphony,也可以先建立 workpad 规则。比如要求每个 agent PR 或 issue 都维护一个固定格式:
## Agent Workpad### Environment`host:/abs/workspace@short-sha`### Plan- [ ] Reproduce- [ ] Implement- [ ] Validate- [ ] Handoff### Acceptance Criteria- [ ] ...### Validation- [ ] ...### Notes- ...### Blockers / Confusions- ...这比让 agent 在最终总结里写“我做了什么”可靠得多。
工具比说明更重要
Symphony 通过 DynamicTool 给 Codex 注入了一个 linear_graphql 工具。
这意味着 agent 不只是读到“你应该更新 Linear”,而是真的能调用 GraphQL 查询和 mutation,并复用 Symphony 配置好的 Linear auth。
这就是 Harness Engineering 的另一个重点:不要只给 agent 规则,也要给它工具。
如果你希望 agent 自己验证服务状态,就给它日志查询工具。如果希望它检查部署,就给它 deploy status 工具。如果希望它处理 issue,就给它 issue read/update 工具。如果希望它验证 UI,就给它 browser automation 和截图工具。
工具设计要克制:
输入 schema 要窄。 默认只读。 写操作要明确。 错误要结构化。 不泄露 secret。 响应要足够 agent 判断下一步。
好的工具能把 agent 从“猜测下一步”带到“观察现实后行动”。
质量规则要变成机器检查
Symphony 里有两个小但很典型的 Mix task:
mix specs.checkmix pr_body.check
前者检查 public functions 是否有相邻 @spec。后者检查 PR body 是否符合模板。
这体现了 Harness Engineering 文章里的一个重要原则:文档不够,规则要机械执行。
如果你只在 AGENTS.md 里写“请保持架构清晰”,agent 很难稳定执行。更好的方式是把规则变成:
lint typecheck architectural test dependency boundary check schema validation PR body check generated file check logging field check
而且错误信息要对 agent 友好。它应该能从失败输出里知道哪里错了、怎么改。
新项目应该如何落地 Harness Engineering
如果你正在启动一个新项目,不建议一上来就接 Symphony。更稳的顺序是从单 agent 可用开始。
第一步,写一个短 AGENTS.md。
它应该告诉 agent:
项目结构。 安装命令。 启动命令。 测试命令。 主质量门。 哪些文件不要改。 变更后怎么验证。 PR 要怎么交付。
第二步,把项目知识拆到 docs/。
至少包括:
docs/architecture.mddocs/validation.mddocs/troubleshooting.mddocs/logging.mddocs/product/
第三步,统一命令。
例如:
make setupmake devmake testmake lintmake typecheckmake verify第四步,改造 issue 模板。
每个任务都应该有:
problem expected behavior acceptance criteria validation constraints out of scope
第五步,要求先复现再修改。
bug 修复必须先有失败测试、错误日志、截图、API response 或明确的复现说明。UI 改动必须有可验证路径。性能问题必须有 baseline。
第六步,让应用对 agent 可观察。
前端给 browser automation、截图、console/network 信息。后端给日志查询、request id、trace、metric、healthcheck。
第七步,把架构规则变成机械检查。
不要停留在“请保持整洁”。要用 ESLint、Semgrep、dep-cruiser、typecheck、custom scripts 或测试把规则固化。
第八步,建立 workspace 隔离。
每个 issue 一个 worktree 或 clone。不要共用主目录。
第九步,定义状态机。
比如:
Backlog:不处理。 Todo:可领取。 In Progress:agent 执行中。 Human Review:等待人审。 Rework:处理反馈。 Merging:执行 merge/land。 Done:终态。
第十步,再写 WORKFLOW.md。
当以上基础都稳定后,才进入 Symphony 这类编排阶段。
一个实用判断标准
什么时候一个项目准备好接入 Symphony?
可以问五个问题:
一个新 agent 能否只靠 repo-local 文档理解项目? 它能否一键启动和验证? 它能否观察应用行为和错误? 它违反规则时,CI/lint 能否明确指出问题? 它中断或失败后,下一次能否恢复,而不是从零开始?
如果大多数答案是否,那么先做 Harness Engineering。否则,orchestrator 只会更快地产生更多失败。
如果大多数答案是,那么 Symphony 的模式就开始有价值:你可以让 issue tracker 成为控制面,让 agent 在独立 workspace 中执行任务,让系统负责 dispatch、retry、cleanup 和 observability。
不要照搬 Symphony 的所有设置
Symphony 是一个 engineering preview,不是所有项目都可以直接生产使用。
尤其不要盲目照搬这些东西:
高并发 agent。 approval_policy: never。 自动 merge。 过于复杂的 Linear 状态流。 对特定团队流程高度定制的 WORKFLOW.md。
更稳妥的方式是:
单 agent。 低权限。 workspace-write sandbox。 严格 validation。 人工 review。 小任务试点。 成功后逐步提升自动化。
最后的理解
读完 Harness Engineering 文章,再看 Symphony 源码,我最大的感受是:AI 编程的核心工程挑战,正在从“如何让模型写代码”转向“如何让系统承载 agent 工作”。
模型能力当然重要,但真正决定 agent 是否能稳定交付的,是仓库本身:
有没有清晰结构。 有没有可执行规则。 有没有稳定测试。 有没有可观测应用。 有没有安全 workspace。 有没有外部工具。 有没有持久 workpad。 有没有状态机。 有没有质量门。
Harness Engineering 做的是地基。Symphony 做的是地基之上的调度系统。
如果一个项目还没有地基,先不要急着上调度系统。先把 repo 变成 agent 能读懂、能运行、能验证、能恢复的环境。等一个 agent 能稳定完成一个任务,再让多个 agent 去处理多个任务。
这就是从 OpenAI Symphony 源码里能读出的 Harness Engineering 实操方法。
参考资料
OpenAI: Harness engineering https://openai.com/index/harness-engineering/OpenAI: An open-source spec for Codex orchestration: Symphony https://openai.com/index/open-source-codex-orchestration-symphony/OpenAI Symphony GitHub repository https://github.com/openai/symphony
夜雨聆风