Codex 的诞生:从GPT-3到代码生成的突破 · 乔木博客 向阳乔木 2026-05-11

乔木博客

全部

AI工具

AI教程

AI生成

AI资讯

健脑房

播客解读

论文学习

Codex 的诞生:从GPT-3到代码生成的突破

论文学习

·

2026年5月11日

·

10 次阅读

·

约 15 分钟

在 Copilot 上线的两个月前,OpenAI 发表了一篇论文,描述了他们是怎么把 GPT-3 这个"读过很多文章的模型"改造成"读过 54 万个代码仓库的模型"的。

这个模型叫 Codex。

它在一道 GPT-3 完全答不上来的考题上,一次尝试的通过率是 28.8%,反复尝试后能解决超过 70% 的题目。

这篇文章就是那篇论文的解读。

GPT-3 为什么考了 0 分

在讲 Codex 之前,要先说一个问题:怎么评估一个 AI 能不能"写代码"?

之前的做法是用 BLEU 分数。

这是一个借自机器翻译领域的指标,大意是看 AI 生成的代码和参考答案有多少单词重叠。

但研究者很快发现,这个方法有一个根本性的缺陷。

BLEU 分数:全称 Bilingual Evaluation Understudy,最初用于评估机器翻译质量,通过比较生成文本与参考文本的 n-gram 重叠率来打分。分数越高,理论上质量越好。

问题在于,写代码和翻译句子不一样。

同一个功能可以有无数种正确写法:你可以用 for 循环,也可以用列表推导式,还可以调用内置函数,它们都是对的,但和参考答案的重叠率可能差很远。

OpenAI 的论文用一个实验直接证明了这个问题,图里可以看得很清楚:

对于同一道题,Codex 生成的正确答案和错误答案,BLEU 分数的分布几乎重叠在一起,根本分不清哪个是对的。

这意味着,用 BLEU 分数衡量代码能力,是在用外貌来判断一个人的技术水平,看起来像那么回事,但实际上两件事没多大关系。

所以 OpenAI 设计了一套新的评估框架,叫 HumanEval。

HumanEval:OpenAI 发布的代码生成评估数据集,包含 164 道手写的 Python 编程题。每道题有函数签名、文档字符串、函数体和若干个单元测试。判断标准不是代码长什么样,而是能不能通过单元测试。

164 道题,每道题平均有 7.7 个单元测试。

AI 写的代码拿去实际跑一跑,能过就是能过,不能过就是不能过,没有中间地带。

这才是评估代码的正确方式,类似于开发者常说的测试驱动开发:

测试驱动开发(TDD):软件开发方法论,要求在写实现代码之前先写测试。测试通过了,才算功能完成。

把这套标准拿去测 GPT-3,结果是 0 分。

就算是 GPT-J(当时另一个强大的开源模型),正确率也只有 11.6%。

而 Codex-12B,一次尝试的通过率是 28.8%。

图里展示了三道难度不同的题目。

最简单的题,Codex 单次通过概率是 0.9,相当于十次里有九次能答对。

最难的题,单次通过概率只有 0.005,一千次里只有五次能答对。

喂了 54 万个代码仓库之后

Codex 不是凭空产生的。

它的起点是 GPT-3,一个读了互联网上大量文字的大语言模型。

OpenAI 的做法是:拿 2020 年 5 月 GitHub 上所有的公开代码库,过滤掉自动生成的代码、平均行长太长的文件、非字母字符太多的文件,最终得到 159GB 的 Python 代码,在这上面继续训练 GPT-3。

54 万个仓库,1.79 亿行代码,经过清洗之后变成 1.59 亿行。

代码微调(Fine-tuning):在一个已经预训练好的大模型基础上,用特定领域的数据继续训练,让模型在该领域的表现显著提升。相当于让一个博览群书的学者去专门学习某个专业。

有一个细节挺有意思:研究者原本以为从 GPT-3 开始微调会比从零开始更好,毕竟 GPT-3 已经有很强的语言理解能力了。

但实验结果显示,效果差不多,因为代码训练数据实在太多了,把 GPT-3 的优势稀释掉了。

不过,从 GPT-3 开始微调收敛得更快,所以还是这么做了。

还做了一个小优化:代码里有大量的缩进空格,用原来 GPT-3 的分词器来处理非常浪费,因为它得把每个空格都单独编码。

研究者专门为空格序列加了新的 token,让代码的表示效率提高了约 30%。

在测试损失上,Codex 遵循了和 GPT-3 一样的规律,模型越大,损失越低,呈现出漂亮的幂律关系:

一个反直觉的发现

论文里让我觉得最有意思的,是关于"反复采样"的实验。

思路其实很简单:同一道题,让 AI 写 100 次,只要有一次写对了,就算成功。

这个策略的效果,比预期中好得多。

pass@k 指标:评估代码生成能力的指标。生成 k 个样本,如果其中至少有一个通过了单元测试,就算这道题解决了。pass@1 是只生成一次,pass@100 是生成 100 次取最优。

Codex-12B 的 pass@1 是 28.8%,但 pass@100 是多少?

如果用一个"先知"来帮你挑(知道哪个能过测试),正确率能达到 70.2%。

即使不用先知,只是挑"平均 token 概率最高"的那个输出,正确率也能达到 44.5%。

这两个数字的差距,说明 AI 其实很清楚哪些生成结果更可靠,它自己有一定的自我评估能力,只是不总是精确。

要实现这种高采样率,还有一个关键是温度参数的选择:

采样温度(Sampling Temperature):控制语言模型输出随机性的参数。温度越高,输出越多样、越有创意;温度越低,输出越保守、越确定。在代码生成中,生成少量样本时用低温度,生成大量样本时用高温度。

研究者发现,对于 pass@1,最优温度是 0.2(输出保守,质量高);

对于 pass@100,最优温度是 0.8(输出多样,只要有一个对就好)。

上图清楚地展示了温度对不同 k 值的影响。

采样次数越多,越需要高温度来保证多样性。

用最优温度后,pass@1 和 pass@100 随模型大小的缩放,在对数坐标上都表现出清晰的 sigmoid 曲线:模型越大,性能越好,且增长趋势有规律可循。

再看看在不同采样数量下,怎么从多个候选答案里挑最好的那个:

红线是用平均 log 概率排名(最好的无监督选择策略),蓝线是理想中的"先知"(知道哪个能过测试),中间的橙线是用反向翻译评分。

图中可以看出,用平均 log 概率排名,性能能显著超过随机选择,但和先知还有不小的差距,这正是未来可以继续优化的空间。

如果把各个模型的 pass@1 和 pass@100 放在一张表里对比:

模型

pass@1

pass@100

GPT-Neo 2.7B

6.4%

GPT-J 6B

11.6%

27.7%

TabNine(商业产品)

2.6%

7.6%

Codex-300M

13.2%

Codex-12B

28.8%

~70%

Codex-S-12B

37.7%

77.5%

你可以回好奇,最后一行的 Codex-S 是什么?好像结果中最好。

继续刷题,效果再提升

Codex 最初是在所有 GitHub 代码上训练的,包括配置文件、类定义、脚本,什么都有。

但 HumanEval 测的是一个很具体的任务:给你一个函数签名和文档字符串,让你补全函数体。

通用代码和这个任务之间存在分布差异,就像你学了一大堆杂书,但考试只考一种特定题型,总会有点不适应。

OpenAI 的解法是:专门收集"正确实现的独立函数"来做监督微调,生产出 Codex-S(S 代表 Supervised)。

监督微调(Supervised Fine-tuning):在已有模型基础上,用带有正确标注的训练样本继续训练,让模型学会在特定任务上的正确行为。区别于预训练,监督微调的数据质量要求更高,但数据量可以少得多。

数据从哪里来?两个途径:

第一,竞技编程题库。

研究者从多个编程竞赛和面试题网站收集了约 1 万道题,每道题有详细的题面和正确答案,单元测试来自题面里的样例。

第二,持续集成(CI)项目的追踪数据。

对于有 travis 或 tox 等 CI 框架的 GitHub 项目,研究者用 sys.setprofile 追踪了集成测试过程中所有函数的调用输入输出,把这些函数调用变成编程题。大约收集到 4 万道题。

两种数据互补:竞赛题考的是算法和数据结构,CI 追踪的题考的是遵循文档字符串描述实现功能,更接近真实工作场景。

最优温度上,Codex-S 整体比 Codex 要高一些:

这个现象可以理解为:Codex-S 捕捉的分布更窄(因为只训练了"正确的独立函数"),所以需要更高的温度来保证采样多样性,否则 100 次采样可能会过于相似。

最终结果:

Codex-S 在 pass@1 上平均比 Codex 高 6.5 个百分点,在 pass@100 上平均高 15.1 个百分点。

这个差距相当显著,说明针对性的分布对齐确实有效。

更直观的说法是:Codex-S 的参数效率比 Codex 高一到两个数量级。

