构建 COBOL 依赖知识图谱后我发现:现代化败在检索而非翻译;更大的上下文窗口永远堵不上那个缺口。
COBOLLegacy SystemsSoftware Modernization

单个 COBOL 文件把除了那条要紧事实之外的一切都告诉了 AI,所以我先建了地图。

Ashutosh SinghalAshutosh Singhal2026年6月30日15 min

引发这一切的那行 COBOL 只有三个词,而每一个都在骗我。

COMPUTE WS-RESULT = WS-WIRE-AMOUNT - TRN-LIMIT. 我当时在为一个中型银行的电汇子系统搭建演示用代码资产,而这正是位于名为WIRETXN的程序中的那行要命代码。它看起来像一年级学生都能移植的算术:从一个金额里减去一个限额,再写出结果。如果你把那单个文件交给任何一个现代模型,让它生成 Java,大约四秒内它就会给你干净、能编译、能通过单元测试的 Java。它会把TRN-LIMIT写成long。而在第一笔真实电汇时,它就会把损坏的字节写进生产数据库。

我之所以知道,是因为TRN-LIMIT并不是long。它是一个压缩十进制COMP-3字段,定义在三个文件之外,其运行时解释由一个完全不同的程序里设置的标志决定,而该标志又由凌晨两点运行的批处理作业排序。这一切均不可见于WIRETXN。那个包含危险COMPUTE的文件,并不包含任何使它危险的事实。

正是这个缺口,让我建造了CodeGraph,而这篇文章讲的是我在那条路上犯过的错。一开始我确信问题出在翻译质量。我错了。真正的问题是模型看不到它需要看到的东西,而我花了一段时间向自己证明:无论怎么「给它更多上下文」,都解决不了这个问题。

那行看起来安全、其实并不安全的 COMPUTE

我先手工映射了这次电汇改动,然后才敢信任任何工具去做,而一次正确迁移必须知道的事实恰好有九条。

其中三条住在WIRETXN里,对单文件阅读者来说是真正可见的。WIRETXN使用TRN-LIMIT于那条COMPUTE中,位于第 33 行。它导入了一本名为CBACCT的 copybook,仅按名称,在第 13 行。它发出一次UPDATE,针对 DB2 表ACCOUNTS,位于第 37 行。文本窗口工具能看到这三条。如果这些就是全部事实,朴素移植就会没问题。

另外六条才是伤人的。TRN-LIMIT被声明为PIC S9(9)V99 COMP-3,位于CBACCT.cpy第 11 行,这意味着压缩十进制,亦即BigDecimal在 Java 中,而绝不是long。紧挨着它下面,TRN-LIMIT-ALPHA REDEFINES TRN-LIMIT,把同一段六个字节叠在该字段上当作原始文本。第三个字段LIMIT-TYPE-FLAG在运行时决定这两种解释里哪一种是生效的。该标志由一个名为LIMITSET的程序写入,也由一个名为BATCHUPD的夜间批处理作业再次写入。而 JCL 作业NIGHTLY在 02:00 作为电汇作业的前置运行,这是整个资产里唯一记录了「设置标志」与「执行转账」之间顺序的地方。

CodeGraph 针对 TRN-LIMIT 的影响面板:图检索回收 9/9 条事实,朴素单文件仅 3/9,每条回收事实都带有来自 WIRETXN.cbl 与 CBACCT.cpy 的文件与行号溯源。
已交付合成夹具上的 TRN-LIMIT 闭包。图检索回收 9/9 条真值事实,朴素单文件窗口只看到 3/9,且每条事实都自带文件与行号。F4 到 F9——那六条会搞垮移植的——在单文件视图中被标为隐藏。

六条事实。每一条都为真,每一条都是承重的,每一条从真正做计算的那个文件里在结构上都不可见。当我把它们这样排开时,让我不安的并不是朴素移植是错的。而是朴素移植根本无从知道自己错了。它读了被交给它的那一个文件,而那一个文件对六条要紧的事实沉默不语。

包含那行危险代码的文件,并不包含任何使它危险的事实。这不是翻译缺陷。这是披着翻译缺陷外衣的检索失败。

我为什么不再试图把上下文窗口做大

我的第一反应和眼下每个人的本能一样,我也想老实承认自己追过一阵:只要再多给模型一些就行。

这套推理听起来无懈可击。如果失败是因为模型只看到一个文件,那就连 copybook 一起喂给它。把触碰该标志的程序也喂进去。把 JCL 也喂进去。上下文窗口如今已经巨大,每个季度还在变大,所以答案显然是别再吝啬,把整片邻域代码一股脑倒进提示词。我真心以为这会奏效;对一个玩具例子,它勉强能行——因为当你已经知道该粘贴哪六个文件时,你其实已经手工解决了真正的问题。

裂缝就在这里。要把正确的上下文喂给模型,我首先得知道什么才是正确的上下文。而知道TRN-LIMIT的类型由写在BATCHUPD中的标志决定,并由 02:00 的 JCL 作业排序——这并不是靠把WIRETXN读得更用力就能挖出来的。那是你只有先沿着依赖图追踪完才能得到的东西。上下文窗口并不会告诉你该往上下文窗口里放什么。我一直在用答案本身去回答那个问题。

随后数字把这一点钉死了。这些银行实际运行的资产不是六个文件。它们是一百万到一千万行 COBOL,有时更多;全行业仍有 2200 亿行处于活跃生产(行业元分析,2025)。一次真实的电汇改动,其传递闭包可能是四十个文件,也可能是四百个。那永远塞不进上下文窗口——今天不行,三年后发布的模型版本也不行——因为资产比窗口涨得更快,而窗口本来就不是约束。约束是:在一千万行里知道这四十个文件是哪四十个,并证明你找到的是全部四十个,而不是三十八个。

更大的上下文窗口,是对我已不再追问的那个问题的更好答案。问题不是「模型能不能装下更多代码」,而是「哪段代码,以及你如何证明那就是全部」。

这一重框定,正是 CodeGraph 不是翻译器的全部理由。我刻意不做粘贴 COBOL、交回 Java 这种事。地图才是产品,而翻译是地图存在之后任何工具都能做的下游用例。我构建的是底下的理解层。在已交付的夹具上,该资产解析为一张 47 个节点、70 条边的类型化知识图谱;「一次改动的影响」是一次图遍历——改动触及的一切的传递闭包——每条边都带着它来自的file:line。这刻意是无聊的纯 Python 图工作,热路径上没有模型,因为我需要它的不是聪明。我需要它完整且可复现。同一夹具进,同一闭包出,每一次都如此。

我把它当作一条规则反复对自己说。智能体建议,代码裁决。演示里可选的语言层——用白话回答关于闭包的问题的那部分——默认关闭,并锁在密钥后面。价值并不依赖它。价值在于检索与证明,而这两者都不是模型能力。

朴素视图到底删掉了什么?

我特意在演示里做了一个开关,好看着那六条事实消失,因为在亲眼看见之前,我并没有完全相信这种失败。

勾选「朴素 AI 上下文视图」,图就会塌缩到单个源文件加上改动周围若干行的窗口——这正是文本窗口工具喂给模型的东西。原本显示 9/9 的面板掉到 3/9。文件内的三条事实保持点亮。另外六条变灰、沉默:COMP-3类型、REDEFINES叠加、控制标志、它的两个跨模块写入者,以及 02:00 的 JCL 前置。一条红色横幅用应用自己的话说出后果:只拿到三条可见事实时,模型会发出long TRN_LIMIT并损坏数据库。

CodeGraph 开启朴素 AI 上下文视图,将九条事实中的六条变灰,红色横幅写明:仅有 3/9 条事实住在 WIRETXN.cbl 内,其余对文本窗口工具不可见。
朴素单文件视图——模拟文本窗口工具实际看到的内容,而不是实时连接器。六条事实变灰。横幅点名每一件消失之物:COMP-3 类型、REDEFINES 叠加、控制标志、它的两个写入者,以及 02:00 前置。

我想在这里谨慎一些,因为这正是创始人容易夸大其词的地方。9 对 3 的结果测量于已交付的合成电汇夹具——我为这次演示手工撰写的资产,正是为了让真实依赖集已知,召回数字成为有标签的真测量,而不是感觉。它不是对你的 COBOL 的保证。朴素视图是模拟,不是实时 z/OS 流水线。图在内存中,底下是 SQLite,不是生产级图平台。我造了一家合成银行,因为我不能合乎伦理地向你展示一家真实银行,也因为已知真值是唯一诚实的方式,好说「图拿到全部九条,单文件拿到三条」。

但失败的形态并不是合成的,而这才是要紧的部分。那个COMP-3字段——类型在别处决定、标志由批处理作业设置、顺序只存在于 JCL——这些是四十年银行资产的寻常纹理,不是奇异边角案例。当大约 70% 到 80% 的大型机现代化项目未能达成目标(行业元分析,2025)时,我不再认为是因为翻译步骤差。翻译步骤没问题。它被喂的是一张裁掉了六条最重要事实的图。

没有证明,就不算数

我最自豪的功能,是那个承认自己做不到什么的功能;直到一次合规对话替我重新框定,我才真正体会到这一点。

工程师要的是正确的迁移。监管者要的是不同且更难的东西:证据。在 DORA 下,银行欠一份 ICT 资产清单。在 SOC-2 下,它欠变更控制回执。模型说「相信我,我找到了依赖」满足不了其中任何一项。他们需要完整性证明——工具实际能解析代码库多少的声明,以及更重要的,对它未能解析之物的诚实标注。于是我建了一道完整性门控。夹具里每一次PERFORMCALLCOPY以及 DB2 引用都必须解析到图中的真实节点,否则标为「需要复核」。任何东西都不允许悄然消失。

在夹具上,该门控解析了 34 个引用中的 33 个,覆盖率 97.1%。它无法解析的那一个是名为DISPATCH的程序,它做一次动态CALL WS-PROGNAME——一个运行时计算的目标,任何静态解析器都跟不上,因为目标要等程序运行才知道。而正确做法不是去猜。而是举起一面旗,写着「这里需要人来看一眼」,并把它留在报告里。

CodeGraph 审计页显示 97.1% 的引用已解析,1 项标为待复核;被标项是 DISPATCH 在 DISPATCH.cbl 第 15 行的动态 CALL WS-PROGNAME,列为已标注而非悄然丢弃。
夹具上的完整性门控。34 个引用中解析 33 个,97.1%,唯一未解析的——DISPATCH 对运行时计算目标的动态 CALL——被标为待复核而非丢弃。对它跟不上的那一条的诚实,才是重点,不是脚注。

那次被标注的DISPATCH调用是整次构建里我最爱的东西,我说真的。一个解析 97%、并确切告诉你哪 3% 它做不到的工具,比一个声称 100% 却藏着缺口的工具更有价值,因为那个隐藏的缺口,正是损坏电汇栖身之处。完整性门控产出可导出的「代码库拓扑与完整性报告」——一份 JSON 和一份可打印 HTML,含节点与边摘要、带file:line溯源的逐模块闭包、召回结果,以及带时间戳的标注项。那份产物才是重点。它是你可以交给监管者、下个季度再跑一遍、因为确定性而得到相同答案的东西。

我宁愿交付一个承认自身空洞的数字,也不要一个更圆滑却把它藏起来的数字。被标注的动态 CALL 不是演示的弱点。它就是演示。

这也是不会过时的那部分。一个完美模型——从不幻觉出一行 Java——仍然无法向监管者证明它检索到了哪些依赖。它仍然无法静态跟上一次运行时计算的CALL,因为那是代码的属性,不是阅读者的属性。溯源与完整性是你围绕模型构建的系统的属性,不是靠扩大规模就能解锁的能力。

你触碰事物的顺序

图最后给我的,是一件我起初甚至没打算建造的东西:一套安全的开工顺序。

一旦你有了完整的依赖拓扑,就可以按缠结程度给每个程序打分。我用一个朴素公式,把耦合对COMP-3陷阱、JCL 关键性与未解析调用加权,把夹具里的十四个程序排成绞杀榕提取顺序。风险最低的程序最先提取,上帝程序最后。在夹具上,AUDITLOG排在第 1 位,风险分为零,因为它没有耦合,也没有任何东西依赖它正确。那是安全的起点。WIRETXN程序——我们一直担心的那个——排在第 11 位,带着它那一个COMP-3陷阱与它的 JCL 关键性。DISPATCH带着未解析的动态调用,排在第 12 位。而ACCTMGR——一切倚靠的上帝程序——排在最后第 14 位,风险分 15。

CodeGraph 提取页显示夹具十四个程序按绞杀榕顺序排名:AUDITLOG 第 1 位风险分 0,ACCTMGR 第 14 位风险分 15;列含耦合、COMP-3 陷阱与 JCL 关键性。
夹具上的绞杀榕提取顺序。AUDITLOG 以风险 0 最先提取,上帝程序 ACCTMGR 以风险 15 最后提取,WIRETXN 与 DISPATCH 因其 COMP-3 陷阱与未解析动态调用而位居前列。顺序是图的属性,不是主观判断。

我没料到自己会像现在这样在意排序。但这是同一课的第三次。你可以安全从哪里开始,是关于拓扑的事实,不是你在规划会上争论的意见。一支盯着百万行代码的团队,其实并不在争论如何翻译一个段落。他们无休止、昂贵地争论的是从哪里开始,以及先碰错东西会弄坏什么。那是一个图问题,而图每次运行都以同样的方式回答。

提取顺序、完整性门控、影响闭包——它们是从三个角度看的同一个对象。检索真正的切片,证明它是完整切片,再按风险给切片排序。这三样都不是翻译问题,也都不是更聪明的模型能解决的。

我不断回到的那个问题

我开始对每一个见到的 AI 现代化推销——包括我自己的——只问一个问题,而它悄悄成了我唯一信任的问题。

不是「它能不能写出好的 Java」,因为答案几乎总是能,而且几乎从来无关紧要。更难的问题是TRN-LIMIT那行教会我的:它能不能此刻证明检索到了哪些依赖,而这份证明能否扛住一个想让它失败的监管者。如果工具无法向我展示带file:line溯源的闭包,也无法诚实地告诉我它未能解析什么,那么输出看起来再流畅也无关紧要。那是带着好语法的猜测,而我亲眼见过正是那种猜测把long打在压缩十进制字段上,然后伸向数据库。

行业花了十年把翻译步骤做得更好,而 70% 到 80% 的项目仍未达成目标(行业元分析,2025),我认为那是因为风险从来就不在翻译步骤。风险住在拓扑里,住在六条看不见的事实里,住在凌晨两点设置的那个标志里。如果你想看图把那六条事实找回来、再诚实地标出它做不到的那一条,演示在这里:veriprajna.com/zh-Hans/demos/legacy-cobol-modernization

如果你宁愿看它跑起来,而不是听我描述,这里是整件事端到端运行的样子。

我不再相信下一次模型发布会解锁这些迁移。更大的窗口能装下更多代码;它不知道是哪段代码,也无法证明它找到了全部。当我敲下解析器第一行时这就是真的,而我相信在我用来建造它的那个模型退役很久之后,这依然是真的。地图从来都是难的那部分。我们只是一直盯着翻译,因为那是我们知道怎么打分的部分。

相关研究

同步发布于

满怀信心地构建您的 AI。

与一支在打造新一代企业级 AI 方面拥有深厚经验的团队携手合作。让我们助您设计、构建并部署一套值得信赖的 AI 战略。

Veriprajna 深度科技咨询公司 专注于为医疗健康、金融和监管等领域构建安全攸关的 AI 系统。我们的架构均依据成熟的规范进行验证,并配有完善的合规文档。