← 返回文章列表
009 — AI · #逆向工程 #AI Agent #遗留系统 · 2026-08-19 · 17 MIN READ

把祖传系统「翻译」成文档资产:AI 逆向工程流水线总览

每家公司都有一套没人敢动的系统

它可能是一个跑了八年的报销影像处理系统,一套用 VBS 脚本驱动 SAP 界面的清账平台,或者一个前后端都停留在 ExtJS 时代的风控模块。共同点是:最初写它的人早已离开,需求文档停留在几年前的某个版本,剩下的只有代码本身,和几位「大概知道哪块归谁管」的老员工。

这时候来了一个新需求。第一个问题是:这个按钮点下去,数据流经哪些服务、写哪几张表?没人能完整回答。第二个问题是:改了这里,会影响到谁?更没人敢打包票。于是团队只有两条路:要么安排人花三个月通读代码再动手,要么凭着局部理解直接改,然后在线上交学费。

「代码即文档」这句话在这样的系统面前会失效。当代码里既有 Vue 组件也有 JSP 页面,既有 MyBatis 的 XML 也有 psycopg2 拼出来的 SQL,还有调 SAP、调 OCR、读写共享文件夹的脚本时,「读代码」本身就是一个跨语言、跨边界的考古工程。交接会上口口相传的那点信息,每传一轮就衰减一轮,三个月后人走了,知识再次归零。

既然如此,能不能让 AI 来啃这块骨头?能,但直接把代码丢给一个大模型问「帮我理解这个系统」,得到的多半是一段正确却无用的概述。要让 AI 稳定地产出可交付的文档,需要的不是更强的模型,而是一套有章法的工程化流水线——这正是本系列 13 篇文章要完整展开的东西。

流水线全景:七步逆向,一步正向

这条流水线的输入是一整个遗留代码库——不限技术栈;输出是一套结构化的文档资产:功能清单、链路图、业务需求文档、数据字典,最后接上一步正向开发规范。全程由 8 个独立技能(skill)串联,每个技能只做一件事,做完把产物写成文件,交给下一个技能。

mermaid
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:新功能开发时的行为规范,要求先读真实代码、沿用项目既有模式——它消费的正是前面所有步骤沉淀下来的文档资产。

执行序技能职责关键输入关键产物
1feature-extract从入口文件识别功能点页面 / 脚本 / 服务文件doc/function-list/*.json
2link-diagram追踪跨层调用链并绘图function-list JSONdoc/link_diagram/*-链路图.md
3business-requirement翻译成纯业务语言需求链路图 mddoc/business/*-业务需求.md
4business-config按内容自动归类模块business/*.mddoc/business.json
5module-merge按模块合并,带质量门禁business.json + mddoc/merged/{序号}-{模块}.md
6module-index生成功能清单与总索引merged/*.mddoc/merged/00_索引.md
-database-dictionaryDDL 解析与注释修正doc/sql/*.ddl11/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 会话本身)捕获这行标志,校验文件确实存在,然后启动下一步。

mermaid
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:编排协议。产物文件 + 完成标志行构成技能间的全部通信。

一次真实的执行过程,在控制台里长这样:

text
# 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 篇)

步骤深挖(6 篇)

横切实践(3 篇)

场景延伸(2 篇)

三种读法供参考。只想了解思路:总览、编排协议、质量控制三篇足够,它们不依赖具体流水线细节。想复刻一条自己的流水线:按功能点提取到数据字典的顺序读,每一篇都带着完整的规则集和反面案例。管理视角评估可行性:总览、编排协议、三栈复盘,重点看协议成本和三栈适配的真实工作量。

结语

回头看这套流水线做过的事:它把「理解一个系统」这件原本只能发生在某个人脑子里的隐性工程,拆成了七个可执行、可验证、可断点续跑的显性步骤,每一步的产物都落成文件,最终汇成一套从功能清单到数据字典的文档资产。三个月后人再离职,知识不会跟着走——它已经躺在 doc/merged/ 里了。

文档在这套方法里不是逆向的副产品,而是让系统重新变得可维护的核心资产。接下来的篇章里,我们会进入流水线里最难的一步:如何约束大模型,把一段 if-else 和拼接 SQL,诚实地翻译成客户也能看懂的业务语言

Comments