TECHNICAL ARTICLE

模型越来越强,研发工作流应该变重还是变轻?

当模型已经内化了搜索、拆解、规划和大部分代码协作能力,研发工作流还需要继续叠加更多 Skill、Agent 和状态文件吗?本文以一次 Feature Workflow 的复盘为例,讨论 Harness Engineering 如何从流程编排转向边界、状态与验证设计。

强模型让复杂研发工作流逐渐化为一条更轻、更清晰的交付路径

一个不太舒服的问题

过去半年,我们很容易得到一个直觉:模型越强,工作流就应该越复杂。

模型会写代码了,于是我们给它增加需求拆解、任务编排、上下文装载、历史检索、测试修复、并行 Agent、状态文件和自动循环。每一个环节单独看都很合理,合在一起就变成了一套小型研发操作系统。

但最近我开始怀疑这个方向。

不是因为 Harness Engineering 不重要,而是因为我们经常把“让模型学会怎么做”写成了流程,把本来已经被模型内化的能力又外置编排了一遍。结果是:工作流看起来更可靠,实际却让每个 Feature 需要经过更多等待、更多上下文搬运和更多状态同步。

模型能力增强之后,研发工作流究竟应该变重,还是应该变轻?

我的答案是:流程应该变轻,边界应该变清楚,验证应该变严格。

我们复盘了一套什么样的工作流

我把自己之前开发的 Feature Workflow 重新拿出来,做了一次完整梳理。这套用于驱动软件研发的工作流,原本的设计很完整:

创建需求
  → 价值点分析
  → 需求拆分
  → 文档充实
  → 规格审查
  → 创建分支和 Worktree
  → 实现
  → 验证
  → 合并、打 Tag、归档
  → 自动调度下一个 Feature

它还有三层架构协作:

  • 需求层:new-featuresplit-featureenrich-featurereview-spec
  • 执行层:start-featureimplement-featureverify-featurecomplete-feature
  • 调度层:dev-agent、SubAgent、workflow state 和 hooks

这套系统解决了很多真实问题。它能隔离并行开发,能保存 Feature 文档,能在完成后留下归档,也能在 Agent 中断后继续执行。它不是一个错误的设计,恰恰相反,它是在模型还不够稳定时很自然的工程回应。

复盘前的问题出在另一个地方:它把太多能力都变成了强制阶段。

一个普通 Feature 可能需要反复读取 spec.mdtask.mdchecklist.mdproject-context.mdarchive-log.yamlnew-feature 已经生成了价值点和验收场景,enrich-feature 又重新充实一遍,review-spec 再按照六个维度评分;历史归档还会在多个阶段被重复扫描和深度加载。

这时工作流不再只是帮助模型完成任务,而开始规定模型必须以什么姿势完成任务。

这套设计为什么曾经需要这么重

如果只看今天的结论,很容易误以为之前的设计是在过度工程化。其实不是。Feature Workflow 的起点并不是“给模型增加流程”,而是解决 AI Coding 里几个非常具体的工程问题:需求之间会互相污染,多个 Agent 不能安全并行,开发到一半的上下文很难恢复,代码合并之后又缺少可追溯的验收证据。

它借鉴的是 FDD(Feature-Driven Development)的思想:以一个对用户有价值的特性作为开发单位,把需求做成垂直切片,而不是把数据库、API、前端分别拆成三个只有技术意义的任务。一个用户能感知到的 Feature,才是一个适合交给 Agent 独立完成的边界。

这也是为什么 Feature Workflow 里一直强调三件事:

  1. 按用户价值拆分:超过几个独立价值点,就拆成可以独立交付的子 Feature。
  2. 用依赖关系组织开发:Feature 之间形成一个可以调度的 DAG,而不是一堆互相看不懂的任务。
  3. 用 Worktree 做物理隔离:一个 Feature 对应一个分支、一个目录和一套独立上下文,多个 Agent 才能真正并行。

