一个 search 工具能挖多深:解剖 Agent 工具箱里最不起眼的函数

search(query) -> results,看起来是 agent 工具箱里最简单的函数。结合 SWE-agent、SLIM(Lost in the Maze)、ParallelSearch、Search-R1、ZeroSearch 五篇论文,逐层解剖它的设计空间:返回什么、问什么、怎么学会用、搜索引擎本身要不要是真的——每一层都藏着能让性能翻倍或减半的决定。

Agent 工具箱里最不起眼的函数长这样:search(query) -> results。一个字符串进,一堆结果出,没有比这更简单的接口了。但有个实验值得先看:给 agent 一个”翻页式”搜索工具(像人用 Vim 那样一条条看结果),解决率 12.0%;把这个工具删掉,解决率反而涨到 15.7%;换成摘要式返回,18.0%(SWE-agent, NeurIPS 2024)。同一个函数签名,实现方式的差距大于工具本身的有无。

如果你只带走一句话,就带走这个:

search 工具的函数签名骗了你。query -> results 这一行下面至少压着四层设计决定——返回什么、问什么、怎么学会用、以及搜索引擎本身要不要是真的——每一层都有论文证明它能让性能翻倍或减半。工具越”简单”,它藏起来的设计空间越大。

这是 agent 工程系列的第四篇,也是前三篇的交汇点:search 工具是接口设计(harness 篇)最典型的案例、是上下文(遗忘篇)最大的供给侧、也是”规则让位给学习”(提示词篇)走得最远的地方。下面从外往里,一层层拆。

第一层:返回什么——搜索结果是上下文的”进口关税”

先建立一个视角:agent 每调一次 search,返回的内容就进了它的工作记忆。 上一篇讲过 context rot——上下文里的噪声会直接压低答对率 ρ\rho。所以搜索结果的呈现格式不是”显示问题”,是上下文的进口关税政策:放什么进来、放多少、以什么形态。

三个证据,从代码搜索到开放网页搜索一路成立:

证据一:格式塑造行为。 SWE-agent 的消融实验里,翻页式搜索之所以比没有搜索更糟,是因为接口给了逐条查看的能力,agent 就真的会去穷举每一条匹配——把轮数和上下文烧光。改成一次性返回摘要列表、上限 50 条、超限就提示”把查询写得更具体”,行为立刻矫正。接口的形状就是行为的模具。

证据二:search 和 browse 应该是两个工具。 COLM 2026 的 SLIM(论文标题就叫 Lost in the Maze)分析了深度研究类 agent 失败的主因:轨迹一长,“积累冗长嘈杂的内容,撞上上下文和工具预算的墙,或者提前放弃”。它的解法简单得近乎朴素——把检索拆成 search(返回轻量的标题+摘要列表,用来定位)和 browse(对选中的页面取全文,用来读)两个工具,再加定期总结轨迹。就这两条,配 o3 在 BrowseComp 拿 56%、HLE 拿 33%,超过所有开源框架 8 和 6 个点,工具调用少 4–6 倍,幻觉率显著更低。拆开的道理是关税逻辑:定位用的信息(便宜、可以宽进)和阅读用的信息(昂贵、必须严选)税率不该一样。

证据三:返回前先消化。 Search-o1 式的”reason-in-document”(先用模型把搜索结果读一遍、只把结论并进上下文)和 OpenDeepResearch、SearchSwarm 式的”子 agent 即工具”(搜索子 agent 只向主 agent 返回完成摘要,原始网页永不进入主上下文),都是同一个思想的不同深度:把消化放在工具边界内侧,让上下文只接收成品。 代价是额外的 token 开销——这是一笔”预处理税 vs 污染税”的权衡账。

第二层:问什么——agent 的查询不该长得像人的查询

传统搜索栈的每一环(查询建议、拼写纠正、结果多样化)都是为人类优化的。但 《A Multi-Agent Perspective on Modern Information Retrieval》指出了一个正在发生的错位:发查询的越来越多是 agent,它们生成的查询性质和人类根本不同——人类受打字成本约束、发短查询然后翻页;agent 可以瞬间发出十个精确的长查询,翻页反而是它的弱项(见第一层)。

这一层最实用的成果是 NVIDIA 的 ParallelSearch:很多复杂问题天然可以拆成互相独立的子查询(“A 和 B 谁的海拔更高”= 查 A + 查 B,两条可以同时发),但现有 agent 严格串行地一条条搜。它用 RL 训练模型识别可并行结构,奖励函数同时考虑答案正确性、分解质量和并行收益。结果:可并行问题上提升 12.7%,整体只用串行基线 69.6% 的 LLM 调用

注意这和上一篇 harness 的分工原则咬合得很紧:识别”这个问题能不能拆”是判断,归模型;把拆好的子查询并发执行,是物理,归 harness。 你的 search 工具支不支持批量并发调用,决定了模型学会的分解能力有没有地方施展。

第三层:怎么学会用——工具使用是训练出来的能力,不是说明书

前两层都是设计时决定。第三层的问题更根本:模型怎么知道什么时候该搜、搜什么、搜到不满意要不要换个问法?

Search-R1 的回答是:别写说明书,直接用 RL 让模型在”推理-搜索”交错的轨迹里自己学。训练时模型一边逐步推理一边自主发起(多次)检索,奖励只看最终答案对不对——DeepSeek-R1 式的 outcome reward,没有过程监督。在七个 QA 数据集上,比同设置的各种 RAG 基线提升 41%(Qwen2.5-7B)/ 20%(Qwen2.5-3B)。

