01 · 当 AI 学会"按规矩办事"——规范驱动 Agent 工作流总览

系列第 1 篇

学完本篇你能:

  1. 理解 “规范驱动 Agent 工作流” 是什么、为什么需要它;
  2. 用 5 个核心抽象(Run / Stage / Manifest / Gate / Profile)描述任意一个 Agent 流水线;
  3. 现在就能动手:花 10 分钟搭一个最小可跑的"分阶段 + 可审批"AI 任务执行器。

0. 翻车现场:你肯定见过

场景换一个所有人都熟的——“让 AI 帮我重构一个老 Python 模块”:

“把这个 legacy_order.py 文件重构一下,拆成 service / repo 两层,加上类型注解,补单元测试。”

你扔给 Cursor / Claude Code / 任意 AI 助手,结果通常是:

  1. 直接开冲:上来就写代码,写到一半发现没看 db_session.py 的依赖,类型对不上。
  2. 半截烂尾:80% 写完了,剩下 20% 反复修;你也说不出来是哪一步歪了。
  3. 越改越乱:你说"这里不对",它改 A 又改坏 B,上下文越来越长。
  4. 没法复盘:成功了你也复述不出来它到底做了哪些决策。
  5. 没法暂停:会话一断,下次从零开始,前面 50 轮全丢。

根因只有一个:你把 AI 当"超长 prompt 里的执行器",没把它当"流水线"来设计。

这一篇要回答的问题:怎么把"让 AI 改一个真实仓库"做成可控、可暂停、可回放的工程化流程?


1. 核心立场:流水线,不是聊天框

如果你熟悉 CI/CD(Jenkins、GitHub Actions),那就好办了——规范驱动 Agent 工作流 = 把 AI 编码做成 CI/CD

   ❌ 聊天框模式                   ✅ 流水线模式
   
   ┌────────────────┐             ┌────────────────────────────┐
   │ 一个超长       │             │ 阶段 1 → 阶段 2 → ... → N  │
   │ system prompt  │             │   ↓        ↓                │
   │                │             │ 产物 1   产物 2             │
   │ AI 自由发挥    │             │   ↓        ↓                │
   │                │             │ 审批门   审批门             │
   │ 输出 = 一坨    │             │                            │
   └────────────────┘             │ 状态可查 / 失败可重跑 /    │
                                  │ 中断可恢复 / 全程可复盘    │
                                  └────────────────────────────┘

CI/CD 的执行体是 shell 脚本,规范驱动 Agent 工作流的执行体是 LLM。别的,全一样——分阶段、出产物、卡审批、可恢复。

动手 30 秒:打开你常用的 AI 编码工具,回想最近一次让它做大型重构的对话。数一下:那次任务跨了几个阶段?每个阶段的产物存在哪?如果中途断了你怎么恢复?答不上来的越多,越说明你需要这套东西。


2. 五个核心抽象:背下来够用一辈子

不管哪个具体的 Agent 框架(Aladdin / LangGraph / CrewAI / 自己写的),看到下面这五个抽象就能秒懂:

抽象 一句话 类比
Run 一次任务执行实例,有唯一 ID GitHub Actions 的一次 workflow run
Stage run 内部的一个阶段(需求/设计/实现/验证…) CI 流水线里的一个 job
Manifest 记录这个 run 走到哪了的状态文件 数据库里的 task 表那一行
Gate 阶段之间的审批闸门 PR review / CI manual approval
Profile 适配不同技术栈的可换插件 Docker 镜像变体(python:3.11 vs node:20)
┌─────────────────────────── 一个 Run ────────────────────────────┐
│                                                                  │
│   Stage 1   ─►   [Gate]   ─►   Stage 2   ─►   [Gate]   ─►  ...  │
│   ↓                            ↓                                 │
│  产物 1                       产物 2                             │
│                                                                  │
│   ┌───────────────────────────────────────────────────────────┐  │
│   │  Manifest(YAML 文件):                                  │  │
│   │    run_id: 20260630-abc123                                │  │
│   │    current_stage: Stage 2                                 │  │
│   │    lifecycle: AWAITING_APPROVAL                           │  │
│   │    artifacts: { stage1: ./design.md, stage2: ... }        │  │
│   └───────────────────────────────────────────────────────────┘  │
│                       ▲                                          │
│                       │ 通过 Profile 注入"这次用什么技术栈"     │
│                       │                                          │
└───────────────────────┼──────────────────────────────────────────┘
                        │
                ┌───────┴────────┐
                │ Profile (YAML) │
                │  - 编译命令     │
                │  - 阶段实现者   │
                │  - 模板路径     │
                └────────────────┘