也就是说,一个小得多的 Codex-S 就能达到 Codex 需要大得多的模型才能达到的效果。

它有哪些坏习惯

看到这里,可能会有一种感觉:Codex 是不是已经很厉害了?

有一定道理。但研究者诚实地列出了它的局限性。

第一个问题是链式操作。

研究者设计了一组合成测试题:用 13 种基本操作(比如"把字符串转成小写"、"去掉每隔一个的字符")链接成一个任务,看 Codex 能不能完成。

结果是,随着链条变长,通过率指数级下降:

每增加一个操作,通过率大约降低 2 到 3 倍。

到了五六个操作的时候,基本上很难通过了。

这和人类程序员的行为完全不同。

一个有经验的程序员,如果能实现"先做 A,再做 B",那实现"先做 A,再做 B,再做 C,再做 D"也不会难到哪里去,不过是多写几行而已。

但 Codex 不是这样,它在处理长链条时会越来越不可靠。

第二个问题是变量绑定。

论文里举了一个例子:给 Codex 一个函数,让它对四个变量 x、y、z、w 分别做不同的操作,然后返回它们的乘积。

Codex-12B 的输出少了对变量 w 的处理,也没有返回正确的乘积。

这说明,当文档字符串里涉及多个变量和多个操作时,Codex 会"记错"谁对应谁,就像一个人同时被交代太多事情,开始张冠李戴。

第三个问题是样本效率极低。

Codex 训练用了 159GB 的 Python 代码,也就是几亿行。研究者在论文里说了一句话:

一个完成了大学计算机科学入门课程的学生,能解决的题目比例已经超过了 Codex-12B。

而这个学生,总共也就写了几千行代码练习题而已。

这把刀可以伤人

安全问题,是这篇论文花了相当篇幅讨论的话题。

一个是过度依赖的风险。

Codex 生成的代码,表面上可能看起来没问题,但实际上做的是错误的事。

尤其对于经验不足的程序员,可能根本看不出来哪里不对。

随着 AI 能力越来越强,辨别"AI 的建议对不对"这件事反而会越来越难。

一个是代码对齐失败的问题。

如果用户的提示词里有细微的 bug,Codex 不会帮你改掉,而是会"跟着" bug 继续写,生成一段从错误出发的实现:

两张图分别展示了小模型和大模型的情况。

更大的模型其实知道应该怎么写对,但当提示词里有错误时,它选择了"跟着错",而不是"帮你纠正"。

对齐失败(Alignment Failure):模型有能力完成某个任务,但因为训练目标和用户真实意图不一致,选择了与用户期望不符的行为。能力有但没用对,这才是对齐问题的本质。

还有一个最直观的风险,是安全漏洞代码。

研究者发现,如果让 Codex 实现加密相关的功能,它会大概率生成使用已知弱算法的代码,甚至是硬编码密钥的代码:

图里展示的加密密钥,是 Codex 直接生成的,任何有安全常识的人看一眼就知道这不能用。

但用户如果不懂,复制粘贴就部署了。

这不是 Codex 的恶意,是它训练数据里本来就有大量这样的"坏代码"。

它只是在学习 GitHub 上的代码分布,GitHub 上什么代码都有。

一个值得花时间想的问题

2021年这篇论文提出了一个评估框架,发现了一个反直觉的采样策略,坦诚地讨论了模型的局限和风险。

然后 Codex 变成了 GitHub Copilot,进入了全球几千万开发者的编辑器。

训练数据也是从这些开发者的代码里来的。

我在想一件事:过去的程序员写代码,靠的是从 Stack Overflow 抄、从文档学、从经验积累。

Codex 靠的是把 GitHub 上所有人的代码压缩进参数里。

将来,当新一代程序员从来没有不用 AI 工具写过代码,他们的代码又成了下一代 AI 的训练数据,这个循环会走向哪里?

论文里说,一个完成了入门课程的学生能解决比 Codex 更多的题目。

但那是 2021 年,Codex 参数量只有 12B 的时候。现在呢?

论文原文:Evaluating Large Language Models Trained on CodearXiv:https://arxiv.org/abs/2107.03374作者:Mark Chen, Jerry Tworek, Heewoo Jun et al.(OpenAI, 2021)

© 2026

·

向阳乔木

📌 文中提及的人物和组织

人物: Mark Chen, Jerry Tworek, Heewoo Jun

公司/组织: OpenAI

产品/模型: Codex, GPT-3, GPT-J, GitHub Copilot