Thinking思考
Summary摘要
遗留代码现代化改造颇具挑战,尤其是将复杂的 Fortran 77 系统迁移到现代 C++ 时。Mistral 成功迁移了一个物理计算密集型的油藏模拟器的 40,000 行代码:为此构建了用于数值验证的一致性校验框架,借助 AI 智能体为代码库编写文档,并采用带人工监督的结构化工作流,以确保代码高质量且可维护。关键经验包括:优先保证数值一致,在迁移前先整理好文档,以及在智能体自主性与人工审查之间取得平衡。
Legacy scientific codebases accumulate over decades, and when original authors leave, the knowledge embedded in the code becomes hard to recover. Moreover, using languages with no active developer ecosystem means missing out on the opportunity to build on top of others’ work. Mistral helped a European energy operator migrate 40,000 lines of Fortran 77 to C++, a physics-intensive reservoir simulator with no test suite and no centralized documentation.遗留科学代码库往往历经数十年积累,当原始作者离开后,代码中蕴含的知识便很难恢复。此外,使用没有活跃开发者生态的语言,也意味着错失在他人成果之上继续构建的机会。Mistral 帮助一家欧洲能源运营商将 40,000 行 Fortran 77 迁移到 C++;这是一个物理计算密集型的油藏模拟器,既没有测试套件,也没有集中化的文档。
Moving beyond code translation in legacy code modernization.遗留代码现代化改造:超越代码翻译。
Translating syntax from one language to another is a largely solved task. Asking any recent model to translate a snippet from a non-completely-obscure language to another, will likely converge to an acceptable outcome in few iterations. However, migrating a full system from a procedural language to object-oriented C++ creates the need for architectural refactors that make the task non-trivial.把语法从一种语言翻译成另一种语言,基本上已经是已解决的问题。只要让任何近期模型把一段并非完全冷门语言的代码翻译成另一种语言,通常几轮迭代就能得到可接受的结果。然而,将整个系统从过程式语言迁移到面向对象的 C++,需要进行架构层面的重构,这让任务变得并不简单。
Fortran 77 was standardized in 1977, as the name may suggest, and code written in it reflects those constraints directly: no modules, no namespaces, no structured types. State lives in COMMON blocks—global memory shared across the entire program. Variables are implicitly typed by their first letter, so a misspelled name silently creates a new variable instead of raising a compiler error.Fortran 77 于 1977 年标准化,正如其名称所示,用它编写的代码也直接反映了那些限制:没有模块,没有命名空间,没有结构化类型。状态存放在 COMMON 块中——即整个程序共享的全局内存。变量按其首字母隐式确定类型,因此拼错名称会悄无声息地创建一个新变量,而不是触发编译器报错。
For a simple but illustrative example, take the following implementation of a first-degree Taylor expansion. Inputs and outputs are globals in a COMMON block, and IC is an integer only because its name starts with a letter between I and N. Variable names are quite cryptic, as their length is capped to 6 characters.举一个简单但能说明问题的例子:下面是一阶泰勒展开的实现。输入和输出都是 COMMON 块中的全局变量,而 IC 之所以是整数,只是因为它的名字以 I 到 N 之间的字母开头。变量名相当晦涩,因为其长度被限制在 6 个字符以内。
SUBROUTINE GASDEN INCLUDE 'common.h' DO 10 IC = 1, NCELL10 RHOG(IC) = ROG(IV) + DROG(IV)*(P(IC)-PTAB(IV)) ENDIn C++, one will be able to leverage explicit types, write object-oriented code, and return a value returned instead of a global write:在 C++ 中,可以利用显式类型、编写面向对象代码,并通过返回值返回结果,而不是写入全局变量:
double gasDensity(const GasProperties& gas, double pressure) { size_t i = lookup(gas.pressure, pressure); return gas.density[i] + gas.slope[i] * (pressure - gas.pressure[i]);}The scattered COMMON arrays become a single GasProperties parameter and the grid loop moved out to the caller, so there's no line-for-line correspondence to check, which is what makes verifying the migration hard.分散的 COMMON 数组变成一个单一的 GasProperties 参数,网格循环也被移到调用方,因此不存在逐行对应的关系可供检查,这正是验证迁移的困难所在。
These structural differences, plus the requirement to integrate modern scientific computing frameworks such as PetSc, raised a few important questions even before starting the migration:这些结构性差异,再加上集成 PetSc 等现代科学计算框架的要求,甚至在开始迁移之前就引出了几个重要问题:
How to prove the migrated codebase matches the legacy one numerically如何证明迁移后的代码库与遗留代码库在数值上一致
How to split the migration into manageable chunks如何将迁移拆分成可管理的块
How to best use autonomous agents to speed up the process如何最好地利用自主智能体来加速这一过程
Building a parity harness before migrating legacy code.在迁移遗留代码之前构建一致性校验框架。
Before letting agents loose, we needed a way to prove the two codebases agreed. Here, "agreement" meant numerical equality of the outputs—both the final results and a set of critical intermediate points flagged by the client's reservoir engineers.在放手让智能体工作之前,我们需要一种方法来证明两个代码库结果一致。这里所说的“一致”,指的是输出在数值上相等——既包括最终结果,也包括客户油藏工程师标记出的一组关键中间点。
We added:我们添加了:
subroutines allowing to export the state of the Fortran codebase用于导出 Fortran 代码库状态的子程序
a test framework to load the checkpoints into C++一个将检查点加载到 C++ 中的测试框架
Skill.md files to steer agents into using them correctlySkill.md 文件,用于引导智能体正确使用这些工具

In the migration workflows, agents successfully instrumented the Fortran codebase to dump state snapshots and used the C++ test framework to verify correctness of migrated modules.在迁移工作流中,智能体成功地对 Fortran 代码库进行了插桩,以转储状态快照,并使用 C++ 测试框架来验证已迁移模块的正确性。
Building this part of the harness first was a net-positive investment for the project: it made long agent runs safer, and numerical parity is an easy-to-verify and compelling argument to show a piece of code has been successfully migrated. We believe this should be one of the first steps for any code modernization engagement.先构建校验框架的这一部分,对项目来说是一笔净收益:它让长时间的智能体运行更安全,而数值一致性是一种易于验证且有说服力的论据,可证明某段代码已成功迁移。我们认为,这应当成为任何代码现代化项目最先采取的步骤之一。
The example below illustrates this. We first inserted a line into the Fortran code to dump the value of the RHOG variable (42.71834 in this run), and then used that same value as the reference checkpoint when testing the migrated C++ module.下面的例子说明了这一点。我们首先在 Fortran 代码中插入一行,用于转储 RHOG 变量的值(本次运行中为 42.71834),然后在测试迁移后的 C++ 模块时,将同一个值用作参考检查点。

Using AI agents to understand and document legacy codebases.使用 AI 智能体理解和记录遗留代码库。
The project’s documentation was scattered across old PDFs and comments buried in the Fortran itself, and one of the largest side-wins of the whole effort was reconciling this documentation and moving it next to the code.该项目的文档散落在旧 PDF 和埋在 Fortran 代码里的注释中,而整个工作中最大的附带收获之一,就是将这些文档整理统一,并移到代码旁边。
Luckily, procedural code like Fortran has a convenient property: the whole program can be drawn as a single caller-callee tree. We generated that tree by parsing the codebase with a custom parser, then used Vibe CLI to spawn over a hundred agents to document it. Each agent could pull in the relevant PDFs through document libraries and Mistral OCR.幸运的是,像 Fortran 这样的过程式代码有一个便利特性:整个程序可以绘制成一棵单一的调用者-被调用者树。我们通过自定义解析器解析代码库,生成这棵树,然后使用 Vibe CLI 启动一百多个智能体来为它编写文档。每个智能体都可以通过文档库和 Mistral OCR 引入相关的 PDF。
Starting from the leaves of the tree and working upward, each node spawned a subagent to document it and open a PR to the original repository. A reviewer agent running in a loop on a cron schedule looked for newly opened PRs, reviewing them and scheduling fix tasks when necessary.从树的叶子节点开始向上推进,每个节点都会派生一个子智能体来为它编写文档,并向原始仓库提交 PR。一个审查智能体按 cron 计划循环运行,查找新打开的 PR,进行审查,并在必要时安排修复任务。

Utilizing the AI agents for code modernization.利用 AI 智能体进行代码现代化。
On our first attempt, we gave agents full autonomy: one agent per Fortran subroutine, each translating its function to C++ independently over the course of a week. The result was functional, but it couldn't be called code modernization. COMMON blocks became global structs, one-to-one. GOTO-driven control flow stayed intact instead of being restructured into loops or early returns. It looked like Fortran retyped in C++ syntax rather than modernized code.第一次尝试时,我们给了智能体完全自主权:每个 Fortran 子程序对应一个智能体,各自在一周内独立地将其函数翻译成 C++。结果虽然能运行,但称不上代码现代化。COMMON 块被一对一地变成全局结构体。由 GOTO 驱动的控制流原样保留,而没有重构成循环或提前返回。看起来像是用 C++ 语法重新打了一遍 Fortran,而不是现代化的代码。
In the second attempt, we addressed this by giving agents structure instead of just autonomy: a planner, a coder, a tester and a code quality reviewer working together on each module. Code quality improved substantially over the first attempt. But the source code's complexity caught up with the agents eventually. They would hit a bug, attempt a few fixes, and stall, with no one available to intervene.第二次尝试中,我们通过给智能体提供结构、而不仅仅是自主权来解决这个问题:让规划者、编码者、测试者和代码质量审查者共同处理每个模块。代码质量相比第一次大幅提升。但源代码的复杂性最终还是让智能体难以招架。它们会遇到 bug,尝试几次修复,然后卡住,而没有人能介入。
We landed on a middle ground: a human operating a workflow of coder, tester, and reviewer agents, migrating the codebase module by module. This preserved the code quality of the second attempt while adding a human checkpoint to unblock agents when they got stuck. The next section covers this workflow in detail.我们最终找到了一个折中方案:由人类操作一个包含编码、测试和审查智能体的工作流,逐模块迁移代码库。这既保留了第二次尝试的代码质量,又增加了一个人工检查点,在智能体卡住时帮它们解围。下一节将详细介绍这一工作流。
Running structured AI agent workflows for complex code migration.为复杂代码迁移运行结构化 AI 智能体工作流。
With the codebase documented and the parity harness in place, the remaining fun bit was tuning how much autonomy we could hand the agents while still getting mergeable code out. We tried both extremes, from fully autonomous runs to closely supervised manual sessions. The structured workflow below is where we landed for this use case.在代码库已有文档、一致性校验框架也已就位之后,剩下有趣的部分就是调整能给智能体多少自主权,同时仍能产出可合并的代码。我们试过两个极端:从完全自主运行到密切监督的人工操作。下面这个结构化工作流,就是我们在这一用例中最终确定的方案。
Working with the client's reservoir engineers, we used the caller-callee tree to identify independent modules—self-contained subtrees of manageable size (empirically, less than ~10’000 lines of Fortran). Each module ran through the same workflow:我们与客户的油藏工程师合作,利用调用者-被调用者树来识别独立模块——即规模可控(根据经验,少于约 10,000 行 Fortran)的自包含子树。每个模块都经过相同的工作流:
Generate the target C++ architecture.生成目标 C++ 架构。
Review it with a reservoir engineer.与油藏工程师一起审查。
On approval, break it into a task queue.批准后,将其拆分为任务队列。
Run an implementation sub-workflow per task: plan → implement → test → repeat.为每个任务运行一个实现子工作流:规划 → 实现 → 测试 → 重复。
A human reviews the resulting PRs and requests changes until they merge.由人工审查生成的 PR,并提出修改要求,直到它们被合并。
Recognizing the limits of AI assisted legacy code modernization.认识 AI 辅助遗留代码现代化改造的局限。
The first sprint covered core functionality: 40,000 of 300,000 lines. The Fortran codebase was self-contained and runnable, which is a favorable starting condition. Migrations that depend on external systems, lack a runnable baseline, or encode physics documented nowhere would bring additional challenges not discussed in this post.第一个冲刺覆盖了核心功能:300,000 行中的 40,000 行。该 Fortran 代码库自包含且可运行,这是一个有利的起点。如果迁移依赖外部系统、缺少可运行的基线,或编码了任何地方都未记录的物理模型,就会带来本文未讨论的额外挑战。
Applying three principles for modernizing complex legacy systems.应用三项原则来现代化改造复杂遗留系统。
Three lessons from this project should carry over to any large legacy migration.这个项目带来的三条经验,应当适用于任何大型遗留系统迁移。
Build the parity harness before you write migration code—numerical agreement is the cheapest, most convincing proof that a module is done.在编写迁移代码之前先构建一致性校验框架——数值一致是证明模块已完成的最廉价、最有说服力的方式。
Get the documentation in order before you lean on the agents, because you can't migrate code nobody can read.在依赖智能体之前,先把文档整理好,因为没人能读懂的代码无法迁移。
And at this scale, structured workflows with human review gates beat both full autonomy and hand-driven manual sessions.而在这种规模下,带人工审查关卡的结构化工作流,胜过完全自主运行,也胜过手动驱动的人工操作。
We are hiring!我们正在招聘!
Mistral's Applied AI team is a group of engineers building full-stack solutions around Mistral models and Enterprise platform. We ship high-stakes, domain-specific solution to solve some of the world’s hardest problems.Mistral 的应用 AI 团队由一群工程师组成,围绕 Mistral 模型和企业平台构建全栈解决方案。我们交付高风险、领域特定的解决方案,以解决世界上一些最难的问题。
If this is the kind of work you want to be involved in, apply to join our team.如果这正是你想参与的工作,欢迎申请加入我们的团队。