早期版本把这些原则进一步实现为 Command、Agent 和 Skill 三层结构。dev-agent 负责读队列、检查依赖和批量派发,独立的 Feature 执行上下文串起 start → implement → verify → complete,具体能力再由 Skill 提供。早期这里使用专门的 DevSubAgent,后续则改成由调度器向通用 SubAgent 注入明确的生命周期协议。它解决的是“如何让一个不稳定的模型也能重复完成交付”这个问题。

Feature Workflow 最重要的亮点:一次触发,自驱动完整研发周期

Feature Workflow 真正有区别度的地方,并不是 Skill 数量,而是它采用了一种预编排、自驱动、多隔离执行上下文的研发方式。

一次触发沿 Feature DAG 分派多个隔离执行上下文,完成后回写结果并释放下一批依赖

在开发启动前,需求已经被整理成 Feature,Feature 之间的依赖、优先级和验收标准也已经进入队列。用户不需要逐个打开任务、逐次提醒 Agent 下一步做什么,而是通过一次触发启动调度器:

一次触发 /dev-agent

读取 Feature 队列和依赖关系

选择当前可以执行的 Feature

为每个 Feature 创建隔离执行上下文

start → implement → verify → complete

归档结果,释放依赖,调度下一批 Feature

直到整个任务图完成,或在明确的阻断点停止

这里的执行隔离非常关键。每一个 Feature 都在自己的 Agent 上下文和 Worktree 中完成一个独立开发周期,拥有自己的需求上下文、代码空间、测试结果和归档记录。一个 Feature 完成后,这个执行上下文就可以结束;后续 Feature 再创建新的上下文,根据队列状态和已完成产物继续工作。

因此,它不是让一个 Agent 在越来越长的上下文里持续完成所有事情,而是把一个大型研发目标变成多个可独立恢复、独立验证、独立交付的开发周期。调度器负责全局推进,每个执行上下文只负责自己的 Feature 闭环。

它和 Loop、Goal 模式有什么不同

现在比较常见的自主执行方式,大致有两种。

一种是 Loop:让 Agent 围绕一个任务持续尝试,检查结果,不满足条件就继续下一轮。它适合解决单点问题,例如反复修复测试、持续观察外部状态,或者迭代到某个明确退出条件。

另一种是 Goal:给 Agent 一个长期目标和完成条件,让它自主规划并持续推进。它给模型更大的自由度,适合目标清楚但路径无法提前完全确定的工作。

Feature Workflow 选择的是第三种方式:先把研发对象和依赖关系编排成任务图,再让多个隔离执行上下文按状态机自驱动执行。

方式核心驱动力适合场景主要风险
Loop同一个任务反复执行,直到满足退出条件修复、监控、探索性迭代容易在局部循环,长期上下文持续膨胀
Goal围绕一个目标自主规划路径路径未知、需要较强自主判断的复杂任务过程边界较弱,进度和中间产物不容易标准化
Feature Workflow预编排的 Feature DAG + 生命周期状态多任务、可拆分、需要完整开发和验证的软件项目前期需要定义 Feature、依赖和验收边界

它的优势是整体开发过程更可控:

  • 用户可以在启动前看到完整任务图,而不是等 Agent 边做边生成所有计划。
  • 每个 Feature 都有明确的输入、状态、验收和完成产物。
  • 单个执行上下文失败不会丢失整个项目进度,可以从对应阶段恢复。
  • 多个 Feature 可以并行,但并行数量和依赖释放由统一队列控制。
  • 开发与验证属于同一个 Feature 周期,不会出现“代码都写完了,最后才发现没有可验收标准”的情况。
  • 一次触发可以驱动多个任务完成开发、验证、合并和归档,同时在质量门失败时准确停下。

这是一种介于“完全固定的流水线”和“完全开放的自主 Agent”之间的设计。它把全局可控性放在外部任务图和生命周期协议中,把局部自主性留给每一个 Feature 执行上下文。

