市面上已经有很多成熟的skill了,但是我想自己拥有一个skill,一来是可以熟悉软件开发的流程,另一个是学习skill的创作

但真正让我决定搞这个skill的,是AI编程过程中AI总干出来的一些让人哭笑不得的事。

一、遇到的问题

1、起手就是干

只说了一句"帮我实现登录",它已经开始写了
第一轮测试,我给的 prompt 很简单:“帮我实现一个用户登录功能”。

AI拿到需求后,嘎嘎开始写, 给我生成了一整个登录模块。数据库表设计?没做。技术栈确认?没问。异常处理策略?不存在。AI也不会反问你,或者提醒你还差什么,这次开发计划是什么也不列出来,总之挖了很多坑,demo也是跑不起来的

2、新任务等于又要描述一遍

每个新对话都是一张白纸,因为上下文过长,导致一个窗口继续开发会效果不好,所以有时候会新开任务,但是新开任务就要和它重新描述,甚至还要去老窗口把之前的问题复制过来,很痛苦

3、让它检查自己写的代码,它说"挺好的"


让 AI 审一下自己刚生成的代码。它看了一眼说"代码质量不错,结构清晰"。

这不是 AI 不够聪明,是它没法把自己和产出物分开。就像让一个作家评价自己刚写完的小说,很难客观。

4、每天生成的文档长得都不一样


今天的需求分析文档分了 5 个章节,明天只有 3 个。有的写了数据字典,有的没写。有的列了约束条件,有的只列了两条。

我一开始想"内容完整就行了"。后来发现不对——自动化解析这些文档的时候,格式不一致意味着每个文档都得单独写解析器。

5、AI说“搞定了”、“我已经修复了”,实际没动手


最离谱的一次,AI 说"需求分析文档已完成并写入文件"。我跑去一看,文件系统里什么都没多出来。

它不是故意的。这是 LLM 的"虚假完成"问题——在语言层面上 AI 觉得自己完成了,但实际上文件写入操作根本没执行

这五个问题让我意识到一件事:AI 的能力确实强,但它不会自觉遵守流程。 就像你不能指望一个天才程序员在没有代码审查、没有设计评审、没有自动化测试的情况下交付可靠代码。

流程和约束不是为了浪费时间,是为了兜底。

所以要开始想办法了。下面是我一步步填坑的过程,按遇到的时间先后顺序来写,不分优先级。

二、开始填坑

1、接力棒的应用

以前我用 AI 批量处理数据的时候——Token 超限、网络闪断、浏览器崩溃,什么情况都有。每次重新来,AI 都是从零开始,完全不知道之前处理到哪里了。

后来我学了一招:每处理完一个批次,比如固定多少条,往一个日志文件里写一条记录"已处理到第 XXX 条"。即使断掉,新对话先读这个文件,就能续上。

这个经验被我照搬到了 ReqPlan-v3 里。

在项目根目录塞了个文件 .agent/harness/_baton.md。结构很简单:

## 元信息
| 字段 | 值 |
|------|-----|
| 当前状态 | ANALYZE |
| 模式 | NORMAL |
| 重试计数 | 0 |

## 进度追踪
- [x] START - 启动
- [ ] ANALYZE - 分析
- [ ] CONFIRM - 确认
- [ ] DESIGN - 设计
- [ ] IMPLEMENT - 实现
- [ ] VERIFY - 验证
- [ ] JUDGE - 判断
import json
from datetime import datetime
from pathlib import Path

