Skip to content

feat(agent): deepResearch 多跳网络检索子代理工具 - #108

Open
wangkailang wants to merge 9 commits into
mainfrom
feature/deep-research-multi-hop
Open

feat(agent): deepResearch 多跳网络检索子代理工具#108
wangkailang wants to merge 9 commits into
mainfrom
feature/deep-research-multi-hop

Conversation

@wangkailang

Copy link
Copy Markdown
Owner

Summary

新增 deepResearch —— 一个把「分解 → 并行搜索 → 并发抓取 → 逐页抽取压缩 → 充分性判断 → 改写再搜」整套多跳循环封进单个工具内部的子代理工具。主对话只收到压缩后的结论 + 引用,原始网页永不进入主 loop 上下文,对标 Claude Code subagent + 结果过滤模式。

对标做法:Codex(缓存优先+抗注入)/ Claude CLI(agentic 链式 + 代码动态过滤)/ NotebookLM(管道内 RAG)。

关键设计

  • 内层 LLM 调用复用 result-summarizer.ts 范式:generateText/generateObject + createTimeoutController(30s) + 失败降级,弱模型(MiMo)畸形输出循环不崩;
  • 复用现有 webSearch(Tavily)/ webFetch(Readability)的 .execute,不重写;
  • 硬上限封顶成本:MAX_TOTAL_FETCHES=12 / FETCH_CONCURRENCY=4 / maxHops≤5 / maxSubQueries≤6
  • 触发判据写进工具描述("USE FIRST / ALWAYS when / Do NOT / Examples"),而非系统提示——研究表明仅改描述就能大幅改变命中率;webSearch/webFetch 反向交叉引用消除歧义;
  • 三路接线:对话 (ai-handlers)、计划执行 (plan-runner)、fork-skill (fork-skill-runner);门控 = Tavily 凭证 + model 句柄;
  • GAIA eval 工具表也接入,便于跑分量化命中率。

改动

  • src/main/core/agent/tools/deep-research.ts —— 新工具
  • agent-tools.ts / ai-handlers.ts / plan-runner.ts / fork-skill-runner.ts —— 生产三路接线
  • web-search.ts / web-fetch.ts / system-prompt.ts —— 描述与系统提示优化
  • eval/gaia/tool-registry.ts / eval/gaia/runner.ts —— GAIA eval 接入

Test plan

  • 新增 deep-research.test.ts:覆盖 sufficient 停止 / 多跳 / URL 去重 / fetch 上限钳制 / 内层畸形输出降级 / 预 abort / 输出紧凑性 7 个用例
  • agent-tools.test.ts 加注册门控断言
  • GAIA tool-contract.test.ts 加 deepResearch 注册条件断言
  • 全量测试 73 文件 / 839 passed
  • tsc --noEmit 0 error
  • Biome 已格式化
  • 端到端:配 Tavily 凭证后实跑多跳问题,确认模型选 deepResearch、citations 正常、主对话无原始页面泄漏
  • gaia-eval 对比启用前后多跳题正确率(注意 token 开销会上升)

🤖 Generated with Claude Code

