- name
- web-research-router
- description
- Searches the web, finds papers, explores GitHub source code, verifies facts, searches social/video/forum platforms (Twitter/Reddit/B站/小红书/YouTube/V2EX/雪球/小宇宙/RSS via Agent-Reach), and runs multi-step deep-research loops using Exa/Brave/web_search/Tavily/SearXNG (5 engines) plus local knowledge (Supermemory/qmd/Obsidian/CodeGraph). Includes verbatim-quote extraction (anti-hallucination), query decomposition, and forced-answer fact-recall. Use when the user needs to 搜索, 检索, 查找, 调研, 核实, 深挖, 出报告, 找资料, 找项目, 搜推/看reddit/b站搜/查口碑, search, research, deep-research, find, look up, or verify information. Routes GitHub source code tasks to github. Do NOT use for local file ops.
- type
- routine
- version
- 5.2.0
- author
- Hermes Agent
- license
- MIT
- platforms
- ["macos","linux","windows"]
- metadata
- {"hermes":{"tags":["search","research","router","searxng","exa","tavily","brave","academic","papers","citations","sources","mcp","deep-research","verbatim-quote","anti-refusal","wechat","sogou","agent-reach","platform","social","twitter","reddit","bilibili","xiaohongshu","youtube","rss"],"related_skills":["content-source-workflow","exa-research","source-verification","qmd","obsidian","native-mcp","github","scrapling","agent-reach"]}}
# Web Research Router v3.11
> 🆕 **v3.12 (2026-06-27)**: 🛟 **引擎 fallback 从文档落地为运行时**。`extension.ts` 的 `web_search`/`web_fetch` 现实现**自动 fallback**:未显式指定 provider 时按 `exa → brave → searxng` 降级(任一引擎抛异常**或命中 0 条**即切下一个,每引擎只试一次防雪崩);**显式指定 provider 时禁用 fallback**(尊重意图,向后兼容);Tavily 限流,不入自动链,仅作显式 provider;SearXNG 需 `SEARXNG_URL`,未配置则在链中自动跳过。返回值新增 `details.actualProvider` / `details.fallbackChain` 保证可观测。**技术债修复**:`extension.ts` 的 Brave key 由错误的 `BRAVE_SEARCH_API_KEY` 统一为 `BRAVE_API_KEY`(与 profile `.env` / 本文档一致;旧命名导致 brave provider 一直取不到 key)。**运行态澄清**:本文档大量出现的 `mcp_brave_search_*` / `mcp_tavily_*` / `mcp_searxng_*` 为历史 MCP 文档;`config.yaml` 实际无 `mcpServers` 块、`web:` 段为空,运行时搜索由 `toolsets: [hermes-cli]` 加载的 `extension.ts` 提供。验证:`scripts/test-engines.sh`(连通性)+ `scripts/fallback-logic-test.mjs`(控制流 7/7)。详见 `references/engine-fallback-strategy.md`。
> 🆕 **v3.11 (2026-06-17)**: 🧲 **last30days 源码吸收(6 机制,一条链)**。在不碰 wrr-core 核心约束的前提下吸收 [last30days-skill](https://github.com/mvanhorn/last30days-skill) v3.3.2 的 6 项机制,全部 prompt/脚本层、向后兼容:**①Step 0.6 预搜索实体接地**(命名实体类 query 主搜前解析官方域/repo/subreddit/handle,喂主搜+platform 通道定向)→ **②ENTITY_MISS 闸**(deep loop 不提实体的漂移结果不进 facts.jsonl);**④SOURCE_QUALITY 权威度权重表** + **⑤intent-aware 融合权重** → **③weighted RRF**(`dedup_rrf.py --weights`,默认均权向后兼容);**⑧薄源重试**(命中 <3 先简化 query 重试同引擎再切)。**唯一红线**:engagement/social 权重永不抬 `source_tier`(封顶 0.50,CQI §14.6)。改动文件:SKILL.md / research-modes.md / source-map-schema.md / deep-research-loop.md / platform-mode.md / dedup_rrf.py / trigger-tests.md。新机制是 wrr-core 阶段 1 `route()`/registry 将**吸收而非推翻**的 prompt spec(CQI §14.5 许可的 Week-1 落地)。
> 🆕 **v3.10 (2026-06-17)**: 🔌 集成 **Agent-Reach platform mode**——5 引擎全在公网搜索空间的结构性盲区(Twitter/X 口碑、Reddit 讨论、B站/小红书/YouTube 内容、V2EX/雪球垂直社区、小宇宙播客、RSS)现由第 6 个 `platform` mode 补齐,调用 Agent-Reach 11/13 可用通道(doctor 实测:linkedin/exa_search 为 off,exa_search 与本 router Exa 重叠故无需)。**platform mode 是 5 mode 之外的补充模式,不替换 Exa/Brave/Tavily 主链路**;CLI 原始信源统一经 WRR 标准管线(extractor → source map `source_tier: social` → cross-check → 三分栏 → `[s<id>]` citation)。每次激活先跑 `agent-reach doctor`,不可用通道静默跳过。新增 `references/platform-mode.md`。
> 🆕 **v3.9 (2026-06-02)**: 🆕 集成 Sogou/微信公众号搜索 via weixin-search-mcp (PyPI v0.2.1)。搜索 + 加密链接解密 + 正文提取完整链路,Scrapling CLI stealthy-fetch 作为内容抓取 fallback(张睿 2026-06-01 验证)。新增 `references/sogou-wechat-source.md`。
> 🆕 **v3.7 (2026-05-29)**: 🔥 跨平台交叉验证后的路由大改。regent(macOS) + pi(Windows) 同日实测确认 **SearXNG 实例本身已损坏**(Google 失效 / Bing 降级 / DDG CAPTCHA,换 MCP 客户端无救)。SearXNG 从「默认起手」降级为「兜底 + 抓取专用」,Exa/Brave 升为双主力,Tavily 为深度调研专用。新增 MCP Configuration & Deployment 章节、Step 0 强制四步本地检查、Output Contract 强制 `[s<id>]` inline citation + 三分栏、common-pitfalls 新增 4 条(含 fetch 类工具 `urls:[...]` 数组参数陷阱)。
> 🆕 **v3.6 (2026-05-29)**: 引擎全量可用。Brave/Tavily API key 已配置,测试满分/Brave 9/9、Tavily 8/9。路由表升级为 5 引擎全矩阵,SearXNG 降级为广撒网后备。Quick Reference 重写。
> 🆕 **v3.5 (2026-05-28)**: 引擎可用性大修。第一轮流测揭示 SearXNG/Tavily/Brave MCP 缺失。路由表更新为 `web_search` 起手+Exa 精准。tool-names.md 重写。16 profile MCP 全量同步。
> 🆕 **v3.4 (2026-05-28)**: 基于好伴AI深度研究案例 RCA,新增 3 条 deep loop Red Flag 与 4 条质量验证清单(事实解耦/Claim 溯源/补搜回路/口径确认)。详见 `references/deep-research-loop.md` 与 `references/deep-loop-verification-pattern.md`。
> ⚙️ **Tuning:** `CROSS_CHECK_DEPTH=1` (fast, single-source) to `3` (thorough, triple-verify). Default: `2`.
---
## 🚨 Red Flags: DO NOT SKIP THIS ROUTER
Before calling ANY search tool, check this table. If any excuse below sounds familiar, **STOP — you are about to violate the decision tree.**
| Excuse your brain will make | Why it's wrong |
|------------------------------|----------------|
| "This is a simple query, I'll just use `web_search`" | `web_search` is a generic fallback. The router picks the best engine per query type. Even "simple" factual queries benefit from multi-engine cross-check (web_search + Exa)。 |
| "I already know the answer" | Training data is stale. Current facts need current search. |
| "I already loaded the skill, that's enough" | Loading ≠ following. Loading tells you WHAT to do; you still need to DO it. |
| "The loaded skill / context already has info on this — I can answer from that" ★ | **2026-06-01 真实违规。用户追问"你搜索了吗"。** 加载了 claude-code skill 后,基于 skill 内容和先验知识直接回答了 CC agent team 模型选择机制——但这是关于外部产品当前能力的 factual 问题。skill 里的信息可能过期、不完整或被后续更新推翻。**任何外部事实/版本/能力/当前状态的问题,即使已加载的 skill 看似覆盖了该领域,也必须走 Step 0 + 公网搜索。skill 是工作流指南,不是事实权威来源。** |
| "我已经本机实测过 CLI/help,所以可以开始设计" ★ | **2026-06-26 真实违规边缘。用户提醒“你要搜索”。** 本机 `--help` / config path / probe 只能证明当前安装行为,不能替代官方 docs/source。涉及外部工具机制、profile/config/auth/permission 边界、版本能力、模板设计等需求讨论时,必须在本地实测后补官方 docs/source 搜索与源码 fetch,再下设计结论。 |
| "The decision tree is too complicated for this" | It's 4 branches. Pick one. Takes 5 seconds. |
| "I'll cross-check later" | Cross-checking after the fact is twice the work. Do it in the right order now. |
| "我直接 Exa 单引擎一次到位" | 单引擎容易遗漏独立索引盲区(Exa 的神经索引 vs Brave 的独立爬虫覆盖不同源)。默认双主力 Exa + Brave 交叉,web_search 广扫兜底。 |
| "我不会 deep research / 单轮就够了" | 议题维度 ≥3、需可引用报告、单轮 source map 覆盖 <70% → 升级 deep loop(`references/deep-research-loop.md`)。不升级 ≠ 答得对;只是把幻觉藏起来。 |
| "fetch 完直接综合答案就行,省一步" | fetch + 综合答案放一次 LLM call → 幻觉高发。正确:fetch → extractor(verbatim quotes only) → 独立 call 综合。详见 `references/fetch-extract-pattern.md`。 |
| "section 写完就行,facts.jsonl 太麻烦" ★ | **fetch-write 耦合是 deep loop 80% 偏差的根因。** 营销话术一旦被叙事化("已有1亿用户、竞争压力巨大"),REFLECT 看到的是流畅叙事而非原子事实卡片,无法回头推翻。SECTION 阶段必须先产 `facts.jsonl`(指标/口径/来源/可信度/原始URL),write 读卡片不读原始页面。详见 `references/deep-research-loop.md` Step 2。 |
| "REFLECT 过一遍就够了,不用再做 Claim 溯源" ★ | REFLECT 是同一 Agent 在相同上下文做自审 → 只能发现"段落间逻辑矛盾",无法发现"整个上下文 based on 一个错误前提"。含"第一/最/突破/领先/超过/首家"或带规模数字的 claim **必须独立 search 溯源**,由独立 LLM call 在新上下文中验证。详见 `references/deep-loop-verification-pattern.md`。 |
| "中文搜索词够了,议题是国内的" ★ | 跨语言盲区是**系统性**的——中文 query 几乎召不回英文公告(Anthropic Claude for Healthcare 案例)。MERGE 前必须有"盲区检视 → 反向假设('国际玩家最近做了什么')→ 跨语言补搜"回路。详见 `references/deep-research-loop.md` Step 4。 |
| "本地能回答的问题别上公网 / I'll just hit the web, it's faster" ★ | **跳过 Step 0 是 v3.6 测试 P1 缺陷的根因。** Supermemory/session/qmd/CodeGraph 已沉淀过往结论、verbatim quote、user-validated facts —— 跳过 = 重新付一遍 token + 把已验证事实降级为"再次查证"。公网召回的还可能与本地结论矛盾,反而引入冲突。**强制 4 步本地检查(Supermemory → session_search → qmd/Obsidian → CodeGraph),全部 miss 才上公网。** 不查本地 ≠ 答得快;只是把 token 账单和幻觉风险一起放大。 |
**If you caught yourself thinking any of these → re-read the decision tree below and start over.**
---
## 🔀 Routing Decision Tree (ALWAYS RUN THIS FIRST)
### Step 0: Local knowledge first — MANDATORY 4-STEP SEQUENCE
> 🛑 **STOP.** Before ANY public search engine call, you MUST run all 4 local checks below in order. Each step is one tool call. Skipping = router violation.
- **Step 0.1 — Supermemory (cross-session memory)**
- check: 过往 session 是否已问过同一议题,是否已有结论 / source map / facts.jsonl 可复用
- tool: `supermemory_search`
- skip only if: 议题明显是实时性新闻(今日股价、刚发生的事件)且 < 24h
- escalate to public if: 命中 < 2 条 OR 命中结论已过期(> 90 天且涉及版本 / 价格 / 排名)
- **Step 0.2 — session_search (this session context)**
- check: 本轮对话上文是否已 fetch 过相关页面、抽过 verbatim quote、用户是否已给原文 / 截图
- tool: in-context scrollback / session transcript search
- skip only if: 新议题与本轮上文零重叠(首条用户消息即新主题)
- escalate to public if: 本轮上文未覆盖该子问题 OR 上文 source 不足以下结论
- **Step 0.3 — qmd / Obsidian (knowledge base)**
- check: 本地知识库(qmd 向量库、Obsidian vault、个人 wiki)是否已有该主题笔记 / 卡片
- tool: `qmd search` / Obsidian search / `mcp_obsidian_*` query
- skip only if: 议题为外部公司 / 产品 / 最新动态,本地不可能有
- escalate to public if: 命中 0 条 OR 命中笔记 > 180 天且涉及变动信息
- **Step 0.4 — CodeGraph (local code & repos)**
- check: 若问题涉及本地代码、内部仓库、接口定义、函数实现,先查 CodeGraph / `gh search code` 本地索引
- tool: `mcp_codegraph_*` / `serena` / 本地 `rg` / `gh api`(本地 repo)
- skip only if: 议题与代码 / 仓库零相关(纯事实、纯新闻、纯背景)
- escalate to public if: 本地仓库无相关实现 OR 需要对比外部上游版本
**只有以上 4 步全部"已查 + 未命中或不足",才允许调用 web_search / Exa / Brave / Tavily / SearXNG。** 在最终回答的 Verification Checklist 中必须显式声明这 4 步的执行结果(命中 / 未命中 / 跳过+原因)。
### Step 0.6: Pre-search entity grounding — 预搜索实体接地(命名实体类 query,🆕 v3.11)
> 🎯 **门控触发:仅当 query 含具体命名实体**(人 / 产品 / 项目 / 公司 / 开源库 / 社区)。纯概念 / 背景 / how-to 类(无命名实体)**跳过**——省一次预搜索。
> 思路偷自 last30days `resolve.py`(87 行**纯正则 + 频率计数,零 LLM**):在主搜索发动前,把实体解析成「权威落点」,让后续检索锚定实体而非空打。
- **怎么做(一次轻量预搜索,不展开成多轮):**
1. 用 `web_search` + `Exa` 仅就 topic 跑一次(不拆 sub-query)。
2. 对返回标题/URL 做**正则**提取四类落点(不做语义理解):
- 官方域(频率最高的非聚合站域名)
- GitHub repo(`github.com/<owner>/<repo>`,后缀规范化:`-action` / `-sdk` → canonical)
- subreddit(`r/<name>` 或 `reddit.com/r/<name>`)
- X/Twitter handle(`@<name>` 或 `(twitter|x).com/<name>`)
3. 频率计数排序;**URL 模式匹配权重 ×3 > 纯文本匹配 ×1**;过滤通用 handle(`twitter`/`x`/`home`/`search`/`i`/`intent`/`share`)。
- **解析结果喂三处:**
- **(a) 主搜精确化** —— 把实体名 / 官方域作锚(加引号 NAMES 或 `site:官方域`),喂 Step 2 主链路。
- **(b) platform mode 通道定向** —— 解析出 subreddit → `reddit subreddit`;handle → `twitter user-posts`;repo → `github`。**用户不必手动指名平台**(详见 `references/platform-mode.md` §2)。
- **(c) #2 ENTITY_MISS 接地基准** —— deep loop 用它过滤语义漂移结果(见 `references/deep-research-loop.md` Step 2)。
- **关联:** 实体类别提取复用 `references/query-decomposition.md` 的 **NAMES** 类口径。
- 🔧 **wrr-core 收口:** 本步是 prompt 层 spec。wrr-core 阶段 1 将其并入 `route()` 预搜索管线,用 registry `vertical_domains` 做权威域目标表(CQI §3.5 路由函数化 + §14 线程 E2);当前 prompt 形态即该 spec 的 Week-1 落地,route() 落地后**收口为单一路径,不留双轨**。
### Step 1: Is this a GitHub source code task?
- "看看 X 项目源码" / "这个函数怎么实现" → load `github`.
### Step 2: Pick the search mode and engine
> ⚠️ **引擎可用性声明(2026-05-29 v3.7 跨平台交叉验证后):**
> ✅ **Exa 9/9 + Brave 9/9 满分** → 升为双主力(语义精准 + 独立索引交叉)。
> ✅ Tavily 8/9 → 深度调研专用(含 `tavily_extract` 结构化抽取)。
> ✅ web_search 13/15 → 广扫兜底 + 通用查询。
> 🔧 **SearXNG 实例本身已损坏**:Google 完全失效 / Bing 严重降级 / DDG CAPTCHA — 跨平台系统性缺陷,**换 MCP 客户端无效**。
> ⛔ `mcp_searxng_searxng_web_search` 仅作**最后兜底**;`mcp_searxng_web_url_read` 仅作**抓取通道**保留。
>
> **默认路由:web_search 广扫 → Exa 语义精准 → Brave 独立交叉 → Tavily 深度调研 → SearXNG 兜底。**
#### 六模式路由(v3.6 五模式 + v3.10 platform mode)
- **discovery** — 背景调研 / landscape / "有没有相关项目"
- Primary: `web_search` 广扫 → `Exa` 语义精准
- Cross-check: `Brave`(独立索引交叉)
- Fallback: `SearXNG`(仅当前三家命中 <3 条)
- **grounding** — 日期 / 数字 / 价格 / claim / 新闻核实
- Primary: `Exa` + `Brave`(双引擎并行,独立索引交叉)
- Cross-check: `web_search`(通用兜底)
- Fallback: `Tavily`(结构化抽取数字 / 口径)
- **research** — 实质 brief / 决策备忘 / 市场扫描
- Primary: `Exa` + `Brave`(双主力并行)
- Cross-check: `Tavily`(深度结构化 + `tavily_extract` 抽事实卡)
- Fallback: `web_search` 广扫补盲区;SearXNG 不再参与
- 🆕 **补充源:** 主链路跑完后,对 §不稳定高质量源 做 pre-flight check → 可用则追加搜索(权威源互补覆盖)
- **academic** — 论文 / 引用 / SOTA / arXiv / DOI
- Primary: `Exa` + `arXiv`(curl / `scripts/search_arxiv.py`,见 `references/arxiv-semantic-scholar.md`)
- Cross-check: `Brave`(学术域名独立交叉)
- Fallback: `web_search`(SearXNG **不**推荐——学术信源被实例噪声淹没)
- **recovery** — 死链 / 迁移源 / 缺失材料
- Primary: `web_search` + `Brave`(双引擎广扫候选)
- Cross-check: `Exa Fetch`(`mcp_exa_web_fetch_exa` 抓 cache / mirror)
- Fallback: `mcp_searxng_web_url_read`(仅作抓取通道;**不**用 SearXNG 搜索)
- **platform** 🔌 — 社交媒体 / 视频 / 论坛 / RSS / 垂直社区(v3.10 新增,**补充模式,不替换主链路**)
- 触发条件:query 涉及 Twitter/X/推 · Reddit · B站/bilibili · 小红书/xhs · YouTube/yt · V2EX · 雪球 · 小宇宙 · RSS;或动作+平台(搜推/看reddit/b站搜);或内容类型(推文/帖子/弹幕/笔记/字幕/播客/口碑评价)
- **Step P0 先体检**:pre-flight 一行计数 `agent-reach doctor --json 2>&1 | grep -c '"status": "ok"'`(期望 >=10;**别数纯文本 `✅`**——图例+标题会虚高到 13),再按完整 `agent-reach doctor --json` 的各平台 `active_backend` 选命令组;不可用通道**静默跳过不报错**。⚠️ doctor 状态随 mcporter 连接/登录态**波动**(同一通道在 `off`/`[X]`/`ok` 间跳),是快照非契约——每次重跑、别缓存;**`exa_search` 永远 hardcode 跳过**(WRR 已有 Exa 满分主力,不复用其重叠通道,与 doctor 当下状态无关)
- Primary: Agent-Reach CLI 路由到对应通道(`opencli twitter/reddit/xiaohongshu search` · `bili search` · `yt-dlp` · V2EX/雪球公开 API · feedparser · 小宇宙 transcribe)
- Cross-check: 多平台交叉(同一议题 Twitter + Reddit)或公网验证(Exa/Brave 对社交结论做事实交叉)
- Fallback: 通道不可用 → 回退 `web_search` 搜该平台公开索引(如 `site:reddit.com`)
- Output: CLI 原始信源**必须**经 WRR 标准管线——extractor 抽 verbatim quote → source map(`source_tier: social` + `platform` 字段)→ cross-check → 三分栏 → `[s<id>]` citation
- ⚠️ 交互环境依赖:Twitter/Reddit/小红书走 OpenCLI(复用浏览器登录态),**无头/cron 环境不可用**,需标注「需要交互环境」
- 详见 `references/platform-mode.md`(通道速查 + 触发映射 + 输出映射 + DO/DON'T)
> 🔁 **薄源重试(thin-source retry,🆕 v3.11):** 任一引擎命中 **<3 条**时,**先**用 core-subject 简化 query(≤3 词,剥离修饰词)**重试同引擎一次**,**再**按该 mode 的 Fallback 切下一引擎 / SearXNG。每引擎只薄重试一次;详见 `references/research-modes.md` §薄源重试。
> 🔁 **何时升级到 deep-research loop?** 议题维度 ≥ 3 / 需可引用结构化报告 / 单轮 source map 命中 <70% / 用户显式说"深挖" → 进入
> `references/deep-research-loop.md` 的 plan → section research(含 `fetch-extract-pattern.md` extractor) → reflect → merge 循环。
> Deep loop **不替换**上述 5 mode;它是 `research` mode 的可选升级路径。
Detailed mode instructions: `references/research-modes.md`
### Step 2.5: Intent-aware fusion weighting — 多引擎融合权重(🆕 v3.11,可选)
> 6 mode 是**粗粒度 intent 代理**;同一议题的**细粒度 intent** 决定融合时**哪个引擎的结果该被加权**。仅当你把多引擎结果喂 `scripts/dedup_rrf.py` 融合时启用——单引擎/不融合可跳过。
**权重 = 源权威度基线 × intent 乘子:** `final_weight = quality_weight(source_tier) × intent_multiplier(provider)`
- `quality_weight` 来自 `references/source-map-schema.md` §SOURCE_QUALITY(#4 表)。
- `intent_multiplier` 按下表取(偷自 last30days `planner.py` 的 intent-aware source weighting,换形为 prompt 层):
| 细粒度 intent | 加权引擎(multiplier) | 依据 |
|---|---|---|
| breaking_news / 时效 | Brave 1.0 ≥ web_search 0.9 > Exa 0.8 | 独立爬虫最新,神经索引有滞后 |
| concept / technical / comparison | Exa 1.0 > Brave 0.85 | 语义精准 |
| factual / numerical / date | web_search 1.0 + Brave 0.9 > Exa 0.7 | Exa 精确事实易漂移(pitfall #8) |
| product / opinion / how_to | Brave 0.95 + Exa 0.9 | 均衡 |
- **落地:** 算出 `final_weight` → 传 `dedup_rrf.py --weights exa=..,brave=..,social=..`(per-provider;社交档恒受 0.50 上限约束)。
- 🛑 **红线:** intent 乘子**只调引擎间相对顺序**,**不抬 `source_tier`**——social 信源乘完仍封顶 0.50(CQI §14.6)。
- 🔧 **wrr-core 收口:** 当前是 prompt 层提示;wrr-core 阶段 1 由 `route(query, mode, signals)` 的 `signals` 携带 intent → registry 注入 `--weights`(CQI §3.5 路由函数化)。
### Step 3: Cross-check only when warranted (respect `CROSS_CHECK_DEPTH`)