news 2026/10/17 1:39:31

存量代码微创手术:SKILL编排驱动AI辅助重构实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
存量代码微创手术:SKILL编排驱动AI辅助重构实战

你身边有没有这种情况:AI工具装了一堆,网页版对话、IDE插件、命令行工具、本地大模型,各管各的,真到要对存量代码动手的时候,却帮不上忙——要么答非所问,要么改完的代码不敢合入,要么关键模块一碰就崩。

这套“什么都会但什么都不精”的用法,就是“散装 AI”。它的问题不在模型能力,而在组织方式:没有统一的技能封装,没有流程编排,每个AI都在单打独斗。这篇想聊的,是我最近一直实践的一种思路——用 SKILL 对存量代码做“微创手术”。把AI能力拆装成一个个可复用的技能单元,再用 workflow 编排成一套完整的手术方案,让每个改动都足够小、足够可验证。适合正在维护老项目的技术团队,也适合一个人扛一条业务线的全栈开发者。

1. 存量代码为什么需要“微创手术”,而不是重写

1.1 存量代码的真实困境

我在不少项目里见过同一种病灶:一个核心函数七八百行,嵌套四五层 if-else,全局变量到处共享,文档约等于零。写这个模块的人可能早就离职了,新接手的人全靠 Ctrl+F 猜逻辑。业务方还在不停提需求,没人敢动这块代码,因为一改就炸。

这种代码叫存量代码。它最大的特点不是“写得很烂”,而是“价值很高但状态很脆弱”。它承载着线上真实业务,出过一次事故就够团队紧张一阵。直接重写?成本太高。业务不等人,需求还在排期,重构窗口通常只有一两周。而且重写风险极大,旧逻辑里的边界条件、隐式依赖、异常分支,很多已经没人说得清了。

这时候真正需要的是“微创手术”:在不改变系统整体结构的前提下,选定一个最小切口,把最危险的那段逻辑拆出来、理顺、替换掉。目标不是“代码变漂亮”,而是“行为不变,结构变安全”。

1.2 “散装 AI”的三次翻车现场

我最早尝试用常规AI对话去处理这种存量改造,失败过很多次,现在回头看,问题非常清楚。

第一次翻车,是让AI帮忙梳理一个支付回调函数的调用链。我贴进去代码片段,AI分析得头头是道,但追问两句就露馅了——它只看到了我贴的那一段,根本不知道别的文件里还有谁在调这个函数。上下文窗口有限,隐式依赖它看不见,最后给出来的影响面报告,我核对完发现漏了整整两个上游调用方。

第二次,是让AI重构一个函数的内部逻辑。它确实改出来了,但把整个函数从头到尾重写了一遍,风格完全变了,连变量命名习惯都换了。diff一出来几百行,我根本没法评审。业务逻辑倒是“等价”的,可这种改动谁敢合进去?

第三次更离谱,AI建议我引用一个工具类,说“项目里已经有了”。实际一查,那个工具类只在某个测试环境的分支里存在。这个错误如果没发现,上线必炸。

这些翻车有个共性:单次对话型AI只适合处理“局部、单文件、一次性”的问题。存量改造是“跨文件、多步骤、需要验证”的复杂工程,散装AI根本接不住。

1.3 “微创手术”的完整解题思路

后来我转变了思路,不再指望一个AI会话搞定一切,而是做三件事:

第一,把AI能力封装成 SKILL。一个SKILL就是一个“工种说明书”,比如“函数影响面分析”“代码安全抽离”“新旧逻辑对比”。每个SKILL只做一件事,输出格式固定,完成标准明确。

第二,用 workflow 把SKILL串起来。就像手术室里有主刀、有麻醉、有器械护士,各有分工,按流程推进。一个SKILL输出结果,交给下一个SKILL作为输入,中间设置人工确认节点,关键步骤停下来复核。

