675. NeurIPS 2025 - Google Code Golf Championship | google-code-golf-2025
副标题:利用并行采样和动态基于 AST 的提示词,借助大语言模型获得第 4 名。
首先,感谢所有参与者和组织者举办这场精彩的比赛!
这是我大约 20 年来第一次在代码高尔夫(Code Golf)上花费如此多的时间。回想当年,作为一名代码高尔夫爱好者,我喜欢用 C++ 高尔夫化各种 ICPC 问题。这次,我作为 AI Agent 和测试时推理(test-time inference)的爱好者参与其中,每一刻都乐在其中。我发现自己无休止地花费时间试图推动 AI 能力的边界。实际上,比赛终于结束了,我感到如释重负☺️。
至少对于我的贡献而言,我会说我的解决方案 98% 是由大语言模型(LLM)生成的,只有大约 2% 是人工 effort。老实说,我甚至不理解大多数最终的高尔夫代码。在这里,我将描述我们团队方法中我负责的部分。
我的核心策略是让 LLM(gpt5-codex)并行使用工具执行代码高尔夫。gpt5-codex 具有非常高的工具利用能力,能够独立分析 REPL 中的 JSON 测试用例并执行各种操作。对于每个任务,我们会运行一个包含 10-30 个回合的单一会话。整个过程每天都会重复多次。单个回合的持续时间根据问题的难度而变化,从 5 分钟到超过一小时不等。
下图说明了会话中的一个“回合”。它从一个提示开始,生成 4 个并行版本。然后,评估每个生成的代码,并选择最短的有效代码。代码高尔夫通过下一个回合的后续提示继续进行。
通过实验,我发现为 LLM 提供具体的改进想法是有效的。基础后续提示很简单:
"Please make it as short as possible in bytes for Code Golf and tell me the file size."
(“请使其在代码高尔夫中字节数尽可能短,并告诉我文件大小。”)
在此基础上,我使用代码的 AST(抽象语法树)生成了额外的基于规则的提示。例如:
re 包进行代码高尔夫。这可能是突破的关键。”def 定义的,我提示它使用 lambda。虽然并不总是最优,但这通常是更好的选择。我与 grok4-code-fast-1 和 gpt5-codex 共同开发了基于 AST 的提示生成脚本。如果我在这些规则中嵌入更多特定领域的代码高尔夫知识,改进速度可能会更快。
如果分数连续 $s$ 个回合没有提高,我就终止会话。如果连续 $t$ 个回合没有改进(其中 $t$ < $s$),我会提示模型更具探索性,指令如下:
"Analyze the test cases generation code."
"Rethink a more compact algorithm."
# "Focus on reducing the number of bytes, even if it means sacrificing some functionality."
(“分析测试用例生成代码。”
“重新思考更紧凑的算法。”
# “专注于减少字节数,即使这意味着牺牲一些功能。”)
我停止使用第三个注释掉的提示,因为我发现它不是很有效。
除了 8 月的前两周,我主要使用 Codex Cloud,遵循上述框架。在 Codex Cloud 中,你不能显式选择模型,但我认为第一个月使用的是 gpt5,后两个月使用的是 gpt5-codex。我并行运行了大约 15 个会话,每个会话中的每个回合执行 4 个并行版本 (N=4)。
所有这一切都是在 ChatGPT Pro 订阅的限制内完成的。
这个工作流本质上是一个人机协同(human-in-the-loop)算法:我根据一组规则手动操作 Codex Cloud。即使我不在电脑前——在公交车上、火车上或等待航班时——我也每天都在智能手机上粘贴提示并提交,持续了三个月。感觉就像身处反乌托邦世界中的工人。
在 Codex Cloud 中每天复制粘贴的工作很痛苦,所以我尝试使用 codex exec (CLI) 和 API 积分来自动化和扩展这个过程。由于成本限制,我没有经常运行它。我在睡觉或工作时运行它。
为了创建一个安全的代码改进环境,我设置了一个 Docker 容器并在其中运行 codex exec (CLI)。这些实验的结果被记录到 SQLite 数据库中。使用像 katakate 这样的托管沙盒环境可能是更好的方法。
我还尝试了集成不同的模型,如 Grok4,但我没有花足够的时间进行提示工程,在获得好结果之前就放弃了。例如,当我将 grok4-code-fast-1 与 codex 一起使用时,我记得它试图用 curl 下载 ARC 测试数据,未能正确使用工具,并且思考过程迂回。这可能通过更好的提示调整得到改善。grok4 表现相对较好,但以惊人的速度消耗我的 API 积分,所以我很快就放弃了。
当使用 Codex Cloud (网页版) 时,模型可以访问包含先前生成代码的存储库。这通常导致它陷入局部最优,无法摆脱现有解决方案。
为了解决这个问题,当使用 codex exec (CLI) 时,我为每个新会话创建了一个干净的空白沙盒环境。这迫使模型从零开始。我记得用这种方法在几个任务上突破了一些困难的局部最优。
我也试图在 Codex Cloud (网页版) 中通过明确指示模型从头开始来实现这一点。这并不完美,但我认为它有效。提示中包含这样一行:
"Ignore the code that's already implemented and write it from scratch."
(“忽略已经实现的代码,从头开始编写。”)
在最后 2 周,我通过让 LLM 优化“压缩友好型”代码显著提高了我们的分数。这个想法是生成可以通过 zip(zopfli) 高度压缩的代码。我使用了相同的并行采样框架,但更改了评估函数,基于压缩后的文件大小进行评分。提示如下:
"This must be achieved with minimal Kolmogorov complexity and is evaluated based on the file size after zip compression."
(“这必须以最小的柯尔莫哥洛夫复杂度实现,并根据 zip 压缩后的文件大小进行评估。”)
我以为这是一个其他团队可能没有尝试过的独特改进,但最后,他们的代码通常更短,这有点令人失望。我确实有一个💎解决方案,这项技术效果特别好:Task 324。你可以在此处查看我们的压缩解决方案:https://gcgc.pages.dev/task324。
def p(a):
n=sum(a,[]);c=n.count;o=n[c(n[0])<4];f,s={},{()}
for i,e in enumerate(a):
for j,t in enumerate(e):
if c(t)<4:f[o in e and o in n[j::len(e)]]=t;s|={i+j,(i-j,)}
for i,e in enumerate(a):
for j,t in enumerate(e):
if{i+j,(i-j,)}&s:e[j]=f[o in e and o in n[j::len(e)]]
return a
我可能会稍后添加有关其他小技巧的更多细节。
最后,我要感谢我的队友 Jokrasa,尽管大学日程繁忙,他还是为这次比赛投入了大量时间。我最初对基于正则表达式改进持非常怀疑的态度,但他完全改变了我的想法。
我还要感谢 Thunder Thunder,他为我们的 AI 方法完全停滞的任务带来了老练的高尔夫球手视角。他的手动改进对于突破局部最优至关重要,正如你在我们仪表板上的解决方案历史中看到的那样。恭喜你成为 Kaggle Master!