记住这张图。后面 4 篇都是在它的某一格里深挖。

动手 30 秒:在你电脑上随便建个目录,写个 manifest.yaml

run_id: my-first-run
current_stage: design
lifecycle: RUNNING
artifacts: {}

这就是 Run Manifest 的最小形态。一行 Python yaml.safe_load(open("manifest.yaml")) 就能读它。


3. 一个完整流程长什么样

把上面五个抽象串起来,就是一个完整 Agent 流水线。下面是一个通用版(不限技术栈):

                    ┌──────────────────────────────────────────────┐
   用户需求 ──────► │           规范驱动 Agent 工作流              │
                    │                                              │
                    │  ┌────────┐    ┌────────┐    ┌────────┐     │
                    │  │  S1    │ ─► │   S2   │ ─► │   S3   │     │
                    │  │ 需求   │    │ 设计   │    │ 任务   │     │
                    │  │ 整理   │    │ 文档   │    │ 拆解   │     │
                    │  └────┬───┘    └────┬───┘    └────┬───┘     │
                    │       │             │             │         │
                    │     [审批门]      [审批门]      [审批门]    │
                    │       ▼             ▼             ▼         │
                    │       └─────►──────┴──────►──────┘         │
                    │                                              │
                    │       ┌────────┐                             │
                    │       │   S4   │ ◄── 唯一允许改业务代码的阶段│
                    │       │ 实现   │                             │
                    │       └────┬───┘                             │
                    │            ▼                                 │
                    │  ┌─────────────── S5 验证回环 ─────────────┐ │
                    │  │  S5.1 静态审计 ─► S5.2 编译 ─► S5.3 跑│ │
                    │  └─────────────────────┬─────────────────┘ │
                    │                        │                   │
                    │              ┌─────────┴────────┐          │
                    │              ▼                  ▼          │
                    │       PASS ─► S6 总结      失败 ─► 回 S4 ─┐│
                    │                                           ││
                    │     不确定/卡住 ──► HITL(人在回路)──────┘│
                    └──────────────────────────────────────────────┘
                                     ▲
                                     │
                ┌────────────────────┴──────────────────────┐
                │  全程读写:runs/<run_id>/manifest.yaml    │
                │  (唯一的"项目档案袋",状态机的真相源)   │
                └───────────────────────────────────────────┘

HITL = Human-In-The-Loop(人在回路):AI 拿不准 / 信息不足 / 状态冲突时,主动停下等人,而不是硬猜着往下走。这是这套方法论的灵魂之一。

三个最关键的不变量,记住就行:

  1. S4 是唯一允许写业务代码的阶段——之前只能产出"规范"(需求文档、设计文档、任务清单)。
  2. S5 是验证回环——静态审计 → 编译 → 跑通必须串行,不能合并。
  3. 任何阶段之间都可能卡审批,AI 自己不能开闸。

动手 30 秒:拿你最近做过的一个 AI 任务,套到这张图上。哪几步是你心里"默默做了"的?把它们显式地命名出来——这就是开始"工程化"的第一步。


4. 关键设计:把"下一步做什么"从 LLM 手里拿走

这是整套方法论里最值得偷的一招

反例:把流程描述写在 system prompt 里,让 LLM 自己判断"我现在该走哪一步"。

❌ 反例(vibe coding 常见做法)

   ┌──────────────────────────────────────┐
   │  超长 system prompt:                │
   │  "你是 AI 工程师,先写需求,         │
   │   再写设计,再写代码……               │
   │   如果失败就回到实现阶段……"          │
   │                                      │
   │   LLM 自己判断状态                   │
   │   LLM 自己决定跳转                   │
   │                                      │
   │   ⚠ 状态飘忽 / 逻辑漂移 / 上下文爆炸│
   └──────────────────────────────────────┘

正例:把"下一步走哪"做成一个确定性函数,LLM 只能调用、不能改写。

✅ 正例(规范驱动)

   ┌──────────────────────────────────────┐
   │  prompt 只说:"你现在做 S2 设计"     │
   │                                      │
   │  下一步走哪?───┐                    │
   │                ▼                     │
   │  ┌────────────────────────────────┐  │
   │  │  next_action()  ← 纯函数       │  │
   │  │   读 manifest.yaml             │  │
   │  │   按规则判断                   │  │
   │  │   返回枚举值                   │  │
   │  └────────────────┬───────────────┘  │
   │                   ▼                  │
   │  RUN_STAGE / WAIT_APPROVAL /        │
   │  BLOCKED / COMPLETE                  │
   │                   │                  │
   │  LLM 严格照办 ◄───┘                  │
   └──────────────────────────────────────┘

