我给自己的 AI 研发流程写过一套控制平面

拆解一套强调可追溯、可恢复和权限隔离的文件式 AI 研发控制平面。

本页目录 · 15 节

我给自己的 AI 研发流程写过一套完整的 Workflow Harness,名字叫 Marshall。

这里的 Harness 不是「先思考、再编码、最后测试」这种 Prompt 模板。它是一套位于代码仓库内的控制平面:用户只给出目标,系统负责选择阶段、绑定当前证据、限制执行者权限、持久化运行状态,并在每次状态推进前验证依赖与结果。

它试图回答一个比「模型会不会写代码」更难的问题:当一次任务跨过多个上下文窗口、多个执行者和多个有副作用的工具后,系统怎样证明当前结果仍然来自正确的输入、正确的权限和正确的执行顺序?

下面描述的是这套系统的完整设计与运行契约,而不是一个理想化流程图。

两个平面:规则与运行事实必须分开

Marshall 首先做了一个非常重要的拆分:

平面 位置 回答的问题
稳定控制平面 仓库内受版本控制的规则目录 允许怎样工作,谁拥有哪种权限,什么才算完成
单次运行平面 被忽略的单次证据目录 这一次实际读了什么、做了什么、产出了什么、停在哪里

稳定控制平面包含宪章、路由、阶段图、Artifact Map、Worker 契约、JSON Schema、领域规格和运行时代码。单次运行平面则保存 state.json、追加事件日志、不可变结果、Worker Report、设计或评审材料、补丁与回执。

这条边界避免了两种常见污染:

  • 把某次任务生成的结论误当成长期规则;
  • 把一份长期文档的更新时间误当成某次运行的实际顺序。

稳定文档定义「应该怎样」,运行包记录「实际怎样」。两者都需要,但权威不同。

整体链路

flowchart LR
    U[用户目标] --> R[Route / Command]
    R --> G[Stage Graph]
    G --> S[StateV3 + Lease/CAS]
    S --> C[Context / Evidence]
    C --> X{Executor Type}
    X --> P[Parent]
    X --> D[Deterministic]
    X --> W[Worker]
    X --> E[Isolated Executor]
    X --> H[Trusted Host]
    X --> V[Provider Adapter]
    P --> N[NodeResultV1]
    D --> N
    W --> N
    E --> N
    H --> N
    V --> N
    N --> B[Completion Barrier]
    B --> T[StageResultV1]
    T --> S

从左到右看,它有八个关键环节:

  1. 路由只确定目标和副作用边界;
  2. stage-graph.yaml 决定节点、依赖、执行者和完成屏障;
  3. StateV3 为当前尝试分配 Lease、Generation、Revision 与 Fence;
  4. Context 层从当前仓库、规格和 Provider 中挑选证据;
  5. 每个节点只能由图中声明的 Executor Type 执行;
  6. 结果必须发布为绑定输入与输出 Hash 的 NodeResultV1
  7. 完成屏障确认所有必需结果仍然有效;
  8. StageResultV1 才能授权状态推进或合法 Transition。

它不是一条 Prompt 驱动的流水线,而是一套「模型负责语义判断,Runtime 负责状态与权限」的混合系统。

控制平面里谁拥有最终解释权

复杂 Harness 最怕一条规则在多个位置各写一遍。因此成熟版明确了所有权:

组件 唯一职责
constitution.md 不可覆盖的事实、授权与报告原则
routes/commands/ 人类入口、接受的输入、阶段拒绝边界
stage-graph.yaml Node DAG、Executor、Barrier、Transition 与 Mode 上限
stage-artifacts.yaml 逻辑 Artifact Role 到物理路径的映射
Worker Schema 与 Runtime 精确实例、上下文、输出、并发与汇合契约
templates/runtime/*.schema.json 可由程序验证的数据形状
specs/ 仓库与业务的稳定事实
Runtime Lease、CAS、事件、恢复、权限与 Provider 执行

路由文档可以解释阶段,但不能重新定义节点顺序;Worker Team 可以描述语义角色,但不能绕开 Worker Plan 自己增加实例;Markdown 可以展示结果,却不能替代 Hash 绑定的 Result。

这种设计本质上是在对抗「重复事实」。如果每层都能解释下一步,任何一个较少使用的分支都会逐渐漂移。

Stage 不是一个标签,而是一张可执行 DAG

每个 Stage 都包含:

  • purpose 与可接受前序;
  • 输入绑定及 Freshness Policy;
  • nodesdepends_on 与 Executor Type;
  • 每个节点的必需输出 Role 和确定性 Check;
  • completion_barrier
  • 允许的后续 Transition。

例如成熟版 design 并不是「生成一个设计文档」,而是:

perception-bootstrap
  -> context-selection
  -> explore
  -> pre-draft-specialists
  -> question-gate
  -> design-draft
       ├─> deterministic-verifier ─┐
       └─> post-draft-critic ──────┤
                                   v
                           repair-decision
                                   -> final-design

确定性验证和批判性评审关注不同证据,可以并行;repair-decision 必须等待两个分支;只有 final-design 到达完成屏障,Stage 才能结束。

impl 则把代码写入明确分成计划、能力签发、低信任执行、补丁校验、可信提升和目标工作区回读。图中的顺序不是建议,而是权限链。

六种 Executor,代表六种不同信任边界

成熟版没有把所有节点都交给「一个更聪明的 Agent」。它区分六种执行者:

Executor 可以做什么 不可以做什么
parent 阅读、推理、综合,生成阶段产物 冒充 Provider 或绕过写入边界
deterministic Schema、Hash、依赖、Freshness 等纯校验或转换 做开放式语义判断或外部写入
worker 对一个窄问题产生只读、可归因报告 修改源码、完成 Stage、替主 Agent 下结论
provider 执行一个已注册、已批准、可回读的外部操作 自由拼接未授权 Payload
isolated-executor 在隔离 worktree 内按一次性 Grant 修改白名单路径 写用户当前工作区或扩大范围
host 校验补丁并提升到目标工作区 创作代码修改

Executor Type 不是角色名称,而是权限模型。同一个 LLM 即使能完成所有逻辑,也不能因此跨越信任边界。

StateV3 为什么不只是一个进度 JSON

StateV3 保存的是当前运行投影。除 stagestatus 外,它还包含:

  • attemptresume_epochactive_generation
  • CAS 使用的 revision
  • 当前 Lease 与 Fencing Token;
  • 前序 StageResultV1
  • 输入、输出与 Artifact Hash;
  • Node 与 Node Result;
  • Worker Selection、Plan、Run 与 Result;
  • Question、Approval、Mutation Intent、Delivery 与 Freshness;
  • Late Result、Partial Commit 与下一条 Transition。

状态更新必须在锁内比较 Revision。旧 Generation 的 Worker 即使晚到,也不能把结果写进新一轮尝试;过期 Lease 不能继续发布;Question Gate 收到用户答复并恢复同一 Generation 后,新的 resume_epoch 会区分答复前后的执行身份。

这就是 Fencing 的意义:取消一个执行器,不只是告诉它「请停下」,还要让它即使没有停下,也失去提交结果的资格。

Event、State 与 Artifact 各自证明不同的事实

Marshall 的追加事件日志不是普通 Debug Log。每个有状态动作遵循:

decision -> action -> outcome

事件包含顺序号、父子关系、Correlation、前一事件 Hash 和当前事件 Hash。action 必须引用一个已存在的 decisionoutcome 必须引用且只能完成一次对应的 action。Runtime 在发布结果之前预留 Decision/Action,执行后先读回结果投影,再追加 Outcome。

与此同时:

  • State 回答「现在是什么状态」;
  • Event 回答「为什么会到这里」;
  • Artifact 回答「下游实际要消费什么内容」。

例如「设计已完成」不能由状态字符串单独证明。它至少需要一个 StageResultV1,其中包含输入指纹、输出绑定、Verification、Open Risks、Transition,以及 Decision/Action/Outcome 的 Event ID。绑定文件的字节发生变化,Hash 失效,完成状态就不能继续被复用。

Worker 不是固定团队,而是一次运行中的精确实例

成熟版虽然准备了领域、数据运行时、安全、分层、Critic、Verifier 等角色,但真正的运行权威是两份对象:

  1. WorkerSelectionV1:为什么选或不选 Worker,当前有哪些风险轴,是否需要拆分;
  2. WorkerPlanV1:具体实例、阶段、上下文、Prompt/Model/Config Hash、只读权限、输出路径、并发与修复上限、Barrier。

Mode 分成 lightstandarddeep。低风险、路径已知的单仓改动可以是零 Worker;迁移、Backfill、IAM、生产写入、跨仓、跨领域或来源权威不确定,会把设计推向 Deep;超过容量时先拆任务,而不是无限增加 Agent。

Worker Report 只有通过 Plan、Node、Generation、Context Hash 和 Schema 校验,才有资格进入 Barrier。主 Agent 仍然是唯一综合者,避免多个 Worker 各自把局部结论当成最终方案。

一次实现任务怎样穿过写入边界

实现阶段最能体现这套架构的信任模型:

branch-gate
  -> task-trace
  -> modification-plan
  -> StageWriteGrantV1
  -> isolated-executor
  -> PatchBundleV1
  -> PatchVerificationReceiptV1
  -> trusted host promotion
  -> PatchPromotionReceiptV1
  -> post-promotion verification
  -> spec-sync

StageWriteGrantV1 绑定仓库身份、Branch、Base Commit/Tree、目标文件前置状态、允许的 Create/Modify/Delete、执行实例、Generation、Fence、使用次数和过期时间。它只有一次使用机会。

Executor 在独立 worktree 内生成结构化 Patch Bundle,里面不是一段不透明 Diff,而是每个路径修改前后的存在状态、Mode、内容 Hash 和 Blob Ref。Trusted Host 重新检查目标工作区是否仍满足前置条件,才把补丁提升进用户正在使用的 checkout。

这里的 Promotion 不是上线,而是从低信任执行区进入高信任工作区。提升成功以后还必须回读目标文件并重新运行验证,因为隔离环境的成功不能证明目标环境相同。

外部写入为什么必须是 Preview、Approval、Execution、Readback

Jira、PR、评论和其他 Provider 写入不能只靠一句「用户说可以」。成熟版把一次外部动作拆成四段:

  1. 解析精确目标与 Payload;
  2. 展示当前预览并取得针对该内容的确认;
  3. 由注册 Provider Adapter 执行一个幂等 Intent;
  4. 从 Provider 重新读取 ID、字段、状态和 Revision。

如果请求超时,系统不能直接重试。它必须先查询 Provider:对象可能已经创建,只是响应丢了。否则所谓「重试」会生成第二个 Jira 或重复评论。

这条链同时区分能力和授权:工具里有 Token,只证明技术上能写;只有当前 Intent、目标、Payload 和确认仍然一致,才证明这一次被允许写。

恢复不是重新读一遍聊天

任务中断后,Runtime 会从 State、Event 与不可变结果恢复:

  1. 校验事件 Hash Chain 与 State Projection;
  2. 识别过期 Lease、旧 Generation 和不完整 Decision/Action;
  3. 验证已完成节点的输入、依赖与 Artifact Hash;
  4. 将不再新鲜的结果标为 stale,保留失效原因;
  5. 从最近仍有效的 Barrier 前重新调度,而不是从头重复副作用。

恢复的难点不在「记住上次做到哪里」,而在判断哪些结果仍然有执行权。没有 Generation、Fence 和 Idempotency,恢复很容易变成重复执行。

成熟版重点防的失败模式

失败 机制
多个执行者同时推进同一 Stage Lease + Revision CAS + Fencing Token
旧 Worker 在新一轮完成后晚到 Generation / Resume Epoch 校验,Late Result 隔离
下游读取旧尝试留下的产物 Path + SHA-256 Binding 与 Freshness
Worker 数量很多但风险未覆盖 Risk Profile、Required Role 与 Completion Barrier
Executor 修改范围外文件 Write Allowlist、隔离 worktree、Patch Verification
Promotion 时用户工作区已经变化 Base/Target Preconditions 与目标回读
Provider 超时后重复创建 Mutation Intent、Idempotency 与 Live Reconciliation
State 写了 completed 但产物不存在 Node/Stage Result + Artifact Registry + Readback
Compaction 后模型凭摘要继续 Runtime State 与 Event Chain 高于聊天记忆

这些都是工作流系统而非 Prompt 才能真正解决的问题。

这套架构适合什么,不适合什么

它适合:

  • 跨进程运行数小时或数天;
  • 外部调用不可安全重复;
  • 多个执行者可能并发或晚到;
  • 需要暂停、恢复、审计与责任追踪;
  • 写入对象价值高、回滚困难;
  • 合规要求必须证明谁在什么授权下做了什么。

它不适合默认包住每一个日常代码修改。一个当前会话内能完成、文件范围清楚、失败可用 Git 撤销的任务,如果也要承担 Lease、Schema、Artifact、Worker、Patch 与 Recovery 全套成本,控制面本身就会成为主要复杂度。

Temporal 的 Durable Execution 和 AWS Step Functions 都说明了类似边界:持久化历史、状态机、重试和暂停对真正的长运行流程非常有价值;价值来自流程需要这些性质,而不是因为「步骤多」就应该上工作流引擎。

分步骤阅读

  1. 目标路由:授权的是结果边界,不是「一路做到底」
  2. Progressive Context:怎样让高信号证据先进入上下文
  3. Stage Graph:什么时候一张 DAG 比模型计划更可靠
  4. State、Event 与 Artifact:当前投影、因果历史和结果内容怎样分工
  5. Worker:如何把多 Agent 变成风险驱动的证据系统
  6. Write Isolation:一次性写入能力与隔离 worktree
  7. Patch Promotion:候选修改怎样跨越信任边界
  8. Verification Readback:为什么测试、CI、部署和线上行为不能互证

参考资料

相关文章

在做类似的事情?

很乐意就分布式系统、交付流程和应用 AI 交换意见。

[email protected]