这个亮点今天仍然应该保留。我们要剥离的是每个执行上下文内部已经失去信息增量的重复步骤,而不是取消任务图、上下文隔离和自驱动调度本身。

这段演进过程可以在Feature Workflow 的第一篇介绍Feature Workflow v3 的架构复盘中看到。根目录的 FDD 驱动 AI Coding 工作流演示则把它和 FDD 五阶段、Feature Map、垂直切片以及多 Agent 拓扑放在了一张图里。

所以,今天要做的不是否定这套设计,而是承认一个变化:当模型已经能够稳定执行其中一部分认知动作时,原来用于托住模型的脚手架就需要重新校准。

有些 Harness 能力已经被模型内化了

这里说“内化”,不是说模型永远不会犯错,而是说这些能力已经不值得在每个项目里被拆成固定的人工编排步骤。

搜索和上下文组装

早期我们需要专门的 Context Skill 告诉模型先读哪些文件、按什么顺序读历史归档。现在的模型已经能够根据任务在代码库中搜索、追踪引用、识别相邻模块,并判断哪些上下文与当前改动相关。

这不代表上下文管理不重要。真正重要的是定义上下文的边界:哪些文件是契约,哪些目录不能碰,哪些历史决策必须保留。至于每次具体搜索哪些文件,可以更多交给模型。

任务拆解和实现计划

把大需求拆成可执行任务仍然重要,但“固定先拆成三层、每层再生成 checklist”不一定重要。模型通常能在读完需求和代码后形成一个更贴近当前实现的计划。

对小需求来说,强迫它先生成完整的任务文档,很可能只是把实现前的等待变长。任务文档应该保留为可恢复的工作记录,而不是为了形式完整而存在的审批表。

历史归档检索

归档很有价值,但自动深读三到五个历史 Feature 并不总是有价值。历史案例只有在存在明确的相似架构、兼容性风险或迁移约束时才需要加载。否则,一个轻量索引加上模型按需打开的能力已经足够。

普通代码协作

模型已经可以自行完成相当一部分“读代码、改实现、补测试、修复失败”的循环。工作流继续把这些动作拆成很多必须串行调用的 Skill,容易造成上下文切换,而不是提升质量。

换句话说,Harness 的重点正在从“告诉模型下一步做什么”转向“确保模型做错时不会造成不可逆损失”。

从 FDD 的“特性”到模型的“工作单元”

FDD 对 Feature 的要求是“对用户有价值、可以独立完成、能够在短周期内交付”。在传统团队里,这个边界主要是为了控制协作和迭代成本;在 Agent 团队里,它又多了一层含义:Feature 同时是模型的工作单元、上下文单元和恢复单元。

这解释了为什么“按用户价值拆分”比“按技术层拆分”更重要。feat-auth-dbfeat-auth-apifeat-auth-ui 可能是工程任务,却不是三个独立的用户价值。它们会把一个本来可以闭环验证的工作拆散,让 Agent 需要不断跨上下文协调,反而增加复杂度。

但这也带来一个新的反思:工作单元需要清晰,不代表每个工作单元都需要完整走一遍所有仪式。Feature 的边界应该保留,围绕它的过程应该根据风险伸缩。

可以把 FDD 的原则和新的自适应工作流对应起来:

FDD / Feature Workflow 原则现在应该保留的部分可以交给模型的部分
Feature 是垂直切片用户价值、范围边界、验收结果具体文件搜索和实现顺序
Feature Map / 依赖 DAG依赖关系和启动条件普通任务的局部拆解
独立 Worktree文件系统、分支和副作用隔离工作区内的探索与修改
规约驱动验收标准和不可违反的约束checklist 的具体展开
持续验证测试、类型检查、验收和证据失败后的局部修复循环

这不是把 FDD 变成一个更轻的 Scrum,而是让“特性驱动”真正成为 Agent 的边界设计,而不是一份需要逐项打勾的文档模板。

不是所有东西都应该交给模型

工作流变轻并不等于取消约束。恰恰相反,有几类信息应该继续外置,而且应该比以前更明确。

