一个面向复杂问题的开源深度检索 Agent:自主拆解问题、规划搜索路径、访问网页、提取证据,并通过多源验证生成简洁答案。
DeepSearch 基于 ReAct(Reason + Act)范式构建。它不是一次性“搜索后总结”的固定流水线,而是让模型在推理、检索、阅读和验证之间动态循环:先拆解问题,再根据当前证据决定下一步行动,直到满足约束或触发运行时兜底。
普通搜索解决的是“把相关页面找出来”;一次性问答解决的是“根据已有上下文写一段话”。但真实问题往往同时包含时间、人物、地点、因果关系或格式要求,答案分散在多个来源中,页面之间还可能存在噪声、缺失和表述差异。此时,先搜到一个看似合理的结果就开始总结,容易出现过早收敛、漏掉约束和把推测当成事实的问题。
DeepResearch 的核心意义,是把“回答问题”变成一个可检查的研究过程:
- 先理解,再检索:把原问题拆成实体、约束和关系,围绕高区分度线索规划查询。
- 边搜边验证:搜索负责发现候选,网页访问负责阅读原文,多个独立来源共同确认关键事实。
- 让证据驱动下一步:每轮观察结果都会回到 Agent 上下文,模型可以继续换关键词、换搜索源或深入页面,而不是被固定流程锁死。
- 把不确定性显式化:搜索失败、网页不可访问、内容被过滤、上下文过长或任务超时,都有可观察的降级路径。
- 在有限预算内完成闭环:研究不是无限搜索,而是在轮次、时间和上下文预算内持续提高答案可信度,并在必要时安全收束。
因此,DeepSearch 关注的不只是最终文本,还关注答案背后的“问题拆解 → 检索 → 证据提取 → 交叉验证 → 格式校验”链路。本项目把这条链路封装为可复用的 HTTP 服务,方便接入知识助手、研究工具和需要实时信息的业务系统。
- 多跳检索:将复杂问题拆成可独立验证的子问题,逐步收敛候选答案。
- 中英文双路搜索:支持 Google/Serper 与阿里 IQS,并按模型选择或查询语言自动路由。
- 搜索自动降级:弱结果会切换搜索源;双路结果均较差时自动简化查询重试。
- 目标导向网页阅读:优先通过 Jina Reader 获取正文,失败后使用
httpx + BeautifulSoup降级抓取。 - 证据压缩:使用独立摘要模型围绕当前目标提取
evidence与summary,减少无关上下文。 - 长任务保护:包含 SSE 心跳、超时、Token 上限、最大轮次、内容过滤重试和强制回答机制。
- 宽容的工具协议:兼容 XML 标签、Qwen function 标签和裸 JSON 三种工具调用格式。
- 可重复评估:提供 JSONL 批量运行与断点续跑脚本,便于比较 Prompt 和工具策略。
架构图以当前源码为准,包含主调用链、ReAct 回路,以及搜索、网页访问和运行时保护的降级路径。可编辑的 Mermaid 源码见 docs/architecture.mmd。
一次请求的核心流程如下:
- FastAPI 接收问题,以普通 JSON 或带心跳的 SSE 方式保持请求。
- Agent 注入系统提示词、当前日期与用户问题,调用主推理模型。
- 模型输出答案或工具调用;工具结果经过截断后作为观察信息写回上下文。
search在双搜索源之间路由和降级;visit并发读取网页并提取目标证据。- Agent 持续执行 Think → Act → Observe,最终完成多源验证并归一化答案。
.
├── agent.py # FastAPI 服务入口,支持 JSON 与 SSE heartbeat
├── agent_loop.py # ReAct 主循环、工具调度和运行时保护
├── prompts.py # System、User 与网页证据提取 Prompt
├── tools_search.py # Serper / IQS 搜索、路由、Key 轮换与降级
├── tools_visit.py # 网页抓取、正文清洗、并发访问与证据摘要
├── eval.py # JSONL 批量运行脚本
├── test_eval.py # 带参考答案的本地评估脚本
├── skills.py # Agent Skills 发现与加载能力
├── skills/ # 示例 Skills
├── docs/
│ ├── architecture.mmd # Mermaid 架构图源码
│ └── architecture.svg # README 使用的渲染结果
└── requirements.txt
需要 Python 3.10 或更高版本。
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt在项目根目录创建 .env:
# 必填:主推理模型与网页摘要模型
DASHSCOPE_API_KEY=your_dashscope_api_key
AGENT_MODEL=qwen3.5-plus
# 至少配置一个可用搜索源
SERPER_API_KEYS=key_1,key_2
IQS_API_KEY=your_iqs_api_key
# 可选:不配置时网页访问自动降级为 httpx + BeautifulSoup
JINA_ENABLED=1
JINA_API_KEYS=key_1,key_2搜索源可以单独配置,但双路都可用时,中英文检索和自动降级能力更完整。多个 Serper/Jina Key 使用英文逗号分隔,遇到限流时会自动轮换。
uvicorn agent:app --host 0.0.0.0 --port 8000服务启动后,可访问 http://localhost:8000/docs 查看交互式 API 文档。
curl -X POST http://localhost:8000/ \
-H 'Content-Type: application/json' \
-d '{"question":"解释 RAG 与 DeepSearch 的差异,并给出适用场景。"}'响应:
{
"answer": "..."
}对于耗时较长的深度检索,可请求 SSE。服务端每 5 秒发送一条 heartbeat,任务完成后发送 Message 事件。
curl -N -X POST http://localhost:8000/ \
-H 'Content-Type: application/json' \
-H 'Accept: text/event-stream' \
-d '{"question":"梳理一个需要多来源交叉验证的问题。"}'agent_loop.py 维护完整对话上下文。每一轮由模型决定:
- 输出
<tool_call>:解析参数并执行search或visit; - 输出
<answer>:经过早答检查后归一化并返回; - 未产生有效动作:注入 nudge,要求继续调用工具或回答。
复杂问题若在前三轮且 120 秒内过早回答,系统会拦截一次,并要求重新检查约束和补充确认来源。
tools_search.py 支持在单次工具调用中提交多条查询:
- 显式指定
google时使用 Serper;指定bing时使用 IQS; - 未指定时,中文查询默认使用 IQS,其他查询默认使用 Serper;
- 主搜索源结果过短、为空或报错时,切换另一搜索源;
- 两个搜索源均不理想时,简化查询后再次尝试。
bing是模型工具协议中的兼容名称,当前代码实际接入的是阿里 IQS,并非 Microsoft Bing API。
tools_visit.py 支持并发访问多个 URL。单页处理顺序为:
Jina Reader → httpx 直连 → BeautifulSoup 正文清洗 → qwen-plus 目标摘要
摘要模型只围绕本轮 goal 提取证据;抓取或摘要失败会以可观察的错误结果返回主循环,而不会让整个请求直接中断。
| 机制 | 当前实现 |
|---|---|
| 主循环最大轮次 | 100 轮 |
| 单次请求超时 | 540 秒 |
| 上下文估算上限 | 500,000 tokens |
| 单次工具结果上限 | 15,000 字符 |
| 单网页正文上限 | 50,000 字符 |
| 单 URL 访问上限 | 120 秒 |
| 内容过滤 | 两次中性措辞重试,随后清理上下文并强制回答 |
| SSE 心跳 | 每 5 秒一次 |
这些值目前定义在 agent_loop.py、agent.py 与 tools_visit.py 中,可根据模型上下文、网关限制和成本预算调整。
eval.py 从 question.jsonl 读取问题,结果按行追加写入,重复执行时会跳过已完成 ID:
python eval.py 0 20 my_results.jsonl参数依次为起始 ID、结束 ID(不包含)和输出文件。test_eval.py 适用于包含参考答案的本地 JSONL 数据,并输出归一化后的精确匹配统计。
建议用于自有数据时采用以下格式:
{"id": 0, "question": "你的问题"}- 在
agent_loop.py::_execute_tool中注册新的检索或数据工具。 - 在
prompts.py中扩展工具描述与输出约束。 - 为搜索结果增加去重、来源可信度评分和引用输出。
- 将运行参数迁移为环境变量或配置文件,便于不同部署环境调优。
- 接入可观测性系统,记录每轮耗时、Token、搜索源与降级原因。
- 不要提交
.env、API Key 或包含敏感信息的运行结果。 - 网页内容属于不可信输入;用于生产环境时,建议增加 URL 白名单、内网地址拦截和提示词注入防护。
- 当前服务未内置身份认证、限流和租户隔离,公开部署前应在网关层补齐。
本项目基于 MIT License 开源。