☰
编码代理工作流重构:AI-Infra-Auto-Driven-SKILLS v0.1.5实战解析
2026/10/13 11:36:15 网站建设 项目流程

大概八个月前,我把自己的编码工作流从"一个塞满各种小技巧的提示文档"重构成了一套有版本号、有技能目录、有推理解析路径的工作流,也就是现在的 AI-Infra-Auto-Driven-SKILLS v0.1.5。名字确实很长,但核心解决的事情特别具体:当你同时面对 Codex 和 Claude Code 这类有自主规划能力的编码代理时,怎么让它们拿到同一个需求,用同一套思考路径拆解,而不是靠模型的临场发挥。

先说结论:如果你的需求是"帮我把这个函数改成异步",那么直接对话就够了,上框架反而是负担。但如果你经常让编码代理处理跨多文件、有依赖关系、需要回归验证的任务,比如升级依赖、重构模块、补测试,那么一套"技能目录 + 推理编排 + 执行钩子"的工作流,价值会立刻体现出来。这篇内容适合两类人:一类是在两个 CLI 工具之间来回切换,受够了行为不一致的工程师;另一类是刚开始搭自己的编码代理基础设施、想少踩几个坑的人。

下面我把 v0.1.5 背后的设计思路、实际落地步骤、走查案例和翻车记录都摊开写一写。

1. 先说痛点:编码代理不是不会干活,是经常在错误的时机干活

1.1 为什么"多扔几个 Prompt 进去"这条路走不通

早期我做提示词资产的方式很朴素:把几十个常用任务的指示写进一个大文档,然后让编码代理任何时候都带着这份文档工作。听起来很完整,实际上用起来很痛苦。第一个问题是上下文被大量无关指令占据,代理在长会话里处理到一半,往往会把某个任务的规则带入另一个任务;第二个问题是任务路由完全靠模型自己猜,同一个需求今天可能命中这个分支,明天可能命中另一个分支,输出稳定性很差。

后来我把方案改成"按需加载",但很快就发现,按什么依据来决定加载哪些指令,比我预想的复杂得多。依赖升级的规则需要加载,测试生成的规则也需要加载,可如果两条规则同时命中,代码风格约束又要听谁的?这时候我才意识到,缺的不是更多指令,而是一个能让代理"先想清楚再行动"的固定框架。

1.2 推理框架到底和普通提示词模板差在哪

普通提示词模板是一份静态文本,模型动手之前看一遍,然后就进入正常对话了。推理框架则是把"处理一个需求"的过程拆成几个明确阶段,每个阶段都有对应的输入、输出标准和检查动作。你可以把它理解成给代理装了一个内置的流程状态机,它在每个阶段必须产出特定结构的内容,才能进入下一阶段。

在 v0.1.5 里,我固定了五个阶段:REP 代表重述需求,ANA 代表分析任务类型,PLAN 代表生成执行计划,EXE 代表动手修改,VERIFY 代表验证结果。这个编排层做的事,就是强制代理在改代码之前,先花几个输出 token 把问题边界拉清楚。很多人担心这会拖慢速度,实际测试下来,大部分简单任务只会增加不到两秒的延迟,但复杂任务的返工率下降非常明显。

2. 框架的骨架:技能目录、推理编排、执行钩子三件套

2.1 技能层:一份跨 CLI 的技能规格

整个框架最底部是技能目录层。v0.1.5 不是直接往各个 CLI 的配置文件里塞提示词,而是先定义一套中立的技能规格文件,再由同步脚本生成不同工具需要的格式。每个技能包含四个核心字段:唯一标识、路由条件、执行指令、验证标准。其中路由条件是整套框架能跑起来的重中之重,它描述的是"什么任务该触发这个技能,什么任务不该触发",这部分写得越清楚,技能路由准确率越高。

下面是技能规格的一个片段,我用依赖升级技能举例:

skills: - id: dep_upgrade name: 依赖升级与回归验证 triggers: include: ["升级依赖", "更新 package.json", "处理 lockfile 冲突", "依赖版本过期"] exclude: ["新增依赖功能", "不涉及版本变更的普通修改"] instructions: - 先读取当前依赖清单和锁定文件,识别直接依赖与传递依赖 - 执行升级命令,记录升级前后的版本差异 - 运行项目已有测试套件,并针对升级包相关代码补测 - 输出变更报告,标明需要人工关注的不兼容项 verify: - 锁定文件是否一致 - 测试是否全量通过 - 是否有未记录的版本变更

这份规格本身不绑定任何 CLI 工具。Codex 环境下它可以生成一份独立 markdown 文档,Claude Code 环境下则生成对应的 SKILL.md。这种设计让维护成本大幅降低,改一次规格,两个环境同步生效。

2.2 编排层:五个固定阶段,每个阶段都有输出要求

技能层解决的是"每种任务该怎么干",编排层解决的是"代理该按什么顺序想问题"。v0.1.5 里,我把编排层的提示词做成一段固定注入文本,要求代理在每个工作流周期里按 REP、ANA、PLAN、EXE、VERIFY 顺序输出。

这五个阶段各自的职责可以看下面这张表:

阶段核心动作必须包含的输出常见跳过后果
REP用自己的话重述需求明确的任务边界、涉及文件列表遗漏非典型文件,只改表层
ANA给任务分类命中的技能 ID、不命中其他技能的理由多技能互相抢规则,输出漂移
PLAN编写执行计划按依赖关系排序的操作步骤先改依赖后改代码,编译不过
EXE执行修改对应技能指令的具体落地无
VERIFY验证结果测试结果、变更清单、遗留风险改完不测,或者只测了冒烟

这段编排文本本身像一张表格,但实现时不是让模型输出表格,而是要求它把每个阶段压缩成一到三行短句。一开始我把每个阶段写得很复杂,结果模型花大量时间在写计划而不是执行,后来把所有阶段都改成"够用即可"的输出规格,效果反而稳定多了。

2.3 执行钩子层:把验证动作固化到工作流边界上

纯粹靠提示词让模型自律,上限很有限。v0.1.5 里我在工作流边界上加了一些轻量钩子,主要做三件事:第一,在 EXE 阶段开始前,自动检查当前分支的工作区状态,避免代理在一堆未提交改动里叠新改动;第二,在 VERIFY 阶段调用预设的验证命令集,比如测试、构建、锁文件一致性检查;第三,把每次工作流的阶段输出追加到独立的日志文件,方便事后退查。

钩子层的位置很讲究,不能放在代理每说一句话都触发的位置,那样会频繁打断思路,而要在"阶段切换"时触发。v0.1.5 的实现方式是让代理在阶段输出里带一个特定标记行,外部脚本监视输出流,碰到标记就执行对应的钩子。这种方法有轻微延迟,但胜在不需要改 CLI 本身的行为,通用性更强。

3. v0.1.5 的双端落地:在 Codex 和 Claude Code 里分别怎么接

3.1 同步机制:一份技能源,两个 CLI 各取所需

很多人在 Codex 和 Claude Code 之间反复横跳,最容易崩溃的就是两边的技能写法完全不同。Claude Code 有相对成熟的 Skill 目录格式,Codex 则主要靠项目级指令文件里的索引来触发按需加载。v0.1.5 用一个小脚本把这层差异抹平了。技能源文件是一个 YAML,脚本读取后,分别生成两个目标:

# sync_skills.py 的简化逻辑 import yaml from pathlib import Path with open("skills.yml") as f: data = yaml.safe_load(f) for skill in data["skills"]: # 生成给 Claude Code 的 SKILL.md claude_path = Path(".claude/skills") / skill["id"] / "SKILL.md" claude_path.parent.mkdir(parents=True, exist_ok=True) claude_path.write_text(build_claude_skill(skill)) # 生成给 Codex 的独立技能文档 codex_path = Path("docs/skills") / f"{skill['id']}.md" codex_path.write_text(build_codex_doc(skill)) # 再生成 AGENTS.md 里需要追加的技能索引段落 append_codex_index(data["skills"])

这一步看起来平平无奇,但它是整个 v0.1.5 能双端共存的基石。没有这个同步层之前,我经常在 Codex 里调好了技能,转头在 Claude Code 里忘了补一份,行为分裂到让人崩溃。

3.2 Codex 端:AGENTS.md 只写索引,技能文件按需展开

很多人在 AGENTS.md 里越堆越多,恨不得把整个团队的编码规范都写进去。我的建议是反过来的:AGENTS.md 里永远只放骨架和索引,具体技能内容放 doc 文件,等命中需求时再让代理去读取。这样做的原因很简单,AGENTS.md 的内容几乎全程在上下文里,它有 2000 字,就相当于白白占了 2000 字,越臃肿,代理越容易忽略关键信息。

我在 AGENTS.md 的末尾加了这样一段索引:

## AI-Infra-Auto-Driven-SKILLS v0.1.5 技能索引 当任务是以下类型之一时,先完整读取对应技能文档,再开始规划: - dep_upgrade: docs/skills/dep_upgrade.md - test_gen: docs/skills/test_gen.md - refactor_module: docs/skills/refactor_module.md 读取技能文档后,按 REP-ANA-PLAN-EXE-VERIFY 的顺序输出并执行。

这套机制能在 Codex 里生效,靠的是代理先看到索引,再自主决定读取哪个文档。只要技能文档的标题和开头说明足够清晰,代理的文档拉取准确率相当高。

3.3 Claude Code 端:Skill 目录里最容易忽略的两个约定

Claude Code 端相对标准,每个技能放在.claude/skills/<技能ID>/SKILL.md。这份文件由两部分组成:YAML frontmatter 里的 name 和 description,以及正文里的指令、示例和验证清单。frontmatter 的 description 特别重要,因为它是技能路由的依据,模型就是靠它来决定当前任务要不要激活这个技能。

我写的一个典型 SKILL.md 长这样:

--- name: dep_upgrade description: 当用户要求升级项目依赖并做回归验证时使用。触发条件包括版本号变更、锁文件处理、依赖冲突解决。如果任务不涉及依赖版本变动,切勿使用此技能。 --- # 依赖升级与回归验证 ## 执行步骤 1. 读取依赖清单与锁定文件,标记直接依赖和传递依赖 2. 执行升级操作,记录升级前后版本差异 3. 运行全量测试,针对性补测升级包相关用例 4. 输出变更报告,标注兼容性风险 ## 验证清单 - [ ] 锁定文件与清单文件一致 - [ ] 全量测试通过 - [ ] 无未经确认的版本跳跃

有两个约定是最容易踩的。第一个是 description 里必须写"不触发条件",只写触发条件的话,代理会把很多相邻任务都路由进来。第二个是正文首行不要写"你是一个专家"这类废话,直接写执行的第一个动作,模型在激活技能后需要极快地进入干活状态,情绪铺垫没有任何价值。

3.4 装好之后的第一件事:写一个最小技能验证路由

接入完成的验证方式,不是直接拿真实项目试,而是先做一个一比一的最小案例。我当时的做法是建一个只有两个文件的小仓库,一个技能是"给函数补 JSDoc",另一个技能是"把函数改为 async"。然后给同一段代码发同一个需求,观察两个 CLI 是否正确只命中一个技能、是否输出了完整的五个阶段、是否在技能激活时读取了正确文档。

这个验证过程帮我提前发现了大量路由和提示词写法问题。如果你跳过了这一步,直接在大型仓库里用,出了问题很难分清是技能写得不对,还是仓库本身的复杂度干扰了代理的判断。

4. 完整走查:一次依赖升级需求是怎么被框架拆解执行的

4.1 REP 和 ANA:动手之前的两个刹车

拿一个真实场景走查一下。某仓库里某依赖版本落后,我向代理发出指令:"把某个工具库从 3.x 升到 4.x,跑一遍测试看看有没有破坏性变更。"

按框架要求,代理第一步先输出 REP。它会把需求重述为:需要修改依赖声明文件、锁定文件以及与之相关的引用代码,目标是测试通过且无隐藏破坏。REP 写的不是复述原话,而是把任务边界列清楚,比如"该需求不涉及更新其他无关依赖"。

第二步是 ANA,代理需要输出对任务类型的判断。它会把命中技能 dep_upgrade 的关键词列出来,同时说明为什么没有命中 test_gen 和 refactor_module。这一阶段看起来有点浪费,但我实测下来,它大幅减少了多技能指令打架的概率。没有 ANA 的时候,代理经常把测试生成技能里的"补测试"要求和依赖升级技能里的回归规则混在一起执行,最后产出一堆互相矛盾的改动。