持久状态

模型可以记住当前对话里的计划,但不能把队列状态、完成记录和恢复点只放在上下文里。Claude 版使用 queue.yaml,Codex 版使用 queue.json;无论载体是什么,队列、归档记录和 Git tag 都仍然是很有价值的外部状态。

但状态源必须收敛。复盘前,一个 Feature 同时存在于 queue、workflow state、Git branch、Worktree、pending 目录、active 目录和 archive 目录中。每个来源都合理,组合起来却很容易不一致。

更好的原则是:

业务状态:一个队列
代码状态:Git
持久产物:归档目录和 Tag
临时调度状态:仅在批量调度需要时保留一个短生命周期 state 文件

其他信息尽量从这几个来源推导,不再让每个 Skill 自己维护一套状态。Codex 版进一步取消了持久调度状态,直接从队列、Git、活动文档和验证结果恢复;Claude 版只在 /dev-agent 批量运行期间保留短生命周期的 workflow-state.json

权限和副作用边界

删除 Worktree、合并主分支、推送远程、修改数据库、发送消息,这些动作都不是“模型会不会做”的问题,而是授权和可恢复性问题。模型能力越强,越应该把副作用边界写成机器可执行的约束。

可以让模型自由探索代码,但不能让它无确认地推送生产;可以自动修复测试,但不能让验证失败的 Feature 继续自动合并。修订后的默认配置关闭 main 和 tag 的远程推送,是否开启配置与用户是否在当前任务中授权推送也被明确区分。

验证和质量门

模型可以自己写测试,也可以自己判断测试结果,但不能让“验证失败”只变成一条 warning,然后流程继续完成。

在复盘前的工作流里,自动模式原本规定:验证失败重试两次后记录警告,继续进入 complete。这个策略看起来有利于自动化,实际上把最重要的质量门变成了日志。

更合理的处理是区分两类失败:

  • 非阻断问题:记录 warning,可以继续
  • 测试、类型检查、验收场景失败:标记 needs_attention,停止自动合并

自动化的目标不是让流水线永远往前走,而是让它在正确的地方停下来。这次修订把这个原则落成了硬门禁:验证阶段写入机器可读的 verification-status,完成阶段在产生 Git 副作用前和合并前各执行一次校验;缺少证据、checklist 未完成或任何阻断项大于零,都会拒绝 complete。--auto 也不再隐式跳过质量门。

工作流应该从“固定剧本”变成“自适应协议”

这次修订后,研发工作流明确分成两种模式。

Lite 与 Deep 两条路径根据风险选择不同深度,最终汇入同一个质量门

Lite:默认模式

大多数普通 Feature 只需要:

start → implement → verify → complete

其中:

  • spec.md 保存需求、边界、依赖和验收标准
  • task.md 可以由模型根据实际代码动态维护
  • 历史归档默认只读索引
  • 不强制 enrich
  • 不强制 review-spec
  • 不强制深度加载 project context

Deep:按风险升级

以下情况才升级到完整流程:

  • 涉及多个业务模块
  • 涉及公共 API 或数据库迁移
  • 需要并行拆分为多个 Feature
  • 存在高风险外部依赖
  • 有明显的权限、数据一致性或兼容性风险
  • 用户明确要求严格审查

这时再启用:

split → enrich → review → [parallel development] → deep verification

关键变化是:enrichreview、历史深读和并行开发不再是所有需求的固定阶段,而是按风险和授权调用的能力。

这也改变了我们对“自动化”的理解。旧的自动化是:把所有步骤提前写好,然后让 Agent 不停地往下执行。新的自动化应该是:把状态转移、权限边界和质量门写清楚,让 Agent 自己选择在边界内需要哪些能力。

例如,一个已经有清晰验收标准、只改一个模块的小 Feature,可以直接进入 Lite 流程;一个包含数据库迁移、公共 API 和多个子模块的 Feature,则自动升级到 Deep 流程。升级依据会作为具体的 risk_signals 写入 Feature,而不是用“这个 Feature 看起来很重要”作为模糊判断。