第三,严格控制每次改动的“切口”大小。一次PR只允许改一个文件、几百行以内,所有相关改动必须能在十分钟内评审完。方法论上就是:先切小口,再上夹子,最后缝合,每一步都能回退。

这套思路的核心是:不让AI“决定”系统走向,而是让AI“执行”你设定好的路径。你定方案,AI出力气。

2. SKILL:把 AI 从“临时工”变成“专科医生”

2.1 到底什么是 SKILL

简单说,SKILL就是给大模型写的一份“工种说明书”。它告诉模型:你是什么角色、在什么情况下触发、按什么步骤执行、输出什么格式、做到什么程度算合格。

SKILL、Agent、Workflow,这三个词经常混着出现,我用自己的理解区分一下:

概念类比核心特点典型用法
SKILL专科医生单一能力,输入输出明确,可复用函数影响面分析、代码抽取、trace对比
Workflow手术流程表定义步骤、节点、分支、人工确认点存量改造流程、发布流程、审查流程
Agent带目标的执行团队有自主规划能力,能调SKILL,按目标决策自动修复任务、长链路分析任务

实际使用中三者常常嵌套:Agent负责理解目标,Workflow负责流程控制,SKILL负责具体执行。你做存量改造,核心单位其实是 SKILL + 人工确认点,Agent反而是可选项。

2.2 一个 SKILL 的四个核心组成部分

我写过十几个SKILL,踩过不少坑之后总结出来,一份优秀的SKILL定义至少包含五个字段:

  • name:技能名,简短,其他流程调用时靠它定位
  • description:什么时候用这个SKILL,写清楚触发边界,避免“万金油”
  • steps:给模型的执行步骤,必须具体可操作
  • done criteria:完成标准,没有这一项,AI会给你一堆“我觉得差不多了”的结论
  • output:输出格式,报告型输出最好固定模板

新手最容易犯的错误,是description写得太泛,比如“分析代码”。这句话等于没说。AI触发之后不知道该往哪使劲。我后来改成“当用户要求评估某个函数的改造影响时,触发本SKILL,输出调用图、风险点和推荐切口”,效果立刻不一样。原因很简单:模型在模糊指令下会主动“发挥”,而你根本不需要它发挥,只需要它执行。

2.3 一个最小可用的 SKILL 示例

下面是我最常用的“函数影响面分析”SKILL,你可以直接拿去改。我用的是 YAML 格式,大部分支持SKILL的工具都能兼容。

name: skill-fn-impact-analysis description: > 当用户需要对存量代码中的某个函数做改造前评估时,触发本技能。 适用范围:重构、接口拆分、逻辑迁移前的调用链分析。 triggers: - 包含“影响面”“调用链”“能不能改”“分析这个函数”等意图 - 输入内容包含函数名或文件路径 steps: 1. 定位目标函数所在的文件,解析文件AST 2. 生成目标函数的函数调用图(正向:它调用了谁;反向:谁调用了它) 3. 标记外部依赖(数据库、MQ、Redis、第三方接口) 4. 按影响程度输出改造风险等级:高/中/低 5. 推荐最小改造切口和需要人工复核的点 done_criteria: - 已输出调用图 - 已输出风险等级列表 - 已列出至少3个需要人工复核的关注点 output: | ## 影响面报告 ### 函数调用图 ... ### 风险等级列表 - [高/中/低] 风险项描述 ### 推荐改造切口 ...

看到这个结构你可能已经发现,它和普通prompt最大的区别是多了“输出格式”和“完成标准”。有了这两项,AI就不会给你一个开放性答案,而是交一份格式固定、便于人工复核的报告。生产环境里,这份报告可以直接进文档系统存档。

2.4 把 SKILL 变成团队资产

现在很多开源工具链里都有人分享现成的SKILL仓库,比如针对前后端重构、代码扫描、测试生成的技能包。你可以直接拿过来改,不需要从零发明。但我有两点建议。

