大型语言模型 (LLM) 在软件工程领域的应用前景令人惊艳。你输入提示词,模型就能吐出可运行的代码。对于简单的任务——比如编写斐波那契数列或基本的 SQL 查询——目前的模型 (如 GPT-4) 已经相当精通。
然而,专业软件开发的现实情况往往没有那么简单。现实世界的编码涉及复杂的库 (如 TensorFlow 或 Pandas) 、复杂的逻辑以及特定的数据结构。当 LLM 面对这些“复杂代码生成”任务时,它们经常会臆造不存在的库,编写出能运行但结果错误的代码,或者无法处理边缘情况。
在这篇文章中,我们将深入探讨 CoCoST (Automatic Complex Code Generation with Online Searching and Correctness Testing,即: 基于在线搜索和正确性测试的自动复杂代码生成) ,这是一篇旨在弥合“玩具级”编码问题与现实世界开发之间差距的研究论文。CoCoST 不只是让 LLM 猜测代码;它强制模型像人类开发者一样行事: 规划、去 Google 搜索答案、编写测试,并根据实际执行结果进行调试。
问题: 为何简单的生成会失败
在理解解决方案之前,我们必须了解为什么标准的 LLM 在复杂代码上会遇到困难。研究人员指出了阻碍模型成为真正自主开发者的三个主要挑战:
- 静态知识局限: LLM 是在离线数据上训练的。如果你需要上周刚更新的某个库中的特定函数,或者问题需要训练集中不常见的函数利基组合,LLM 就会像无头苍蝇一样乱撞。
- 缺乏测试用例: 在竞技编程数据集 (如 HumanEval) 中,通常提供了测试用例。但在现实世界中,当你要求 AI “分析这个数据集”时,并没有预先写好的测试来验证输出。
- 隐蔽的 Bug: 改进 AI 代码的一种常用方法是“自我调试 (Self-Debugging) ”,即 AI 修复那些崩溃 (报错) 的代码。但在复杂的数据科学中,代码通常能运行且不崩溃,但会产生错误的结果 (例如,错误的张量形状或错误的统计计算) 。这些“静默 Bug”是最难捕捉的。
图 1 展示了人类开发者如何处理这些问题,并与标准模型进行了对比。人类不只是猜测;他们会搜索文档,写草稿,测试,然后优化。

如上所示,CoCoST 旨在模仿这种确切的人类工作流。
CoCoST 框架
CoCoST 框架在两个不同的阶段运行: 检索 (Retrieval) 和优化 (Refinement) 。
其核心理念很简单。系统不完全依赖神经网络的权重,而是主动从互联网 (StackOverflow、文档) 检索信息,然后针对生成的输入对生成的代码进行严格测试。

让我们详细拆解这两个步骤。
第一阶段: 基于战略规划的检索
在许多检索增强生成 (RAG) 系统中,模型只是简单地使用用户的提示词来搜索数据库。然而,对于复杂的编码问题,用户的提示词可能太模糊或涉及面太广,无法产生良好的搜索结果。
CoCoST 引入了一个规划 (Planning) 阶段。在写任何一行代码之前,LLM 会分析问题 (\(D\)) ,并生成一个分步计划 (\(P\)) 和一组搜索查询 (\(Q\)) 。

这意味着模型会确定它不知道什么。如果计划涉及模型不确定的特定 Pandas 操作,它会生成像“pandas calculate value counts normalized (pandas 计算归一化值计数) ”这样的查询。
然后,系统使用搜索引擎 (如 Google) 执行这些搜索,以检索 URL 并提取相关信息 (\(INFO\)) 。

利用这些最新的外部信息,模型生成初始代码 (\(W_0\)) 。这通过将生成过程建立在真实文档的基础之上,有效地解决了“幻觉”问题。

第二阶段: 通过正确性测试进行优化
这是 CoCoST 与以前的“自我修复”机制不同的地方。大多数现有方法只有在代码崩溃 (例如 TypeError) 时才进行修复。CoCoST 关注的是正确性 。
但是,如果没有标准答案,你如何验证正确性呢?作者引入了测试用例生成 (Test Case Generation) 。
生成测试用例
由于现实世界的问题没有附带单元测试,CoCoST 要求 LLM 根据问题描述生成输入 (\(I\)) 。

关键在于,模型只生成输入,不生成预期的输出。它使用这些输入来运行生成的代码并观察会发生什么。
复杂输出的挑战: 序列化
在简单的编程任务中,输出通常是整数或字符串。在复杂的数据科学任务中,输出可能是巨大的 NumPy 数组、Pandas DataFrames,甚至是 Matplotlib 图表。LLM 无法简单地“阅读”图表或原始二进制对象。
CoCoST 通过序列化 (Serialization) 解决了这个问题。它将复杂对象转换为 LLM 可以理解的基于文本的表示形式。
- DataFrames/Arrays: 转换为包含类型信息、形状和截断数据预览的字符串。
- Images (Charts): 转换为可缩放矢量图形 (SVG) 代码,这是基于文本且 LLM 可读的格式。