同一个协议,两种 Harness 实现

Claude Code 版保留了 Command、Skill、SubAgent 和批量调度 hooks,适合从 /dev-agent 一次触发整个 Feature DAG;Lite/Deep 路由、Deep 启动审查和完成硬门禁都落在现有生命周期里。

Codex 版则进一步做轻:不再复制十几个 Slash Command,而是使用一个可自动发现的主 Skill,根据当前意图按需加载规划、交付、调度或归档参考。队列写入、状态转移和完成校验交给确定性脚本,代码搜索、任务计划、实现和局部修复继续交给模型。并行 Agent 只有在用户授权且存在互不干扰的 Feature 节点时才启用。

两种实现的外形不同,但共享同一个协议:Lite 默认、Deep 按风险升级、Feature 负责边界、Git 负责代码状态、队列负责业务状态、验证失败必须停止。

归档不是流程负担,而是组织记忆

减轻工作流时,最容易误伤的是归档。因为归档看起来像文档工作,实际上它保存了团队未来的判断依据。

不过归档也不应该变成一份不断膨胀的流水账。一个好的归档记录至少应该稳定回答这些问题:

id: feat-example
status: completed
completed_at: 2026-08-25T09:30:00Z
archive_path: features/archive/done-feat-example-20260825
tag: feat-example-20260825
verification:
  status: passed
  scenarios_total: 4
  scenarios_passed: 4

我们最后把归档索引统一成 records,用 completed_atarchive_pathtag 和验证结果作为稳定字段,并要求按 Feature ID 幂等更新。这样,归档既能被人读,也能被模型按需检索,不需要每次都把整段历史装进上下文。

Harness 的下一阶段:少编排,多约束

模型变强之后,Harness Engineering 不会消失,只是重心发生了变化。

过去我们更关注:

  • 给模型多少个 Skill
  • Agent 要经过多少个阶段
  • 是否自动生成更多文档
  • 是否把每一步都写成脚本

接下来更应该关注:

  • 哪些状态必须持久化
  • 哪些动作必须可恢复
  • 哪些失败必须阻断
  • 哪些信息只需要按需加载
  • 哪些操作需要权限和人工确认
  • 如何让模型在一个清晰的边界内拥有更大的自主空间

这不是从“重流程”走向“无流程”,而是从程序化编排走向声明式约束。

好的工作流不应该让模型显得更像一个执行脚本。它应该让模型有足够空间发挥能力,同时让项目在模型犯错、上下文丢失、Agent 中断或多人并行时仍然可以恢复。

我的判断

当模型越来越强时,继续堆叠 Harness,往往是一种安全感,而不一定是工程质量。

我们真正需要的不是更长的流水线,而是更少、更稳定的协议:

需求边界清楚
状态来源唯一
副作用可控
验证结果可信
失败可以恢复
复杂任务按需升级

这也是我现在对 Feature Workflow 的新定义:它不再是一条要求每个需求都走完的流水线,而是一套围绕 Feature 的自适应交付协议。它保留 FDD 的垂直切片、Worktree 的物理隔离和可追溯的验证归档,但把需求充实、历史深读、规格审查和多 Agent 调度都变成按需启用的能力。

如果一个小 Feature 需要经过十几个 Skill 才能开始写代码,说明工作流可能已经开始服务于自身。反过来,如果模型可以在清晰的边界内完成探索、实现和验证,而系统只负责保存状态、控制副作用和守住质量门,那么这套 Harness 才真正发挥了作用。

模型变强之后,最值得删除的不是约束,而是那些已经不再提供信息增量的过程。

这可能是 Harness Engineering 下一阶段最重要的工作:不是继续为模型增加更多“应该怎么做”的提示,而是持续识别哪些能力已经被模型吸收,然后把系统的注意力转回状态、边界、验证与恢复。

相关实践: