乔木博客
全部
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
·
向阳乔木