基于 LangGraph + deepAgents 的深度研究智能体实战
从官方 Demo 到工程化落地的完整复盘
前言
LangChain 官网有一套 Deep Research with LangGraph 的教程,教你怎么用 LangGraph 搭一个研究智能体。官方 demo 写得很好,但毕竟是教学用的,代码全堆在一个文件里,真要在团队里跑起来,还得自己做工程化。
这篇文章记录的是我从官方 demo 到实际项目的完整过程:核心代码逻辑是什么、整体流程怎么跑、踩了哪些坑。不会讲太多"什么是 Agent"这种概念性的东西。
一、整体架构
先上一张图,后面的内容都对这张图负责:
markdown
用户输入(研究主题)
│
▼
┌─────────────────────────────────────┐
│ 主 Agent(编排层) │
│ │
│ Plan → Save Request → Delegate │
│ ↓ │
│ 子 Agent(研究层) │
│ 搜索 + 反思 │
│ ↓ │
│ Synthesize → Write Report │
└─────────────────────────────────────┘
│
▼
输出结构化研究报告 + 引用来源
主 Agent 负责任务规划、委托、汇总;子 Agent 负责具体的搜索和反思。
二、核心代码逻辑
2.1 Agent 创建(deep_agents/core/agent.py)
python
agent = create_deep_agent(
model=llm,
tools=[tavily_search, think_tool],
system_prompt=INSTRUCTIONS,
subagents=[research_sub_agent],
backend=FilesystemBackend(
root_dir=workspace,
virtual_mode=True,
),
debug=True
)
create_deep_agent 是 deepAgents 框架的核心接口,参数说明:
| 参数 | 说明 |
|---|---|
model |
LLM 实例,这里用的 ChatOpenAI(GLM-5 via 自定义端点) |
tools |
主 Agent 自带的工具列表,这里是 [tavily_search, think_tool] |
system_prompt |
系统级指令,控制 Agent 的整体行为 |
subagents |
子 Agent 列表,research_sub_agent 是唯一的研究执行者 |
backend |
文件系统后端,virtual_mode=True 开启沙箱隔离 |
debug |
开启 debug 模式,输出详细日志 |
为什么要 virtual_mode=True?
Agent 运行时会调用 write_file() 写 research_request.md、final_report.md 这些中间文件。如果不限制,它理论上可以读写服务器上的任意文件。开启虚拟模式后,所有路径被强制映射到 workspace 目录下,../ 穿越被阻止。
2.2 子 Agent 定义(deep_agents/subagents/researcher/agent.py)
python
def get_research_sub_agent():
current_date = datetime.now().strftime("%Y-%m-%d")
return {
"name": "research-agent",
"description": "Delegate research to the sub-agent researcher. "
"Only give this researcher one topic at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search, think_tool],
}
research_sub_agent = get_research_sub_agent()
子 Agent 是一个 dict,不是 class。框架在内部会把它实例化成一个独立的 Agent。关键字段:
name:子 Agent 的标识名,主 Agent 通过它来委托任务system_prompt:子 Agent 的行为指令,这里用的是RESEARCHER_INSTRUCTIONStools:子 Agent 可用的工具,和主 Agent 共享同一套工具
2.3 搜索工具(deep_agents/tools/tavily_search.py)
python
@tool(parse_docstring=True)
def tavily_search(
query: str,
max_results: Annotated[int, InjectedToolArg] = 1,
topic: Annotated[Literal["general", "news", "finance"], InjectedToolArg] = "general",
) -> str:
# 1. 用 Tavily 发现 URL
search_results = tavily_client.search(
query,
max_results=max_results,
topic=topic,
)
# 2. 遍历每个 URL,抓取内容并转 markdown
result_texts = []
for result in search_results.get("results", []):
url = result["url"]
title = result["title"]
content = fetch_webpage_content(url)
result_text = f"""## {title}
**URL:** {url}
{content}
---
"""
result_texts.append(result_text)
# 3. 拼接返回
response = f"""🔍 Found {len(result_texts)} result(s) for '{query}':
{chr(10).join(result_texts)}"""
return response
流程是:Tavily 搜索 URL → HTTP 请求抓取页面 → markdownify 转 HTML 为文本 → 拼接输出。
InjectedToolArg 注解表示这个参数是由框架注入的,不是用户直接输入的,这样可以防止用户通过 prompt 注入手脚。
2.4 反思工具(deep_agents/tools/think_tool.py)
python
@tool(parse_docstring=True)
def think_tool(reflection: str) -> str:
"""Tool for strategic reflection on research progress and decision-making."""
return f"Reflection recorded: {reflection}"
这个工具看起来什么都没干,但它的作用是强制 Agent 在每次搜索后停下来思考:
- 我找到了什么关键信息?
- 还缺什么?
- 要继续搜还是该总结了?
没有这个工具,Agent 会变成"搜索狂魔",同一个词能搜一百遍。
三、工作流程详解
3.1 Prompt 三层设计
系统的行为靠 Prompt 控制,Prompt 分成三层:
第一层:工作流指令(workflow.py)
python
RESEARCH_WORKFLOW_INSTRUCTIONS = """# Research Workflow
Follow this workflow for all research requests:
1. **Plan**: Create a todo list with write_todos
2. **Save the request**: write_file() to `/research_request.md`
3. **Research**: Delegate to sub-agents using task() tool
4. **Synthesize**: Review findings, consolidate citations
5. **Write Report**: Write `/final_report.md`
6. **Verify**: Read `/research_request.md` and confirm coverage
"""
定义了标准流程:规划 → 保存请求 → 委托研究 → 汇总 → 写报告 → 验证。
第二层:委托策略(delegation.py)
python
SUBAGENT_DELEGATION_INSTRUCTIONS = """# Sub-Agent Research Coordination
**DEFAULT: Start with 1 sub-agent** for most queries:
- "What is quantum computing?" → 1 sub-agent
**ONLY parallelize when the query EXPLICITLY requires comparison:**
- "Compare OpenAI vs Anthropic vs DeepMind AI safety" → 3 parallel sub-agents
## Parallel Execution Limits
- Max {max_concurrent_research_units} parallel sub-agents per iteration
- Stop after {max_researcher_iterations} delegation rounds
"""
控制并发:默认单个子 Agent,只有显式比较才并行,最多 {max_concurrent_research_units}=3 并发,最多 {max_researcher_iterations}=3 轮迭代。
第三层:研究者指令(researcher.py)
python
RESEARCHER_INSTRUCTIONS = """# Instructions for sub-agent researcher
**CRITICAL: Use think_tool after each search to reflect**
**Tool Call Budgets**:
- Simple queries: 2-3 search tool calls
- Complex queries: up to 5 search tool calls
**Stop Immediately When**:
- You can answer comprehensively
- You have 3+ relevant sources
- Your last 2 searches returned similar info
"""
给子 Agent 的执行指南:每次搜索后必须反思,限制搜索次数,提前停止条件。
3.2 主 Agent 的调度逻辑
python
INSTRUCTIONS = (
RESEARCH_WORKFLOW_INSTRUCTIONS
+ "\n\n"
+ "=" * 80
+ "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=max_concurrent_research_units,
max_researcher_iterations=max_researcher_iterations,
)
)
主 Agent 加载的是 WORKFLOW + DELEGATION 两层 Prompt。子 Agent 单独加载 RESEARCHER_INSTRUCTIONS。
3.3 端到端执行流程
scss
1. 用户输入:"研究量子计算的基本原理"
2. 主 Agent 收到任务,执行 workflow 第1步:
→ 调用 write_todos() 创建 TODO list
[ "研究量子计算的基本概念", "研究量子计算的实现方式", "研究量子计算的应用场景" ]
3. 执行第2步:
→ 调用 write_file("/research_request.md", "研究量子计算的基本原理")
4. 执行第3步(委托研究):
→ 调用 task("研究量子计算的基本概念"),委托给 research-agent
5. 子 Agent research-agent 收到任务:
→ 调用 tavily_search("量子计算基本概念")
→ 调用 think_tool("找到了什么,还缺什么")
→ 调用 tavily_search("量子比特原理")
→ 调用 think_tool("信息够不够")
→ 返回研究成果
6. 主 Agent 汇总所有子 Agent 的发现
7. 执行第5步:
→ 调用 write_file("/final_report.md", "《量子计算研究报告》")
8. 执行第6步(验证):
→ 调用 read_file("/research_request.md")
→ 确认报告覆盖了原始问题
四、部署与测试
4.1 环境配置
bash
# 安装依赖
uv sync
# 配置环境变量
cp .env.example .env
# 填入:
# MODEL_API_URL=你的GLM端点
# MODEL_API_KEY=你的密钥
# MODEL_NAME=glm-5
# TAVILY_API_KEY=你的Tavily密钥
4.2 启动 LangGraph 服务器
bash
langgraph dev
LangGraph 会读取 langgraph.json 配置:
json
{
"dependencies": ["."],
"graphs": {
"research": "./deep_agents/core/agent.py:agent"
},
"env": ".env"
}
graphs.research 指定了图的入口点。启动后访问 http://127.0.0.1:2024,通过 Web 界面提交研究任务。
4.3 测试数据
| 场景 | 耗时 | 结果 |
|---|---|---|
| "量子计算的基本原理" | 约3分钟 | 输出了量子比特、纠缠、量子门等概念,引用了5个来源 |
| "Python vs JavaScript Web开发对比" | 约4分钟 | 两语言分维度对比,有小结 |
| "AI Agents最新进展" | 约5分钟 | 涵盖4-5个方向,有时效性 |
五、项目地址
GitHub : github.com/liangshengx...
bash
deepAgents-deepSearch/
├── deep_agents/ # 核心包
│ ├── core/agent.py # Agent 创建
│ ├── prompts/ # 三层 Prompt
│ ├── tools/ # 工具实现
│ └── subagents/ # 子 Agent 独立分包
├── examples/ # 示例
└── agent_chat_ui/ # 聊天 UI
代码完整开源,可以直接 clone 下来 langgraph dev 跑起来。
六、总结
GitHub : github.com/liangshengx...
bash
deepAgents-deepSearch/
├── deep_agents/ # 核心包
│ ├── core/agent.py # Agent 创建
│ ├── prompts/ # 三层 Prompt
│ ├── tools/ # 工具实现
│ └── subagents/ # 子 Agent 独立分包
├── examples/ # 示例
└── agent_chat_ui/ # 聊天 UI
代码完整开源,可以直接 clone 下来 langgraph dev 跑起来。
六、总结
这个项目的核心价值在于:把 LangChain 官方 demo 变成可维护、可扩展的工程化项目。
几个关键点:
virtual_mode=True一定要开,安全隔离是底线think_tool不是花招,是控制 Agent 搜索行为的有效机制- Prompt 三层分离让迭代更灵活,不需要为了改一个策略重写整个 Prompt
- 子 Agent 独立分包不只是"整洁",而是真的人员可以独立开发和测试
如果你也在做类似的事情,欢迎交流。
参考:LangChain Academy - Deep Research with LangGraph