96SEO 2026-05-06 06:17 14
想要在几分钟内完成一次系统性的文献调研、行业报告甚至学术综述,光靠人力Yi经吃力不讨好。Mini DeepResearch 正是为了解决这个痛点而生——它把大语言模型和网络工具组合成一个“会思考的检索机器人”。下面我将用一种轻松却不失严谨的方式,带你从准备环境到跑通全流程,真正把这套系统装进自己的机器里。

Ru果把普通的 ChatGPT 比作“一位会聊天的老师”,那么 Mini DeepResearch geng像“一位会上网查资料、写报告的助理”。它的核心思路Ke以拆成三块:
规划根据用户的提问,生成一系列搜索关键词和对应的检索目的。
并行搜索一次性向搜索引擎发起多条请求,把得到的网页摘要拉回本地。
结构化输出把所有摘要融合,生成符合预设大纲的长篇报告或论文草稿。
这套「状态机」式架构让 LLM 不再是“一次性输出”,而是Ke以在不同状态之间来回切换——要么直接回答,要么继续搜集证据,再Zuo决定。
为什么叫「Mini」?官方提供了一个企业级的大模型版本,但对个人开发者来说它太重。Mini 版只保留Zui核心的三个 Agent,代码量不到两千行,却Neng完成「从提问到报告」的一整套闭环。轻巧、易部署,是学习和实验的理想起点。
二、环境准备——先把厨房弄干净下面列出的依赖dou是经过实测Ke以直接跑通的。Ru果你Yi经装好 Python 3.10+,只需要照着执行几条命令即可。
1️⃣ 创建虚拟环境 & 安装依赖python -m venv .venv
source .venv/bin/activate # Windows 用 .\venv\Scripts\activate
pip install --upgrade pip
pip install uv # 推荐使用 uv 加速依赖解析
uv pip install -r requirements.txt # requirements.txt Yi经列好 LangChain、Pydantic 等
小贴士:Ru果网络不太顺畅,Ke以把镜像源切换成阿里云或清华大学镜像。
2️⃣ 配置 .env 文件——钥匙放对位置才Neng开门# 必填
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxx
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
# 可选:DuckDuckGo 搜索 API
DDG_API_KEY=your_ddg_key
.env 文件请放在项目根目录,不要提交到 Git 仓库,以免泄露密钥。
3️⃣ 环境检测脚本——别等跑到一半才发现缺东西了项目自带 test_setup.py,只要执行一次就Neng帮你检查 Python 版本、依赖是否齐全以及关键环境变量是否可用:
uv run test_setup.py
# Ru果一切 OK,你会kan到 “All checks passed! Ready to roll.”
三、系统结构总览——一张图kan懂全局流向
ResearchManager: 接收用户查询,串联 Planner → Searcher → Writer 三个 Agent。
Planner Agent: 使用 LLM 的结构化输出功Neng,把查询转化为 WebSearchPlan 对象,其中包含若干 WebSearchItem。
Searcher Agent: 并发调用 DuckDuckGo / Bocha 等搜索工具,把每个关键词对应的网页摘要抓回并返回。
Writer Agent: 调用 LLM,将所有摘要按大纲拼接成完整报告;若 JSON 超长导致截断,则自动降级为纯文本输出,保证不中断。
Pydantic 数据模型层 : 为每一步提供强类型约束,让 LLM 必须遵守固定格式输出,从根本上避免「JSON 语法错误」。
四、核心代码拆解——不怕kan不懂,就怕不动手 4.1 数据模型from pydantic import BaseModel, Field
from typing import List
class WebSearchItem:
reason: str = Field
query: str = Field
class WebSearchPlan:
searches: List = Field
class ReportData:
short_summary: str = Field
follow_up_questions: List = Field
content: str = Field
Pydantic 会在运行时校验字段类型,一旦 LLM 输出不符合 schema,就会抛异常,我们随后会捕获并走兜底路径。
4.2 Planner Agent —— 用 Prompt + with_structured_outputfrom langchain.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="qwen-plus",
temperature=0,
api_key=os.getenv,
base_url=os.getenv,
)
planner_prompt = ChatPromptTemplate.from_messages()
planner_chain = planner_prompt | llm.with_structured_output
这里Zui关键的是 `with_structured_output` —— 它直接让模型返回一个Yi经实例化好的 Pydantic 对象,无需自行解析 JSON 字符串。
4.3 Searcher Agent —— 并发抓取页面摘要from langchain_community.tools import DuckDuckGoSearchResults
from langchain_core.runnables import RunnablePassthrough, RunnableLambda
search_tool = DuckDuckGoSearchResults
search_chain = (
RunnablePassthrough.assign(
search_results=RunnableLambda(
lambda x: search_tool.invoke
)
)
| ChatPromptTemplate.from_messages()
| llm
)
`RunnablePassthrough.assign` Neng在保持原始输入字段不变的情况下为字典额外添加 `search_results`,实现「输入‑ ‑输出」的一站式流水线。配合 `abatch` 与 `max_concurrency` 参数,我们只需一行代码就Neng实现Zui高五路并发,而不会因为单条失败导致整体中断。
4.4 Writer Agent —— 把碎片拼成完整报告writer_prompt = ChatPromptTemplate.from_messages()
writer_chain = writer_prompt | llm.with_structured_output
# 降级方案:当 JSON 被截断时用普通文本模式继续生成。
writer_chain_plain = writer_prompt | llm
`ReportData` 中除了正文,还包括简短概述和后续问题,让Zui终产出geng具可读性与延展性。Ru果结构化输出因 token 超限报错,我们会捕获异常并回退到 `writer_chain_plain`,确保任务始终有返回值。
4.5 ResearchManager —— 把所有部件串起来class ResearchManager:
def __init__:
self.planner = planner_chain
self.searcher = search_chain
self.writer = writer_chain
self.writer_fallback = writer_chain_plain
async def run:
# 1️⃣ 策划搜索计划
try:
plan:WebSearchPlan = await self.planner.ainvoke
except Exception as e:
print
# 简单兜底:使用原始 query + 常规补充词构造计划
plan = WebSearchPlan(searches=)
# 2️⃣ 并发执行所有搜索任务
inputs=
raw_results=await self.searcher.abatch(
inputs,
config={"max_concurrency":5},
return_exceptions=True,
)
summaries=
# 3️⃣ 合成Zui终报告
payload={"query":query,"research_results":"\
---\
".join}
try:
report:ReportData=await self.writer.ainvoke
except Exception as e:
print
report_text=await self.writer_fallback.ainvoke
report=ReportData(short_summary=f"关于 {query} 的简要报告",
follow_up_questions=,
content=report_text)
# 保存到本地文件系统
filename=f"research_reports/{self._slug}.md"
os.makedirs, exist_ok=True)
with open as f:
f.write
print
def _slug:
return "".join else "_" for c in text)
# 示例调用:
# manager=ResearchManager
# asyncio.run)
五、一键启动 Mini DeepResearch 🚀
准备工作全部搞定后只需要两条命令即可感受成果:
检查依赖与密钥:
uv run test_setup.py # 若显示 All checks passed,即可继续。
运行主程序:
uv run main_langchain.py --query "ChatGPT 与企业知识库融合方案"
# 稍等片刻,你会kan到类似:
# Planning... ✅
# Searching... ✅
# Writing... ✅
# Report saved to research_reports/ChatGPT_与_企业_知识库融合方案.md
cat research_reports/ChatGPT_与_企业_知识库融合方案.md | less -R
Aha!一篇包含概述、大纲、正文以及后续探索方向的完整报告Yi经诞生。Ru果想进一步定制,只需要修改 Prompt 或者替换搜索工具即可——比如换成付费geng精准的 Bing API 或者自建爬虫模块,dou非常友好。
六、实战中的几个常见坑 & 小技巧 Pitfall 1 – Structured Output 被截断LLM 输出超过 token 限制时会出现 JSON 不完整导致 Pydantic 报错。解决办法有两种:
a) 在 Prompt 中显式要求「只返回必要字段」,尽量压缩内容;
b) 加入降级链,如上文所示,当捕获到异常后直接走普通文本模式,再自行包装成 ReportData。
Pitfall 2 – 搜索频率被限速DuckDuckGo 免费接口有每分钟约30次请求上限。Ru果你的计划里有超过十条关键词,请适当调小 `max_concurrency` 或者在两轮之间加上 `await asyncio.sleep` 的小延迟,以免被封禁。
Pitfall 3 – 环境变量泄露风险.env 文件千万不要提交到公共仓库;Ru果必须共享项目,可提供 `.env.example` 并提醒团队自行填入密钥。同时建议在 CI 中使用 GitHub Secrets 注入环境变量,而不是硬编码在代码里。
Pitfall 4 – 中文分词导致摘要冗长
LLM 有时会把一句话拆得hen细,导致Zui终报告字数膨胀。这时候Ke以在 Writer Prompt 加入「总字数控制在 X 字以内」或「每段不要超过 Y 行」等限制,让模型自觉压缩信息密度。
七、进阶玩法 – 给 Mini DeepResearch 增添新功Neng
• 多模态输入: 将图片 OCR 或 PDF 文档转文字作为额外数据源,引入 Vision 模型,实现文献图表解读;
• 自定义检索器: 用 Elasticsearch 本地索引代替公网搜索,提高隐私安全;
• 循环迭代: 在 Writer 完成初稿后 触发 Planner,根据缺口自动补足新的子问题,实现“逐步逼近”式深度调研;
• 前端交互: 将后端服务包装为 FastAPI 接口,再配合 Vue/React 前端Zuo成在线研究平台,一键分享链接给同事或客户。
• 多模型混搭: Planner 使用通义千问保证规划质量,Searcher 用 Claude 或 Gemini 提升摘要准确度,而 Writer 则交给 GPT‑4o 打磨语言风格,实现“各司其职”。 \end{ul}
八、常见 Q&A 🎤