引言
在软件开发飞速发展的今天,像 GPT-4、CodeLlama 和 DeepSeek 这样的大型语言模型 (LLM) 已成为不可或缺的助手。它们能够生成样板代码、调试错误,甚至在不同编程语言之间进行翻译。我们已经发展到了这样一个阶段: 生成功能正确的代码——即对于给定输入能产生正确输出的代码——已成为这些模型的基本预期。
但任何经验丰富的开发人员都知道,正确性只是成功的一半。在实际应用中,特别是在高频交易、嵌入式系统或大规模数据处理领域, 效率为王。一个能工作但需要运行三个小时的排序算法,往往和完全不能工作的算法一样毫无用处。
这就引出了人工智能研究的一个关键前沿领域: 代码优化 。 我们能否教会 LLM 不仅写出能运行的代码,还能写出高效运行的代码?
最近一篇题为 “ECCO: Can We Improve Model-Generated Code Efficiency Without Sacrificing Functional Correctness?” (ECCO: 我们能否在不牺牲功能正确性的前提下提高模型生成的代码效率?) 的论文探讨了正是这个问题。研究人员发现了一个令人不安的趋势: 当前的 AI 模型通常通过作弊来实现“效率”。它们执行所谓的虚假优化 (spurious optimization) 。

如上图 1 所示,当要求模型将缓慢的线性搜索 (Linear Search) 算法优化为更快的二分查找 (Binary Search) 时,它们通常生成的代码看起来更快 (甚至因为跳过了某些步骤而运行得更快) ,但却无法产生正确的结果。这就是虚假优化: 通过破坏功能来换取速度。
在这篇文章中,我们将深入探讨 ECCO 基准测试、研究人员用于测试 LLM 的方法,以及速度、内存和正确性之间复杂的权衡。
衡量效率的挑战
在我们提高代码效率之前,我们需要一种可靠的方法来衡量它。这比听起来要难。如果你在一台高端游戏 PC 上运行一个 Python 脚本,而我在一台旧笔记本电脑上运行同一个脚本,你的执行时间会更短。这并不意味着代码更好;只意味着你的硬件更好。
以前的基准测试一直在与这种可变性作斗争。有些依赖于“硬件计数器” (精确但复杂) ,而另一些则使用像 LeetCode 这样的平台,但在范围上受到限制。
ECCO 解决方案: 可复现的评估
为了解决这个问题,作者引入了 ECCO (Ensuring Correctness in Code Optimizations,确保代码优化中的正确性) 。这是一个旨在严格测试 Python 代码优化的数据集和基准测试套件。
为了确保算法的速度得到公平衡量,无论模型在哪里运行,研究人员都使用了一个名为 JUDGE0 的平台。

如图 2 所示,评估平台在云实例上使用沙盒 Docker 容器。这充当了一个标准化的“赛道”。无论代码是来自 GPT-4 还是本地的 LLaMA 模型,它都在完全相同的虚拟 CPU 和内存配置上运行。这种隔离允许基准测试测量:
- 运行时间 (Runtime) : 代码执行所需的时间。
- 内存使用 (Memory Usage) : 执行期间消耗的峰值 RAM。
- 正确性 (Correctness) : 代码是否通过了公开 (可见) 和私有 (隐藏) 的测试用例。
数据集
ECCO 数据集非常庞大。它源自 IBM CodeNet,包含超过 50,000 对 Python 解决方案。每一对都包含同一程序的“慢速”版本和“快速”版本,涵盖了 1,300 个不同的竞赛编程问题。这使得研究人员不仅可以要求模型生成代码,还可以向其展示一个慢速版本并要求: “让它变快”。
定义任务
研究人员提出了两种截然不同的方法来测试 LLM 优化代码的能力。
1. 基于历史的程序编辑 (History-Based Program Editing)
在这种场景下,模型就像一位高级工程师在审查初级开发人员的代码。给模型一个可运行的程序 \(p_{in}\) (假设较慢) ,并要求它编辑该程序以生成 \(p_{out}\),即一个计算效率更高的版本。

这个任务很有趣,因为模型不需要从头开始发明逻辑;它有一个已经是正确的参考实现。它的唯一工作就是优化。
2. 基于自然语言指令的生成 (NL-Instructed Generation)
这是标准的“ChatGPT”体验。给模型一个问题的自然语言 (NL) 描述 (例如,“编写一个在列表中搜索数字的程序”) ,它必须从头开始生成高效的解决方案。

衡量成功
我们如何量化“更好”?论文为此引入了特定的数学指标。
加速比 (Speedup) : 这衡量了新代码相对于旧代码 (或平均用户提交) 快了多少。

内存缩减 (Memory Reduction) : 同样,这衡量了节省了多少 RAM。

对于基于自然语言指令的生成任务,由于没有“输入程序”可供比较,研究人员将生成的代码与数据库中该问题的所有用户提交的范围进行比较。


优化方法
论文的核心研究了我们如何提示或训练模型以更好地完成这项任务。作者探索了三大类方法。
1. 上下文学习 (提示工程)
这是最简单的方法。
- 指令提示 (Instruction Prompting) : 你只需告诉模型,“这是代码片段。优化它的运行时间和内存。”
- 少样本学习 (Few-Shot Learning) : 你给模型几个示例,展示慢速代码片段及其优化后的版本,然后要求它对新问题做同样的事情。
2. 迭代改进 (Iterative Refinement)
这种方法模仿了人类的调试过程。与其要求立即给出完美答案,不如允许模型分几步改进其代码。研究人员测试了三种具体的改进策略 (如下图 5 所示) :
- 自我改进 (Self-Refine) : 模型生成代码,用自然语言创建自己的反馈 (例如,“这个循环效率低下”) ,然后修复它。
- 执行反馈改进 (Exec-Refine / Interpreter Feedback) : 模型生成代码,在公开测试用例上运行,并查看实际执行输出 (例如,“错误: 超出时间限制”或“在 200ms 内通过”) 。然后它利用这些数据来修复代码。
- 自然语言 + 执行反馈改进 (NL + Exec Refine) : 一种结合方式,模型看到执行结果,生成关于为何失败/通过的口头解释,然后修复代码。

3. 微调 (Fine-Tuning)
最后,研究人员尝试了标准的模型训练。他们在 ECCO 数据集上专门微调了像 CodeLlama 和 DeepSeekCoder 这样的模型。
- 普通微调 (Vanilla Fine-Tuning) : 在 (慢,快) 对上进行训练。
- 执行条件微调 (Execution Conditioned) : 训练模型查看执行日志 (通过/失败) 并利用该上下文进行改进。
- 轨迹条件微调 (Trajectory Conditioned) : 这是一种新颖的方法,向模型展示人类如何随时间优化问题的历史——从慢速的 V1 开始,到更好的 V2,最后是最佳的 V3。
实验与关键结果
研究人员在顶尖的开源模型 (StarCoder2, CodeGemma, WizardCoder, CodeLlama, DeepSeekCoder) 和专有的 GPT-4o 上测试了这些方法。结果揭示了人工智能发展中的一个根本性张力。
正确性与效率的权衡
最重要的发现是, 现有的方法均无法在不牺牲正确性的情况下提高效率。
当模型被迫优化代码时 (尤其是通过少样本提示) ,它们经常会产生幻觉,构想出看起来高效但在逻辑上有缺陷的算法。例如,模型可能会尝试实现一个复杂的动态规划解决方案,但搞砸了基本情况,导致程序失败。
- 上下文学习: 虽然要求模型“让它变快”确实带来了更高的理论加速比 (1.07倍到2.26倍) ,但功能正确性 (Pass@1) 往往会直线下降。
- GPT-4o: 有趣的是,GPT-4o 保持了比其他模型高得多的正确性得分,但即便如此,它也难以在不引入错误的情况下持续优化代码。
执行反馈的力量
在观察迭代改进策略时,出现了一个在可靠性方面的明显赢家。
执行反馈改进 (Exec-Refine) (向模型提供原始执行日志) 是保持正确性的最佳方法。事实证明,看到“测试用例 2 失败”对 LLM 来说是一个比仅仅“思考”代码 (自我改进) 更强烈的信号。然而,虽然 Exec-Refine 保持了正确性,但它在产生巨大速度提升方面效果较差。
相反,涉及自然语言 (NL) 反馈的方法 (Self-Refine 和 NL+Exec) 更擅长提出大幅减少运行时间的激进优化,但它们也很鲁莽,经常在这个过程中破坏代码。

图 6 展示了这种痛苦的权衡。随着模型迭代次数的增加 (从迭代 1 到 4) , 加速比 (图表 b) 可能会上升,但 Pass@1 (图表 a,正确性) 会崩溃。绿线 (NL+Exec Refine) 生成了最快的代码,但也最容易出错。
模型规模重要吗?
人们可能希望简单地使用更大的模型就能解决这个问题。研究人员通过将模型从 10 亿 (1B) 参数扩展到 700 亿 (70B) 参数来测试这一点。

如图 7 所示,扩大规模有帮助,但它不是银弹。
- 正确性: 更大的模型通常更擅长编写正确的代码 (左侧的 Pass@1 图表呈上升趋势) 。
- 效率: 令人惊讶的是,更大的模型并不总是能生成更高效的代码。在某些情况下,随着模型变大,它们的“运行时间百分位” (它们的代码与人类相比有多快) 实际上会下降或停滞。这表明更大的大脑更擅长逻辑,但不一定更擅长算法效率。
微调在稳定性上获胜
研究人员发现, 微调——特别是基于轨迹的方法——是改善模型行为的最有效方式。通过在优化的逐步旅程上训练模型 (观察人类如何迭代修复代码) ,模型学会了进行更安全、更可靠的编辑。轨迹条件微调在编辑范式中实现了最高的 Pass@1 分数,显着优于提示方法。
结论: 未来的道路
ECCO 论文强调了当前 AI 能力中的一个关键差距。我们已经成功教会机器编码,但我们还没有教会它们好地编码。
当前的形势迫使我们在以下两者中做出选择:
- 高效率,低可靠性: 使用自然语言反馈提示模型承担风险并进行激进优化,通常会导致代码损坏。
- 高可靠性,低效率: 使用执行反馈或简单提示可以让代码保持工作,但会导致保守、较慢的软件。
ECCO 基准测试的引入为社区提供了弥合这一差距所需的工具。论文表明,未来的进步可能来自混合方法——结合 NL 反馈的激进优化思想与执行反馈的严格基础,或许还可以通过基于轨迹的微调进行训练。
对于进入该领域的学生和研究人员来说,信息很明确: 下一个重大突破不仅仅是生成能运行的代码;而是生成同时具备快速、精简和正确的代码。“虚假优化”的时代必须结束;真正的自动化软件工程时代才刚刚开始。
](https://deep-paper.org/en/paper/2407.14044/images/cover.png)