class Baton:
    """
    AI Skill 接力棒 — 记录当前执行状态,支持断点续跑
    """
    def __init__(self, project_root: str):
        self.baton_path = Path(project_root) / ".agent/harness/_baton.md"
        
    def read(self) -> dict:
        """读取接力棒,获取当前状态"""
        if not self.baton_path.exists():
            return {"status": "START", "mode": "NORMAL"}
        content = self.baton_path.read_text(encoding="utf-8")
        # 从 Markdown 表格中解析状态
        return self._parse_status(content)
    
    def write(self, status: str, mode: str = "NORMAL", retry: int = 0):
        """更新接力棒状态"""
        content = f"""## 元信息
        
| 字段 | 值 |
|------|-----|
| 当前状态 | {status} |
| 模式 | {mode} |
| 重试计数 | {retry} |
| 更新时间 | {datetime.now().strftime("%Y-%m-%d %H:%M")} |

## 进度追踪

- [{'x' if status == 'START' else ' '}] START - 启动
- [{'x' if status == 'ANALYZE' else ' '}] ANALYZE - 分析
- [{'x' if status == 'CONFIRM' else ' '}] CONFIRM - 确认
- [{'x' if status == 'DESIGN' else ' '}] DESIGN - 设计
- [{'x' if status == 'IMPLEMENT' else ' '}] IMPLEMENT - 实现
- [{'x' if status == 'VERIFY' else ' '}] VERIFY - 验证
- [{'x' if status == 'JUDGE' else ' '}] JUDGE - 判断
"""
        self.baton_path.parent.mkdir(parents=True, exist_ok=True)
        self.baton_path.write_text(content, encoding="utf-8")
        
    def _parse_status(self, content: str) -> dict:
        """解析 Markdown 中的状态字段"""
        lines = content.split("\n")
        for i, line in enumerate(lines):
            if "当前状态" in line and "|" in line:
                status = line.split("|")[2].strip()
                return {"status": status, "content": content}
        return {"status": "UNKNOWN", "content": content}


每次 AI 做完一个阶段就更新这个文件。新对话启动后第一件事就是读它。叫它"接力棒"是因为它真的像接力赛里那个棒子——谁拿到了就知道现在跑到哪一步了。

现在关掉对话多少次都无所谓,重新打开后 AI 会主动说:“当前处于 ANALYZE 阶段,需求分析已完成,等你确认。”

顺便它还解决了一个我没想到的问题。AI 在修 Bug 的时候会陷入死循环——修一次没过,再修一次,还没过,继续……我见过它连续修了七次,到第八次我才反应过来不对。所以我在接力棒里加了个"重试计数",上限 2 次。同一个阶段修了 2 次还不过,直接标记 FAILED,通知我来处理。不允许 AI 自我感动式地无限修复。

2、状态机的应用

接力棒解决了"失忆"问题,但没解决"跳步"问题。

AI 还是动不动就跳阶段——我刚说"分析一下",它已经开始写代码了。我给它的自由裁量权太多了。

于是设计了 7 个严格顺序的阶段:

START → ANALYZE → CONFIRM → DESIGN → IMPLEMENT → VERIFY → JUDGE → DONE

其实就是:

项目启动 → 需求分析 → 方案确认 → 方案设计 → 开发实现 → 测试验证 → 评审判定 → 项目完成


我一开始搞了 5 个,后来发现 CONFIRM 这个环节得单独抽出来。因为它是整个流程里唯一需要人类拍板的节点——AI 可以帮你分析、设计、编码、测试,但"这事儿做不做"的决策权不能在 AI 手里。

class SkillStateMachine:
    """AI Skill 7阶段状态机 — 防止跳步"""
    
    # 合法转换表:(当前状态 → 允许的下一个状态)
    TRANSITIONS = {
        "START":    ["ANALYZE"],
        "ANALYZE":  ["CONFIRM"],
        "CONFIRM":  ["DESIGN", "ANALYZE"],  # 确认不通过可以回 ANALYZE
        "DESIGN":   ["IMPLEMENT"],
        "IMPLEMENT":["VERIFY"],
        "VERIFY":   ["JUDGE"],
        "JUDGE":    ["DONE", "DESIGN", "IMPLEMENT"],  # 不通过可以回修
        "DONE":     ["START"],  # 新任务重置
        "FAILED":   [],  # 终止态
    }
    
    def __init__(self):
        self.baton = Baton("./")
        
    def transition_to(self, target_state: str) -> bool:
        """尝试转换到目标状态,非法转换直接阻断"""
        current = self.baton.read()["status"]
        allowed = self.TRANSITIONS.get(current, [])
        
        if target_state not in allowed:
            print(f"[阻断] 非法转换:{current} → {target_state}")
            print(f"        允许的下一状态:{allowed}")
            return False
            
        print(f"[状态机] {current} ✅ → {target_state}")
        self.baton.write(target_state)
        return True
    
    def run(self, task_description: str):
        """入口 — 自动识别当前状态并恢复执行"""
        state = self.baton.read()["status"]
        print(f"当前状态:{state},任务:{task_description[:30]}...")
        
        # 按状态路由,自动进入对应阶段
        handlers = {
            "START":    self._do_analyze,
            "ANALYZE":  self._do_confirm,
            "CONFIRM":  lambda: print("等待用户确认..."),
            "DESIGN":   self._do_implement,
            "IMPLEMENT":self._do_verify,
            "VERIFY":   self._do_judge,
        }
        handler = handlers.get(state)
        if handler:
            handler()
    
    # 模拟各阶段处理
    def _do_analyze(self):
        print("执行需求分析...")
        self.transition_to("CONFIRM")
    
    def _do_confirm(self):
        print("展示分析报告,等待确认...")
    
    def _do_implement(self):
        print("执行方案设计→编码...")
        self.transition_to("VERIFY")
    
    def _do_verify(self):
        print("运行验证检查...")
        self.transition_to("JUDGE")
    
    def _do_judge(self):
        print("综合判定...")
        self.transition_to("DONE")