wangkailang and others added 3 commits May 28, 2026 10:16
把「分解→并行搜索→并发抓取→逐页抽取压缩→充分性判断→改写再搜」的
多跳循环封进单个工具内部,主对话只收紧凑结论+引用,原始网页不进上下文
(对标 Claude Code subagent + 结果过滤)。内层 LLM 调用复用
result-summarizer 范式(generateText/generateObject + 超时 + 失败降级),
弱模型畸形输出循环不崩。接入对话(ai-handlers)、计划执行(plan-runner)、
fork-skill 三条路径,门控为 Tavily 凭证 + model 句柄。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
模型主要依据工具描述决定是否调用,系统提示里的 passive bullet 权重低、
常不命中。改为:deepResearch 描述采用「use FIRST / ALWAYS when / Do NOT /
Examples」格式含中英正反例;webSearch/webFetch 反向交叉引用引导多跳问题
改用 deepResearch;系统提示对应段降级为指向工具描述的一行指针(L1/L2 对齐)。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
buildEvalToolRegistry 增 model/providerOptions;tavilyKey + model 齐备时
注册 deepResearch。内部传未包 result-cap 的原始 webSearch/webFetch(抽取
需看完整页面),注册副本仍包 cap 兜底。runner 先解析 model+adapter 再
构造工具表。便于用 gaia-eval 量化多跳命中率/正确率。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 28, 2026 02:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces deepResearch, a sub-agent tool that encapsulates a full multi-hop web-research loop (decompose → parallel search → concurrent fetch → per-page extract → sufficiency check → reformulate) inside a single tool call so the main conversation only receives compact findings + citations. Inner LLM calls reuse the timeout/fallback pattern from result-summarizer.ts, and the tool reuses the existing webSearch / webFetch .execute implementations rather than re-implementing them. The tool is wired into all three execution paths (chat, plan-runner, fork-skill-runner) and into the GAIA eval registry, gated on Tavily credentials + a model handle.

Changes:

  • New src/main/core/agent/tools/deep-research.ts with hard-coded budget caps (12 fetches, 4 concurrent, 30s inner timeout, 6KB findings cap) and safeGenerateObject fallback wrapping
  • Registry wiring (agent-tools.ts, ai-handlers.ts, plan-runner.ts, fork-skill-runner.ts, eval/gaia/tool-registry.ts, eval/gaia/runner.ts) with conditional registration on model + Tavily availability
  • Tool-description cross-references in web-search.ts / web-fetch.ts and a new "Web Research" rule in system-prompt.ts to steer the model toward deepResearch for multi-hop questions

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/main/core/agent/tools/deep-research.ts New multi-hop sub-agent tool implementation
src/main/core/agent/tests/deep-research.test.ts 7 unit cases covering loop, dedupe, caps, fallback, abort
src/main/ipc/agent-tools.ts Threads model/providerOptions, registers deepResearch
src/main/ipc/ai-handlers.ts Passes model/providerOptions into the registry
src/main/ipc/plan-runner.ts Passes model (no providerOptions) into the registry
src/main/ipc/fork-skill-runner.ts Reuses one providerOptions; passes model into the registry
src/main/ipc/tests/agent-tools.test.ts Gate-coverage tests for deepResearch registration
src/main/core/agent/tools/web-search.ts Description now cross-links to deepResearch for multi-lookup
src/main/core/agent/tools/web-fetch.ts Description now cross-links to deepResearch for multi-page reads
src/main/ipc/system-prompt.ts Adds Web Research routing rule
src/eval/gaia/tool-registry.ts Registers deepResearch when both tavilyKey and model present
src/eval/gaia/runner.ts Builds model/adapter before the eval registry so model can be injected
src/eval/gaia/tests/tool-contract.test.ts Conditional-registration assertions for deepResearch

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

wangkailang and others added 6 commits May 28, 2026 10:46
GAIA runner 用的是独立 system prompt(与生产 OPERATING_PRINCIPLES 解耦),
其「Available capabilities」段未列出 deepResearch,导致弱模型
(Xiaomi MiMo)选不到它——尽管工具已注册、描述也已优化。

修复:将 deepResearch 加入 capabilities 列表并新增 Multi-step research
strategy 段,明确指示「多跳问题先 deepResearch、超过两次 raw 检索未
收敛立即切换」。L2 c61d22de 题验证:修复后模型确实把 deepResearch 作为
FIRST tool call、参数为完整原题。

剩余优化空间(不属本次修复):
- 内层 generateObject 在 MiMo 上偶尔解析失败,safeGenerateObject 已兜底;
- 模型拿到 deepResearch 结论后仍倾向二次验证,导致触顶 maxStepsPerTurn。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
generateObject 对 OpenAI 兼容提供方(Xiaomi MiMo 经 DeepSeek 适配器)只能走
compat 模式,弱模型常把 JSON 包进 ``` 围栏或混入解释文字,导致每次内层调用都
抛 "could not parse the response"、退化为 fallback,分解/抽取质量受损。

改法(②A+B):
- safeStructured 用 generateText 取文本 → extractJsonObject 宽容提取首个平衡
  {...}(剥 ``` 围栏 + 字符串转义感知的括号配平)→ zod 校验 → 失败回退;
- decompose / extract 提示词加 JSON 示例 few-shot。

GAIA L2 c61d22de 实测:内层解析失败从「每跑必现」降到 0 次,模型成功产出语义
正确答案(egalitarianism,仅词形未通过 exact-match)。新增围栏解析单测。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
软提示触发在弱模型上不可靠:L2×5 实测 MiMo 一道都没选 deepResearch、全部
陷入无界 raw webSearch/webFetch 循环并撞 5 分钟墙。本 flag 把"是否多跳"从
模型决策挪到管道:当 deepResearch 可注册(TAVILY_API_KEY + model)时,对外层
隐藏原始 webSearch/webFetch/webScrape,只暴露 deepResearch(其内部仍用原始
def 抓全页);deepResearch 不可注册时自动忽略并回退,避免外层无 web 能力。
系统提示在强制模式下同步切换为「deepResearch is your ONLY web tool」。

验证:同样 5 道 L2,强制后模型从「deepResearch 0/5」变为每题都走 deepResearch
(q1=1 次、q2=2 次且为唯一工具)。新增 2 个注册门控单测。

注:本次正确率测量被 Xiaomi 端点的瞬时 TLS 断连(疑似限流)污染,待网络稳定
窗口重测。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
针对慢推理模型(Xiaomi MiMo)强制 deepResearch 时跑不完的问题,分层修复:

① 并行抽取:逐页 extract 从串行 for-await 改为 mapWithConcurrency(4)。弱模型单次
   内层调用数十秒,串行 N 页吃光墙钟;并行后单跳抽取 N×t → ~t。
② 墙钟放宽:GAIA per-question 超时 5min → 10min。
   内层超时 INNER_CALL_TIMEOUT_MS 30s → 90s(快模型 2-5s 碰不到;MiMo 带 thinking
   常 >30s,30s 会把合法调用误判超时降级成垃圾)。
③ 结构化结论 + 信任 + 上限:
   - synthesis 改为产出 { directAnswer, confidence, findings }(safeStructured 兜底);
   - 同任务 deepResearch 调用硬上限 2 次,超出短路返回提示外层基于已有 findings 作答;
   - 默认 maxHops/maxSubQueries 3→2,减少内层调用数;
   - GAIA 提示:confidence 高/中时直接用 directAnswer 作答、最多调 2 次。

实测(L2 c61d22de,强制模式):内层超时/解析失败/TLS 全部归零,deepResearch
第 1 次调用即返回正确答案 directAnswer="egalitarian" confidence=high,硬上限在
第 3 次成功短路。残留瓶颈为外层 MiMo 不遵守"高置信即收口"指令、继续调工具至
墙钟耗尽——属弱模型指令遵循天花板,非工具问题。测试更新至 10 例。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
弱模型(MiMo)实测会在 deepResearch 第 1 次就拿到正确答案(directAnswer
="egalitarian" confidence=high)后仍继续调工具重研究、直到墙钟耗尽、从不
emit FINAL ANSWER。

新增 GAIA 专用 reflection 规则:本轮某次 deepResearch 返回 high/medium 置信
的非空 directAnswer、且尚无合格 FINAL ANSWER 时,retry + forceNoTools 并把
该 directAnswer 直接喂回,逼模型输出 `FINAL ANSWER: <directAnswer>`。排在
missingFinalAnswer 之前(给具体答案而非泛化提示)。规则为纯函数、7 个单测覆盖。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
官方现直接以 USD per 1M tokens 报价(不再需 CNY÷7 折算):
- mimo-v2.5-pro: input(miss) 0.43→0.435 / output 0.86→0.87 / cache hit 0.0036
- mimo-v2.5:     input 0.14 / output 0.29→0.28 / cache hit 0.0029→0.0028
注释与 pricing.test.ts 断言同步更新。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants