Universal Search — 通用搜索编排器 v5.3.2
强制搜索引擎。discover.js 是唯一真相来源。广度全量并行,深度自动迭代直到收敛。全链路锚点锁定——偏离即作废。
⚡ 快速开始(安装后必读)
安装此 skill 后开箱即用,无需任何配置。完整能力按以下步骤增强:
-
(可选)安装搜索相关 skill,装后 orchestrator 自动发现并纳入调用,零配置:
-skillhub search search— 查看可用的搜索类 skill
- 缺 API key 的 skill 会被如实标为degraded(如missing_env:BAIDU_API_KEY),不会被误调用,也不阻塞其他工具。 -
(可选)配置 API Key(仅对已安装且声明了 env 依赖的 skill 有意义):
- 写入该 skill 目录下的.env或config.json(也支持scripts/config.json)
- 或写入~/.openclaw/.env全局配置
- 或设为环境变量
- 🆕 v5.3.2:以上任一位置配置即会被discover自动识别为ready(此前仅环境变量参与 readiness 判定,配置在.env的 key 会被误标degraded)。键名需以_KEY/_TOKEN/_SECRET结尾(文件来源的安全过滤,与环境变量来源不同);orchestrate调用时自动把 key 注入子进程,无需重复 export。 -
验证发现:
node scripts/discover.js --cache确认工具清单(ready/degraded/non_executable三态) -
(可选)运行内置回归测试:
node scripts/test-fixtures/run-tests.mjs(T1-T6 共 35 断言,覆盖发现/锚点/agent-in-loop/端到端收敛/防死循环/key 本地自动发现;支持--filter T6单跑) -
一键搜索:
node scripts/orchestrate.mjs "你的查询"
> 💡 没有任何搜索 skill 或 API key 也能用:此时 orchestrator 降级为 agent-in-loop 模式——输出 status:"needs_agent_execution" 与扁平 agent_tasks 并以 exit 3 等待;agent 执行这些任务(如内置 web_search/web_fetch),把结果写入 .qwenpaw/cache/search-orchestrator/runs/<run_id>/agent_results.jsonl,再运行 node scripts/orchestrate.mjs --resume <run_id> 合并审计出最终结果。整个过程绝不把"未执行/未收敛"假报为成功(质量判据只看 converged_all_checks,见下文「结果字段消费规则」)。
🛑 硬门槛(开始搜索前,逐条过,少一条禁止搜索)
GATE-0: 先跑 discover.js --cache。不跑=违规。跳过=偷懒。没结果=别搜。
GATE-1: 从 discover 输出提取 ready 数组 → tool_count = ready_skill + ready_builtin(两类都算,见下文「GATE 更新」)
GATE-2: ready 中每个工具都必须被调用。不允许选择性调用。
GATE-3: 所有工具并行发起,不准串行、不准分批准。
GATE-QUERY: 不同工具用不同 query。中文喂中文/英文喂英文/地理加限定词。禁止同 query。
GATE-RELEVANCE: 所有 query(广度 + 深度每一轮)必须包含用户原始问题的核心关键词。偏离=无效轮次。
GATE-4: 回复前自检 tool_skip_ratio_skill = (expected_skill - called_skill) / expected_skill(脚本已算,见 gate_checklist)。
必须为 0。builtin(web_search/web_fetch/browser)由 agent 侧调用、脚本无法感知,故 tool_skip_ratio_total 为 n/a,
agent 必须自报 builtin 侧是否漏调 —— 缺了 builtin = 违规(自报格式见「agent 执行清单」⑤)。
♟️ 自动化脚本(v5.2+,当前 v5.3.2)
三个轻量脚本接管 v5.1 的手动步骤,向下完全兼容原有流程。不强制使用,但推荐所有 L1/L2 搜索先跑 prepare 再跑 audit。
scripts/prepare.mjs — 搜索前准备
echo "原始问题" | node scripts/prepare.mjs
# 输出 JSON: { anchor_words, complexity, intent, tool_queries, gate_checklist }
接管内容: 锚点提取(中英文/分隔词切割+实体识别)→ 复杂度分级(L0/L1/L2)→ 意图路由 → GATE-QUERY 分流 → GATE checklist 全量
scripts/audit.mjs — 搜索后审计
echo '{"query":"...","anchor_words":[...],"results":[...]}' | node scripts/audit.mjs
# 输出 JSON: { summary, backlink_details, signals, convergence, recommendations }
接管内容: 逐条三层回链 → 7信号自动检测 → 收敛判断 → 信息密度评分 → 低相关标记 → 建议
容错保证: 非法输入(空 query / 全空锚点 / malformed JSON / 文件不存在)一律输出结构化错误并 exit=1,不会挂起或裸栈崩溃;空锚点元素(""/纯空白)会被自动剔除,--anchor "a,,b" 中的空段会被过滤(v5.3.1 修复了空锚点导致的 CPU 死循环,T5 回归锁定)。
scripts/orchestrate.mjs — 全自动一键编排(v5.2 新增)
node scripts/orchestrate.mjs "搜索内容"
# 或: echo "搜索内容" | node scripts/orchestrate.mjs
# 一次 exec 完成 prepare → 并行搜索 → audit → 输出 JSON
自动化内容: prepare + 全工具并行调用(自动加载 API key)+ 结果归一化 + audit,输出聚合 JSON
集成方式
discover.js --cache → 环境发现(同 v5.1)
orchestrate.mjs → 🆕 一键:prepare → 并行搜索 → audit
或手动分步:
prepare.mjs → 代替人工:锚点 + Q + 门
(agent 并行搜索) → 同 v5.1
audit.mjs → 代替人工:回链 + 信号 + 收敛
(agent 决策输出/深度) → 同 v5.1
已知限制: 跨语言锚点字面匹配(中文锚点 vs 英文结果);长复合词(如"磷酸铁锂电池")未切分;信号⑤事实冲突需人工。
第零步:环境发现(强制,不可跳过)
node skills/search-orchestrator/scripts/discover.js --pretty --cache
- 首次运行:扫描 1-3 秒,写入工作区私有缓存
<workspace>/.qwenpaw/cache/search-orchestrator/discover-cache.json(权限 0600,含缓存内容校验,拒绝执行缓存中的越界模板) - 后续 1 小时内:秒级缓存命中;安装/卸载 skill 后请加
--force --cache刷新 - 手动强制刷新:加
--force(注意:--force只重扫描,需同时带--cache才写缓存)
从输出中提取:
- tools:完整工具列表及其 call.template
- ready:可直接调用的工具(id / strengths / call.template)
- degraded:缺 key 或缺依赖的工具(记录原因)
第一步:复杂度分级
| 级别 | 特征 | 处理 |
|---|---|---|
| L0 | 单一事实、标准答案("Python 最新版本号") | 单工具 + web_fetch 验证 → 跳过深度 |
| L1 | 常规查询、新闻、对比、资讯 | 全量并行 → 深度检查 → 多轮迭代 |
| L2 | 深度研究、报告、全面分析 | 全量并行 → 强制≥2轮深度 → 不收敛不停 |
铁律:不确定时走高级别。L0 升级到 L1 的门槛极低。
第二步:意图路由
按查询特征匹配意图,决定 preferred_tools 排序,但不限制最终工具集:
意图 → 偏好排序
geographic → amap-lbs 优先
chinese_news → baidu 优先
chinese_general → baidu 优先
english_news → tavily 优先
technical → web_search 优先
fact_check → web_search 优先
comparative → web_search 优先
deep_research → web_search 优先
english_general → tavily 优先
default → web_search 优先
偏好排序只影响调用顺序,不影响调用全集。
第三步:广度搜索 Round 1(全量并行,一个不漏)
工具调用规则
1. 从 discover ready 列表中取所有工具
2. 排除纯地理工具(仅 geographic 标签)——但仅限非地理意图时
3. 其余全部纳入调用列表 → 并行执行
4. L0 可只调 1 个,L1/L2 必须全量
builtin 工具
直接调系统工具:web_search / web_fetch / browser
skill 工具
从 discover 输出取 call.template,替换 {skill_dir} 为 skillPath:
discover 输出 call.template: "cd {skill_dir} && BAIDU_API_KEY=... python3 scripts/search.py '<JSON>'"
→ exec("cd /path/to/skills/baidu-search && BAIDU_API_KEY=... python3 scripts/search.py '{\"query\":\"...\"}'")
全部并行 exec 执行。某工具报错/超时→记录跳过,不阻塞其他。
GATE-QUERY:工具分流 query(禁止所有工具吃同一个 query)
不同工具擅长的语言和场景不同。必须按工具能力分流:
中文工具(baidu-search) → 中文 query,含中文关键词
英文工具(tavily / web_search) → 英文 query,语义相同但语种切换
地理工具(amap-lbs) → 加城市/坐标限定词
web_fetch → 抓 Round 1 返回的高价值 URL
browser → 仅 web_fetch 被拦截时兜底
违规: 所有工具用同一个 query = 浪费工具能力。
GATE-RELEVANCE:query 锚定规则(所有轮次强制,违反=无效搜索)
核心原则:每个 query 必须是原始问题的子集展开,不是新问题。偏离=本轮作废。
-
提取锚点词(强制执行):
- 从用户原始问题中提取 2-4 个不可丢弃的核心词(实体名、动作、主题)
- 锚点词必须是排他性限定词——换个词整个问题的语义就变了
- 示例:"中日军事冲突风险分析" → 锚点=["中日", "军事冲突"](丢掉任何一个,问题变为别的议题)
- 反例:"Python 性能优化" → 锚点=["Python", "性能优化"];"编程语言优化"=❌ 锚点已丢
- 锚点词写入本轮记录开头,每轮 query 对照检查 -
query 构造公式:
锚点词(必须原样出现) + 本轮要探索的子维度(必须是原始问题的子问题)
- ✅"中日军事冲突 2025 东海演习"(锚点 + 时间线子维度)
- ✅"US-China military tensions South China Sea 2025"(锚点译版 + 地理子维度)
- ❌"东海军事部署历史"(丢了"中日"锚点,变成泛东海议题 → 本轮作废)
- ❌"亚太安全局势分析"(锚点全丢,主题漂移 → 本轮作废)
- ❌"中国海军现代化建设"(从"中日冲突"滑向"中国海军" → 子维度脱离原始问题) -
三层检查(缺一不可):
- 层1「锚点在位」:query 中是否原样包含所有锚点词(或合理译版)?
- 层2「去锚测试」:去掉锚点词后,query 是否有独立语义?有 → 违规,主题已漂移
- 层3「回链测试」:这个 query 搜出来的结果,能直接回答原始问题的哪个部分?答不上来 → 违规 -
web_fetch 同样锚定:只抓取与原始问题直接相关的 URL。标题/摘要中不含锚点词 → 跳过。内容中锚点词出现<2次 → 低相关,仅摘录直接相关段落。
-
地理工具特殊处理:锚点词可能被地理限定词替代(如"北京周边"代替"朝阳区"),但原始问题语义必须保留。地理搜索 query 必须与原始问题有明确的地理语义关联。
-
违规处置:任何 query 未通过三层检查 → 该 query 结果标记「锚点偏离」,不计入独立源统计,不触发深度信号。整轮违规率 >30% → 本轮标记「低相关」,需重搜。
第四步:深度迭代 Rounds 2-5(自动触发,强制收敛)
L0 跳过深度。
L1:min_depth = 1 轮。 默认至少多搜一轮,除非 Round 1 已含 ≥3 个独立源且所有实体均有背景。
L2:min_depth = 2 轮。 默认至少多搜两轮,不收敛不停止。
自动触发信号(匹配任一即进入下一轮)
每轮结束时,扫描结果中是否出现以下信号。出现任意一条 → 必须进入下一轮,不可停止:
① 时效信号:查询含"最新/新闻/今天/突发/刚刚/热点/近日/本周"关键词
② 追问信号:查询含"为什么/原因/分析/对比/怎么样/具体/如何/影响/细节"关键词
③ 空壳实体:人名/公司/产品/事件名仅在结果中一笔带过,无背景展开
④ 单源数据:金额/百分比/日期/数字仅在 1 个来源中出现
⑤ 事实冲突:两个来源对同一事实描述不一致
⑥ 强要求信号:用户明确说"全面/深入/详细/研究报告/透彻"
⑦ 信息不足:整体独立源 < 3 个,或主题覆盖明显不完整
每轮执行
从上一轮结果中提取候选深挖方向 → 逐一过「锚点相关性门」 → 最多保留 3 个。
门控规则(逐条回答,缺一不可):
① 该方向源自哪个具体结果片段?(必须可追溯)
② 该方向能直接帮助回答原始问题的哪个部分?(必须明确指出来,不能用"提供背景"敷衍)
③ 去掉锚点词后,该方向是否仍有独立语义?(有→丢弃)
④ 搜索该方向后得到的信息,能在最终答案中占据≥2句话的位置吗?(不能→丢弃)
从以下维度中选至少 2 个不同维度发散(每个维度必须锚定原始问题):
- 时间线:锚点 + "起因/后续/历史背景/最新进展"(不是泛时间线——必须与锚点实体直接相关的时间节点)
- 地理:锚点 + 特定城市/地区(不是泛地理搜索——必须是锚点事件发生/影响的地理范围)
- 人物/组织:锚点 + 具体实体名(仅限结果中露名但未展开、且与锚点事件有直接参与关系的实体)
- 因果链:锚点 + "为什么会发生" / "会有什么影响"(不是独立的因果分析——因果关系必须指向锚点事件)
- 数据验证:每个单源数字/金额/日期 → 锚点 + 数字 → 找第二源(不要搜到无关领域的数字)
- 🚫 禁止方向:泛背景综述、泛领域科普、泛相关话题——这些是搜索膨胀的主要来源
↓
针对每个方向定向搜索(web_search / web_fetch / 原引擎定向 query)
每次 depth query 必须包含锚点词(遵循 GATE-RELEVANCE 三层检查)
↓
合并去重 → 过滤与锚点无关的结果(逐条过回链测试) → 检查收敛 ← 不收敛 → 再来一轮
**本轮输出前自检**:本轮新增的每条信息,能否直接填入原始问题的答案?能→保留展开,不能→压缩为一句话背景或直接丢弃。
收敛条件(全部满足才停)
✅ 每项核心结论 ≥ 2 个独立源
✅ 收敛自证:上一轮搜索新增了哪些与原始问题直接相关的独立源?列举出来。无新增相关源=收敛。
✅ 独立源总数 ≥ 3(仅统计通过回链测试的锚点相关源)
✅ 主题漂移检查:本轮新增内容 ≥80% 与锚点词直接相关。否则本轮标记「低相关」,不计入有效轮次,不计入源数。
✅ 膨胀检查:本轮新增内容中,有没有整段可以删除而不影响回答原始问题?有→未收敛,需更聚焦重搜。
✅ 达到最大轮数(L1 ≤ 4, L2 ≤ 5 — 硬上限,不管收敛与否都得停)
✅ 所有信号①-⑥已消除,且⑦已满足
✅ 信息密度合格:每条保留的信息都能回答"这一句在答案中起什么作用?"——事实支撑/因果解释/数据佐证/必要背景。答不上来→删除。
不收敛 → 继续。达到硬上限 → 强制停并标注「已达到最大轮数」。
第五步:输出
输出前强制审计(不可跳过)
每条待输出信息逐条过「回链测试」:
- 这条信息能直接回答原始问题的哪个部分?
- 去掉这条信息,原始问题的答案会缺失什么?
- 答不上来 → 删除(不降级为背景,直接删除)
信息密度自检:
- 每个段落/句子承载的独特信息量是否≥1个事实?
- 有无套话、空泛描述、无关铺垫?有→删除。
- 背景信息是否超过总篇幅的15%?超过→压缩。
最终答案结构:
结论(1-3句,直接回答)→ 核心证据(有源数据)→ 补充细节(必要时)
输出规则
- 结论先行,再展开
- 独立源 ≥ 2,每项核心结论至少 2 个独立来源支撑。仅统计通过回链测试的来源。
- 相关性过滤:所有内容必须通过回链测试。不能直接回答原始问题的信息:不展开、不保留。
- 信息密度优先:每个句子承载一个事实/数据/观点。删除铺垫、套话、重复、泛背景。
- 禁止输出:泛领域背景、泛相关话题科普、仅"可能相关"的周边信息。
- 信息来源标注(回复末尾必须包含):
【信息来源】
1. <标题> — <URL>(<引擎>)
2. <标题> — <URL>(<引擎>)
- 仅列通过回链验证的来源(
backlink_passed_results),与第 2 条「独立源仅统计回链通过」同口径;未通过回链的来源不得列入。 - 回链通过数为 0 时:如实写「本次搜索无通过回链验证的来源」——不凑数。
- 编排指标块(回复末尾必须包含,与第 6 条同时给出;字段一律取自
orchestrate.mjs/audit.mjs的真实输出,缺失字段如实写n/a,禁止编造):
【广度链路】已发现工具: N | 已并行调用: N | tool_skip_ratio_skill: N | 锚点偏离query: N
收敛: converged_all_checks=true|false | force_stopped=true|false(质量判据只看前者)
引擎: toolA + toolB + ... + builtin 自报: web_search ×N(CN/EN) / web_fetch ×N / browser ×N
锚点词: [x, y, z] | 回链通过率: X%
【深度链路】轮次: R1..Rn(total_rounds=N)| 有效轮: N
Round 2 → 锚定子方向: "XX详情" / "YY背景" | 新增源: N | 丢弃: "ZZ"(无锚点词/回链失败)
低相关轮次: R× (如有,标注原因)
收敛原因: <convergence_reason>
【汇总】X 独立源(已过滤) | Y 轮有效深度 | 锚点相关率: Z% | 信息密度: 高|中|低
- 字段口径(一一对应,不得张冠李戴):
- 已发现工具 =
tools_available长度;已并行调用 =tools_called_skill长度 tool_skip_ratio_skill=gate_checklist['GATE-4_skip_ratio'].tool_skip_ratio_skill;tool_skip_ratio_total在 builtin 侧为n/a(脚本不可感知)- 锚点偏离query =
backlink_failed_results条数 - 引擎 =
tools_called_skill(+ 本次由 agent 实际补调的 builtin 工具,次数按「agent 执行清单」⑤ 自报;0 次如实写) - 锚点词 =
anchor_words;回链通过率 =backlink_passed/results_total - 轮次/新增源/丢弃 =
round_log[]的round/new_sources/label;收敛原因 =convergence_reason - 独立源 =
backlink_passed_results长度;锚点相关率 =anchor_relevance_rate;信息密度 =information_density force_stopped=true(或result_completeness="partial")时,除指标块外还须在正文声明「结果可能不完整」(见「结果字段消费规则」)。- 降级/未收敛时不省略指标块——把真实状态写出来,正是该块存在的意义。
- 信源整合(足够信源后再整合;不足则如实声明):
整合顺序: 合并去重 → 过滤 → 分级采信 → 交叉验证 → 出结论
- 够不够的判据(用脚本真实字段,不拍脑袋):
anchor_relevance_rate ≥ 80%且「汇总」独立源 ≥ 3 且每项核心结论 ≥ 2 个独立源;辅以converged_all_checks判定(false而轮数已打满时须声明)。 - 去重:URL 归一化(去
#fragment、?query、utm 参数)后按 URL 去重;同一稿件的转载只算 1 个独立源;正文中区分「独立源数」与「独立域名数」。 - 分级采信:官方配置库/厂商官网/官方条文 > 权威媒体实测 > 自媒体稿;榜单类 SEO 稿不得作参数依据;同一数字多源冲突时不择一采信 → 标注冲突并加一轮定向核实,仍无解则标「未知」。
- 信源不足时:正文必须写明「信源不足:<缺哪一路>」并列出已穷尽的路径(限流 429 / 超时 / 官方未公布),不得用推测填充。
- 英文补源轮的来源:默认不进独立源计数;仅在与中文源或官方源交叉验证后方可并入证据,并在来源清单标注
(英文补源轮)。
🖥️ System Tool Co-Execution(内置工具并行补调)
orchestrate.mjs 是子进程,只能执行 shell 命令,无法调用 OpenClaw agent 的 web_search / web_fetch / browser 系统工具。
这些系统工具必须由 agent 并行补调,否则工具覆盖率不完整。
触发时机
| 阶段 | 系统工具 | 何时调 |
|---|---|---|
| 启动 | web_search × 2 |
与 orchestrate.mjs 同时并行启动(强制);system_tool_calls.web_search[] 里每一条都要发,一条不漏 |
| R1 后 | web_fetch |
orchestrate 第一轮结束(拿到 URL 清单后):默认全抓;>10 条按优先级取前 10(官方源/一手条文优先) |
| 补源 | orchestrate(英文轮) |
执行 system_tool_calls.pending_translation → 见「agent 执行清单」⑥ |
| 降级 | browser |
web_fetch 被拦截时兜底 |
agent 执行清单(强制)
① 跑 discover.js --cache → 确认 builtin:web_search / builtin:web_fetch 状态
② 同时并行启动(强制,不得只跑 shell 而漏 builtin):
├── exec: node orchestrate.mjs "原始问题" ← shell 子进程
├── web_search: search_term=query_CN (中文综合) ← agent 系统工具(参数名以本环境真实 schema 为准)
├── web_search: search_term=query_EN (英文交叉) ← agent 系统工具
└── 脚本已给 system_tool_calls.web_search[] 时:逐条按其中的 search_term 发(勿自造、勿只发一条)
③ orchestrate 跑完 → 读取输出中的 system_tool_calls.web_fetch
├── 默认全抓:对列出的每个 URL 调 web_fetch 取全文(深度信源的主要来源)
├── 条目 >10 时按优先级取前 10:官方源/配置库/一手条文 > 权威媒体实测 > 自媒体稿
├── 单个失败(反爬/付费墙/超时)如实记,不因此放弃整批;失败 ≥3 个时用 browser 兜底一次
└── 自报格式: `web_fetch ×N(成功S/失败F)`,失败清单在正文注明,不得静默略过
④ audit 审计时 web_search/web_fetch 的结果一并纳入回链检查
⑤ 收尾自报 builtin 侧调用(脚本不可感知,自报是唯一口径):
├── 报什么: web_search ×N(注明 CN / EN 各几次)/ web_fetch ×N(成功/失败) / browser ×N
├── 报在哪: 【广度链路】「引擎」行 +「已并行调用」后的括号(见「编排指标块」字段口径)
├── 0 次必须给出不可用原因(工具报错 / 无 key / 被拦截)——**无原因即视为漏调**
└── 确有漏调时: 必须在该轮回复中明写「本轮 builtin 侧漏调:X」,不得静默略过
⑥ 必须执行 pending_translation(英文补源轮):
├── 读 system_tool_calls.pending_translation[](脚本给出 tool / got_query / reason:
│ 载荷为纯中文 query,而该工具(如 tavily)英文检索更强,脚本无翻译能力故外包给 agent)
├── 动作:agent 自行把 query 译成英文关键词,对该工具补跑一轮
│ (例:`node orchestrate.mjs "Leapmotor D19 EREV 80.3kWh LFP SUV flat folding rear seats"`)
├── 定位:**补源轮**——只用于扩展信源(国际媒体 / 官站 / 英文一手资料);
│ **不计入主轮收敛判定**,其来源不得单独作为结论依据,须与中文源或官方源交叉验证后方可写入结论
├── 噪声过滤:英文长尾常带无关域名(实测出现域名停靠站、社交平台、无关站点),
│ 必须按锚点词 + 主题双重过滤后再纳入;过滤不掉的坚决不写进结论
└── 自报:在【广度链路】引擎行注明「英文补源轮: <EN query> → 新增 N 独立域名(已过滤 M)」
GATE 更新
GATE-0: discover → 同时列出 skill 工具 + builtin 工具
GATE-1: tool_count = ready_skill + ready_builtin(两类都算)
GATE-2: 每个 ready 工具都必须被调用 — skill 由 orchestrate 调, builtin 由 agent 调
GATE-4: tool_skip_ratio_skill = (expected_skill - called_skill) / expected_skill,必须为 0;
builtin(web_search/web_fetch/browser)脚本无法感知 → tool_skip_ratio_total = n/a,由 agent 自报
结果字段消费规则(必读:防止误读脚本输出)
脚本输出里有两个"收敛"概念,不得混用:
| 字段 | 含义 | 怎么用 |
|---|---|---|
converged |
旧口径 = allPassed \|\| forceStop(质量达标 或 轮数耗尽都为 true),仅为向后兼容保留 |
禁止单独用它判断"调研是否充分" |
converged_all_checks |
真正的质量收敛(全部 check 通过且未被硬上限截断) | 判质量只看这个 |
force_stopped |
被轮数上限截断而停止 | 为 true 时必须声明"结果可能不完整",且顶层 result_completeness 应为 partial |
result_completeness |
结果完整性:full / partial / null |
force_stopped=true 时为 partial;质量收敛时为 full;未产出完整结果时为 null |
round_log[].converged_all_checks / force_stopped |
逐轮同义字段 | 用于定位是哪一轮被截断 |
不变式:force_stopped=true ⟹ converged=true;converged_all_checks=true ⟹ converged=true ∧ force_stopped=false。
脚本退出码:0 表示 converged_all_checks=true(质量收敛);1 表示 fatal/崩溃或输入非法;2 表示执行完成但未质量收敛(含 force_stopped=true),不得当成脚本崩溃;3 表示 needs_agent_execution(已产出 agent_tasks/run_id,需 agent 执行后 --resume)。自 contract 5.3 起,exit 0 的质量判据是 converged_all_checks,不是 legacy converged。
gate_checklist['GATE-RELEVANCE_anchored'].status 为三态:
passed/failed—— audit 正常,以check_detail为准;not_audited—— audit 不可用(崩溃 / 未产出 convergence)。此时不得宣称"相关率不达标",应重跑或人工判断。
pending_translation 是脚本如实暴露的能力缺口(脚本无翻译能力,不得装作已覆盖):
web_search (EN)→ agent 自行用英文关键词补一轮;skill:*→ 该引擎缺对应语种版本,由 agent 决定是否补;GATE-QUERY_diverse.status=partial是如实状态,不是缺陷。
降级
| 场景 | 处置 |
|---|---|
| 无可执行搜索 skill / 未配 API key | agent-in-loop:输出 status:"needs_agent_execution" + 扁平 agent_tasks,exit=3;agent 执行后写 agent_results.jsonl,再 orchestrate.mjs --resume <run_id> 合并审计(contract 5.3 起) |
| 某 skill 缺 key/缺依赖 | discover 标 degraded(如 missing_env:BAIDU_API_KEY),不调用、不计入 ready,不阻塞其他工具 |
| 搜索相关但子进程不可执行(如 browser skill) | discover 标 non_executable,不进入搜索全集 |
| 仅 1 个 ready | 单工具 + web_fetch 抓 ≥2 关键页补源 |
| 某工具超时/报错 | 跳过并记录 tool_errors(含限流自动重试一次),不阻塞 |
| 全部返回空 | web_fetch 试候补 URL,诚实告知;未收敛 exit=2,不假报成功 |
| discover 报错 | 输出结构化 error:"discover_failed" 并 exit=1(致命错误不降级、不假报);agent 可临时直接用内置 web_search/web_fetch 兜底 |
示例
L1 标准搜索
用户: "中日军事冲突风险分析"
→ 锚点词提取: ["中日", "军事冲突", "风险分析"]
→ discover.js --cache → ready: [baidu, tavily, web_search, web_fetch, browser, amap-lbs]
→ L1 标准搜索,意图 chinese_news
→ 同时并行启动:
├── exec: orchestrate.mjs → baidu + tavily + ... (shell 子进程)
├── web_search: "中日军事冲突 风险分析" (agent 系统工具—中文)
└── web_search: "China Japan military conflict risk" (agent 系统工具—英文)
→ orchestrate R1 结束 → 读取 system_tool_calls.web_fetch
→ web_fetch × 3 高价值 URL 全文抓取
→ Round 1 结束:触发清单 ☑ ③空壳实体(仅名提及"东海""钓鱼岛"等未展开)
→ 过锚点门:东海→锚点+"东海军事部署"✅ / 钓鱼岛→锚点+"钓鱼岛争端"✅
丢弃项:泛"东亚地缘政治"→❌ 无关锚点,跳过
→ Round 2 深挖 2 个锚定方向
→ 收敛 → 输出
【信息来源】
1. 中日在东海的军事部署态势 — https://example.com/a(baidu-search)
2. 钓鱼岛争端与冲突风险分析 — https://example.com/b(tavily-search)
3. 中日军事冲突风险报道全文 — https://example.com/c(web_fetch 全文抓取)
【广度链路】已发现工具: 6 | 已并行调用: 2 (+ agent 补调 web_search ×2, web_fetch ×1) | tool_skip_ratio_skill: 0 | 锚点偏离query: 4
收敛: converged_all_checks=true | force_stopped=false(质量判据只看前者)
引擎: skill:baidu-search + skill:tavily-search + builtin:web_search + builtin:web_fetch
锚点词: [中日, 军事冲突, 风险分析] | 回链通过率: 92%
【深度链路】轮次: R1..R2(total_rounds=2)| 有效轮: 2
Round 2 → 锚定子方向: "东海军事部署" / "钓鱼岛争端" | 新增源: 5 | 丢弃: "东亚地缘政治"(无锚点词/回链失败)
低相关轮次: 无
收敛原因: 所有条件满足
【汇总】8 独立源(已过滤) | 2 轮有效深度 | 锚点相关率: 95% | 信息密度: 高