跳到主要内容

代码智能体中的束搜索:为什么贪婪生成是可靠性陷阱

· 阅读需 13 分钟
Tian Pan
Software Engineer

一个通过了 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%。在需要非直观算法选择的问题上,这一差距还会进一步扩大。

实践层面的启示是:如果你正在为代码智能体实现重试逻辑,而它却持续失败,那么问题很可能出在策略层面,而非实现层面。在不尝试不同方法的情况下增加迭代优化次数,通常收效甚微。

什么时候计算开销是值得的

树搜索会成倍增加你的推理成本。束宽 (beam width) 为 10 意味着需要大约 10 倍的 token 生成预算。预算为 20 次评估的 MCTS(蒙特卡洛树搜索)需要 20 次模型调用加上评估开销。你需要仔细权衡这种交易在何时是值得的。

以下情况最适合使用搜索:

错误答案代价高昂的问题。 如果你的代码智能体生成的生产代码会被提交、评审并部署,那么一个细微漏洞的成本远超生成时 10 倍的推理成本。每个任务的计算预算是固定的,但调试错误答案的后续工程成本却是不可控的。

可获得执行反馈的情况。 没有可靠评分的搜索只是昂贵的采样。如果你有单元测试或沙盒环境可以快速验证候选方案,树搜索将放大这些基础设施的价值。如果没有这些,你就是在根据噪声进行评分,收益会迅速递减。

成功率的提升相对于计算量倍率显著。 粗略的启发式法则是:如果搜索将你的通过率从 30% 提高到 45%(相对提升 50%),那么从“单次成功输出的成本”来看,10 倍的计算倍率是收支平衡的。如果只是从 30% 提升到 33%,那你几乎是在白花钱。

可以容忍延迟。 每一个探索步骤都会增加延迟。对于用户期望亚秒级响应的交互式代码补全,树搜索是不可行的。对于处理批处理任务的自主智能体——如修复 issue、生成测试、代码评审——增加几秒钟的探索通常是可以接受的。

相反,在以下情况下应跳过搜索开销:

  • 问题很简单,你的基准通过率已经超过 80%
  • 你正在进行实时补全,延迟是首要考虑因素
  • 你没有可靠的执行反馈,且无法廉价地构建它
  • 错误答案的后续后果很轻微(用户可以轻松重试)

生产部署模式

树搜索的计算成本正在迅速下降。推理价格在两年内下降了约 100 倍,而硬件改进(量化、连续批处理、投机采样)使实际的每 token 成本比原生部署降低了 10–16 倍。2023 年昂贵到无法承受的成本,到 2026 年在生产环境的智能体工作负载中已具备经济可行性。

几种部署搜索增强型代码智能体的实践模式:

自适应搜索预算。 不要对每个任务都运行完整的树搜索。通过轻量级启发式模型或问题描述分析来估算传入问题的难度,并据此分配搜索预算。简单问题采用贪婪生成。中等问题采用 5 选 1 (best-of-5)。困难问题采用带有执行反馈的完整树搜索。这样可以在保持平均成本可控的同时,在关键点提高可靠性。

模块化约束组合。 将束宽或 MCTS 参数硬编码到智能体循环中会导致系统脆弱。相反,应将解码策略和评分约束视为可组合的组件:语法检查器、测试运行器、LLM 评分器、束宽设置。这让你可以进行 A/B 测试配置,并在不重新实现搜索逻辑的情况下适应新的问题类型。对这些配置进行自动贝叶斯优化,可以找到比手动调优的 MCTS 变体表现更好的组合(例如 SMC + 单元测试)。

投资于测试协同生成。 基于执行的搜索的限制因素通常是测试质量,而非生成质量。如果你的问题没有自带测试用例,那么在生成代码的同时生成测试——让智能体同时产生两者,然后将针对测试的执行结果作为评分信号。关于代码-测试双重生成的研究表明,这种方法比使用 LLM-as-judge 作为主要评分机制能产生更可靠的反馈循环。

记录失败的分支,而不只是最终输出。 标准的智能体检测模式只捕获输入和输出。对于基于搜索的智能体,失败的分支同样有价值——它们告诉你模型尝试了哪些策略、在何处进行了剪枝以及原因。这些数据对于诊断是搜索本身失败了(例如,所有分支都探索了错误的算法族),还是评分函数给出了错误信号至关重要。

你缺失的可靠性原语

现在的基准测试证据已经足够充分,我们可以将树搜索(tree search)视为一种可靠性原语,而不仅仅是一种研究技术。在艰巨的代码生成任务中,执行反馈引导的树探索相比于贪婪式单次生成,在无需更改模型的情况下,能将通过率提升 30%–130%。

架构原理非常直观:贪婪生成优化的是局部概率,而搜索优化的是全局正确性。当局部概率与全局正确性高度相关时——这常见于简单且普遍的问题——贪婪生成表现良好。而当二者发生偏离时——这在复杂且新颖的问题中经常发生——搜索就是通往正确输出的唯一可靠路径。

随着自主编码智能体承担起跨度更长的任务(多文件更改、跨仓库重构、测试套件生成),贪婪生成失效的问题类别也在不断扩大。那些将搜索视为推理栈核心组件而非可选增强功能的团队,最终将开发出在关键工作中真正可靠的智能体,而不仅仅是在那些旨在单次尝试即可解决的基准测试中表现出色。

References:Let's stay in touch and Follow me for more thoughts and updates