跳到主要内容

Local Deep Researcher — 架构与原理

30 秒导读: 给它一个话题,它就用一个「生成搜索词 → 搜网 → 摘要 → 反思找知识缺口 → 生成新搜索词」的循环,迭代几轮,最后输出一份带来源引用的 Markdown 报告。全部逻辑跑在你本机的 Ollama 或 LMStudio 上,不必调用任何云端大模型。

1. 这是什么(零基础也能懂)

一句话定义: Local Deep Researcher 是一个本地运行的网络研究助手——你丢给它一个话题,它自动上网查资料、边查边写、写完再反思还缺什么、然后接着查,循环几轮后交给你一篇带引用的报告。

解决什么问题 / 给谁用: 假设你想快速摸清一个陌生话题(比如「2025 年最新的向量数据库有哪些」),但又不想:

  • 一条条手动搜、一篇篇手动读、手动把要点抄下来;
  • 也不想把话题和资料喂给云端大模型(隐私、成本、离线场景)。

它替你把「搜 → 读 → 记 → 想还缺啥 → 再搜」这套动作自动化,而且模型跑在你自己电脑上。适合:想要私密/离线做资料调研的工程师、研究者,以及想学「深度研究 agent 到底怎么搭」的人——因为它极其精简(核心就 7 个 Python 文件)。

它能做什么(功能):

  • 把一个话题变成一条优化过的搜索查询;
  • 用四种搜索后端之一(DuckDuckGo / Tavily / Perplexity / SearXNG)去搜;
  • 用本地 LLM 把搜到的内容滚动式总结成一段不断增长的摘要;
  • 反思当前摘要、找出「还没讲清楚的地方」,自动生成下一条追问式搜索词;
  • 循环用户指定的轮数,最后拼出一篇 ## Summary + ### Sources 的 Markdown 报告。

用起来什么样: 你不写代码,而是在 LangGraph Studio 里(或通过 API)给图一个输入,只有一个字段:

# 示意,非源码——这是喂给图的输入形状
{
"research_topic": "2025 年主流的开源向量数据库对比"
}

跑完后,图的输出也只有一个字段 running_summary,内容形如:

## Summary
(这里是迭代若干轮后攒出来的一大段研究摘要……)

### Sources:
* Milvus 官方文档 : https://milvus.io/...
* Qdrant vs Weaviate 基准 : https://...

一句话直觉/类比: 把它想成一个勤奋但健忘的实习生:它没法一次读完全网,所以采用「小步快跑」——查一点、总结进笔记本、看看笔记本还缺什么、再针对性地查下一点。那本「不断被改写的笔记本」就是全项目的灵魂:running_summary

本项目的思路来自论文 IterDRAG(把一个复杂问题拆成子问题,逐个检索、逐个作答,后面的答案建立在前面的答案之上;见 README.md:165)。

2. 顶层全景(它大概怎么转)

整个系统就是一张 LangGraph 状态图(state graph,一种「节点 + 边 + 共享状态」的编排方式:每个节点是一个函数,读共享状态、返回状态更新;边决定下一个走谁)。

怎么读下面这张图:START 往下是主流程,走到 reflect 后有一个菱形判断决定「再来一轮」还是「收尾」——这就是「深度研究」的循环所在。

START


┌──────────────────┐
│ ① generate_query │ 话题 → 一条搜索查询
└──────────────────┘


┌──────────────────┐
│ ② web_research │◀────────────┐ 搜网、格式化来源
└──────────────────┘ │ loop_count += 1
│ │
▼ │
┌──────────────────┐ │
│ ③ summarize │ │ 把新资料并进「笔记本」
└──────────────────┘ │
│ │
▼ │
┌──────────────────┐ │
│ ④ reflect │ │ 找知识缺口 → 生成下一条查询
└──────────────────┘ │
│ │
◇ route ◇ loop<=max? ──是──┘



┌──────────────────┐
│ ⑤ finalize │ 去重来源 + 拼 Markdown
└──────────────────┘


END

部件一句话职责:

部件干什么在哪个文件
SummaryState贯穿全程的共享状态(话题、当前查询、摘要、来源、轮数)src/ollama_deep_researcher/state.py:7
Configuration所有可调项(模型、搜索后端、最大轮数、结构化输出模式…)src/ollama_deep_researcher/configuration.py:16
generate_query把话题变成一条搜索查询graph.py:138
web_research调搜索后端、格式化并累加来源graph.py:192
summarize_sources用 LLM 把新资料并入 running_summarygraph.py:265
reflect_on_summary找知识缺口、生成追问式查询graph.py:331
finalize_summary去重来源、拼成最终 Markdowngraph.py:387
route_research条件边:决定再循环还是收尾graph.py:421
搜索后端四个搜索函数,输出统一形状utils.py:166-387
prompts五段提示词 + 两套结构化输出指令prompts.py

主线走一遍(高层,不进代码):

  1. 输入只有 research_topic
  2. generate_query 让本地 LLM 把话题写成一条好搜的查询。
  3. web_research 拿这条查询去搜,得到几条来源,格式化成一段文本,轮数 +1。
  4. summarize_sources 让 LLM 读这段文本:没摘要就新建,有摘要就并进去(而不是重写)。
  5. reflect_on_summary 让 LLM 审视摘要、指出「哪块还没说清」,并据此写下一条追问查询。
  6. route_research 看轮数够不够:不够就带着新查询回到第 3 步;够了就往下。
  7. finalize_summary 把一路攒的来源去重,拼在摘要后面,产出最终 Markdown。

从这里往哪读: