用 Codex 把 COBOL 老代码迁到 Java/Python:GPT-6.1 Sol 实测步骤、推理强度怎么选、金额舍入坑

OpenAI 10 月 19 日公布 GPT-6.1 Sol 在 COBOL 迁移评测上低推理强度 86.6%、高推理强度 97.9%。本文用 Codex 接 gpt-6.1-sol,把一个带定点金额和缺失记录的 COBOL 程序迁到 Python,低、高两档实测耗时与测试结果,并讲清截断和四舍五入的坑。

7 分钟阅读
用 Codex 把 COBOL 老代码迁到 Java/Python:GPT-6.1 Sol 实测步骤、推理强度怎么选、金额舍入坑

先说结论:OpenAI 在 2026 年 10 月 19 日发布的《Advancing coding in low-resource programming languages》里公布,GPT-6.1 Sol 在它自己的 COBOL 迁移评测上,低推理强度准确率 86.6%,上一代 GPT-5.6 Sol 同设置只有 5.4%;调到更高推理强度能到 97.9%。这些都是 OpenAI 自己测的数。

我们自己也跑了一遍:用 Codex 接本站的 gpt-6.1-sol,把一个带定点金额计算和缺失记录处理的小 COBOL 程序迁到 Python。低推理强度 113 秒、高推理强度 221 秒,两次的迁移结果都和 GnuCOBOL 编译运行原程序的输出逐字节一致,各自生成的测试全部通过。

对维护银行、金融和传统企业老系统的程序员来说,这意味着 AI 迁移老代码已经能干活了,但前提是:先拿原程序跑出真实输出当基准,再让 AI 迁,再用测试逐字节对比。

创建 API Key,开始用 gpt-6.1-sol →

两个评测怎么读

OpenAI 这次做了两个评测,测的是两种不同的能力:

  • COBOL 迁移评测:把现有 COBOL 程序迁到 C++、Java、Kotlin、Python 或 Rust。用隐藏测试检查,要求可观察输出逐字节一致,所有测试都过才算这次迁移成功。测的是「保住老程序的行为」。
  • MultiLangBench:让模型用指定语言从零写一个兼容 SQLite 的数据库引擎,覆盖 20 种语言,用 SQLite 改编来的测试检查通过率。测的是「在冷门语言里写新代码」。OpenAI 已把测试集放到 GitHub 上。
评测对比旧模型新模型
COBOL 迁移(低推理强度)GPT-5.6 Sol → GPT-6.1 Sol5.4%86.6%
COBOL 迁移(更高推理强度)GPT-6.1 Sol—97.9%
MultiLangBench 20 种语言平均(最高推理强度)GPT-5.6 Sol → GPT-6 Astra26.8%87.4%
MultiLangBench:COBOLGPT-5.6 Sol → GPT-6 Astra10.9%72.1%
MultiLangBench:FortranGPT-5.6 Sol → GPT-6 Astra21.4%83.5%
MultiLangBench:Visual BasicGPT-5.6 Sol → GPT-6 Astra27.5%89.4%
数据来源:OpenAI 官方文章 https://openai.com/index/low-resource-programming-languages/ ,均为 OpenAI 自己的评测结果。COBOL 在 MultiLangBench 里仍是最难的一门语言。

OpenAI 在文中也专门提醒:COBOL 的定点运算默认会丢掉多余的小数位,除非显式写了 ROUNDED;如果重写时改成了四舍五入,程序照样能跑、不报错,但金额会不一样。上生产前仍然需要专家复核,并按系统的业务规则和依赖做测试。

实操:用 Codex + gpt-6.1-sol 迁移一个 COBOL 程序

① 创建 API Key

在本站注册登录后,进控制台创建一个 API Key,复制下来备用。

去创建 API Key →

② 配好 Codex

Codex 的安装方法见 Codex 接入配置教程。装好后编辑全局配置文件 ~/.codex/config.toml:

toml
model_provider = "aicodewith"
model = "gpt-6.1-sol"
model_reasoning_effort = "low"

[model_providers.aicodewith]
name = "aicodewith"
base_url = "https://api.aicodewith.ai/chatgpt/v1"
wire_api = "responses"
experimental_bearer_token = "sk-你的Key"

把 sk-你的Key 换成上一步复制的 Key。model_reasoning_effort 就是推理强度,low 和 high 都可以写;也可以不改文件,在命令行用 -c model_reasoning_effort=high 临时切换。更多配置项见 config.toml 配置详解。

我们实测时先直接调用了一次接口,返回的模型 id 是 gpt-6.1-sol,Codex 运行日志里显示的也是 model: gpt-6.1-sol。

③ 准备 COBOL 示例,先跑出原程序的基准输出

示例程序读两个文件:accounts.dat 是账户和利率,txns.dat 是交易金额。每笔交易按利率算利息(COMPUTE 没写 ROUNDED,所以会截断),找不到账户的交易记一次缺失并跳过,最后输出合计。

cobol
       IDENTIFICATION DIVISION.
       PROGRAM-ID. INTEREST.
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT ACCT-FILE ASSIGN TO "accounts.dat"
               ORGANIZATION IS LINE SEQUENTIAL.
           SELECT TXN-FILE ASSIGN TO "txns.dat"
               ORGANIZATION IS LINE SEQUENTIAL.
       DATA DIVISION.
       FILE SECTION.
       FD  ACCT-FILE.
       01  ACCT-REC.
           05 A-ID          PIC X(4).
           05 A-RATE        PIC 9V9999.
       FD  TXN-FILE.
       01  TXN-REC.
           05 T-ID          PIC X(4).
           05 T-AMT         PIC 9(7)V99.
       WORKING-STORAGE SECTION.
       01  WS-EOF           PIC X VALUE "N".
       01  WS-N             PIC 99 VALUE 0.
       01  WS-I             PIC 99.
       01  WS-FOUND         PIC X.
       01  WS-TABLE.
           05 WS-ENT OCCURS 20 TIMES.
              10 WS-ID      PIC X(4).
              10 WS-RATE    PIC 9V9999.
       01  WS-INT           PIC 9(7)V99.
       01  WS-TOTAL         PIC 9(9)V99 VALUE 0.
       01  WS-MISS          PIC 99 VALUE 0.
       01  D-AMT            PIC Z,ZZZ,ZZ9.99.
       01  D-INT            PIC Z,ZZZ,ZZ9.99.
       01  D-TOT            PIC ZZZ,ZZZ,ZZ9.99.
       PROCEDURE DIVISION.
           OPEN INPUT ACCT-FILE
           PERFORM UNTIL WS-EOF = "Y"
               READ ACCT-FILE
                   AT END MOVE "Y" TO WS-EOF
                   NOT AT END
                       ADD 1 TO WS-N
                       MOVE A-ID TO WS-ID(WS-N)
                       MOVE A-RATE TO WS-RATE(WS-N)
               END-READ
           END-PERFORM
           CLOSE ACCT-FILE
           MOVE "N" TO WS-EOF
           OPEN INPUT TXN-FILE
           PERFORM UNTIL WS-EOF = "Y"
               READ TXN-FILE
                   AT END MOVE "Y" TO WS-EOF
                   NOT AT END PERFORM PROCESS-TXN
               END-READ
           END-PERFORM
           CLOSE TXN-FILE
           MOVE WS-TOTAL TO D-TOT
           DISPLAY "TOTAL INTEREST " D-TOT
           DISPLAY "MISSING ACCTS  " WS-MISS
           STOP RUN.
       PROCESS-TXN.
           MOVE "N" TO WS-FOUND
           PERFORM VARYING WS-I FROM 1 BY 1
                   UNTIL WS-I > WS-N OR WS-FOUND = "Y"
               IF WS-ID(WS-I) = T-ID
                   MOVE "Y" TO WS-FOUND
                   COMPUTE WS-INT = T-AMT * WS-RATE(WS-I)
                   ADD WS-INT TO WS-TOTAL
                   MOVE T-AMT TO D-AMT
                   MOVE WS-INT TO D-INT
                   DISPLAY T-ID " " D-AMT " INT " D-INT
               END-IF
           END-PERFORM
           IF WS-FOUND = "N"
               ADD 1 TO WS-MISS
               DISPLAY T-ID " MISSING ACCOUNT - SKIPPED"
           END-IF.

两个数据文件内容如下,注意第三笔交易的账户 A009 并不存在:

text
accounts.dat
A0010035
A0020125
A0030399

txns.dat
A001000123456
A002000099999
A009000050000
A003001234567
A001000000099

基准输出一定要用真编译器跑出来,不能让 AI「推算」。在 Debian/Ubuntu 上装 GnuCOBOL,编译运行:

bash
sudo apt-get install -y gnucobol
cobc -x INTEREST.cbl
./INTEREST > expected_output.txt

我们用 GnuCOBOL 3.2.0 跑出来的真实输出:

text
A001     1,234.56 INT        43.20
A002       999.99 INT       124.99
A009 MISSING ACCOUNT - SKIPPED
A003    12,345.67 INT     4,925.92
A001         0.99 INT         0.03
TOTAL INTEREST       5,094.14
MISSING ACCTS  01

看前两行就知道截断有多关键:1,234.56 × 0.035 = 43.2096,COBOL 给的是 43.20,四舍五入会是 43.21;999.99 × 0.125 = 124.99875,COBOL 给的是 124.99,四舍五入会是 125.00。

④ 让 Codex 迁到 Python,并生成逐字节比对测试

在放这几个文件的目录里(建议先 git init 提交一次,方便回看改动),运行:

bash
codex exec "把 INTEREST.cbl 迁移成 Python 3(interest.py),要求输出和原 COBOL 程序逐字节一致(包括定点运算截断、金额格式、缺失账户处理)。expected_output.txt 是用 GnuCOBOL 编译运行原程序得到的真实输出。再写一个 test_parity.py:运行 interest.py,把 stdout 和 expected_output.txt 逐字节比较,并额外构造几条会暴露“四舍五入 vs 截断”差异的测试数据,用 cobc 编译原程序跑出期望值做对比。最后运行测试并报告结果。"

想迁到 Java,把提示词里的 Python 3 和文件名换掉即可,比对测试的思路一样。日常怎么跟 Codex 交互,可以看 Codex 怎么用。

低推理强度那次生成的核心计算是这样的,它用整数「分」来算,并用整除实现截断,注释里也写明了原因:

python
amount = number(record[4:13])
# No ROUNDED clause: discard fractional cents before adding to total.
# Assignment to unsigned PIC fields also discards excess high digits.
interest = (amount * rates[account] // 10_000) % 1_000_000_000
total = (total + interest) % 100_000_000_000

生成的测试里专门挑了会让截断和四舍五入结果不同的边界值(比如乘出来是 0.5 分、1.5 分、0.9999 分),每组都现场用 cobc 编译原程序算期望值,而不是自己写死答案。

⑤ 低、高两档各跑一次

同一份提示词、同一份文件,分别用 -c model_reasoning_effort=low 和 -c model_reasoning_effort=high 各跑一次。结果:

推理强度耗时生成的测试和原程序逐字节一致
low113 秒6 项,全部通过是
high221 秒11 项,全部通过是

跑完后我们又自己在终端里把 python3 interest.py 的输出和 expected_output.txt 用 cmp 对了一遍,两次都完全一致。

两档的区别主要在测试覆盖:high 档额外测了 Windows 换行、末行无换行、超长行被切成多条记录等文件格式边界,并另做了 5,000 笔随机交易对比。这么小的程序 low 档已经够用;程序越大、边界情况越多,越值得开 high。

必看的坑

截断和四舍五入

COBOL 的 COMPUTE 不写 ROUNDED 就截断,而 Python 的 round()、Java 的 BigDecimal.setScale(2, RoundingMode.HALF_UP) 都是舍入。这种差异不会报错,只会让某些账的最后一分钱对不上。提示词里要写明「保留截断」,测试里要放专门暴露这个差异的数据。

缺失记录

老程序里「找不到就跳过并计数」「找不到就用默认值」这类规则往往就是业务规则本身,迁移时最容易被「顺手改进」成抛异常。示例里我们特意放了一笔不存在账户的交易。

先给老系统补测试,再迁

没有基准就没法判断迁得对不对。先用真编译器把原程序在各种输入下的输出跑出来存好,再动手迁。让 Codex 给老代码补测试的做法,可以参考 用 Codex 修真实 Bug 并跑测试;迁移前顺手清掉没用的段落,可以看 用 Codex 清理死代码。

语法能跑不等于行为一致

新代码能编译、能运行,只说明语法对了。字段宽度、溢出时丢高位、金额显示格式这些细节,只有逐字节对比输出才能发现。OpenAI 的评测也是按「所有测试逐字节通过才算成功」来算的。

怎么选模型:gpt-6.1-sol 还是 gpt-6-astra

  • 迁移现有 COBOL 代码、要求行为不变:用 gpt-6.1-sol。OpenAI 的 COBOL 迁移评测就是用它报的成绩。
  • 用 COBOL、Fortran、VB 等冷门语言写较大的新功能:可以试 gpt-6-astra。MultiLangBench 的成绩是它在最高推理强度下拿的。

想看 gpt-6.1-sol 和 Claude 的对比,见 GPT-6.1 Sol 和 Claude Opus 5.5 对比。

常见报错

常见问题

Codex 能直接迁移整个 COBOL 系统吗?

可以一个程序一个程序地迁,但每个程序都要先有用真编译器跑出的基准输出和比对测试。OpenAI 也明确说,用到生产系统前仍需专家复核,并按业务规则和依赖测试。

没装 COBOL 编译器,能让 AI 推算出原程序输出当基准吗?

不建议。基准的意义就是「真实行为」,AI 推算的输出本身可能就错在截断或格式上。GnuCOBOL 免费,一条命令就能装好。

推理强度选 low 还是 high?

小程序、逻辑简单,先用 low,速度快一倍左右;程序大、文件格式和边界情况多,用 high,它会自己补更多边界测试。我们这次两档都一次迁对。

能迁到 Java 吗?

可以。OpenAI 的评测覆盖 C++、Java、Kotlin、Python 和 Rust 五种目标语言。把提示词里的目标语言换掉,比对测试的做法不变。

查看 gpt-6.1-sol 模型页 →