这篇有个容易略过但极有含金量的工程细节:retrieved token masking——检索回来的文档 token 要从 RL 损失里屏蔽掉。道理一想就通:那些文本不是模型生成的,把别人写的文字纳入奖惩,等于让模型为它无法控制的东西负责,训练直接不稳定。这是”模型的输出是提案,环境的输入是事实”这条边界在损失函数层面的投影。

对照第一篇的主题:Claude Code 删掉提示词里的工具使用规则,是因为强模型已经在训练里内化了这些判断。Search-R1 这条线(以及后续的 R1-Searcher、StepSearch、ASearcher)就是”内化”具体发生的地方——搜索行为从提示词里的规则,变成了权重里的能力。

第四层:搜索引擎本身要不要是真的——训练环境的惊人反转

最后一层最反直觉。RL 训练搜索能力要抓着真搜索引擎大量 rollout,两个麻烦立刻出现:返回的文档质量不可控(噪声让训练不稳定)、API 成本失控(几十万次请求起步)。

阿里的 ZeroSearch 给出的解法听起来像作弊:训练时不用真搜索引擎,用另一个 LLM 假装搜索引擎。 先用轻量 SFT 把一个模型调成”检索模块”——它对任意查询既能生成有用文档、也能按指定生成噪声文档;然后课程式训练:开局给高质量文档,随训练推进逐步掺噪,让策略模型在越来越难的检索环境里逼出推理能力。

结果是全文最惊人的数字:7B 的模拟引擎训练出的搜索能力追平真搜索引擎,14B 的模拟引擎超过了真引擎。

为什么假的能赢真的?因为训练环境的价值不在”真实”,在可控。真搜索引擎的噪声是随机撒的,你无法安排它从易到难;模拟引擎的噪声是龙头拧出来的,可以精确执行课程表。这本质上是把”数据难度调度”这个老课题搬到了工具环境上——环境也是目标函数的一部分,能设计的环境好过不能设计的现实。

当然要立刻补上边界(下一节详谈):这个结论只对训练成立。推理时该用真引擎还得用真引擎——模拟引擎给不了今天早上的新闻。

合起来:一张解剖图

flowchart TD
    A["search(query) -> results"] --> B["第一层:返回什么<br/>摘要列表+上限 / search-browse 分离 / 返回前消化<br/>SWE-agent · SLIM · Search-o1"]
    A --> C["第二层:问什么<br/>agent 查询 ≠ 人类查询 / 可并行分解<br/>Multi-Agent IR · ParallelSearch"]
    A --> D["第三层:怎么学会用<br/>RL 交错训练 + retrieved token masking<br/>Search-R1 及后续"]
    A --> E["第四层:环境要不要是真的<br/>LLM 模拟引擎 + 课程加噪<br/>ZeroSearch"]
    B -.上下文供给侧.-> F["遗忘篇:context rot"]
    C -.判断归模型 物理归 harness.-> G["harness 篇:分工"]
    D -.规则内化为能力.-> H["提示词篇:从规则到判断"]

四层各自独立可挖,但有一条共同的暗线:每一层都在把”人类搜索的习惯”换成”agent 原生的形态”。 人类需要翻页,agent 需要摘要列表;人类串行搜索,agent 该并行;人类读说明书学工具,agent 在 RL 里内化;人类只能用真实的搜索引擎,agent 的训练环境可以是造出来的。search 工具的进化史,就是它逐渐忘记自己是给人用的历史。

该泼的冷水

简单方案赢了,这本身是个警告。 SLIM 用两个工具加定期总结,打败了所有精巧的多 agent 脚手架——还便宜到三分之一的成本。如果你正打算给搜索加一层 manager-worker 编排,先问问是不是两个工具加一段总结逻辑就够了。复杂度要用性能差距来买,不能用架构美感来买。

模拟环境有保质期和盲区。 ZeroSearch 的模拟引擎生成的是”从参数记忆里回忆出来的互联网”,时效性信息、长尾事实、真实网页的格式脏乱,它都模拟不了。训练能力用模拟,获取事实用真实——混淆这两件事会训出一个自信地检索着幻觉的模型。

这些数字大多来自 QA 型基准。 Search-R1 的 41% 是七个 QA 数据集上的,SLIM 的 56% 是 BrowseComp。代码搜索(SWE-agent 那种 repo 内检索)、企业内网检索、多模态检索的设计空间只有部分重叠——比如”search-browse 分离”在代码场景对应”grep 定位 + 读文件”,迁移得很好;但 ParallelSearch 的并行分解在强依赖链任务上就没有用武之地。

收束:给你的 search 工具的挖掘清单

照四层各问一个问题:

  1. 返回层:你的搜索结果是摘要列表还是原文堆砌?有没有条数上限和”查询太宽泛”的反馈?定位(search)和阅读(browse)分开了吗?
  2. 查询层:工具支持一次发多个查询并发执行吗?如果模型学会了分解问题,你的接口接得住吗?
  3. 能力层:你是在提示词里教模型”何时搜索”,还是选一个已经把搜索内化进权重的模型?前者是补丁,记得定期做第一篇说的体检。
  4. 环境层:如果你要微调自己的搜索 agent,训练环境的噪声是可控的吗?可控的假环境可能好过失控的真环境。

一个函数签名下面能压四层设计、五篇论文——这大概是 agent 工程最诚实的写照:表面越简单的东西,越值得怀疑它把复杂度藏在了哪里。


论文清单

系列:① 删掉 80% 系统提示词之后 → ② 遗忘是一种能力 → ③ 什么才是好的 Harness → ④ 本篇:把前三篇的原理压进一个函数签名。