SearchOS 里要不要开多智能体,判断依据不是这条查询读起来是否复杂,而是它需要几条互相独立的证据才能下结论。单事实查询单跳检索走一次就够,强行拆成多智能体,多出来的只是轮次和合并噪声;只有需要交叉验证,或需要分工覆盖几个互不依赖的子问题时,协作才在覆盖度上带来增量。下面的做法是把「证据数量」显式写进路由判断,再给两条路径各记一组指标,让每次拆分都能事后复盘。
先按需要的证据数量给查询分档:单事实、多来源比对、多轮追问。答案唯一、无需交叉验证、来源单一这三条同时成立时,单跳检索直接走一次,不要拆。只有出现结论冲突、独立来源不足,或子问题彼此独立且都要覆盖时,才升级到协作;升级后记录轮次数、来源数、结论是否被后续推翻,用来判断这次拆分是否值得。
先把查询按需要的证据数量分档
分档的目的不是给查询贴标签,而是让「拆不拆」有可复述的依据。建议在路由前置一步,用下面三个问题判定:结论是否只依赖一个事实点、是否需要≥2 个独立来源互相印证、是否存在若干互不依赖的子问题。三问的答案基本决定档位和最小智能体数。
| 档位 | 判定特征 | 最小智能体数 | 典型例子 |
|---|---|---|---|
| 单事实 | 答案唯一,一处来源即可确认,不需要比对;查询里只有一个待填事项 | 1(单跳检索一次) | 某个配置项默认值是多少、某条命令的参数含义 |
| 多来源比对 | 同一事实存在多处口径,或必须至少两处独立来源才能下结论 | 通常 2:分别取证 + 合并核对;来源更多时按来源数扩,但不要超过实际来源数 | 两个组件对同一字段的定义是否一致、某项限制在两处描述中的差异 |
| 需要多轮追问 | 一句话里包含 2 个以上互不依赖的子问题,或第一轮结果会决定下一轮检索什么 | 2–3,按子问题数量定,智能体数不宜多于子问题数 | 对比两套方案的迁移成本(配置、依赖、回滚路径各自成立) |
「最小智能体数」是一个下限约束,不是目标。判成单事实却起了 3 个智能体,通常说明路由条件写错了,而不是查询真的复杂。分档结果建议作为一条字段随查询一起落日志,后面复盘才有对照物。
看单跳检索在什么情况下已经够用
单跳够用的信号很集中,命中任意两条就基本可以先走一次:一是答案唯一,检索结果里只有一个候选值或一个明确结论;二是无需交叉验证,即便换个来源也只会得到同一句话;三是来源单一,这条结论本来就只存在于一个地方(内部配置、单一接口文档)。这三条同时成立时,多智能体不会让答案更准,只会让合并环节多一次出错机会。
误上协作后多出来的浪费有两类,都可以在日志里观察到:
- 轮次增加:单跳一轮就能收敛的查询,被拆成取证轮 + 合并轮 + 可能的补充轮,端到端时间变长,而答案内容与单跳一致。
- 合并引入噪声:多个分支返回同义但措辞不同的表述,合并步骤要么做无意义的选择,要么把不同语境下的结论拼在一起,反而需要人工回退。
可以先用一段简单的路由骨架把这件事固定下来,字段名按你实际的 SearchOS 配置结构替换:
route:
mode: single_hop # 单跳,检索一次即返回
when_all:
- answer_unique: true # 检索结果只有一个候选结论
- no_cross_check: true # 不需要第二处独立来源印证
- single_source: true # 该结论只存在于单一来源
fallback: escalate_rule # 不满足时交给升级规则判断
验证方式很直接:拿一批判成单事实的查询跑单跳,观察返回结果是否与协作路径的结论一致;若一致且来源相同,这类查询就可以长期留在单跳。
看协作真正带来增量的场景
协作的价值不在更快,而在覆盖度。两类场景比较典型。第一类是交叉验证:某条外部事实在两处来源里口径不同,需要分别取证再比对差异,最后由合并步骤明确「哪一处更可信、依据是什么」。第二类是分工覆盖:一条查询被拆成几个互不依赖的子问题,例如核对某项改动涉及的配置项、依赖版本、回滚路径,三条线各查各的,最后由合并步骤汇总成一份能直接执行的结果。
这两类场景里,增量体现在「有没有把该看的来源都看到」。同样的查询用单跳跑,得到的往往只是第一条命中的来源,覆盖面窄,答案是否成立取决于运气;多智能体跑则把来源清单拉齐。代价是轮次和时延上升,因此只在覆盖度确实构成风险时才值得拆。反过来,如果查询本身不涉及冲突、也不含多个子问题,协作的覆盖度优势没有发挥空间,就成了纯开销。
给两条路径各记一组可比指标
判断要能复盘,就得让单跳和协作的记录字段一致。建议至少记三项:轮次数(该查询实际走过的检索轮次)、来源数(去重后的独立来源条数)、结论是否被后续推翻(后续人工复核或其他查询给出了不同结论)。前两项偏过程,第三项偏结果,合起来才能说明拆分是否值得。
一条记录模板可以参考下面的字段,输出成 JSONL 便于按查询类型聚合:
{
"query_id": "q-0001",
"tier": "single_fact | cross_check | multi_subquestion",
"path": "single_hop | multi_agent",
"agents": 1,
"rounds": 1,
"sources": ["src-a"],
"subquestions_total": 0,
"subquestions_covered": 0,
"conflict_found": false,
"overturned_later": false,
"merged_from": [],
"notes": "答案唯一,单来源即可确认"
}
记录时注意两点:sources 要去重,同一份文档的不同段落不算多个来源;overturned_later 需要在一段时间后回填,别在查询当下就写死。等积累到能按 tier 分组的样本,再回头看「哪些档位走协作后结论被推翻得更少」,比凭印象判断可靠得多。
定一条从单跳切到协作的升级规则
触发条件要写成可判定的谓词,而不是「结果不好」「不够准」这类描述。可用的条件通常是:关键字段出现互相矛盾的取值、独立来源数不足以支撑一条外部事实、子问题清单里存在未取证的项。把这些写成配置,路由才能稳定复现。
escalate:
from: single_hop
to: fanout_verify
when_any:
- conflict: "关键字段出现 >= 1 处互相矛盾的取值"
- insufficient_sources: "独立来源数 < 2 且结论涉及外部事实"
- uncovered: "子问题清单中存在未取证的项"
max_agents: 3
stop_when: "每个子问题至少有 1 条可追溯来源,且关键字段无冲突"
切换之后需要复查的产物有四项:合并后的最终答案是否仍能追溯到具体来源;去重后的来源清单里有没有凑数的重复段落;被丢弃的分支及丢弃原因是否写着;每一轮的检索式是否还能看出从哪来。这四项里任何一项缺失,说明协作路径的实际收益无法评估,建议退回单跳再观察一轮,而不是继续加智能体。
升级规则本身也要留出回退条件,例如在 stop_when 之外再加一条「合并后仍存在未解决冲突则标记待人工复核」,避免协作路径在无法收敛时反复扩轮次。规则写进配置后,用已有的查询日志回放一遍,检查有多少原本被判为单事实的查询会被误触升级条件,再决定是否收紧阈值。