不要直接照抄。别人写的SKILL,触发条件和输出格式都是按他的项目来的。你抄过来,先检查description里有没有“针对XX框架”“适用于XX场景”等限定词,不符合你们项目现状就改掉。

SKILL需要定期维护。代码规范变了、技术栈升级了、工具链换了,SKILL里的步骤也得跟着改。我每个季度会把高频使用的SKILL过一遍,像维护测试用例一样维护SKILL。这样才能保证AI“医生”手里的手术手册,永远和真实手术室一致。

3. 编排:让多个SKILL有条不紊地对存量代码下手

3.1 编排的核心:一次大改造拆成多个“小手术”

SKILL解决的是“单个动作”的问题,但存量改造从来不是单动作,而是完整流程:评估影响面 → 抽离逻辑 → 双写对比 → 人工确认 → 切换主逻辑 → 清理旧代码。每个环节都必须有序执行,前一步的输出是后一步的输入。

我习惯把这个流程画成一张编排图,但不是在白板上画完就完,而是把它落成一份机器可执行的 workflow。选型上我通常用 JSON 或 YAML 格式的编排描述文件,里面定义每个节点的类型、依赖关系、输入输出和人工确认要求。

3.2 实战编排:旧模块微服务化改造的workflow样例

下面是我在做一个远古支付模块改造时实际用过的编排结构,做了隐私处理,但流程是完整的。

{ "workflow": "legacy_payment_refactor", "nodes": [ { "id": "n1", "skill": "skill-fn-impact-analysis", "input": {"target": "PaymentService.confirm()", "source": "src/payment/PaymentService.java"}, "next": ["n2"] }, { "id": "n2", "type": "human_confirm", "purpose": "确认影响面分析结果,核对调用图是否遗漏上游依赖", "next": ["n3"] }, { "id": "n3", "skill": "skill-code-extraction", "input": {"source": "src/payment/PaymentService.java", "extract_target": "channel_dispatcher"}, "next": ["n4"] }, { "id": "n4", "skill": "skill-dual-run-compare", "input": {"legacy": "PaymentService.confirm()", "refactored": "PaymentDispatcher.dispatch()"}, "next": ["n5"] }, { "id": "n5", "type": "human_confirm", "purpose": "对比双写日志,确认新旧逻辑在真实流量下行为一致", "next": ["n6"] }, { "id": "n6", "skill": "skill-cutover-and-cleanup", "input": {"switch": "PaymentService.confirm()", "retain_rollback": "true"}, "next": [] } ] }

这个workflow跑起来大概是这样的。

n1节点先执行影响面分析SKILL,产出调用图和风险清单。完成后,流程停在n2人工确认节点——不是自动往下冲,必须由人点了“确认无误”,才进入n3抽离逻辑。

n3抽离完成之后不会立刻切流量,而是进入n4双写对比。新旧逻辑同时跑,把所有不一致的日志记下来。n5又是人工确认,等确认一致了,n6才做最终切换,并且保留回滚开关。

这套流程最核心的设计是两道人工确认节点。为什么必须停?因为存量改造最大的风险不是“AI改错了”,而是“AI没改错但你不知道它改没改错”。机器自己写的代码,必须有真实流量验证,而这个验证结果必须由懂得业务的人来看。

3.3 人工确认点怎么设计

人工确认点不是越多越好,每停一次,改造周期就拉长一天。我目前习惯只设两三个关键卡点。

第一,影响面确认。AI说“这个函数只有3个调用方”,你得核实一下。环节出错了后面全错。

第二,双写对比确认。这是最重要的一道卡口。新旧逻辑跑了几天,不一致日志有没有收敛到零,必须人眼看过。

第三,切换后的监控确认。上线后观察一段时间,确认无异常才能清理旧代码。有些关键模块我甚至要求保留旧逻辑一个月再删。

人工确认节点上,我会额外加两个字段:expected_output(期望看到的结果),rollback_action(确认失败时如何回退)。比如n2节点,期望看到的是“调用图无遗漏、风险清单完整”,只要有一条不满足,流程直接打回n1重新分析。

3.4 怎么判断手术是否成功

编排最后需不需要有验收标准?太需要了。没有验收标准的手术,切完之后没法缝合。我关心四个指标:

  • 行为一致性指标:双写对比期间,新旧逻辑输出不一致的次数,必须为0
  • 性能指标:改造后P50/P99延迟不劣化,甚至更好
  • 回归测试通过率:全量回归测试通过率100%,不允许红改绿
  • 单Pr体量控制:每次合入的diff控制在300行以内,超过就拆

这四个指标备齐,才算一个合格的“微创手术”。在编排文件里,我会用metadata字段记录这些指标,在各节点执行完后自动汇总到一份验收报告里。

4. 实战记录:用SKILL编排对订单模块做“微创手术”

4.1 目标模块背景

讲一个我最近做完的真实案例。项目是一个老订单服务,里面有一个订单确认函数,650行,支付渠道6种,每种渠道都有自己的回调处理参数、异常分支、重试逻辑。全部堆在一个函数里,if-else嵌套最深的地方有5层。

这个模块之前出过两次线上事故,都因为有人改动某个渠道的回调逻辑时,影响到了其他渠道。最严重的一次,某渠道回调超时异常处理判断错了层级,结果所有订单都走到统一异常分支里,大量正常回调被误判失败。

团队一直想把这块重构掉,但不敢动。接到这个任务之后,我没有一上来就写代码,而是先把改造流程跑成了前面说的那个workflow。

4.2 术前准备:建索引、出报告、埋探针

术前准备我做了三件事。

第一件,跑“影响面分析SKILL”,让它输出完整调用图。结果显示这个函数不仅有6个渠道回调入口,还被上游一个定时任务和下游两个通知服务调用。这个结论,团队里没人能凭经验一次性说全。报告出来之后,我根据报告手动确认了每个调用方,确认无遗漏,才进入下一步。

第二件,埋探针。在函数入口、每个渠道分支出口、每个异常分支,都加了一条日志,记录业务单号、渠道编码、耗时。这一步是必须的,没有探针,后面双写对比的数据无从谈起。我把探针代码作为第一个独立PR合入了。

第三件,观察基线。探针上线后跑了3天,收集了约2万条真实流量日志,把每个渠道的路径分布、平均耗时、错误率都统计出来。这是后面判断改造有没有改出问题的对照基线。没有基线的重构,等于闭眼开车。

4.3 手术执行:三步拆解

整个拆解过程分三步,每步都是独立PR,每步合入后系统都可运行。

第一步,抽离配置。把6个支付渠道的参数、回调URL、超时时间、重试次数,全部抽到一个渠道配置表。原函数里这些参数全是魔法数字,散落在各个 if 分支里。抽出来后,原函数代码量少了大约100行。这一步纯搬移,不改变任何行为,理论上零风险。

第二步,引入“渠道处理器注册表”。这是核心步骤。我没有让AI重构整个函数,而是给它定义了一个SKILL,要求它把“渠道分发逻辑”从大函数里原样搬到一个map里,每个渠道一个处理器,接口统一。下面是当时生成的简化结构:

# 渠道处理器注册表(改造后) PAYMENT_CHANNEL_HANDLERS = { "alipay": AlipayHandler(), "wechat": WechatHandler(), "unionpay": UnionpayHandler(), "card": CardHandler(), "balance": BalanceHandler(), "coupon": CouponHandler(), } def dispatch_channel(channel: str, order: Order): handler = PAYMENT_CHANNEL_HANDLERS.get(channel) if not handler: raise UnknownChannelError(channel) return handler.process(order)

注意,这个注册表只做分发,不改变每个渠道内部的业务步骤。断言的目的是让AI不能自由发挥重写每个handler。这个SKILL里我明确加了约束:“只允许搬移现有分支代码,禁止重写业务逻辑,禁止改动异常抛出类型”。