优化循环
系统使用生成的输入 (\(i\)) 执行代码 (\(W\)) 。它捕获执行结果 (\(o\)) 和任何错误 (\(e\)) 。

然后,LLM 充当审查者。它查看问题描述、它编写的代码,以及——至关重要的是——该代码的序列化输出 。
如果代码运行时没有报错,但产生了一个全为零的 DataFrame,而实际上应该有数值,LLM 就会检测到这个语义错误。然后它根据这个洞察优化代码 (\(\widehat{W}_{j+1}\)) 。这个循环持续进行,直到代码正确或达到限制次数。
实验结果
研究人员在两个具有挑战性的数据集上验证了 CoCoST: DS-1000 (数据科学代码生成) 和 ClassEval (面向对象的类生成) 。
DS-1000 性能表现
DS-1000 因其难度而臭名昭著,因为它涉及七个不同的 Python 库 (NumPy, Pandas, TensorFlow 等) 并需要复杂的逻辑。
如表 1 所示,CoCoST 实现了 71.71% 的 Pass@1 得分,显着优于基础 GPT-4 模型 (64.47%) 和先前的最先进方法 Self-Evolve (66.23%) 。

“Diff-Rewrite”一栏特别有趣。这代表了问题描述被改写或扰动的情况。CoCoST 在这里显示出极大的鲁棒性 (53.09% vs Self-Evolve 的 33.95%) ,表明检索和测试机制使得模型对用户如何提问不那么敏感。
ClassEval 性能表现
ClassEval 测试生成整个类而不仅仅是代码片段的能力。这需要维护内部状态和方法依赖关系。

表 2 显示了更显著的改进。CoCoST 在类级别实现了 46.3% 的 Pass@1 率,几乎是 Reflexion (24.1%) 性能的两倍。这证明了 CoCoST 的优势不仅限于数据科学脚本,还延伸到了结构化的软件工程。
按库细分
当我们查看具体库的数据时 (表 5) ,我们发现 CoCoST 在数据结构复杂且对标准文本处理“不可见”的领域表现出色,例如 Matplotlib (绘图) 和 TensorFlow/PyTorch (张量) 。

图像 (Matplotlib) 和张量的序列化允许 LLM “看到”它的图表是空的或者它的张量形状是错的,从而导致成功的优化。
案例研究: CoCoST 实战
为了真正领会该框架,让我们看看论文中的两个具体例子。
示例 1: 通过在线搜索修复逻辑
在这个 TensorFlow 示例 (图 4) 中,用户想要计算多类数据集中特定类的准确率。初始的代码猜测在语法上是正确的,但在功能上是错误的——它没有使用所需的特定 tensor_scatter_nd_update 逻辑。
通过规划搜索查询 (tensorflow tensor_scatter_nd_update usage) ,CoCoST 检索到了关于如何使用该特定函数的教程。结果是一个与“标准答案”逻辑相匹配的正确实现。

示例 2: 通过正确性测试捕捉静默 Bug
图 3 展示了优化阶段的威力。任务是比较 Pandas DataFrame 中的两行。初始代码使用了简单的比较: row0 != row8。
在 Python 中,NaN != NaN 的计算结果为 True。这是数据科学中一个经典的“坑”。代码运行没有报错,但输出是错误的,因为它将 NaN 的匹配算作了差异。
因为 CoCoST 生成了一个包含 NaN 值的测试用例并序列化了输出,LLM 看到了意想不到的结果。它意识到了错误,并优化代码以使用 isnull() 检查,正确处理了缺失数据。

基础模型的影响
CoCoST 适用于任何模型吗?表 3 比较了使用 GPT-4 与 WizardCoder (一个开源编码模型) 运行 CoCoST 的结果。

虽然 GPT-4 获得了巨大的提升,但像 WizardCoder 这样较小的模型却很吃力,有时甚至在使用该框架后表现更差。这凸显了一个关键发现: 检索和优化需要强大的推理能力。 如果模型无法规划出好的搜索查询或无法理解序列化的反馈,额外的信息就只会变成噪音。
结论
CoCoST 代表了自动代码生成领域迈出的重要一步。通过承认 LLM 无法简单地“死记硬背”所有复杂的编码逻辑,作者构建了一个模仿胜任的人类开发者行为的系统。
对于学生和从业者来说,关键要点是:
- 搜索至关重要: 通过 (经由规划查询的) 实时互联网访问来补充 LLM,解决了知识截止和幻觉问题。
- 输出很重要: 调试不应该只在代码崩溃时发生。序列化输出使得模型能够修复那些原本不可见的语义逻辑错误。
- 自我测试: 我们不需要等待人类提供的测试用例。LLM 有能力生成自己的输入来验证自己的代码。
随着像 GPT-4 这样的模型变得更快、更便宜,像 CoCoST 这样的框架很可能会成为 IDE 助手的标准配置,推动我们从“代码补全”走向真正的“代码生成”。
](https://deep-paper.org/en/paper/2403.13583/images/cover.png)