# 实际使用
sm = SkillStateMachine()
sm.run("帮我创建一个用户登录功能")

规则其实很简单:

每阶段有明确的输入和输出,没完成不准进入下一阶段
阶段之间不能逆行
只有 CONFIRM 阶段会停下来等我确认

3、子agent独立审核的应用

让 AI 自己检查自己这个思路,我想放弃是花了一些时间的。"让 AI 自我审查"听起来很合理——它能写代码,那应该也能审查代码对吧?

但几次测试下来,AI 对着自己写的代码永远是一副"挺好的"的态度。

换了个思路:不自己审了,找个独立的角色来审。

具体做法是拉起一个全新的子 Agent,跟主对话完全隔离。它不知道原始需求是什么,不知道代码是谁写的,甚至不允许它请求额外上下文。它只看产物文件本身,按清单逐项检查。相当于是个蒙着眼睛的质检员。

审核流程分了三个层次:

第1层:阻断检查(一票否决)
  发现严重问题 → 直接 FAILED,不评分
第2层:维度评分(量化评估)
  按 N 个维度打分(0-100分),每项扣分必须有引用证据
第3层:综合判定
  A级(≥90分) / B级(75-89) / C级(60-74) / D级(<60或阻断中断)


这里我踩过一个坑。第一次测试审核机制的时候,AI 说"问题已修复"。结果我检查发现,它只是把文档里"问题描述"那段文字删掉了,代码压根没改。

所以加了修复验证闭环:

1、读取上次审核报告里的"待修复问题清单"
2、逐条检查每个问题是否真的已修复
3、标记修复状态(已修复 ✅ 或 假修复 ❌)
4、有一条假修复 → 整体不通过
后来我还加了个防评分偏移的设计:如果连续 3 次审核都给出 >= 90 分,触发评分偏移告警,标记该轮审核为"可能不可靠",让我手动确认。即使是 AI 自己在审,长期固定标准也需要打个问号。

4、分多个agent角色的应用

在没分工的时候,AI 在一个对话里什么角色都演:分析需求、写代码、做测试、写文档。结果就是它经常串戏——分析需求的时候已经在想数据类型怎么定义了,写代码的时候又想"这功能要不要换个方案"。

我干脆把任务拆给了五个 Agent 角色,每个角色有明确的职责和边界:

1、Analyzer:解析需求、收集上下文、识别可复用资源 → 产出 _analysis.md。不写一行代码。
2、Designer:设计架构、定义模块、拆解实现任务 → 产出 _design.md。必须先读完分析报告才动笔。
3、Implementer:按设计文档写代码、更新进度 → 产出 _implementation.md + 实际代码。读设计文档之前不能开始写。
4、Verifier:执行验证——静态检查、单元测试、构建集成、异常路径覆盖、流程合规 → 产出 _verification.md。只读,不修改源码。
5、Quality Auditor:阻断检查、维度评分、等级判定 → 产出 _quality_audit_*.md。不允许额外上下文,不修改任何产物。
每个 Agent 有自己的产物文件,不碰别人的。一个阶段的产物做得不好不会影响其他阶段——Analyzer 的分析报告如果搞砸了,Designer 还没开始做,所以不受牵连。

