搜了三十次,报告还在长
周五下午,一个研究助手接到任务:“把这个行业最近一年的变化写清楚”。它调用搜索工具三十四次,读了六十一个页面,交出一份四千二百字的报告,引用二十二条。
看起来很勤奋。但读完你会发现:核心问题一个没答,反而多出三个子问题;二十二条引用里,有九条是同一份通稿的转载;三条结论互相打架,因为其中一条引用的是去年八月的旧公告。
问题不在模型不勤快,恰恰在于它太勤快。
很多 Agent 的搜索循环 写成这样:“没找到答案,就再搜一次”。找到什么算答案?谁说了算?没人定义。于是搜索变成一种无法停止的活动,而活动看起来像进展。
搜索次数不是研究进度
先把一个误区摆正:并不是搜索越多、引用越多,结论就越可靠。这句话在 Agent 场景里特别有欺骗性,因为它让“继续搜”永远看起来像一个负责的选择。
真正决定报告质量的是三件事:
- 重要问题有没有被回答,这是覆盖;
- 每条结论有没有证据支撑,这是支持;
- 证据彼此是不是独立,这是独立性。
多搜十次可能一条都不增加;把一条被三篇转载支撑的结论当成三方交叉验证,是把同一个证据数了三遍。
所以 研究型 Agent 的第一件事不是搜索,而是把“研究”变成一份有结构的计划。
第一步:把问题拆成可核验的子问题
不要从关键词开始,要从问题开始。一个研究问题至少要拆出四个维度:
- 范围:哪些算这个对象,哪些不算;
- 时间:截止到哪一天,“最近一年”从哪天算起;
- 对象:具体是哪几家公司、哪几个版本、哪几个地区;
- 待回答的子问题:每一问都要能被某个具体证据回答。
每个子问题还要配两样东西:需要的证据类型,和接受条件。
| 子问题 |
需要的证据类型 |
接受条件 |
状态 |
| 最近一年有哪些版本发布 |
官方发布说明 |
至少一份官方原始公告,带明确日期 |
未覆盖 |
| 定价策略是否变化 |
官方定价页历史快照 |
两期快照对比,且来自同一来源 |
部分覆盖 |
| 用户规模是否增长 |
可核验的第三方统计 |
两个独立来源,方法说明可见 |
未覆盖 |
这张表就是研究计划表。它先于搜索存在,搜索是为了把格子填上,不是为了产出文字。
一个判断表是否合格的简单办法:把表交给一个没参与讨论的人,问他“你现在知道该搜什么、去哪搜、搜到什么程度算够”。
第二步:线索不是证据
搜索结果页给的标题、摘要、链接,都只是线索。能进报告的,是打开原页之后抽出来的东西。
抽取时记三样:断言、日期、来源。其中日期最容易出错,因为它有三个:
- 发布日期:这份材料什么时候写出来的;
- 事件时间:它讲的事情什么时候发生的;
- 研究截止日期:我的研究到哪天为止。
三者混在一起,“去年成立的做法”会被写成“目前的做法”,旧版定价页会被当成当前定价页。这是研究类报告里最常见、也最贵的错。
还有一条纪律:来源打不开就标成打不开,不要凭摘要补全文结论。摘要只给结论,不给限定条件,而限定条件往往才是关键。
第三步:多个域名,可能只是一份证据
转载、同稿分发、互相引用,是开放检索里最常见的重复计数。
做法是维护一张来源谱系:每条证据记下它的首发出处,以及后来谁转载了它。一份通稿被五个媒体转载,在谱系上是一个原始出处、四个转载,不是五份独立证据。
判断独立性的两个信号:
- 措辞高度一致:同一段话、同一组数字、同一张图,几乎必然同源;
- 引用关系:A 引用 B,B 引用 C,追溯回最早那一份。
追溯时优先回到原始出处:官方公告、原始论文、财报原文。如果回到原始出处都困难,说明这条证据本身就该降级,而不是换个域名再搜一次。
第四步:每次追加搜索都要有理由
搜索的触发条件 不该是“还没找到”,而该是“这个缺口还没被覆盖”。
每次发起检索前先写一句话:这次搜索是为了回答哪个子问题、填哪条证据缺口。写不出来的搜索,就不该发出去。
这带来两个直接好处:已经足够支持的部分不会反复扩大候选,预算花在真正空的地方;事后复盘时,哪几次搜索没有收益,一眼看得出来。
搜索记录要留成一张表,每行一次检索:
| 序号 |
对应子问题 |
要填的缺口 |
查询式 |
新增有效证据 |
| 1 |
版本发布 |
缺官方公告 |
官方站点 发布说明 |
是 |
| 2 |
定价变化 |
缺历史快照 |
定价页 存档 |
否,只找到当前页 |
| 3 |
用户规模 |
缺方法说明 |
用户规模 统计方法 |
是 |
这张表还有个副作用:它能直接当运行摘要的素材。任务结束时,哪些子问题还是空的、哪些查询没有收益,一目了然。
第五步:停止条件
停止不该由模型“感觉差不多了”来决定,要提前写死三种信号:
- 新增有效证据:最近连续 N 次检索没有带来任何新的、独立的、能填进计划表某个格子的证据;
- 关键缺口:剩下的缺口是否重要到必须继续,取决于这个决定要花多少钱、错了代价多大;
- 剩余预算:搜索次数、费用、时限,三者取最先触顶的那个。
停止条件的决策树可以这样写:
def should_stop(gaps, budget, recent_new_evidence):
if gaps.critical and budget.remaining():
return "search_again", gaps.top_critical()
if recent_new_evidence == 0:
return "deliver_with_gaps", gaps.list()
return "write_report", None
第二种情况并不是失败。把“我没能确认 X”写进报告,比编一个看起来完整的答案有价值得多。
三个信号不是并列的三选一,而是有优先级的。关键缺口优先于无新增,因为无新增只说明搜索这个手段暂时没进展,换个角度再搜可能就通了;但如果预算已经用尽,再怎么有关键缺口,也只能带着缺口交付。
还有一种情况要单独对待:某个来源反复打不开。这不是“再搜一次”能解决的,该做的是换证据类型,或者把这个子问题标成受限,在报告里写明它没有被验证。
事实、推断、建议要分开写
最后一层是写作纪律。报告里三类句子必须能分开:
- 检索事实:“官方公告写明 X”,后面挂来源;
- 跨来源推断:“结合两份资料看,Y 可能成立”,标明这是推断;
- 建议:“建议下一步做 Z”,标明这是建议。
混在一起,读者没法判断哪些部分可以直接引用,哪些需要自己再核一遍。
还有一条:报告长度不代表研究质量。一份一千五百字、写清三条结论和两个缺口的研究,通常比四千字的综述更有用。
你现在该做什么
- 把手上的研究问题拆成子问题表,每问写清证据类型和接受条件,先有表再搜。
- 每次搜索前写下它对应哪个缺口,事后删掉没有收益的那些。
- 给每条证据记发布日期、事件时间和研究截止日期,三者分开存。
- 建来源谱系,转载只算一份,追溯回首发出处。
- 写死停止条件:连续几次算无新增、哪个缺口必须补、预算怎么封顶。
- 报告分三段写:检索事实、跨来源推断、建议。
- 覆盖不足时交付有限结论和缺口,不拿摘要补全文。
第五条是大多数团队漏掉的。搜索预算不设上限,Agent 就一定会把预算花光,而且往往花在没有价值的地方。
到这里,搜索策略算是有了形状:拆问题、追原页、辨谱系、按缺口搜、按信号停。但这些仍然停在方法论层面,落不到工程上就还是纸上谈兵。真正难的是下一步:把它变成一个能交付、能恢复、能被审阅的东西。