SKILL编排:用AI对存量代码做微创手术,告别散装AI

发布时间:2026/9/26 6:55:20
SKILL编排:用AI对存量代码做微创手术,告别散装AI 先聊聊我这大半年的真实感受AI 写代码早就不新鲜了但很多人包括我自己一直处在一种“散装 AI”的状态里。今天从 GitHub Copilot 聊到 Cursor明天在 Continue 里接一个模型后天又把 Dify 的编排 API 硬塞进工作流看起来什么都会一点实际上每个场景都在重复造轮子提示词散落在对话历史里、Skill 和脚本分不清、存量代码不敢让 AI 动越用越像“缝合怪”。直到最近我把重心从“让 AI 写新代码”转向“用 SKILL 编排对存量代码做微创手术”整个效率才真正发生了质变。这篇文章不是什么平台推广纯粹是我自己在一堆老项目里摸爬滚打总结的实操记录。如果你也经常面对那些跑了几年的旧系统、被各种历史原因搞得很“脆”的代码库又不想推倒重来那你很适合往下看。我会从“为什么散装 AI 会失效”讲起再到 SKILL 怎么设计、怎么选型、怎么写最后给出一套能在本地仓库直接跑起来的“体检—诊断—干预—复检”闭环以及在过程中踩过的大坑和对应的解法。1. 为什么你的 AI 编程总在“散装”1.1 散装 AI 的三个典型症状第一个症状是提示词碎片化。我见过很多朋友的 IDE 里存了几十段“万能 Prompt”今天让 AI 补日志明天让 AI 修边界后天让 AI 做单元测试每段提示词都是独立存在的。表面上看很方便但一旦项目换人、换模型或者换工具这些提示词根本无法复用因为缺少结构化参数和校验逻辑。你会不停地修改措辞、调整温度、重新解释上下文和“散装”没有任何区别。第二个症状是工具各自为政。Copilot 续写是一套体系Cursor 的 Agent 是另一套Continue 可以接各种模型但缺少任务编排Dify 的 workflow 更适合业务应用而不是代码仓库内的精细化改造。于是代码生成的归代码生成、代码审查的归审查、重构的归重构中间没有一条管道把它们串起来AI 的每一步都像是独立作战。第三个症状是知识无法沉淀。你花了两个晚上总结的“如何安全地在老项目中加链路追踪”的经验最后就存在某一次对话记录里。换个项目、换台电脑、换个人又要从头开始。团队里的同事遇到同样问题也只能去翻聊天记录而不是打开一个标准的、写清楚输入输出和校验规则的 Skill 包直接调用。这三个症状叠加起来的后果就是“AI 很强但我用起来总觉得别扭”。你让 AI 改一段存量代码它经常改动超出预期甚至不小心改了方法名、删了边界条件最后还得靠 git diff 手动修比你直接上手改还慢。1.2 从“推倒重写”转向“微创手术”很多人对 AI 重构的理解还停留在“整个模块扔给它重写”。但存量代码最怕的就是大动干戈。一个跑了五年的订单模块背后的状态流转可能隐藏在十几个 if 分支里全局搜索都搜不全。模型看到的是一个局部快照它根本没能力理解所有调用方和隐式约束贸然重写就是灾难。这就是“微创手术”思路的价值不追求大而全的重构而是锁定明确病灶用一套标准话术、标准动作、标准验收标准去处理和替换改动面被控制在最小范围。就像外科手术不是开胸换心而是通过一个小切口精准清理病变组织。放到代码上就是每次干预之前先做一次体检明确要动哪个文件、哪个函数、哪个分支干预过程中严格执行参数约束干预之后必须过编译、跑单测、看 diff。这也是我需要 SKILL 编排的根本原因。单独一段 Prompt 能告诉你“去改什么”但 SKILL 能把“怎么改、改到什么程度、改完之后怎么验证”固化成一等公民再配合 workflow 让它按顺序执行形成一个闭环。1.3 SKILL 与普通 Prompt、Agent 框架的差别在哪里先说清楚概念。普通 Prompt 是“一次性指令”它解决的是“这次让 AI 干什么”。Agent 框架解决的是“AI 怎么自主完成任务、怎么调用工具、怎么规划步骤”。而 SKILL 是“可复用的专业能力包”它介于两者之间既有结构化的说明和示例又有可被编排系统调用的元数据在 AI 需要执行特定任务时被按需加载。举个例子你写一个 Prompt“帮我看一下这段代码有什么循环依赖。” 这是临时话术。但你把它做成一个 Skill在SKILL.md的 frontmatter 里定义name: dependency-check再在正文里写清楚检测范围、检测方法、输出格式、建议修复的边界条件那么任何支持 Skill 的客户端都能稳定复用。这就是为什么社区里关于 “skill 和 agent 的区别”“skill 插件”“codex skill”“opencode skill” 的讨论越来越热。因为大家都意识到单个 Agent 不够可靠真正可靠的是一整套能被反复调用的技能库。所以我的判断是未来 AI 编程的核心竞争力归根结底是看谁能沉淀出高质量的、贴合自己代码库的 SKILL并以 workflow 的方式编排起来。这不是追热点是实打实解决“散装 AI”痛点的路径。2. 开工之前工具选型与 SKILL 格式设计2.1 工具链怎么选别让一堆 Agent 直接碰你的代码这两年“多智能体编排”“agent框架与编排”“deepseek harness 多个智能体”这类关键词非常火很多人一上来就搭了一套多 Agent 系统让 Agent 去动态决策。但在存量代码这件事上我强烈建议你是先用一套能静态定义的流程而不是一上来就让多个 Agent 自主决策。为什么因为多 Agent 的主动性和不可预测性在老旧代码库上是致命的。你可能给了它“检查模块 A 和模块 B 的边界”的任务它在执行中突然觉得“模块 C 的功能可以合并”顺手就给你改了一大片。这对新项目没问题但存量代码承受不起。我在实际项目中更推荐分层的组合底层用像 Claude、Codex 或本地部署模型作为推理引擎中间用支持 Skill 机制的 IDE 插件或 Continue 这类工具作为上下文窗口最后再用一个轻量的 workflow 编排层负责定义任务顺序。Dify 的编排能力可以让非技术人员更容易上手但如果你处理的完全是代码仓库我更倾向于直接用支持 YAML、JSON 描述的本地编排脚本。不需要特别复杂只要你能够定义“先分析、再修改、再编译、再回归”这几个不可跳过的步骤就行。注意无论你选什么工具都一定要问问自己——它能否支持独立的 SKILL 定义、能否拿到 git diff、能否在修改前做预览能否控制 Agent 的行动边界。如果这几个答案是否那它就只适合做纯生成不适合做存量代码干预。2.2 一个合格的 SKILL 长什么样我会参考当前比较成熟的 Agent Skills 方式实现结构通常是一个目录里面放着SKILL.md和若干辅助文件。SKILL.md的头部必须有 YAML frontmatter声明name和description正文则用清晰的 Markdown 结构来告诉模型“什么时候用、输入是什么、输出是什么、应该怎么做、不该做什么”。下面是我自己一直在用的一个模板你可以直接抄--- name: code-surgery-guard description: 用于对存量代码进行最小化、可回滚的定向修改适用于需要精准干预已有逻辑的场景。使用时必须先生成 diff 预览并通过编译和测试。 --- # 角色与目标 你是一位熟悉存量代码维护的工程师。你的目标是完成对指定文件/函数的定向修改不做任何与任务无关的改动。 # 输入参数 - file: 要修改的文件相对路径 - target: 要修改的函数或代码块的精确标识 - issue: 发现的问题/需要修复的目标 - constraints: 额外的约束条件 # 操作步骤 1. 读取目标文件定位 target。 2. 梳理 target 的调用方和依赖关系。 3. 生成修改方案必须包含最小 diff 原则。 4. 修改并确保不删除与目标无关的分支/注释。 5. 展示 diff 摘要等待人工确认。 # 禁止事项 - 不要修改与 target 无关的代码。 - 不要重命名公开函数/接口。 - 不要“顺手”格式化整个文件。 # 输出格式 输出应包含修改摘要、diff 统计、风险点、建议的人工检查点。这里最关键的是最后两条禁止事项和输出格式。AI 模型天然会在指令模糊时发挥“创意”你必须在 SKILL 里明确写出边界。经验是凡是能踩的坑模型都一定会踩凡是你没写清楚的地方模型都会自由发挥。2.3 编写 SKILL 的三个核心设计原则第一个原则是单一职责。一个 SKILL 只做一件事。不要写一个“大而全”的代码助手而是拆成“补日志”、“查死代码”、“查循环依赖”、“修事务边界”等一个个细颗粒度的工具。这样更容易被 workflow 调度也更容易测试和迭代。第二个原则是显式边界。每个 SKILL 都要在 description 里写清楚“什么时候不该用”。比如“死代码检测”这个 Skill在当前的动态语言项目里可能不适用那就要明确写出来。显式边界能防止模型在不合适的场景被错误调用也能帮助人快速判断是否使用这个技能。第三个原则是可回滚。SKILL 的设计必须考虑失败场景。我通常会在 SKILL 的正文里要求模型在操作前先创建分支或快照并且生成一个可一键回滚的方案。你可以给每个 SKILL 的输出格式定义里增加一个rollback字段让模型给出如何恢复到原始状态的命令。这对存量代码来说不是可有可无而是保命符。3. 真正的“手术刀”我常用的五个存量代码 SKILL3.1 定向补日志不要再全局扫一遍再手写在存量系统里排查问题最常见的需求是补日志。但补日志最大的坑是你让 AI 加日志它可能会给全项目几十个文件都加上美其名曰“统一监控”实际上制造了一场日志洪水。这时候我定义了一个专门处理日志补点的 Skill。它的逻辑很清晰只读取你传入的文件和函数只分析该函数的入口、出口和关键分支而生成结构化的日志。参数有三个file、function、log_level。默认log_level是INFO但输出要求里会强制限定日志字段trace_id、action、cost_ms。这样生成的日志不仅对当前排查有用还能为后续的链路追踪打基础。SKILL 片段里有一个步骤很关键“在修改前先输出一个当前函数控制流摘要”。这一步是为了让模型先真正理解这段代码的逻辑分支而不是凭感觉到处插桩。实测下来这个前置摘要能显著减少“日志打错分支”的低级错误。3.2 死代码体检不急于删除先标记再处理死代码是存量代码里最常见、也最危险的处理对象。危险在于你以为是死代码的可能只是在某个特殊条件下才会被触发的“定时炸弹”。所以我的“死代码体检” Skill 不是直接删除而是先输出体检报告。Skill 会扫描指定目录下无引用的函数、未使用的方法、冗余的 import但生成的所有发现都会写成三类safe_delete、needs_review、do_not_touch。能进入safe_delete的必须同时满足“无任何引用、无反射调用、无动态 import、近一年无修改”四个条件。然后它还会生成一个带标记的补丁在删除前先把被删代码放到一个注释块里保留一个开关比如# DEAD_CODE_DISABLED。这个设计看起来总显得保守但非常实用。因为在存量系统里动态调用、配置模板注入、反射工厂这些机制常常会让静态分析失效。快速删除一时爽线上出问题就是火葬场。有了这个 SKILL我可以让 AI 批量整理出一份候选清单再由人工做最后的“死刑”确认。3.3 循环依赖与坏味道检测把小手术做大手术之前的地图老项目在模块之间形成循环依赖通常发生在你没有足够时间做整体重构的阶段。循环依赖不解决你后续的叠加功能很容易踩雷。这个 Skill 的核心不是提供一次性解决方案而是提供一份精确的“依赖地图”。它会解析指定目录下的 import 关系生成模块之间的依赖图并且把其中的循环依赖标成红色节点。注意我这里不会让流程图自动出现而是要求输出成文本形式的清单比如moduleA - moduleB - moduleC - moduleA同时让模型标注每个循环可能造成的具体风险等级。有了这个清单你就可以决定哪些循环可以暂时容忍哪些必须在本次改动中解决哪些需要单独立项。这相当于给你了一张作战地图避免你在手术过程中遇到意外的大出血。3.4 事务边界与异常处理补强专门对付最难捉的 bug存量代码中性能问题往往好查但那些“偶发数据不一致”、“部分成功但报错”的问题最难查根源大多在事务边界和异常处理上。比如在一个方法内部开了事务却悄悄 catch 住了异常导致事务没有回滚或者在循环中多次提交事务导致性能刺头。这类问题靠肉眼 review 很费劲让 AI 直接改又怕它改错。所以我的“事务边界补强” Skill 定义了一套严格的任务流程第一步先输出当前方法的事务调用链第二步是标记所有catch和commit/rollback的位置第三步是在不建议完全重构的前提下通过补充异常判断条件来让事务在异常的时走正确的回滚路径。它也会在输出里要求模型明确标注“本次修改后的数据一致性假设”这个假设是审核的重点。从实际效果看这类 Skill 不适合批量跑更适合在遇到一个具体 bug 时单独执行。它是那种“一次只处理一个病灶”的典型代表但效果极其明显。3.5 命名与可读性规范化批量修复但别破坏外部契约存量代码里最常见的难堪是命名混乱比如data1、tmp2、doThing满天飞。用 AI 做重命名看起来很简单其实风险极大尤其是当某些方法名暴露给外部系统或被序列化框架反射调用时改一个名字就可能搞挂一个线上接口。我的做法是把这个 Skill 做成“契约感知型”重命名。它扫描时需要读取接口定义、序列化注解、配置文件中的引用。输出的修改建议里会区分三种情况确实可以内部重命名、可以重命名但需要同步调用方、不能重命名外部契约。同时执行时默认不做跨文件批量替换而是对每个引用点生成逐条建议。这套流程虽然慢一点但完全杜绝了“改个名字改崩一片”的惨案。4. 从单个 SKILL 到编排闭环一次真实的“组合拳”4.1 编排闭环的四个固定阶段单个 SKILL 是手术刀编排才是完整的手术流程。我把每次对存量代码的干预都固定在四个阶段里体检、诊断、干预、复检。在体检阶段我用“循环依赖检测”和“死代码体检”这类 SKILL 生成报告在诊断阶段我通过阅读报告和问题描述确定具体修哪个点在干预阶段我才调用像“事务边界补强”或“定向补日志”这类精准修改的 SKILL并强制生成 diff在复检阶段我会跑编译、跑核心测试、查看 git diff确认没有超出预期。这四个阶段不只是一种意识而是真的把它们写进一个 workflow 编排文件里让顺序固定下来任何一步或缺失这个流程就自动终止任务。在做大型改动的时候这种“仪式感”会非常蠢地救你的命。4.2 用轻量编排文件描述完整流程我没有用重型工作流引擎而是用一个简单的 YAML 文件描述任务序列。它的结构大致是pipeline: legacy-code-surgery steps: - name: precheck-dependency skill: dependency-check params: scope: src/module_a - name: precheck-deadcode skill: dead-code-scan params: scope: src/module_a - name: human-review-report action: require_input hint: 请检查前两步的报告确认需要修复的 target 列表 - name: apply-fix-transaction skill: transaction-boundary-fix params: file: src/module_a/OrderService.java target: createOrder - name: run-compile-and-unit-test action: execute command: mvn test -pl module_a - name: show-final-diff action: git_diff你会发现我把每个 skill 都对应到一两个步骤中间有一个人工确认节点。这是最重要的一步。在所有关键变更执行前流程都要强制暂停等人确认。几乎每一次预演测试我发现都会在这个节点拦截到 AI 想“顺手”做的额外改动。4.3 本地小型仓库的实战记录为了给你一个直观感受我随便找了一个被接手过很多次的小型 Java 仓库做测试。项目有 3 个模块代码大概 2 万行存在明显的循环依赖和几个异常处理缺口。我先跑了 dependency-check输出结果说module_a和module_c之间存在一个循环依赖而具体链条绕过了消息队列中间层。然后又跑了死代码扫描发现了几个无引用的工具函数。按以前的做法我可能直接就开干、清理掉那些“死代码”然后再尝试解循环依赖。这次不一样。我按流程先人工看报告确定真正要紧的是module_a中的createOrder方法存在事务未回滚风险紧接着调用交易边界的 SKILL。模型给出的 diff 只有 4 处修改每一处都符合预期。最后跑mvn test一次通过。整个过程中我几乎没有和 AI 进行过任何一次“对话式”交流所有输入都通过参数文件传递所有输出都有既定格式。这就是编排的意义把依赖随机生成的对话变成可追踪、可回滚的流水线。4.4 什么时候不该上编排我想特别说明不是所有场景都值得走完整套编排。如果你只是给临时脚本加个打印、或者新建一个小的独立工具函数那直接用最简单的对话式 AI 就好流程反而会成为你浪费时间的作秀。编排的高价值场景有三个共同特征改动会被长期保留、代码有横切依赖、失败会造成较大影响。存量代码的修复大概率都满足这三个特征。但如果你是做一个新的 demo完全不涉及存量逻辑那就别折腾了直接写、快速出结果才是真正的效率。5. 常见问题与避坑技巧实录5.1 常见问题速查表先收藏再用症状可能原因解决办法SKILL 经常被忽略模型私自改代码SKILL 的 description 写得太泛模型不知道何时启用在 description 中写明使用场景和禁止场景把关键词前置改动范围总超预期缺少“操作边界”约束在 SKILL 正文强制加入“禁止修改与任务无关代码”的规则编排流程中留人工确认节点生成代码编译不过上下文窗口没有包含足够的依赖定义在 SKILL 的操作步骤中强制要求先读取相关依赖或编译错误信息死代码扫描误报动态反射、配置注入无法被静态分析识别采用“标记人工确认”策略不直接输出删除建议编排流程无法回滚没有在变更前创建分支或快照在 workflow 的开始阶段增加create_branch或git_snapshot步骤换了模型后效果明显变差不同模型对指令格式要求存在差异将指令细节写入 SKILL并在说明中给出正反例5.2 独家避坑做手术之前先治病我在实际执行中最大的收获是不要动不动就让 AI 做修改先让它做“体检”生成一份问题清单。很多问题的“解决方案”其实并不是当前最重要的真正重要的是把报告排个优先级。举一个例子。有一次我发现支付模块有循环依赖直接就想去解耦但通过依赖检测报告发现循环依赖的源头竟然有一个无用的历史中间层。如果我们不先清理那个死代码直接解耦会花费多好几倍的时间。所以现在的标准流程是先扫描、再排序、再决定做哪一台手术。这相当于先看化验结果再决定治疗方案而不是一进医院就开刀。另外一个经验是你必须在 SKILL 里用“做不出风险等级的结论就不准输出”来约束模型。否则模型只会给你列一堆代码片段让你自己去找重点。做了这个约束之后它每一条发现都会标注优先级、影响范围和修改建议实用性立刻提升了一个档次。5.3 团队如何沉淀、共享、迭代 SKILL一个人用 SKILL 能提升效率一个团队沉淀 SKILL 才是真正的资产。我的做法是在仓库里单独建一个skills/目录每个目录就是一个 SKILL命名规则是领域-动作-对象例如log-append-function、refactor-transaction-boundary。每次修改完存量代码如果发现某个 SKILL 的边界不够清晰就立即更新它的文档和示例。团队里新人上手时不直接看代码先看skills/README.md了解哪些能力包是可用的。当遇到新问题还没有对应的 SKILL 时我们可以先写一个临时 Prompt 解决然后在一周内把它正式化为 SKILL。这是沉淀和迭代的正循环。这里有一个小技巧SKILL 目录里最好附带examples/子目录里面存放“良好输出”和“错误输出”的案例。这对模型校准非常有用也是比满篇幅规则更能提升准确率的手段。我试过很几次看看给模型一张“好学生作答卷”和一张“坏学生作答卷”之间的差别后者能有效拉高模型输出的稳定度。我还建议团队用 git 管理 SKILL每次版本迭代都标准化地记录变更原因。不是为了让项目显得高大上而是因为你在一个模型上调通的 SKILL换一个模型可能就得重新校准。有了历史版本你可以快速回溯是哪条规则造成了退化。写在最后的一些体会做了一段时间之后我最大的感受是真正能加速存量代码改造的不是某个更聪明的大模型而是一套能限制它发挥“创造力”的机制。我反复地和大家说“做标记、做确认、做回滚”不是因为我保守而是因为我在实际项目中损失过太多次。把 AI 当做一个极其聪明但有点莽撞的实习生来看待你才会认真给它写工作手册——而 SKILL 就是工作手册编排就是工作流程。如果你现在还在被“散装 AI”折磨我给你的建议是不要急着搭建复杂的多 Agent 框架先挑一个你每天都在做的小任务把它写成 SKILL。比如就从“定向补日志”开始。把它放进你现在的 IDE 插件里体验一下“参数化、标准化、可复用”到底意味着什么。然后再加上 30 秒能看完的 diff 预览再配上编译和测试你就会明白我说的“微创手术”到底有多省心。最后再分享一个小细节我所有 SKILL 的 description 里都一定会写一行“停止条件”。比如日志补点会写“当函数内已有超过 3 个日志点时不再继续添加”死代码扫描会写“当发现候选死代码代码量超过 50 行时停止输出建议”。别小看这一行它极大地保护了我避免被 AI 的“过度服务”淹没。希望这些经验能让你少走点弯路更好掌控自己的存量代码。