第三步,双写对比。我把旧函数和新注册表同时部署上线,每个订单都走两条路径,只比较结果,不对外返回新路径的结果。每天导出不一致日志,连续跑了5天。

这5天里真抓到两个问题。一个是某渠道处理器在搬移过程中,少复制了一个异常分支的回滚操作。另一个是旧代码里有一个全局计数器变量,新代码没有同步更新,导致两者统计数字不一致。这些问题如果在常规重构里,很可能要上线后一段时间才暴露。双写对比让它们在测试阶段就现了形。

4.4 术后复盘:数据与经验

改造完成后,我复盘了一下效果。

主函数从650行减到不到200行,剩下的主要是入口编排和调用外部服务。每个渠道的处理器独立成类,单文件最长80行。全量回归测试通过,双写对比不一致日志归零,p99耗时不升反降,少了大约12%——因为原来每次处理所有渠道共用同一份全局锁,现在独立调度可以并行了。

经验上最重要的是两条。

第一,人工确认不能省。双写对比第3天出现不一致日志时,如果流程是自动往下走的,这个bug就会直接溜进生产环境。停下来看结果,是这套流程最大的价值。

第二,SKILL里的“禁止重写”约束极其关键。第一次跑SKILL时,我没加这条约束,AI真的把某个渠道的回调逻辑重写了,还在注释里写“优化了异步处理”。我花了一个小时才对比出来差异。后来我在所有涉及存量代码搬运的SKILL里,都用黑体字强调一条铁律:不准顺手“优化”,只准原样搬移。除非你在编排里单独安排一个“优化SKILL”,否则任何隐式的小改动都可能导致线上故障。

5. 避坑指南与排查技巧实录

5.1 高频问题速查表

这套玩法的坑,我在项目里基本都踩过一遍。下面这张表整理了我遇到的典型问题、可能原因和排查方向,你可以直接存着。

问题现象可能原因排查方向
SKILL没触发,AI答非所问description写得太泛,或trigger条件太窄检查description是否包含明确的触发意图词,补一句“当用户提到XX时使用”
输出格式不统一,每次都不一样SKILL缺少output字段的强约束把输出格式写死成模板,要求AI严格按模板输出
AI改完的代码风格突变SKILL里没写“最小变更原则”在steps里明确追加“禁止重写未指定代码” “保持原有命名风格”
影响面分析漏上游调用方分析SKILL只看了单文件升级SKILL:要求必须解析全局符号索引,或者正反两个方向都找调用关系
双写对比不一致日志太多探针日志未加采样,或对比逻辑本身有误先确认探针埋点位置正确,再逐步缩小对比范围到核心路径
编排流程卡死,不推进人工确认节点超时机制缺失给每个human_confirm节点配置超时提醒和默认回退路径
合入后出现新bug双写对比时间窗口太短,没有覆盖完整业务周期拉长对比窗口,至少覆盖一个完整业务周期,比如日报类业务跑满一周

5.2 我踩过的坑:三个反面案例

第一个坑,是SKILL没写完成标准。最早的版本,我给影响面分析SKILL只写了“输出分析报告”,没有done_criteria。结果AI跑完后输出一个“分析完成”的结论,没有任何可执行内容。我去看日志,发现它自己认为“已经回答完毕了”。加上 “必须输出调用图+风险清单” 这条完成标准后,问题立刻消失。

第二个坑,是过期索引导致分析错误。有一次存量改造,我依赖一份调用关系索引文件,但那索引是两个月前生成的,中途有别的团队重命名了一个服务,索引里全乱了。分析SKILL给出的调用图少了一个重要依赖,差点出事。复盘后发现,SKILL的steps里没有加“索引时效校验”这一步,后来我改为每次跑分析前强制重新生成索引。

第三个坑,是编排节点之间没有输入输出校验。n3抽离SKILL的结果,直接作为n4双写SKILL的输入,但中间没有字段校验,结果某次抽离后输出字段名变了,n4直接跑不了。后来我给每个编排节点加了一层“输出schema检查”,这活儿可以用一个小脚本,也可以让n4的第一步先做输入自检。别指望SKILL之间天然兼容,机器之间也要契约。

5.3 什么情况不适合用 SKILL 编排

不吹这套方案万能。有些场景,SKILL编排并帮不了你。

存量代码压根跑不起来、连遵循业务逻辑的完整回归环境都没有。这种情况下,双写对比、探针埋点都无从谈起,AI再强也只能“盲改”。先把构建、测试环境修好,再来谈智能化改造。

架构级重构,比如要从单体直接切到微服务、或要换核心存储。这种结构性变化影响力太大,“微创手术”的切口根本不可能控制得这么小。该做的系统设计、数据迁移规划,都得单独推进。

团队没有能力配合做人工确认。这套流程很依赖“有人能看懂AI输出的影响面报告并做判断”。如果团队里没人对这块代码足够熟悉,那SKILL的介入反而会增加风险。毕竟,手术方案能操作的前提是主刀医生对这个器官够了解。

5.4 我的日常使用建议

现在我接手任何一个存量改造项目,都不会先去碰代码,而是先花小半天把两样东西定下来:三个SKILL(影响面分析、代码抽离、双写对比)和一张编排图。SKILL可以复用,编排图可以根据项目改节点。

然后严格按流程走:配置和探针作为第一批合入,抽离和双写对比作为第二批,切流和清理作为第三批。每批之间有人工确认。这个节奏会让团队里所有人心里都踏实,因为每一步都是可验证的、能回退的。

最后说一个小技巧。双写对比那段时间,我会每天固定一个时间,用一套脚本把不一致日志自动汇总成邮件发出来。如果连续3天累计不一致次数为0,再进入切换阶段。这个“连续3天为0”的门槛,比只看一天数据稳得多。存量改造的隐患,很多是低频异常,一天不漏不代表一周期不漏,时间窗口拉足,准没错。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/17 1:38:05

Fider 部署实战:Docker 三步搭好功能请求与反馈投票系统

Fider 部署实战:Docker 三步搭好功能请求与反馈投票系统 【免费下载链接】fider Open platform to collect and prioritize feedback 项目地址: https://gitcode.com/GitHub_Trending/fi/fider 用户的功能请求散落在工单、应用商店评论和微信群里&#xff0c…

作者头像 李华
网站建设 2026/10/17 1:37:41

一文快速了解分布式版本控制系统Git

文章目录1 版本控制系统的分类1.1 集中式1.2 分布式2 Git的介绍3 Git工作流程图4 Git的安装与配置4.1 Git下载与安装4.2 Git基础配置5 Git本地仓库常用命令5.1 基础命令5.1.1 初始化本地仓库5.1.2 查看仓库状态5.1.3 添加到暂存区5.1.4 提交到本地仓库5.1.5 查看日志5.1.6 版本…

作者头像 李华
网站建设 2026/10/17 1:37:33

Excel 获取当前行的行数

ROW() ✍️获取当前行 ROW()1 ✍️获取当前行然后支持二次开发UNICHAR(9310ROW()1):✍️获取当前行的行数 ① 格式 (讨巧行为表示有限)

作者头像 李华
网站建设 2026/10/17 1:37:29

Structured Streaming核心原理与生产实践指南

1. 这不是传统批处理,是让数据流“活”起来的编程方式你有没有遇到过这样的场景:某天凌晨三点,运维同学突然在群里发来截图——实时大屏上某个关键指标断崖式下跌,但日志里查不到异常,监控告警也没触发。等团队手忙脚乱…

作者头像 李华
网站建设 2026/10/17 1:36:53

多视点图像从几何原理到三维重建的完整技术链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/17 1:36:06

Scala 手写 Kafka 生产消费实例:幂等、手动提交与背压调优

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华