4.2 PLAN 和 EXE:计划要细到能够自查,执行要严格限定范围

进入 PLAN 阶段后,代理会生成按依赖关系排序的执行计划,通常是三步:先升级声明文件里的版本号,再更新锁定文件,接着运行现有测试定位失效用例。这个计划的好处是,代理在 EXE 阶段不会想一出是一出。我设定过一个规则:如果 EXE 过程中发现实际改动和 PLAN 偏离超过一个文件,就必须停下来重写 PLAN。

EXE 阶段还有一条很重要的纪律,代理不能顺手修改与任务无关的代码。很多编码代理表现出色时会顺手做点"自认为应该"的重构,比如把某个旧 API 用法换掉,这往往是回归 bug 的温床。框架在 EXE 阶段加入了提示词约束,同时在钩子层检查了变更文件列表,避免越界修改。

4.3 VERIFY 阶段的闭环:允许自动回退,但必须有记录

VERIFY 阶段做的第一件事是全量测试。第二件事是对照技能文档里的验证清单逐项核验,比如锁定文件是否一致、是否存在未经确认的版本跳跃。第三件事是生成变更报告,把升级前后的版本差异和对测试的影响整理成可阅读的摘要。

这里我说一个实际经验:VERIFY 发现测试失败时,可以让代理尝试自行修复一到两次。v0.1.5 的做法是给代理授权一次回退,回退前必须保存当前改动为补丁文件,这样即使自动修复失败,人力介入时也有完整现场。多数依赖升级导致的测试失败,其实是某个 API 在新版本里改名或删除,代理有能力顺着编译错误找到新 API 并修复,但要给它一个明确的边界,防止它在修复中无限发散。

5. 实测翻车记录:六个最值得写的坑

5.1 技能描述写得太详细,路由准确率反而下降

这是我最开始犯的错。我以为 description 越详细,模型判断越准,于是把触发条件写了好几段,还带各种例子。结果代理在简单任务上频繁误触发,开始用升级依赖的思路去处理不相关的改动。

排查过程很有意思,我把同一个技能分别用"短描述"和"长描述"做了对照测试,短描述版本的路由准确率更高。后来我想明白了,技能路由本质上是模型在做语义匹配,描述太长会引入大量噪声,反而干扰匹配置信度。v0.1.5 的规则是:description 只保留核心触发词、明确的排除条件、一句话任务目标,详细步骤全部放在正文里。

5.2 五个阶段的输出要求,模型总在简单任务上跳过

框架搭好之后,我发现一个规律:复杂任务模型还会按阶段来,简单任务基本上一句话就带过了。刚开始我以为是提示词没生效,后来发现这是很多编码代理的自然倾向,任务越简单,它越觉得没必要走流程。

解决方式不是强行禁止跳过,而是把阶段输出格式设计成"压缩态",允许用极短标记表示。比如 REP 可以压缩成"REP: 升级工具库依赖并验证兼容性",ANA 可以压缩成"ANA: dep_upgrade"。对简单任务,整个框架加速变成了三行文本;对复杂任务,模型会自然展开成多行。这种弹性设计比强制输出要好,因为强制格式只会让代理产生一堆敷衍的空话。

5.3 同一个技能在两个 CLI 里的表现不一致

Codex 端和 Claude Code 端用的是同一份技能规格同步生成的文件,但实测发现,某些技能在 Codex 里执行正常,在 Claude Code 里却总是少了验证步骤。后来定位到问题根源:两边的知识库对技能文档的主次顺序理解不同。Claude Code 端会优先看 SKILL.md 的 frontmatter 和后文结构,Codex 端则更看重文档开头两段。

修复方案是让同步生成器针对两个 CLI 调整了文档排版权重,把执行指令在不同位置的强调程度做了差分处理。这算是一个平台差异的隐性坑,如果你自己搭了同步层,一定要为每个 CLI 单独做一轮文档结构适配。

5.4 上框架之后上下文开销不降反升,问题出在日志钩子

我最初把执行钩子的日志设计得特别详尽,每个阶段都记录长文本,还要求代理在阶段切换时输出一些"思考过程"。结果这些日志和思考过程全部占用了上下文窗口,一个中型任务还没做完,上下文就已经过半了,代理的行为开始明显退化。

后来我把日志内容做了两级降级:内部强制记录改成仅记录标记行,详细内容写入外部日志文件;阶段思考过程的详细度从默认完整缩减为默认两行,只有复杂任务才允许展开。这个改动之后,上下文开销才真正降到比无框架时代更低。记住一个原则:框架的价值在于帮助代理少走弯路,而不是制造额外的上下文负担。

5.5 技能之间的依赖链,处理不好就会互相污染

v0.1.5 里有相当一部分任务是组合型的,比如"先重构模块,再补测试"。独立跑这两个技能都没问题,串行执行时就会出现指令重叠的冲突,代理会同时遵守重构技能里的代码风格约束和测试技能里的用例命名规则,反而两边都不彻底。

我的处理方式是给每个技能声明"前置技能"和"后置技能",并且在编排层增加一条规则:当前一个阶段命中了两个技能时,PLAN 必须明确划分它们的作用范围和交接条件。目前这套机制只处理了一层的链式依赖,递归依赖设计得还不够好,这也是我准备在下个版本重点优化的方向。

5.6 代理反过来修改技能文件,需要设一道安全边界

这个问题很有意思。框架跑得越久,代理对技能文件的熟悉度越高,于是有几次它在处理任务时,顺手把技能文档里的步骤改成了它"认为更好"的版本。从内容上说不一定是坏事,但在没有评审的情况下,技能文件被模型擅自改动,整个工作流的稳定性就无法保证了。

我在同步脚本里加了一步校验:把技能文件视为只读资产,执行前对比哈希值,检测到改动就提示冲突,并回退所有改动。真正想迭代技能的开发者,不应该依靠模型在任务执行中偷偷改配置,而应该回到 yaml 源文件显式调整,再跑同步脚本生成所有端。把变更流程收拢到单一入口,是维护这类基础设施的一个重要原则。

6. 什么场景值得上这套框架,以及后续迭代的方向

6.1 适合与不适合的画像

经过这段时间的实测,我对这套框架的适用边界有了比较明确的判断。它适合的是需要稳定复现、多步骤、涉及验证的工程任务,包括依赖升级、模块重构、批量调整代码风格、生成和补齐测试等。它也适合那些需要多个编码代理协作的场景,至少代理之间能共享同一套任务拆解语言,不至于各想各的。

它不适合的场景也很明确:零散的问答、一次性小改动、原型验证和探索式编程。在这些场景里,框架的强制结构会让代理显得笨重,而且容易扼杀那种发散式的探索过程。我自己的策略是维护两套配置,默认轻量模式不带推理框架,接到复杂任务时再显式激活技能集。这种模式切换的配置字段,也是 v0.1.5 在双端都保留的。

6.2 v0.2 的三个准备方向:路由指标、技能注册表、评审链路

下一步迭代我主要想解决三个问题。第一个是给技能路由加一个可观测层,把每次任务的命中技能、最终是否成功、上下文开销记录下来,用真实数据来调整技能 description 和触发条件。目前很多调整还是靠感觉,我不太满意。第二个是设计一个技能注册表的入口,让同一个技能可以带版本号同时存在,切换版本时能对比行为差异。第三个是技能变更的评审链路,在源文件变更后生成 diff,并附带一次评审测试,只有通过才更新到双端。

如果你在我这种工作流里投入很多,我个人觉得这三块会是下一个阶段的标配。技能资产不该是一堆一次性提示词,而应该像代码一样有版本、有测试、有可追溯的变更记录。这套思路说穿了不复杂,难的是在每个小细节上坚持做结构化,把它做成基础设施而不是临时拼接的脚本。

最后分享一个我现在还在用的习惯:每加入一个新技能,我都会强迫自己先用最小案例跑通双端,再放进真实仓库。这个习惯看着慢,实际上它帮我省掉的返工时间远远超过那几分钟。如果你也想复刻整套框架,不妨从一两个最常做的任务类型开始,跑通路由和双端接入,再逐步扩充技能目录。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询