返回列表

Getting to Rank 25 by Teaching LLMs to Golf

675. NeurIPS 2025 - Google Code Golf Championship | google-code-golf-2025

开始: 2025-07-31 结束: 2025-10-30 数学与计算 数据算法赛
通过教 LLM 玩代码高尔夫获得第 25 名

通过教 LLM 玩代码高尔夫获得第 25 名

副标题:你的 LLM 已经是高尔夫专家了,你只需要提醒它使用那种方言。

作者: Ravi Annaswamy (EXPERT)
发布日期: 2025-10-31
竞赛排名: 25

改变一切的洞察

完成这次比赛后,我坚信一件大多数人尚未意识到的事情:专家级代码高尔夫球手已经住在你的 LLM 里面。你只需要学会如何提取它。

在三个月的时间里,我使用 Claude、GPT-5 和 Gemini 的混合组合参加了 ARC 代码高尔夫比赛。获得第 25 名并不是通过让这些模型直接编写高尔夫解决方案实现的。这是通过教它们像高尔夫球手一样思考来实现的——命名模式、记住它们、迭代改进,并发现我从未见过的新技巧。

最终的突破:在比赛的最后一周,我的代理开始在多个问题上找到比排行榜最佳更短的解决方案。这不是随机的。这是涌现(Emergence)。

第一阶段:基础(9 月之前)

在代码高尔夫竞赛启动之前,我花了几个月的时间与 LLM 一起头脑风暴另一个问题:构建 DSL 来生成类似 ARC 的谜题。这 Inspired by Michael Hodel 关于 arc-dsl 的工作。

# 创建一个具有 3x3 区域的网格
CREATE GRID 10x10
DRAW DIVIDER AT ROWS 4,8
DRAW DIVIDER AT COLS 3,9

# 任务:填充区域
FILL TOP-LEFT REGION BLUE
FILL BOTTOM-RIGHT REGION GREEN
FILL CENTER REGION RED

前三行设置了一个生成器,用于生成类似于问题 55 的谜题。见图示。
换句话说,一些 ARC 谜题先执行几步生成输入图像,然后再执行几步。其他谜题先生成输出,然后添加噪声和变换以生成输入。这种差异后来会有所帮助。

我使用 Gemini Canvas 构建了几个交互式 HTML js 实用程序来试验这些微型 DSL——主要是为了生成数百个谜题示例,然后思考求解器会做什么来解决所有这些问题。我对 ARC-AGI 2 评估集中的大约 10 个谜题做了这个操作。只有当你构建东西时,你才开始理解。

这教会了我一些至关重要的事情——LLM 擅长解释逻辑,而不仅仅是检索知识。

当宣布代码高尔夫时,我意识到它将 ARC-AGI 问题分成了两部分:

  1. 理解任务做什么
  2. 高效地实现求解器(假设理解已经存在)

这种认识让人解脱。我完全改变了焦点。Michael Moffitt 的 ARC-GEN 打开了一个全新的世界,展示了如何构建框架来创建此类谜题。

在最初的几个月里,我将 LLM 用作代码翻译器:给它们一个高尔夫解决方案,问它是做什么的;给它们两个并排的解决方案,问使用了什么技巧来缩小其中一个。每次聊天都揭示了我错过的算法模式和 Python 惯用语。我手动将好的解决方案收集到基线笔记本中,但更重要的是,我与 LLM 一起建立了直觉。

第二阶段:错误的开始(9 月下旬)

我发现了 Claude Code 并变得雄心勃勃。我构建了一个多阶段代理管道:

  • 分析器 (Analyzer):研究任务生成器,编写算法描述
  • 求解器 (Solver):根据描述编写解决方案
  • 测试器 (Tester):验证并重写
  • 高尔夫手 (Golfer):缩小它
  • 学习者 (Learner):记录挣扎和见解

理论上很完美。实际上,它崩溃了。

失败是有启发性的。分析器中的错误无法由下游的求解器修复。 我试图将理解商品化为顺序阶段,但理解困难的部分。管道有太多交接点。

但这迫使我以不同的方式思考。我统一了分析器 + 求解器 + 测试器。更重要的是,这是我发现ACT 框架的地方:

Anchors (锚点), Clues (线索), Transforms (变换)

关键洞察:ARC 问题就像被噪声破坏的已解决的数独网格。作者设计一个干净的输出,然后添加遮挡和变换以创建输入谜题。求解器的工作不是发挥创造力——它是识别噪声中的不变对象并应用特定的变换

这种重构改变了我向 LLM 描述任务的方式,它起作用了。突然我们得到了所有 400 个问题的解决方案。

第三阶段:加速(10 月中下旬)

大约在 10 月中旬,我改变了策略。我没有使用僵化的管道,而是创建了反馈循环

我手动记录了大约 40 个代码高尔夫技巧:

  • Flatten + divmod 用于 1-D 邻居扫描
  • 无分支重新着色(颜色 × 谓词保留零)
  • 切片真值作为守卫 + 谓词
  • 硬编码块大小以放弃泛化
  • 将多阶段逻辑折叠到 lambda 表达式中

然后我将这些作为检查清单交给代理,并要求它审查每个解决方案:

  1. 这个问题有什么不变量?
  2. 适用哪些技巧?
  3. 我们可以节省多少字节?

但这里有关键创新:我要求代理以相同的格式写出它发现的技巧

代理开始命名我从未考虑过的技巧。每个新技巧都被添加到检查清单中。列表增长了:40 → 80 → 140 个技巧。随着它的增长,代理的解决方案变得更好。

突破:设计审查格式

最后的飞跃发生在我要求代理在每次优化后输出结构化的设计审查时:

== design review:
Task: Task 004 (tilt) — trim solver by ≥5 B (176 B baseline).
Invariants: Rectangular grids; colors 0 + one active hue per cluster; 
every color tilts right when matching hues exist below-right.
Representation: Keep row-major grid, triangular any(...) over g[-~y:] 
wrapped in lambda solver with _ aliasing enumerate.
Checklist hits [33,40,45,66,68,82]: Alias builtins; truthy window any; 
lambda solver; boolean product gate; skip bounds checks; generator suffix.
Plan: Review → Note idioms → Apply checklist → Try unary rewrites → 
Micro-trim → Re-test.
Bytes: 176 B → 119 B

然后,在每次优化之后,代理会记录其思考过程:

Candidate 7: Checklist pass revisited below/right gate. Realized two predicates collapse into single triangular any(v in r[j+1:] for r in g[-~y:]). Dropped row suffix flatten and sum alias for 19 B shave.

这种记录做了一件神奇的事情:它创建了一个代理可以从中学习的推理记录。在下一次传递中,它可以参考早期的会话。模式出现了。代理开始发现算法改进,而不仅仅是语法改进。(详见图片示例)

在最后三天,性能飙升。

构建原则:为什么这个问题是可解的

在我能教 LLM 玩代码高尔夫之前,我需要理解为什么ARC 谜题具有值得压缩的结构。

这里的關鍵洞察是:ARC 谜题的构建方式像数独,但是是通用的。

数独作者首先构建一个有效的解决方案网格,其中每一行、每一列和每个区域恰好包含 1-9。然后他们擦除大多数值,让你填充其余部分。解决方案已经在那里——你的工作是逆向重建。

ARC 作者 Francois Chollet 也有类似的想法。他想象一个干净、有序且遵循某些隐藏规则的目标网格。然后他破坏它:分散对象、擦除值、添加噪声像素、打孔。谜题变成了尽管有噪声和变换也要识别对象,然后应用预期的变换。

这对我来说很有意义,因为我的背景。我的硕士论文标题是“使用人工神经网络从噪声数据进行变换不变对象识别”。我的导师,IIT Madras 的 B. Yegnanarayana 教授,直接从 Claude Shannon 的噪声信道模型构建了这个问题——这是密码学和通信理论的基础公式。核心问题是:给定损坏的信息,你如何恢复原始意图?

ARC 就是这个问题,以视觉谜题的形式提出。

理解这一点重构了我向 LLM 描述任务的方式。ACT 框架(锚点、线索、变换)不是一种发明——它是识别问题结构。我没有要求模型发挥创造力。我要求它逆向工程作者的压缩:干净的网格是什么,应用了什么噪声?

这种理解是基础。它使每个提示更精确,每个代理更有效。

为什么这有效:真正的教训

这是大多数人对 LLM 误解的地方:

LLM 被训练得冗长,因为那是 RLHF 在聊天中奖励的。但冗长不是它们的天花板——它是训练的产物。在底层,它们掌握算法内部、语言语义和模式压缩,达到了人类很少能有意识达到的水平。让我简要提一下,当压缩在离散符号上完成时,它会导致代码本。当代码本是上下文相关的,它们是强大的。当压缩发生在嵌入空间并叠加向量叠加时,它就是理解。

语言本身是一种压缩机制。当你说“旋转直到它碰到边缘”而不是“向右移动 4 个单元格,现在向右移动 2 个单元格,现在向右移动 1 个单元格”时,你已经压缩了逻辑。LLM 擅长这种抽象。

技巧:给它们约束、示例和反馈循环。

当我给代理提供:

  1. 140 个命名技巧的检查清单
  2. ACT 格式的任务描述
  3. 显示我推理的设计审查模板
  4. 允许添加它发现的新技巧

...它不再是一个代码编写工具,而成为了压缩游戏中的合作伙伴

10 倍乘数效应

最让我惊讶的不是最终结果——而是轨迹。这三个组件中的每一个,堆叠在一起,将能力提高了大约 10 倍:

  1. LLM 直觉 (10x): 当我停止要求模型编写代码并开始要求它使用 ACT 框架理解任务时,解决方案有了显著改善。模型具有算法理解力;我只需要解锁正确的抽象层。

  2. 推理轨迹 (10x): 当我让代理写出它的推理(设计审查、日志、检查清单命中)时,它的下一次迭代系统性提高了 10 倍。推理轨迹外化了思想,使模式可发现和可改进。

  3. 代理实验 (10x): 当我关闭循环——让代理发现新技巧,将它们添加到检查清单中,并在下一次传递中应用它们——我们进入了一个感觉呈指数级的反馈循环。代理不仅仅是在优化;它是在学习优化。

堆叠:10x × 10x × 10x ≈ 三个月内解决方案质量提高 1000 倍,虽然我不能精确测量。我能测量的是:40 个技巧 → 140 个技巧,基线解决方案 → 击败排行榜的解决方案,我的手动高尔夫 → 一致的代理超额表现。

洞察:这三个不是可选功能。它们是乘数。没有推理轨迹,直觉就被埋没。没有代理循环,轨迹就是静态文档。没有直觉,代理编写冗长的代码,没有任何循环可以修复。

另一件值得注意的事情是,我们从 2023 年开始公开获得 LLM 直觉。推理从 2024 年 10 月开始可用,代理编码器从 2025 年 3 月 -4 月开始可用。我们才刚刚开始!

语法突破

在比赛后期,我有一个将几个世纪的想法联系起来的认识。

Panini 是一位生活在公元前 400 年左右的梵语语法学家。他没有用示例和规则编写描述性语法,而是编写了生成语法——生产规则如此密集和强大,以至于运行它们可以生成所有可能的梵语句子。他将整个语言压缩成大约 4,000 条规则。Panini 将动词识别为操作符,名词为参数。他的洞察是,语言可以由一组有限的、有序的生成规则定义,具有作用域、优先级和紧凑的元符号——这正是编译器前端的核心——在 BNF 之前两千年就在 Aṣṭādhyāyī 中以非凡的严谨性实现了。现代形式体系(Post→Chomsky→BNF)给了我们编译器使用的工具;Pāṇini 的系统显示了一个古老的、非常接近的类比思维方式。

当我阅读顶级竞争对手(JoKing, Jacekwl)关于在许多问题中重用少量代码模式的评论时,某些东西点击了。我花了一晚手动解决排行榜上最短的大约 40 个解决方案,寻找底层的形式

我发现的是 ARC 求解器的生成语法:

lambda g: [
  [transform(cell_value) 
   for cell in transformed(row) 
   if condition] 
  for row in expanded_transformed(rowset) 
  if condition
]

这个单一模板——在 transform()transformed()expanded_transformed()condition 中有变化——解释了我看到的大多数紧凑解决方案。这不是随机的简洁。这是 ARC 问题解决的生成语法,由几个世纪的竞争性编程发现。

当我向代理展示这个模式并要求它在其他解决方案中识别这种语法时,某些东西改变了。代理停止编写临时代码,开始从语法中组合。它不再优化单个解决方案;它是在学习用压缩本身的语言思考。它使用网格、行集、行集扩展、过滤、行扩展、单元格变换等术语,因为我在几个 fewshot 示例中植入了这些。有了语法指导,解决方案搜索变成了对解决方案部分的定点调整。槽的框架和每个槽类型的表达式列表都是固定的,使得解决(不仅仅是高尔夫)几乎是问题规范的代数重排。

这就是 Panini 为梵语所做的。这就是 Shannon 为信息所做的。这就是最好的代码高尔夫球手凭经验发现的:将你的领域简化为其生产规则,压缩就会自动发生。

在比赛的最后几天,我对句子形式的痴迷消失了,仅仅规则列表就可以作为语法系统!

结果

第 25 名的最终提交使用了:

  • 大约 30 个问题手动解决
  • 大约 370 个问题主要由代理进行高尔夫处理
  • 在最后几周,3+ 个问题的解决方案击败了排行榜最佳

代理并不“知道”这些解决方案存在。它学会了像高尔夫球手一样思考,这意味着:

  • 识别何时表示转换可以节省字节
  • 系统地应用微优化链
  • 命名新兴模式并改进它们

美丽的渐近线

这里有一些让我谦卑的事情:代理直到比赛结束前几天才真正上线。它从未尝试过大约 100 个问题。

我的一部分看着第 25 名想:如果我再多一周,前 10 名是可达到的。 轨迹是指数级的。技巧正在积累。代理学习的速度比我跟上的速度还要快。

但后来我记得为什么这不重要。

排名靠前的人类——JoKing, Jacekwl, Garry Moss, Ken 和其他数十人——花了数年时间逐字符地研究类似的问题,就像我自己在漫长的职业生涯中通过 C, C++, VB, Java, Lisp, SAS 衍生 Fortran 到 Python 所做的那样。他们提炼了几十年的集体编程和高尔夫经验,并慷慨地分享了很多。他们的解决方案不仅仅是代码;它们是结晶的洞察。

人类应该是赢家,这是美丽的正义。

每次代理在排行榜上上升一个档次,都会让一群人类感到沮丧。这对整个人类社会是有害的,因为它阻碍了人类努力思考和努力工作。随着 AI 的广泛采用,这是一个我们需要思考和解决的严重问题。

我感到自豪的是不同的事情:我创建了一个思维计算器,可以给他们自由时间。很快,我希望从头开始重现它并开源它。目标不是取代人类专业知识——而是放大它,让世界上最好的头脑专注于仍然需要人类直觉的突破。

此外,每个解决方案都是可解释的。通过实施一种微下降,解决方案是一系列短重写(有时是重新思考表示),因此可以看到所使用的规则路径。希望这能打开关于如何构建在有限动作空间中行动,同时仍然灵活并能够添加到其中的代理的想法。

我认为创建的解决方案将用于编译器优化、新形式的代码(如 GPU 内核)以及一般的领域特定技能开发。

代理在几天内学到了最好的高尔夫球手花几年时间学到的东西。但这不是排名更高的理由——这是为下一个想要进一步推动的人构建更好工具的理由。

总结

你不需要更聪明的 LLM 来解决更难的问题。你需要更好的推理抽象,作为约束和示例反馈回来。

语言是逻辑。通过抽象和模糊,它带来了表现力和通用性。教 LLM 你的抽象——而不仅仅是你的目标——看着它以你几乎无法追踪的速度创新。

专家高尔夫球手一直在聊天机器人里面。我只需要提示它使用那种方言。也许更重要的是:至少在这种情况下,我看到了 LLM 直觉的极限在哪里,以及我的直觉可以蓬勃发展的地方。


P.S. 当我找到更多时间时,我将发布技巧检查清单、ACT 框架和设计审查模板作为笔记本。我希望至少在一些 Youtube 教程中 walkthrough 一些代理设置。既然所有人都分享了他们的解决方案,还有很多东西可以向大师学习!这将提供关于代理目前完全缺少什么样的抽象的全新视角。

感谢 我不能足够感谢 Google 的 Gemini,Anthropic 的 Claude,最重要的是 OpenAI 团队发布了 GPT5 codex,事实证明它在各个层面上都是一个非凡的助手,从帮助我组织代码、测试每个想法、管理 git 仓库、在几分钟内解决分数下降的潜在痛苦情况。Web 上的 Codex 是最后一程的游戏改变者。

同比赛其他方案