我最开始觉得"给 AI 分配不同角色"这事有点玄学——反正底层是同一个 LLM,角色扮演能有多大区别?但实际跑起来我发现真的有区别。分析阶段的 AI 会像产品经理一样追问"这功能给谁用";设计阶段的 AI 像架构师一样画模块图;实现阶段像开发者一样抠细节;测试阶段像个 QA 一样专门挑毛病。同一个模型,不同的上下文设定,思考方式真的会不一样。

5、渐进式披露的应用

另一个头疼的问题是 Skill 文档本身越来越臃肿。ReqPlan-v3 的文章越写越长,从几百字膨胀到几千行。但 AI 的上下文窗口有限,把所有规则一次性塞进去,那些当前任务不需要的知识就白白占了空间。而且信息太多反而影响判断——和人类一样,注意力有限。

我把文档拆成了 4 个块:

chunk-01:意图引导,教 AI 怎么理解用户要什么。每次都得加载。
chunk-02:三个流程的定义(开发推动、分析评估、问题修复)。高频场景才加载。
chunk-03:验证和审查的规则。做验证的时候加载。
chunk-04:存档归档的流程。低频,只在最后阶段加载。

分块加载不只是给 AI 用的。给用户看的信息我也做了分层——CONFIRM 阶段用户看到的只是一个精简摘要。而不是几十页的分析报告。你让人看完几十页再决定要不要继续,他大概率会烦。

6、文档的一致性的应用

前面说到 AI 每次输出的文档格式不一样,而且有时候说"写完了",文件系统里啥都没有。

我对付这两个问题的方式挺粗暴的——给每个产物定了固定的模板结构。

比如分析报告必须是这个结构:

_analysis.md:
  1、基本信息(时间、分析者、场景类型)
  2、需求理解(核心功能表、角色、数据实体)
  3、技术栈(技术选型表、项目结构)
  4、涉及文件(需修改的文件、需新增的文件)
  5、约束条件(技术约束、业务约束)
  6、风险评估(已识别风险、风险等级)

from pathlib import Path
from typing import List

class VerificationChain:
    """
    验证链 — 防止 AI "口头完成" 问题
    三条铁律:计数验证 / 列表验证 / 文件验证
    """
    
    @staticmethod
    def verify_count(claimed: int, actual_items: List[str]) -> bool:
        """计数验证:声称 N 个,就必须有 N 个"""
        actual = len(actual_items)
        if actual != claimed:
            print(f"❌ 计数验证失败:声明的 {claimed} 个,实际 {actual} 个")
            print(f"   实际列表:{actual_items}")
            return False
        print(f"✅ 计数验证通过:{claimed}/{actual}")
        return True
    
    @staticmethod
    def verify_list(items: List[str], keyword: str = "") -> bool:
        """列表验证:不能出现'等'、'等'字省略"""
        for item in items:
            if "等" in item:
                print(f"❌ 列表验证失败:包含模糊词'等' → {item}")
                return False
            if not item.strip():
                print("❌ 列表验证失败:存在空项")
                return False
        print(f"✅ 列表验证通过:{len(items)} 项均已明确列出")
        return True
    
    @staticmethod
    def verify_file_written(file_path: str) -> bool:
        """文件验证:read 确认文件确实写入"""
        path = Path(file_path)
        if not path.exists():
            print(f"❌ 文件验证失败:{file_path} 不存在")
            print(f"   AI 口中的'已写入'不成立,属虚假完成")
            return False
        content = path.read_text(encoding="utf-8", errors="ignore")
        if len(content.strip()) == 0:
            print(f"❌ 文件验证失败:{file_path} 存在但为空文件")
            return False
        print(f"✅文件验证通过:{file_path}({len(content)} 字符)")
        return True
    
    @staticmethod
    def full_check(claimed_count: int, items: List[str], 
                   file_paths: List[str]) -> dict:
        """全量验证,返回通过/失败明细"""
        results = {
            "count_check": VerificationChain.verify_count(
                claimed_count, items),
            "list_check": VerificationChain.verify_list(items),
            "file_check": all(
                VerificationChain.verify_file_write(f)
                for f in file_paths
            )
        }
        results["passed"] = all(results.values())
        return results

# 使用示例
vc = VerificationChain()
result = vc.full_check(
    claimed_count=3,
    items=["/src/auth.py", "/src/db.py", "/src/utils.py"],
    file_paths=["/src/auth.py", "/src/db.py", "/src/utils.py"]
)
# 输出:✅ 计数验证通过:3/3
# 输出:✅ 列表验证通过:3 项均已明确列出
# 输出:✅ 文件验证通过...


模板末尾附带强制检查清单,AI 写完后必须逐项确认:

1、本产物已保存到文件系统
2、产物头部包含版本号
3、已确认产物包含所有必需章节
4、已触发独立质量审核
5、质量审核已通过
6、已更新接力棒
只要有一项没勾选,不能进入下一阶段。这是硬阻断,不是建议。

然后为了解决"对话里说写了实际没写"的问题,我加了三条验证规则:

1、计数验证:说"提取了 N 个功能"→ 必须逐个列出来。声称 5 个但只写了 3 个 → 不通过,回去补。

2、列表验证:说"涉及 3 个文件"→ 必须给出具体路径。"main.py 和 utils.py 等"→ 不通过,把"等"去掉写清楚。

3、文件验证:说"已写入产物文件"→ 必须用 read 命令确认写入成功。对话里说"写好了"不算数。

这三条看着挺死板的,但加了之后"口头完成"的问题真的不再出现了。

六个机制不是各自为政的。它们的分工大致是这样:

机制管理维度作用
接力棒状态告诉 AI 现在该干什么
状态机流程告诉 AI 能干什么、不能干什么
角色分工执行不同阶段用不同角色去做
模板产出每个阶段的产物该长什么样
验证链质量产出之后怎么确认真的做完了
分块加载效率只给当前阶段所需的知识,不超载

以前"建议先分析再做设计"→ 现在分析阶段没完成,直接进不去设计阶段。
以前"建议检查文件是否写入"→ 现在不去 read 一下,检查清单过不了。
以前"建议请独立人员审核"→ 现在强制拉起独立子 Agent,不给上下文。

所有的判定也从感觉变成了证据:

"代码质量不错"→ “代码质量评分 85,扣分项:缺少异常处理(引用第 34 行)”
"所有任务已完成"→ “已完成 5 个中的 5 个:任务1 ✅ 任务2 ✅ 任务3 ✅ 任务4 ✅ 任务5 ✅”
"涉及 3 个文件"→ “涉及文件:/src/a.py, /src/b.py, /src/c.py”

写完这些机制后我回头看了下,发现其实没有新发明的东西。接力棒就是一个 Markdown 文件,状态机就是一张路由表,审核就是一个子 Agent 调用,分块加载就是拆文档。单个拎出来都很朴素。

这些做法也不只对 AI 有用。接力棒配合状态机本质上就是一个轻量的工作流引擎,CI/CD Pipeline、审批流程、ETL 任务都可以用。独立盲审不就是代码审查的最佳实践吗——审查者不看作者的上下文,只检查产物本身。多角色分工更是任何一个成熟团队都在做的事。模板加检查清单就是格式控制的老办法。

做这个项目最大的体感是:AI 身上存在着和人类程序员一模一样的问题——跳步、遗忘、认知偏误、虚假完成。不同的是,我们在软件工程里早就想好了怎么应对:代码审查、设计评审、自动化测试、CI/CD。

ReqPlan-v3 做的事,就是把人类的这些流程翻译成了 AI 能理解和执行的版本。

所以我不太同意"AI 取代程序员"的说法。更接近的说法是——有了流程约束的 AI 加上有流程意识的程序员,这个组合比单打独斗的程序员和没有约束的 AI 都强。

以上这些就是基于实际项目 ReqPlan-v3 的迭代经验整理
感兴趣的朋友可以去下载这个skill使用:
项目地址:Releases · songzhou666/ReqPlan-v3 · GitHub

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