代码智能体中的束搜索:为什么贪婪生成是可靠性陷阱
一个通过了 90% HumanEval 测试的代码智能体 (code agent) 并不算是一个可靠的代码智能体。它只是一个在那些设计为可以单次生成 (single-pass) 解决的问题上表现良好的智能体。如果给它一个带有严格约束的竞赛编程问题,或者一个具有微妙相互依赖关系的多文件重构任务,你会看到通过率骤降至 20–30%。模型失败并不是因为它缺乏知识,而是因为贪婪的单次生成策略会锁定在第一个看起来合理的 Token 序列上,并且永不回头。
解决方案不在于更好的模型,而在于更好的生成策略。最近的研究表明,将树状探索 (tree exploration) 应用于代码生成——在多个候选解决方案中进行分支、对部分程序进行评分并剪掉没有希望的路径——在处理难题时可以将通过率提高 30–130%,而无需更改底层的模型权重。
这不再仅仅是研究上的好奇。在过去两年中,推理成本大幅下降,树搜索 (tree search) 的计算开销对于越来越多的生产负载来说已具备经济可行性。曾经作为竞赛编程的专门技术,现在已成为工程团队构建 AI 代码智能体时的实用 可靠性原语。
为什么贪婪生成在难题面前会失效
当语言模型以贪婪方式生成代码时,它会在每个位置选择概率最高的 Token,从左到右构建输出。当正确答案也是统计上最可能的答案时,这种方法效果很好——这适用于大多数常见且表现良好的编码模式。
问题在于,难题往往需要那些在局部看起来不太可能的解决方案。解决图问题的动态规划方法可能需要在函数体早期选择一些违反直觉的数据结构。一个正确的“差一错误 (off-by-one)”修复可能需要模型锁定一个从先验分布来看似乎是“错误”的循环边界。贪婪生成一次性做出这些决定,并且永不修正。
基准测试数据证实了这一点。在 HumanEval(一组相对简单的 Python 函数实现)上,现代前沿模型通过单次生成可以达到 65–90% 的 pass@1。而在 CodeContests(要求提交单个正确方案的竞赛编程问题)上,同样的模型在贪婪生成下的表现下降到 19–32%。简单与困难之间的差距不在于模型能力,而在于搜索深度。
搜索策略分类
并非所有的搜索策略都同等有效,正确的选择取决于你的问题复杂度及延迟预算。
贪婪解码 (Greedy decoding) 是基准:单次前向传递,确定性,速度快,但在难题上经常出错。
Best-of-N 采 样生成 N 个独立的候选方案并对其进行排名。它实现简单且出奇地有效——核心见解是十个平庸候选方案中的佼佼者往往胜过任何单个方案。问题在于浪费:无论某个样本是否在第二行就明显出错,每个样本都会获得相同的计算预算。
束搜索 (Beam search) 在整个生成过程中并行维持 K 个活跃假设,并在每一步进行剪枝以保留概率最高的序列。对于结构化输出,它比 Best-of-N 的计算效率更高,但存在多样性问题。束搜索倾向于生成彼此高度相似的序列——当你要求十个束 (beam) 时,通常只会得到同一方法的微小 Token 级变体。如果主导策略是错的,那么所有十个束都是错的。
蒙特卡洛树搜索 (MCTS) 借鉴了博弈 AI。MCTS 并不维持固定的束,而是随机地探索解空间——根据估计值和探索奖励的组合来选择要扩展的分支,然后反向传播结果以更新这些估计值。它在探索多样化策略方面优于束搜索,但需要可靠的价值估计,并且对超参数调整很敏感。
具有角色专业化智能体的结构化树搜索是当前的最先进技术。与其将代码生成视为要优化的单个序列,CodeTree 等系统将任务分解为不同的角色:负责探索不同算法策略的 Thinker (思考者)、负责实现每种策略的 Solver (执行者)、负责根据测试结果优化实现的 Debugger (调试者) 以及负责对节点评分并指导扩展的 Critic (评论者)。树结构允许并行探索多种方法,而不仅仅是同一方法的多种实现。
部分程序评分:什么样的信号真正有效
任何树搜索的价值完全取决于用于为中间状态评分的信号质量。如果评分糟糕,你只是在进行昂贵的随机采样。
基于执行的反馈是可用的最强信号。 在测试用例上运行部分实现的函数——即使只有一部分通过——也能提供任何静态分析都无法比拟的语义正确性的直接证据。典型的奖励方案很简单:对失败的测试进行惩罚,对通过的所有测试进行奖励,中间状态按比例评分。关键要求是一个沙箱执行环境,能够安全地运行不可信代码并在毫秒内返回结果。
语法约束成本低廉且出奇地有用。 尽早过滤掉语法无效的部分程序——使用像 Python 的 codeop 模块这样简单的工具——可以在消耗全上下文推理预算之前消除死胡同分支。在 TreeCoder 框架中,将语法约束与单元测试验证相结合,在添加更复杂的搜索之前,就将标准基准测试的通过率从 32% 提高到了 61%。
LLM 作为裁判 (LLM-as-judge) 的评分在没有真值测试用例时填补了空白。一个更强大的模型对中间解的推理质量进行评估,提供了一个有用的近似——但它比执行反馈的噪声更大,并且增加了每个节点评估的推理成本。对于没有全面测试套件的生产系统,投资于测试生成(在生成代码的同时生成测试)通常比仅依赖 LLM 评分更值得。
过程奖励模型 (PRMs) 在中间生成步骤提供密集反馈,而不仅仅是在完成时。PRM 不必等到生成整个函数才评估质量,而是为每个推理步骤或代码块评分,从而能够及早剪掉已经偏离正确推理的路径。来自 SRA-MCTS 的实证发现表明,带有 PRM 指导的自生成推理链 (reasoning traces) 优于从更大模型中提取的蒸馏结果——一个具 有 MCTS 指导推理的 8B 模型在代码基准测试中平均提高了 5.52 个百分点,而标准的思维链 (chain-of-thought) 仅提高了 4.97 个百分点。
BFS 优于 DFS:直觉之外的发现
近期研究中最重要的实践结果之一是:在处理复杂的代码生成任务时,广度优先搜索 (BFS) 的表现始终优于深度优先迭代优化 (DFS)。
迭代优化的直觉非常诱人:生成一个解决方案,运行测试,找出错误,修复它,然后重复。这符合人类工程师调试代码的方式,也是大多数“自愈”智能体 (agent) 模式的基础。问题在于,当初始解决方案的策略从根本上就是错误的时候,再多代码行级别的调试也无济于事。你无法通过打补丁的方式将递归暴力搜索变成动态规划方案。
相比之下,BFS 探索在第一个分支点就致力于尝试多种策略。如果一种策略是错误的,搜索过程不会浪费计算资源试图挽救它,而是有其他分支可以继续发展。CodeTree 论文对此进行了量化:在 CodeContests 测试中,基于 BFS 的树搜索达到了 43.0% 的 pass@1,而优化单一初始策略的重采样方法仅为 32.7%。在需要非直观算法选择的问题上,这一差距还会进一步扩大。
实践层面的启示是:如果你正在为代码智能体实现重试逻辑,而它却持续失败,那么问题很可能出在策略层面,而非实现层面。在不尝试不同方法的情况下增加迭代优化次数,通常收效甚微。