关键点:返回值是枚举值,不是自然语言。LLM 只能按枚举值行动,不能"理解"出第六种可能。

4.1 看一段简化版的伪代码

下面是一个最小可运行next_action()60 行 Python,不依赖任何框架:

# next_action.py - 一个 Agent 流水线状态机的"心脏"

import yaml
from enum import Enum
from pathlib import Path

class Action(str, Enum):
    RUN_STAGE      = "RUN_STAGE"       # 可以进入下一阶段
    WAIT_APPROVAL  = "WAIT_APPROVAL"   # 等待人工审批
    BLOCKED        = "BLOCKED"         # 状态异常,停下
    COMPLETE       = "COMPLETE"        # 全部完成

# 阶段顺序(写死在状态机里,不让 LLM 自己想)
STAGES = ["S1_requirements", "S2_design", "S3_tasks",
          "S4_implement", "S5_verify", "S6_summary"]

def next_action(run_dir: Path) -> dict:
    manifest = yaml.safe_load((run_dir / "manifest.yaml").read_text())
    cur = manifest["current_stage"]
    lifecycle = manifest["lifecycle"]
    gates = manifest.get("approval_gates", {})

    # 1. 流程已经完成
    if cur == STAGES[-1] and lifecycle == "COMPLETED":
        return {"action": Action.COMPLETE, "reason": "all stages done"}

    # 2. 当前阶段还没完成 → 继续干当前阶段
    if lifecycle == "RUNNING":
        return {"action": Action.RUN_STAGE,
                "target_stage": cur,
                "reason": "stage in progress"}

    # 3. 当前阶段产物已出,等审批
    if lifecycle == "AWAITING_APPROVAL":
        gate_status = gates.get(cur, {}).get("status", "pending")
        if gate_status == "approved":
            next_idx = STAGES.index(cur) + 1
            return {"action": Action.RUN_STAGE,
                    "target_stage": STAGES[next_idx],
                    "reason": f"{cur} approved, advance"}
        else:
            return {"action": Action.WAIT_APPROVAL,
                    "target_stage": cur,
                    "reason": "gate not approved"}

    # 4. 状态异常
    return {"action": Action.BLOCKED,
            "reason": f"unknown lifecycle: {lifecycle}"}

这就是规范驱动 Agent 工作流最核心的那 60 行代码。可以扩展(加更多阶段、加 profile、加重试),但骨架就是这样。

动手 10 分钟(即时满足版)

  1. 把上面 60 行存成 next_action.py
  2. 创建 runs/test01/manifest.yaml,内容:
    current_stage: S1_requirements
    lifecycle: AWAITING_APPROVAL
    approval_gates:
      S1_requirements: { status: approved }
    
  3. 跑:
    from pathlib import Path
    from next_action import next_action
    print(next_action(Path("runs/test01")))
    
  4. 你应该看到:
    {'action': 'RUN_STAGE', 'target_stage': 'S2_design', 'reason': 'S1_requirements approved, advance'}
    
  5. status: approved 改成 pending,再跑一次。状态变成 WAIT_APPROVAL

恭喜——你刚才手写了一个 Mini-Aladdin 的核心。


5. Core 与 Profile 的边界:“骨头” vs “肌肉”

最后一个概念,第 4 篇会展开。

   ┌─────────────────────────────────────────┐
   │              Core                       │  ← 骨头
   │  (流程不变量 / 状态机 / Approval Gate)│     所有任务通用
   └─────────────────┬───────────────────────┘
                     │ profile_path 注入
                     ▼
   ┌─────────────────────────────────────────┐
   │              Profile                    │  ← 肌肉
   │  ┌──────────┐  ┌──────────┐  ┌────────┐ │
   │  │  Python  │  │   Java   │  │   Go   │ │  不同技术栈
   │  │  profile │  │  profile │  │profile │ │  完全不同
   │  └──────────┘  └──────────┘  └────────┘ │
   │  - 编译命令:pytest / mvn / go test     │
   │  - 模板路径:自家代码模板               │
   │  - 阶段实现者:调哪个 sub-agent         │
   └─────────────────────────────────────────┘

这就是设计模式里的**开闭原则(OCP)**在 Agent 系统里的体现:核心流程对修改关闭、对扩展开放。新接一个技术栈 = 写一份 profile。Core 一行不动。

动手 30 秒:你现在做的项目,如果要让 AI 跑同一套流程,需要哪些"技术栈相关"的命令?比如 pytest -v 是 Python 的,npm run test 是前端的——把这些写进 profile,core 永远只调 profile.test_command


6. 核心要点回顾

如果只能记三件事:

  1. 复杂任务要切阶段:不要一个 prompt 干所有。切成 S1 → S2 → … → S6,每段独立可审批可重跑。
  2. 状态要有真相源:用文件(YAML/JSON)当唯一真相源,不要让 LLM 自己记。
  3. 决策权要拿出来next_action() 这种结构化裁决函数,比让 LLM 自己想"下一步做什么"靠谱十倍。

7. FAQ:你大概率会问的 7 个问题

Q1:这套东西和直接用 LangGraph / CrewAI 有啥区别?

LangGraph / CrewAI 给你的是框架(提供执行引擎、节点定义、消息协议)。这一篇讲的是方法论——它们是正交的。你完全可以用 LangGraph 实现规范驱动 Agent 工作流,关键是要有 Run / Stage / Manifest / Gate / Profile 这五个抽象,而不是只把节点连起来就完事。

Q2:所有 AI 任务都要用这套吗?写个一次性脚本也用?

不用。判断标准:任务是否要跨多轮、产物是否要复用、失败是否要回滚。一次性问答、简单生成不需要。但凡你想第二天还能复盘的任务,都值得上。

Q3:状态机限制了 LLM 的"灵活性",会不会让结果变差?

恰恰相反。LLM 的"灵活"在语义生成上很值钱,在流程控制上是灾难。你让它写代码很灵活,让它判断"现在该编译还是该先 review"它就开始胡说。把它擅长的留给它,把它不擅长的拿走——结果会更好不会更差。

Q4:Approval Gate 每步都卡审批,那不还是人工干活?

可以配 auto 模式,让审批自动通过;也可以只在关键阶段卡(比如 S4 实现完之后必卡,前面阶段全 auto)。重点不是"必须人工",是"必须留一个能让人介入的口子"。生产环境出 bug 的时候你会感谢这个口子。

Q5:Manifest 文件被 LLM 误改了怎么办?

这就是为什么"所有写入必须通过 run_manifest.py"——脚本里做参数校验,schema 不对就拒绝写。把"能改"的入口收窄到一个,LLM 只能调命令、不能直接编辑文件。这一招在工程上叫 DAO 模式(Data Access Object),AI 系统里同样有效。

Q6:我自己怎么从 0 搭一个?

三步走:

  1. 第一周:把第 4 节的 60 行代码扩到 200 行,加上 init / stage-start / stage-complete / gate-event 命令;
  2. 第二周:接一个 LLM(Claude / GPT),让它每次行动前先调 next_action(),根据返回值决定 prompt;
  3. 第三周:加 profile 系统、加 sub-agent,开始拆"S5 验证回环"。

后面 4 篇会带你过一遍。

Q7:这套东西有什么明显的缺点 / 不适合的场景?

三个:

  • 冷启动成本高:写 profile、定义阶段、调 prompt,前期投入比 vibe coding 大几倍。任务简单或一次性的别上。
  • 调试链路长:流程出错时你要查 manifest、查 gate、查 stage artifacts 三个地方,比看一坨对话窗口累。
  • 不擅长开放式探索:阶段是预定义的。如果任务本身需要"先到处看看再决定怎么做",硬切阶段反而拧巴。

8. 下一篇预告

02 · 状态机与 Run Manifest——把"下一步做什么"从 prompt 手里拿走

我们会把第 4 节那个 60 行的 next_action() 扩展到 150 行的完整最小版,包括:

  • init / stage-start / stage-complete / gate-event / sync-result 五个命令的具体实现;
  • 状态字段 current_stage / lifecycle / waiting_for / resume_from 的语义和读写时机;
  • 如何让 LLM "读懂"状态——一个让 prompt 看得懂 manifest 的小技巧。

读完你能直接在自己项目里跑起来一个最小版状态机。


系列写作承诺(Prompt 工程线)

除了架构拆解,每一篇额外开一节"Prompt 拆解"——挑当篇主题对应的源码 prompt 段落,逐句注释为什么这么写。读完整个系列你会同时学到两件事:

  • 架构线:怎么设计一个 Agent 流水线(Run / Stage / Manifest / Gate / Profile)
  • Prompt 线:怎么把工程规则写进 prompt,让 LLM 真的听话(意图分类、硬边界、必读顺序、不变量声明……)
Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