Search Layer v2.2 — 意图感知多源检索协议
四源同级:Brave (web_search) + Exa + Tavily + Grok。按意图自动选策略、调权重、做合成。
执行流程
CODEBLOCK0
Phase 1: 意图分类
收到搜索请求后,先判断意图类型,再决定搜索策略。不要问用户用哪种模式。
| 意图 | 识别信号 | Mode | Freshness | 权重偏向 |
|---|
| Factual | "什么是 X"、"X 的定义"、"What is X" | answer | — | 权威 0.5 |
| Status |
"X 最新进展"、"X 现状"、"latest X" | deep | pw/pm | 新鲜度 0.5 |
|
Comparison | "X vs Y"、"X 和 Y 区别" | deep | py | 关键词 0.4 + 权威 0.4 |
|
Tutorial | "怎么做 X"、"X 教程"、"how to X" | answer | py | 权威 0.5 |
|
Exploratory | "深入了解 X"、"X 生态"、"about X" | deep | — | 权威 0.5 |
|
News | "X 新闻"、"本周 X"、"X this week" | deep | pd/pw | 新鲜度 0.6 |
|
Resource | "X 官网"、"X GitHub"、"X 文档" | fast | — | 关键词 0.5 |
详细分类指南见 INLINECODE1
判断规则:
- 1. 扫描查询中的信号词
- 多个类型匹配时选最具体的
- 无法判断时默认 INLINECODE2
Phase 2: 查询分解 & 扩展
根据意图类型,将用户查询扩展为一组子查询:
通用规则
- - 技术同义词自动扩展:k8s→Kubernetes, JS→JavaScript, Go→Golang, Postgres→PostgreSQL
- 中文技术查询:同时生成英文变体(如 "Rust 异步编程" → 额外搜 "Rust async programming")
按意图扩展
| 意图 | 扩展策略 | 示例 |
|---|
| Factual | 加 "definition"、"explained" | "WebTransport" → "WebTransport", "WebTransport explained overview" |
| Status |
加年份、"latest"、"update" | "Deno 进展" → "Deno 2.0 latest 2026", "Deno update release" |
| Comparison | 拆成 3 个子查询 | "Bun vs Deno" → "Bun vs Deno", "Bun advantages", "Deno advantages" |
| Tutorial | 加 "tutorial"、"guide"、"step by step" | "Rust CLI" → "Rust CLI tutorial", "Rust CLI guide step by step" |
| Exploratory | 拆成 2-3 个角度 | "RISC-V" → "RISC-V overview", "RISC-V ecosystem", "RISC-V use cases" |
| News | 加 "news"、"announcement"、日期 | "AI 新闻" → "AI news this week 2026", "AI announcement latest" |
| Resource | 加具体资源类型 | "Anthropic MCP" → "Anthropic MCP official documentation" |
Phase 3: 多源并行检索
Step 1: Brave(所有模式)
对每个子查询调用 web_search。如果意图有 freshness 要求,传 freshness 参数:
CODEBLOCK1
Step 2: Exa + Tavily + Grok(Deep / Answer 模式)
对子查询调用 search.py,传入意图和 freshness:
CODEBLOCK2
各模式源参与矩阵:
| 模式 | Exa | Tavily | Grok | 说明 |
|---|
| fast | ✅ | ❌ | fallback | Exa 优先;无 Exa key 时用 Grok |
| deep |
✅ | ✅ | ✅ | 三源并行 |
| answer | ❌ | ✅ | ❌ | 仅 Tavily(含 AI answer) |
参数说明:
| 参数 | 说明 |
|---|
| INLINECODE5 | 多个子查询并行执行(也可用位置参数传单个查询) |
| INLINECODE6 |
fast / deep / answer |
|
--intent | 意图类型,影响评分权重(不传则不评分,行为与 v1 一致) |
|
--freshness | pd(24h) / pw(周) / pm(月) / py(年) |
|
--domain-boost | 逗号分隔的域名,匹配的结果权威分 +0.2 |
|
--num | 每源每查询的结果数 |
Exa 源说明(两层角色):
- 默认仍走
/search,但不再固定死
type=auto
- 当前最小映射:
-
resource →
instant
-
status /
news →
fast
-
exploratory +
mode=deep →
deep
- 其他 →
auto
- 默认附带
contents.highlights.maxCharacters=1200,提升 snippet 质量,避免 Exa 结果因空摘要在本地 ranking 中被低估
-
freshness 会映射为 Exa
startPublishedDate,让 status/news 查询和 Tavily/Grok 时间窗口更一致
- 结果 metadata 中保留
meta.exaType,便于观测实际 resolved type
- 仅当 query 命中复杂
comparison / exploratory / status / news 场景时,在标准候选召回之后追加一段 Exa
type=deep 研究块,并以
research 字段附加到输出
-
research 是附加 contract,不替换
results,保证旧调用方仍可只读
results
- 当前边界:comparison 需显式对比词/判断词/3+ 子查询;exploratory 需判断/因果/对比词;status/news 需判断/因果词,不因普通多查询扩展误触发
- - 暂不把
deep-reasoning / outputSchema 接进默认主路径,避免基础 search-layer 变成重型 research/synthesis 引擎
Grok 源说明:
- - 通过 completions API 调用 Grok 模型(
grok-4.1-fast),利用其实时知识返回结构化搜索结果 - 自动检测时间敏感查询并注入当前时间上下文
- 在 deep 模式下与 Exa、Tavily 并行执行
- 需要在
~/.openclaw/credentials/search.json 中配置 Grok 的 apiUrl、apiKey、model(或通过环境变量 GROK_API_URL、GROK_API_KEY、GROK_MODEL) - 如果 Grok 配置缺失,自动降级为 Exa + Tavily 双源
Step 3: 合并
将 Brave 结果与 search.py 输出合并。按 canonical URL 去重,标记来源。
如果 search.py 返回了 score 字段,用它排序;Brave 结果没有 score 的,用同样的意图权重公式补算。
Phase 3.5: 引用追踪(Thread Pulling)
当搜索结果中包含 GitHub issue/PR 链接,且意图为 Status 或 Exploratory 时,自动触发引用追踪。
自动触发条件
- - 意图为
status 或 INLINECODE44 - 搜索结果中包含
github.com/.../issues/ 或 github.com/.../pull/ URL
方式 1: search.py --extract-refs(批量)
在搜索结果上直接提取引用图,无需额外调用:
CODEBLOCK3
输出中会多一个 refs 字段,包含每个结果 URL 的引用列表。
也可以跳过搜索,直接对已知 URL 提取引用:
CODEBLOCK4
方式 2: fetch-thread(单 URL 深度抓取)
对单个 URL 拉取完整讨论流 + 结构化引用:
CODEBLOCK5
GitHub 场景(issue/PR):通过 API 拉取正文 + 全部 comments + timeline 事件(cross-references、commits),提取:
- - Issue/PR 引用(#123、owner/repo#123)
- Duplicate 标记
- Commit 引用
- 关联 PR/issue(timeline cross-references)
- 外部 URL
通用 web 场景:web fetch + 正则提取引用链接。
Agent 执行流程
CODEBLOCK6
Phase 4: 结果排序
评分公式
CODEBLOCK7
权重由意图决定(见 Phase 1 表格)。各分项:
- - keywordmatch (0-1):查询词在标题+摘要中的覆盖率
- freshnessscore (0-1):基于发布日期,越新越高(无日期=0.5)
- authority_score (0-1):基于域名权威等级
- Tier 1 (1.0): github.com, stackoverflow.com, 官方文档站
- Tier 2 (0.8): HN, dev.to, 知名技术博客
- Tier 3 (0.6): Medium, 掘金, InfoQ
- Tier 4 (0.4): 其他
完整域名评分表见 INLINECODE48
Domain Boost
通过 --domain-boost 参数手动指定需要加权的域名(匹配的结果权威分 +0.2):
CODEBLOCK8
推荐搭配:
- - Tutorial → INLINECODE50
- Resource → INLINECODE51
- News → INLINECODE52
Phase 5: 知识合成
根据结果数量选择合成策略:
小结果集(≤5 条)
逐条展示,每条带源标签和评分:
CODEBLOCK9
中结果集(5-15 条)
按主题聚类 + 每组摘要:
CODEBLOCK10
大结果集(15+ 条)
高层综述 + Top 5 + 深入提示:
CODEBLOCK11
合成规则
- - 先给答案,再列来源(不要先说"我搜了什么")
- 按主题聚合,不按来源聚合(不要"Brave 结果:... Exa 结果:...")
- 冲突信息显性标注:不同源说法矛盾时明确指出
- 置信度表达:
- 多源一致 + 新鲜 → 直接陈述
- 单源或较旧 → "根据 [source],..."
- 冲突或不确定 → "存在不同说法:A 认为...,B 认为..."
降级策略
- - Exa 429/5xx → 继续 Brave + Tavily + Grok
- Tavily 429/5xx → 继续 Brave + Exa + Grok
- Grok 超时/错误 → 继续 Brave + Exa + Tavily
- search.py 整体失败 → 仅用 Brave
web_search(始终可用) - 永远不要因为某个源失败而阻塞主流程
向后兼容
不带 --intent 参数时,search.py 行为与 v1 完全一致(无评分,按原始顺序输出)。
现有调用方(如 github-explorer)无需修改。
快速参考
| 场景 | 命令 |
|---|
| 快速事实 | INLINECODE55 + INLINECODE56 |
| 深度调研 |
web_search +
search.py --mode deep --intent exploratory |
| 最新动态 |
web_search(freshness="pw") +
search.py --mode deep --intent status --freshness pw |
| 对比分析 |
web_search × 3 queries +
search.py --queries "A vs B" "A pros" "B pros" --intent comparison |
| 找资源 |
web_search +
search.py --mode fast --intent resource |
Search Layer v2.2 — 意图感知多源检索协议
四源同级:Brave (web_search) + Exa + Tavily + Grok。按意图自动选策略、调权重、做合成。
执行流程
用户查询
↓
[阶段1] 意图分类 → 确定搜索策略
↓
[阶段2] 查询分解 & 扩展 → 生成子查询
↓
[阶段3] 多源并行检索 → Brave + search.py (Exa + Tavily + Grok)
↓
[阶段4] 结果合并 & 排序 → 去重 + 意图加权评分
↓
[阶段5] 知识合成 → 结构化输出
阶段1: 意图分类
收到搜索请求后,先判断意图类型,再决定搜索策略。不要问用户用哪种模式。
| 意图 | 识别信号 | 模式 | 新鲜度 | 权重偏向 |
|---|
| 事实型 | 什么是X、X的定义、What is X | answer | — | 权威 0.5 |
| 状态型 |
X最新进展、X现状、latest X | deep | pw/pm | 新鲜度 0.5 |
|
对比型 | X vs Y、X和Y区别 | deep | py | 关键词 0.4 + 权威 0.4 |
|
教程型 | 怎么做X、X教程、how to X | answer | py | 权威 0.5 |
|
探索型 | 深入了解X、X生态、about X | deep | — | 权威 0.5 |
|
新闻型 | X新闻、本周X、X this week | deep | pd/pw | 新鲜度 0.6 |
|
资源型 | X官网、X GitHub、X文档 | fast | — | 关键词 0.5 |
详细分类指南见 references/intent-guide.md
判断规则:
- 1. 扫描查询中的信号词
- 多个类型匹配时选最具体的
- 无法判断时默认 exploratory
阶段2: 查询分解 & 扩展
根据意图类型,将用户查询扩展为一组子查询:
通用规则
- - 技术同义词自动扩展:k8s→Kubernetes, JS→JavaScript, Go→Golang, Postgres→PostgreSQL
- 中文技术查询:同时生成英文变体(如 Rust异步编程 → 额外搜 Rust async programming)
按意图扩展
| 意图 | 扩展策略 | 示例 |
|---|
| 事实型 | 加 definition、explained | WebTransport → WebTransport, WebTransport explained overview |
| 状态型 |
加年份、latest、update | Deno进展 → Deno 2.0 latest 2026, Deno update release |
| 对比型 | 拆成3个子查询 | Bun vs Deno → Bun vs Deno, Bun advantages, Deno advantages |
| 教程型 | 加 tutorial、guide、step by step | Rust CLI → Rust CLI tutorial, Rust CLI guide step by step |
| 探索型 | 拆成2-3个角度 | RISC-V → RISC-V overview, RISC-V ecosystem, RISC-V use cases |
| 新闻型 | 加 news、announcement、日期 | AI新闻 → AI news this week 2026, AI announcement latest |
| 资源型 | 加具体资源类型 | Anthropic MCP → Anthropic MCP official documentation |
阶段3: 多源并行检索
步骤1: Brave(所有模式)
对每个子查询调用 web_search。如果意图有新鲜度要求,传 freshness 参数:
web_search(query=Deno 2.0 latest 2026, freshness=pw)
步骤2: Exa + Tavily + Grok(Deep / Answer 模式)
对子查询调用 search.py,传入意图和新鲜度:
bash
python3 /home/node/.openclaw/workspace/skills/search-layer/scripts/search.py \
--queries 子查询1 子查询2 子查询3 \
--mode deep \
--intent status \
--freshness pw \
--num 5
各模式源参与矩阵:
| 模式 | Exa | Tavily | Grok | 说明 |
|---|
| fast | ✅ | ❌ | fallback | Exa优先;无Exa key时用Grok |
| deep |
✅ | ✅ | ✅ | 三源并行 |
| answer | ❌ | ✅ | ❌ | 仅Tavily(含AI answer) |
参数说明:
| 参数 | 说明 |
|---|
| --queries | 多个子查询并行执行(也可用位置参数传单个查询) |
| --mode |
fast / deep / answer |
| --intent | 意图类型,影响评分权重(不传则不评分,行为与v1一致) |
| --freshness | pd(24h) / pw(周) / pm(月) / py(年) |
| --domain-boost | 逗号分隔的域名,匹配的结果权威分 +0.2 |
| --num | 每源每查询的结果数 |
Exa源说明(两层角色):
- 默认仍走 /search,但不再固定死 type=auto
- 当前最小映射:
- resource → instant
- status / news → fast
- exploratory + mode=deep → deep
- 其他 → auto
- 默认附带 contents.highlights.maxCharacters=1200,提升snippet质量,避免Exa结果因空摘要在本地ranking中被低估
- freshness 会映射为Exa startPublishedDate,让status/news查询和Tavily/Grok时间窗口更一致
- 结果metadata中保留 meta.exaType,便于观测实际resolved type
- 仅当query命中复杂 comparison / exploratory / status / news 场景时,在标准候选召回之后追加一段Exa type=deep 研究块,并以 research 字段附加到输出
- research 是附加contract,不替换 results,保证旧调用方仍可只读 results
- 当前边界:comparison需显式对比词/判断词/3+子查询;exploratory需判断/因果/对比词;status/news需判断/因果词,不因普通多查询扩展误触发
- - 暂不把 deep-reasoning / outputSchema 接进默认主路径,避免基础search-layer变成重型research/synthesis引擎
Grok源说明:
- - 通过completions API调用Grok模型(grok-4.1-fast),利用其实时知识返回结构化搜索结果
- 自动检测时间敏感查询并注入当前时间上下文
- 在deep模式下与Exa、Tavily并行执行
- 需要在 ~/.openclaw/credentials/search.json 中配置Grok的 apiUrl、apiKey、model(或通过环境变量 GROKAPIURL、GROKAPIKEY、GROK_MODEL)
- 如果Grok配置缺失,自动降级为Exa + Tavily双源
步骤3: 合并
将Brave结果与search.py输出合并。按canonical URL去重,标记来源。
如果search.py返回了 score 字段,用它排序;Brave结果没有score的,用同样的意图权重公式补算。
阶段3.5: 引用追踪(线索拉取)
当搜索结果中包含GitHub issue/PR链接,且意图为Status或Exploratory时,自动触发引用追踪。
自动触发条件
- - 意图为 status 或 exploratory
- 搜索结果中包含 github.com/.../issues/ 或 github.com/.../pull/ URL
方式1: search.py --extract-refs(批量)
在搜索结果上直接提取引用图,无需额外调用:
bash
python3 search.py OpenClaw config validation bug --mode deep --intent status --extract-refs
输出中会多一个 refs 字段,包含每个结果URL