欧洲一家能源运营商,最近把一套40000行Fortran 77储层模拟器搬到了C++。这听起来像AI公司做的技术demo,但背后是一次实打实的遗留代码现代化手术。Mistral复盘后给出的结论很直接:先别急着让大模型写代码,用数值对齐校验锁住行为,再用结构化Agent工作流去拆解脏活。方法不玄,可迁移性极强。
一、Fortran 77的“遗产”:能跑,但没人敢碰
一套模拟器,背后是几十年的地层逻辑
储层模拟器是用来计算油气在复杂地质结构里怎么流动的。欧洲这套代码,1970年代生根,经历过无数轮油田数据锤炼。里面的物理模型、数值方法、边界条件,已经和地质工程师的经验长在一起。Fortran 77没有任何现代语法糖,没有类,没有指针,一个COMMON块传遍全程序。代码能跑,而且跑得极稳,但没人敢碰。懂Fortran的老工程师陆续退休,年轻的C++团队看着上万行GOTO,只想重写。这里有个关键判断:F77没有错,结构其实是“数值家的结构”,一旦重写,真正的逻辑风险会浮出来。
为什么是现在?人才和效率的双重压力
迁移的直接原因是维护成本到了临界点。Fortran 77编译器在现在的HPC生态里成了异类,新硬件要手工调性能,老模块又无法并行。更麻烦的是,团队招不到人。能源行业要跑得更快的预测模型,要接入机器学习做代理模型,可底层全是F77,年轻工程师根本融不进去。运营商试过内部重构,用了两年,半途而废。这印证了那句老话:遗留代码的根子往往不在代码,而在组织和知识已经断代。于是这次选择借力AI,但方式很克制——每个Agent都被“数值一致性”的镣铐绑住,不许自由发挥。
翻译,还是重写?一次有边界的现代化
最常见的问题是:既然C++是目标,为什么不干脆按现代架构重写?项目复盘的回答是:业务不允许。储层模拟器是生产工具,不是玩具代码。每一行数学方程都对应真实油田的经济决策,换一套算法可能带来微小偏差,导致储层预测完全失真。所以这次迁移的定位很明确:把Fortran 77的行为语义移植到C++,保留原有的数值算法和求解顺序,只在可读性、数据结构和工作流上做面向现代的改造。用三个词说就是“谨慎、分步、可验证”。
二、先给迁移“立规矩”:数值对齐校验是唯一准绳
别让新旧代码各说各话
任何迁移项目的第一块压舱石,都是证明新代码和旧代码在数学上是一家人。Mistral团队没有急着定义什么“重构优先级”,而是先搭了一套数值对齐校验。简单说:同一组输入,跑Fortran旧模块和跑C++新模块,把每一步计算的中间结果抓出来,逐位对比。浮点运算的误差不能靠“差不多”滑过去,而是设定严格的绝对误差和相对误差阈值。他们甚至对比到求解器内部迭代次数、非线性残差序列。这套东西搭完后,回归测试才有真正的底气。
从“行为一致”到让机器承认一致
最难的部分是让数值比较不过度敏感。浮点运算的顺序稍微变一下,结果都会变。比如C++编译器优化后,融合乘加(FMA)指令会把两个运算合成一次,导致结果与Fortran有末位差别。如果直接用“完全一致”来卡,迁移会寸步难行。复盘中的做法是分层对比:宏观上比较最终场分布和累积量,中观上比较每个网格单元的压力、饱和度时间序列,微观上比较关键局部的残差收敛曲线。三层都通过,才叫对齐。这种做法消除了“非黑即白”的误判,也保住了数值行为的可信度。
校验不是一次性工程,它应该是迁移的“墙轨”
更聪明的地方是,这套校验环境不是跑完一轮就扔掉,而是成为整个Agent工作流的持续约束。Fortran代码的每个子程序被翻译成C++后,都要立刻挂到同一组数值测试下。测试用例是从真实生产数据集中摘出来的场景,不是那种“覆盖到了”就满足的低质用例。项目方明确说,校验覆盖率绝不等于行覆盖率,最重要的是边界条件和极端物理状态。这实际上把一次大爆炸式的重构,拆成了几千次小型可验证迁移。每一个小步骤,都有一堵不能越过的墙挡在那里。
三、结构化Agent工作流:如何让AI有条理地干脏活
Agent不是自动补丁机
把40000行F77交给一个通用AI提示词,会得到一堆漂亮的C++代码,但几乎肯定不能过数值检验。Mistral用的不是这种蛮力玩法。他们设计了一个“规划-执行-审查”的Agent闭环。每个Agent只负责一个粒度很细的任务:要么翻译一个没有任何子调用的纯计算函数,要么重写一个内部状态明确的数据块映射。大模型的角色是流水线上的熟练工,而真正的项目经理是外围的流水线控制逻辑。这套结构化的本质,是用可验证的边界来倒逼生成质量。
任务拆解的顺序:先动叶子,后动枝干
结构化体现在一个非常具体的策略:先动叶子,后动枝干。他们把Fortran代码按调用关系梳理成依赖图,然后从没有子程序的底层数学函数开始迁移。这一步最简单,也最容易验证。等底层模块都被C++替身覆盖并通过对齐测试后,再逐步向上替换调用它们的父模块。整个过程像剥洋葱,一层层往里拆,却始终保留可编译的系统状态。任何时刻,代码库里都只存在小范围的“正在迁移”状态,这让排查错误变得异常清晰。
人在回路:哪些节点必须保留人类决策?
项目还有一个容易被忽略的经验:在Agent工作流里设计了三个人类审查闸口。第一道在任务定义时,由领域专家把Fortran代码里那些“看起来多余”的写法和特殊变量命名转译给Agent;第二道在单元对齐完成后,由数值分析师检查对比指标是否合理;第三道在集成回归时,由业务方确认模拟结果在物理上可信。Agent负责速度和一致性,人类负责业务理性和例外情况的判断。这种混合不是最低效的,反而让整个迁移少走了大量回头路。回头看,这次迁移的样本意义,不在于把大模型用在了一个多酷炫的场景,而在于它示范了怎样用工程纪律去约束AI——这才是遗留代码现代化真正需要的核心能力。

