把祖传系统「翻译」成文档资产:AI 逆向工程流水线总览
每家公司都有一套没人敢动的系统
它可能是一个跑了八年的报销影像处理系统,一套用 VBS 脚本驱动 SAP 界面的清账平台,或者一个前后端都停留在 ExtJS 时代的风控模块。共同点是:最初写它的人早已离开,需求文档停留在几年前的某个版本,剩下的只有代码本身,和几位「大概知道哪块归谁管」的老员工。
这时候来了一个新需求。第一个问题是:这个按钮点下去,数据流经哪些服务、写哪几张表?没人能完整回答。第二个问题是:改了这里,会影响到谁?更没人敢打包票。于是团队只有两条路:要么安排人花三个月通读代码再动手,要么凭着局部理解直接改,然后在线上交学费。
「代码即文档」这句话在这样的系统面前会失效。当代码里既有 Vue 组件也有 JSP 页面,既有 MyBatis 的 XML 也有 psycopg2 拼出来的 SQL,还有调 SAP、调 OCR、读写共享文件夹的脚本时,「读代码」本身就是一个跨语言、跨边界的考古工程。交接会上口口相传的那点信息,每传一轮就衰减一轮,三个月后人走了,知识再次归零。
既然如此,能不能让 AI 来啃这块骨头?能,但直接把代码丢给一个大模型问「帮我理解这个系统」,得到的多半是一段正确却无用的概述。要让 AI 稳定地产出可交付的文档,需要的不是更强的模型,而是一套有章法的工程化流水线——这正是本系列 13 篇文章要完整展开的东西。
流水线全景:七步逆向,一步正向
这条流水线的输入是一整个遗留代码库——不限技术栈;输出是一套结构化的文档资产:功能清单、链路图、业务需求文档、数据字典,最后接上一步正向开发规范。全程由 8 个独立技能(skill)串联,每个技能只做一件事,做完把产物写成文件,交给下一个技能。
flowchart LR
subgraph A["理解代码"]
s1["skill1<br/>功能点提取"] -->|"doc/function-list/*.json"| s2["skill2<br/>链路图生成"]
s2 -->|"doc/link_diagram/*-链路图.md"| s3["skill3<br/>业务需求生成"]
end
subgraph B["组织文档"]
s6["skill6<br/>模块归类"] -->|"doc/business.json"| s7["skill7<br/>模块合并"]
s7 -->|"doc/merged/{序号}-{模块}.md"| s4["skill4<br/>索引清单"]
end
subgraph C["指导开发"]
fd["feature-dev<br/>功能开发规范"]
end
s3 -->|"doc/business/*-业务需求.md"| s6
s4 -.消费文档资产.-> fd
ddl["doc/sql/*.ddl"] --> s5["skill5 数据字典<br/>(可与其他步骤并行)"]
s5 -. "11/12-*.md + 注释SQL,并入 doc/merged/" .-> s7
code["任意技术栈的遗留系统<br/>页面 / 脚本 / 服务 / 定时任务 / DDL"] --> s1
classDef phaseA stroke:#b4532a,stroke-width:2px;
classDef phaseB stroke:#1f6e5f,stroke-width:2px;
classDef phaseC fill:#26221a,color:#fbfaf6,stroke:#26221a;
class s1,s2,s3 phaseA;
class s6,s7,s4,s5 phaseB;
class fd phaseC;
图 1:流水线全景。实线为固定顺序的数据流,虚线为消费或并行关系;每步产物都是下一步的输入。
整条流水线可以拆成三段来看。理解代码是 skill 1 到 3:先从入口文件里认出「功能点」,再顺着每个功能点追出完整调用链路,最后把链路翻译成纯业务语言的需求文档。组织文档是 skill 6、7、4、5:把几十份散落的业务文档自动归类到模块、按模块合并成体系化的功能清单、生成总索引,同时从 DDL 反向生成数据字典。指导开发是 feature-dev:新功能开发时的行为规范,要求先读真实代码、沿用项目既有模式——它消费的正是前面所有步骤沉淀下来的文档资产。
| 执行序 | 技能 | 职责 | 关键输入 | 关键产物 |
|---|---|---|---|---|
| 1 | feature-extract | 从入口文件识别功能点 | 页面 / 脚本 / 服务文件 | doc/function-list/*.json |
| 2 | link-diagram | 追踪跨层调用链并绘图 | function-list JSON | doc/link_diagram/*-链路图.md |
| 3 | business-requirement | 翻译成纯业务语言需求 | 链路图 md | doc/business/*-业务需求.md |
| 4 | business-config | 按内容自动归类模块 | business/*.md | doc/business.json |
| 5 | module-merge | 按模块合并,带质量门禁 | business.json + md | doc/merged/{序号}-{模块}.md |
| 6 | module-index | 生成功能清单与总索引 | merged/*.md | doc/merged/00_索引.md |
| - | database-dictionary | DDL 解析与注释修正 | doc/sql/*.ddl | 11/12-*.md + 注释 SQL |
| - | feature-dev | 在既有模式内开发新功能 | 技术栈识别 + 文档资产 | 功能代码 + 开发日志 |
一个容易混淆的细节:技能编号和执行顺序并不一致:skill 6 在 skill 4 之前执行。编号是这套流水线从专用版本演进到通用版本过程中的历史痕迹,本系列后续文章一律按执行顺序而非编号来讲述。
为什么是七步,而不是一个大 Prompt
看到这套结构,第一反应往往是:为什么不把所有要求写进一个巨型 Prompt,让模型一口气输出全部文档?直觉上这最省事,工程上它站不住,原因有三个。
第一个原因是物理约束:上下文装不下
一个功能点从前端按钮走到数据库,平均要穿越 6 到 8 个文件:Vue 组件到 api.js,到 Controller,到 Service 接口和实现类,到 Mapper 接口,到 MyBatis 的 XML,最后才是 SQL 和表。一个中等规模的遗留系统,这样的功能点有几十上百个,再叠加每一步的规则、模板和反面案例,任何上下文窗口都装不下。更麻烦的是,即便塞进去了,长上下文中间部分的信息利用率也会明显下降——规则写在第 30 页,执行到第 300 页时早已被稀释。拆成七步之后,每个技能只装载它需要的文件和上游产物,窗口内始终是高信噪比的内容。
第二个原因是可验证性:文件产物才有判定标准
巨型 Prompt 的输出是「一大坨文本」,合格与否只能靠人眼。流水线每一步的产物是结构化文件,验证可以交给脚本:链路图生成后,检查图里功能点数量是否等于输入 JSON 的数量(N = M 校验);模块合并后,检查输入参数表格是否 100% 保留、业务规则保留率是否达到 90%;不达标就自动重试,三次不过标记人工审核。质量标准从「感觉写得还行」变成了机器可判定的数字。
第三个原因是失败半径:哪步坏了重跑哪步
大模型生成几万字,中途一处幻觉或一次截断,整份产物就不可信,重跑成本等于全部再来一遍。流水线把失败半径缩小到单步,甚至缩小到单步内的某个批次:一百个功能点分成若干批并行处理,坏一批补一批,其余产物不受影响。中间产物全部落盘,流程本身可以断点续跑。
| 维度 | 方案 A:一个巨型 Prompt | 方案 B:七步流水线 |
|---|---|---|
| 上下文 | 整库 + 全部规则一次塞入,必然溢出或稀释 | 每个技能只装载所需文件与上游产物,高信噪比 |
| 可验证性 | 几万字产物没有机器判定标准,靠人眼复查 | N=M 数量校验、表格保留率 100%、规则保留率 90% 门禁 |
| 失败半径 | 一处幻觉污染整份产物,全盘重来 | 缩小到单步甚至单批,坏一批补一批 |
| 交付物 | 一次性输出,无中间沉淀 | 中间产物全部落盘,本身就是文档资产 |
| 代价 | 看似零成本,实际不可维护 | 需要设计输入输出契约与校验规则 |
图 2:两种方案对照。拆步换来的是上下文聚焦、机器可验证的质量门禁和极小的失败半径。
拆步的代价:七步不是免费的午餐:每一步都要定义清晰的输入输出契约、完成标志和校验规则,协议设计的成本集中在这里。这套契约怎么设计,是编排协议设计一篇的主题;它同时也是整个系列里复用价值最高的部分——换一个领域,协议照样成立。
文件即接口:流水线的编排协议
步骤拆定之后,剩下的问题是:谁来衔接它们?这套流水线没有引入数据库、消息队列或者编排引擎,衔接靠的是文件系统本身。每个技能把产物写到约定目录、用约定命名,再在控制台打印一行完成标志,调度器(可以是脚本,也可以是 AI 会话本身)捕获这行标志,校验文件确实存在,然后启动下一步。
sequenceDiagram
participant S as skill3 业务需求生成
participant F as 文件系统 + 控制台
participant D as 调度器
participant C as skill6 模块归类
Note over S: 正在处理第 47/86 个功能点
S->>F: 写入 doc/business/pbk-台账列表-业务需求.md
S-->>D: 打印 输出文件:pbk-台账列表-业务需求.md
D->>F: 校验文件真实存在 + 结构抽检
alt 校验通过
D->>C: 86/86 功能点完成,触发下一步
else 校验失败
D->>S: 按批次自动重试(最多 3 次)
Note over D: 仍失败则标记"需人工审核"并继续
end
图 3:编排协议。产物文件 + 完成标志行构成技能间的全部通信。
一次真实的执行过程,在控制台里长这样:
# skill 3 正在处理第 47/86 个功能点:台账列表 - 双击行
[skill3] 已写入 doc/business/pbk-台账列表-业务需求.md
[skill3] 输出文件:pbk-台账列表-业务需求.md <-- 调度器捕获此行
# ... 其余 39 个功能点依次处理 ...
[调度器] 校验 doc/business/ 下共 86 份文件:通过
[调度器] 输入参数表结构抽检 100% 保留:通过
[调度器] 触发下一步:skill6 模块归类
协议里最「较真」的规定是那行完成标志:输出文件:后面必须跟完整文件名,冒号必须是中文全角,不允许带路径。乍看是官僚主义的格式洁癖,实际上是给自动化消费端上保险——调度器的正则一旦写死,生成端的任何自由发挥都会变成静默失败。宁可约束人(和模型),也不让解析器猜。
两条契约让上下游自动对齐:
| 契约 | 规则 | 效果 |
|---|---|---|
| 目录契约 | doc/function-list/、doc/link_diagram/、doc/business/、doc/merged/ 固定;技能启动先做前置检查,依赖缺失直接报错退出 | 任何技能都能按目录找到上游产物,缺依赖时快速失败而非静默降级 |
| 命名契约 | 同一功能点的产物共享文件名主体,后缀按步骤替换:上游 pbk-台账列表-链路图.md,下游自动变成 pbk-台账列表-业务需求.md | 上下游文件天然一一对应,无需维护映射表 |
文件即接口还有一层更实际的好处:所有中间产物都是人类可读的 Markdown 和 JSON。流程中断了,从任意一步手动续跑;产物有疑点,人直接打开文件改;要审计三个月前的生成过程,文件的时间戳和内容就是证据。中间产物不是流水线的排泄物,它们本身就是交付物的一部分。
同一套流水线,跑通三种技术栈
「技术栈中立」不是写在 README 里的口号,验证方式只有一个:拿完全不同的系统跑同一条流水线。下面三个真实项目,技术栈横跨 Python 脚本、传统 Java 三层架构和 ExtJS 时代的混合前端,全部走完了七步逆向。
报销单影像自动化
- 技术栈:Python + Selenium + Requests + OCR
- 功能入口:脚本内的处理函数,批处理流程的每一步都独立计为一个功能点
- 参数来源:OCR 识别结果、共享文件夹文件、数据库直连查询
- 链路终点:外部 OCR 服务与浏览器页面,统一标注 External
SAP 自动清账平台
- 技术栈:Spring Boot + MyBatis + VBS + SAP GUI
- 功能入口:Controller 注解方法,前后端一体页面按事件函数提取
- 链路模板:注解 SQL 直接关联表,跳过 XML 映射层
- 链路终点:VBS 脚本驱动 SAP GUI 界面,灰色 External 节点收尾
质控往来风险探针
- 技术栈:Spring MVC + Activiti + Hibernate + ExtJS + jqGrid
- 功能入口:JSP 页面里的 ExtJS 按钮与 jqGrid 行事件(双击、勾选、切换)
- 列定义基准:jqGrid 的 colModel,优先级高于实体属性
- 链路特点:工作流引擎节点与 Hibernate 映射纳入同一条追踪规则
三个项目里,步骤本身一行代码没改。差异全部被吸收在各技能的参数化规则里:功能点提取内置七类技术栈的入口特征表,链路追踪内置六种调用链模板,数据字典内置四种 DDL 方言的注释语法。遇到 SAP、OCR 这类异构依赖,规则是统一的——一律画成灰色 External 节点,链路在系统边界处诚实止步,不猜、不编。
改了什么,没改什么:零改动的是骨架:七步拆分、文件协议、质量门禁、目录结构。按栈定制的是规则:入口特征识别、链路追踪模板、输出字段基准、归类关键词。哪些规则沉淀成了方法论、哪些只是参数,这个「从专用到通用」的改造过程在技术栈中立化改造一篇完整拆解,三个项目的完整复盘见三栈实战复盘。
系列地图与阅读路线
本系列共 13 篇。总纲两篇立方法论,步骤六篇拆每一步的完整规则集,横切三篇讲协议、质量与并行的通用工程实践,场景两篇用真实项目收尾。
总纲(2 篇)
- 把祖传系统「翻译」成文档资产:AI 逆向工程流水线总览——七步逆向 + 一步正向的全景与两个核心设计决策(本篇)
- 从专用到通用:Skill 的技术栈中立化改造——从 RuoYi 耦合版到任意栈的四维度泛化过程
步骤深挖(6 篇)
- 功能点提取:让 AI 认出任意技术栈里的功能入口——七类技术栈的入口特征表与排除规则
- 链路图生成:跨边界调用链追踪与 mermaid 语义学——跨边界调用链追踪与不许说谎的图
- 业务需求生成:把代码翻译成人话的质量工程——零合并原则、业务语言翻译与两阶段执行
- 文档资产组织三部曲:归类、合并与索引——归类、合并、索引与 90%/100% 质量门禁
- 数据库数据字典:DDL 解析与业务语境反哺——DDL 多方言解析与业务语境反哺注释
- feature-dev:在读懂的系统里写新代码——先读后写,在读懂的系统里写新代码
横切实践(3 篇)
- AI Agent 流水线的编排协议设计——文件即接口的完整协议规格与取舍
- LLM 输出质量控制的三层防线——红线 Prompt、过程门禁、事后验证
- 子代理并行:大规模任务的分治实践——分批、独立结果文件与完整性核对
场景延伸(2 篇)
- 三栈实战复盘:同一套流水线的伸缩性——Python、Spring Boot、ExtJS 项目的适配差异清单
- 从逆向到正向:文档资产化的完整闭环——文档资产的消费场景与新人上手路径
三种读法供参考。只想了解思路:总览、编排协议、质量控制三篇足够,它们不依赖具体流水线细节。想复刻一条自己的流水线:按功能点提取到数据字典的顺序读,每一篇都带着完整的规则集和反面案例。管理视角评估可行性:总览、编排协议、三栈复盘,重点看协议成本和三栈适配的真实工作量。
结语
回头看这套流水线做过的事:它把「理解一个系统」这件原本只能发生在某个人脑子里的隐性工程,拆成了七个可执行、可验证、可断点续跑的显性步骤,每一步的产物都落成文件,最终汇成一套从功能清单到数据字典的文档资产。三个月后人再离职,知识不会跟着走——它已经躺在 doc/merged/ 里了。
文档在这套方法里不是逆向的副产品,而是让系统重新变得可维护的核心资产。接下来的篇章里,我们会进入流水线里最难的一步:如何约束大模型,把一段 if-else 和拼接 SQL,诚实地翻译成客户也能看懂的业务语言。