系统分析如何将 deep_research 示例的研究能力以 subagent 形式集成至自定义主 agent, 涵盖架构设计、Instruction 整合策略与完整代码实现。
examples/deep_research/agent.py 构建了一个
两层 Orchestrator-Worker 架构:主 agent 负责规划与合成报告,
research-agent subagent 负责实际网络搜索。
# ── 参数配置 ──
max_concurrent_research_units = 3
max_researcher_iterations = 3
current_date = datetime.now().strftime("%Y-%m-%d")
# ── Orchestrator 的 system_prompt(两段拼接)──
INSTRUCTIONS = (
RESEARCH_WORKFLOW_INSTRUCTIONS # 研究流程规范
+ "\n\n" + "=" * 80 + "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format( # 并发调度规范
max_concurrent_research_units=3,
max_researcher_iterations=3,
)
)
# ── SubAgent 定义(TypedDict 格式)──
research_sub_agent = {
"name": "research-agent",
"description": "Delegate research to the sub-agent researcher.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(date=current_date),
"tools": [tavily_search, think_tool],
}
# ── 创建主 agent ──
agent = create_deep_agent(
model=init_chat_model("anthropic:claude-sonnet-4-5-20250929", temperature=0.0),
tools=[tavily_search, think_tool],
system_prompt=INSTRUCTIONS,
subagents=[research_sub_agent],
)
| 参数 | 类型 | 说明 | 集成关键性 |
|---|---|---|---|
model |
str | BaseChatModel | 主 agent 使用的模型 | 必填 |
tools |
list[Callable] | 主 agent 可用工具;subagent 默认继承 | 必填 |
system_prompt |
str | SystemMessage | 主 agent 的系统提示词 | 必填 |
subagents |
list[SubAgent | CompiledSubAgent] | 注册 subagent 列表;主 agent 通过 task() 调用 |
集成核心 |
checkpointer |
Checkpointer | 持久化状态(可选) | 可选 |
interrupt_on |
dict[str, bool] | 人工审批 hook(可选) | 可选 |
class SubAgent(TypedDict):
name: str # 唯一标识,task() 调用时使用
description: str # 主 agent 据此决定何时委派
system_prompt: str # subagent 的完整系统提示
tools: NotRequired[list] # 不填则继承主 agent 工具
model: NotRequired[str] # 可使用不同模型(如 Haiku 降本)
middleware: NotRequired[list]
interrupt_on: NotRequired[dict]
permissions: NotRequired[list]
归属:主 agent system_prompt
归属:主 agent system_prompt
max_concurrent_research_unitsmax_researcher_iterations归属:research-agent subagent system_prompt
搜索策略
硬性限制
RESEARCHER_INSTRUCTIONS 永远只属于 subagent,
不应混入主 agent 的 prompt。主 agent 的身份是"规划者与合成者",
不执行搜索;subagent 的身份是"执行者",不做报告合成。
| 维度 | 方案一:扁平两层(推荐) | 方案二:三层嵌套 |
|---|---|---|
| 架构 | 自定义主 agent → research-agent | 自定义主 agent → deep-researcher → research-agent |
| 框架支持 | 官方支持,示例验证 | SubAgent 内部嵌套 SubAgent 未有官方示例 |
| 调度并发 | 主 agent 直接控制,逻辑清晰 | 中间层增加延迟,调度复杂 |
| Instruction 整合 | 研究调度逻辑合并至主 agent prompt | 研究调度逻辑放在中间层 subagent prompt |
| 适用场景 | 大多数自定义集成需求 | 需要严格隔离研究职责的场景 |
| 实现难度 | 简单 | 高,风险大 |
# your_agent.py
from datetime import datetime
from langchain.chat_models import init_chat_model
from deepagents import create_deep_agent
# 复用 deep_research 的 prompts 和 tools
from research_agent.prompts import (
RESEARCHER_INSTRUCTIONS,
RESEARCH_WORKFLOW_INSTRUCTIONS,
SUBAGENT_DELEGATION_INSTRUCTIONS,
)
from research_agent.tools import tavily_search, think_tool
# ① 你自己的领域 prompt
YOUR_DOMAIN_INSTRUCTIONS = """
You are a [your role description].
Your primary responsibilities:
- [Domain task A]
- [Domain task B]
When research is needed, delegate to the "research-agent" subagent
via the task() tool. Never conduct web searches yourself.
"""
# ② 整合:领域 prompt + 研究调度规范
MAIN_INSTRUCTIONS = (
YOUR_DOMAIN_INSTRUCTIONS
+ "\n\n" + "=" * 80 + "\n\n"
+ RESEARCH_WORKFLOW_INSTRUCTIONS
+ "\n\n" + "=" * 80 + "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=3,
max_researcher_iterations=3,
)
)
# ③ SubAgent 定义(与原示例完全相同)
research_sub_agent = {
"name": "research-agent",
"description": "Conducts web research on a single topic. "
"Provide one focused research task at a time.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(
date=datetime.now().strftime("%Y-%m-%d")
),
"tools": [tavily_search, think_tool],
# 可选:用更轻量模型降低成本
# "model": "anthropic:claude-haiku-4-5-20251001",
}
# ④ 创建你的主 agent
agent = create_deep_agent(
model=init_chat_model("anthropic:claude-sonnet-4-6", temperature=0.0),
tools=[
your_domain_tool_1, # 你自己的工具
your_domain_tool_2,
tavily_search, # 主 agent 也持有,供 subagent 继承
think_tool,
],
system_prompt=MAIN_INSTRUCTIONS,
subagents=[research_sub_agent],
)
# 中间层:deep-researcher subagent(扮演原始 agent.py 的角色)
deep_researcher_subagent = {
"name": "deep-researcher",
"description": "Conducts comprehensive deep research with multiple "
"parallel sub-researchers. Use for complex, multi-"
"faceted research requiring exhaustive coverage.",
"system_prompt": (
RESEARCH_WORKFLOW_INSTRUCTIONS
+ "\n\n" + "=" * 80 + "\n\n"
+ SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=3,
max_researcher_iterations=3,
)
),
"tools": [tavily_search, think_tool],
}
# 主 agent:只包含自己的领域职责
agent = create_deep_agent(
model=init_chat_model("anthropic:claude-sonnet-4-6"),
tools=[your_domain_tool_1, your_domain_tool_2],
system_prompt=YOUR_DOMAIN_INSTRUCTIONS,
subagents=[deep_researcher_subagent], # 注意:无 research-agent
)
| Prompt 组件 | 放置位置 | 是否必须 | 说明 |
|---|---|---|---|
YOUR_DOMAIN_INSTRUCTIONS |
主 agent system_prompt 开头 |
必须 | 定义主 agent 身份,放在最前确保优先级最高 |
RESEARCH_WORKFLOW_INSTRUCTIONS |
主 agent system_prompt 中段 |
必须 | 告知主 agent 如何通过 task() 委派研究 |
SUBAGENT_DELEGATION_INSTRUCTIONS |
主 agent system_prompt 末段 |
建议 | 控制并发策略,防止不必要的 token 消耗 |
RESEARCHER_INSTRUCTIONS |
subagent system_prompt |
必须 | 仅属于 research-agent,不得混入主 agent |
def build_main_instructions(
domain_prompt: str,
max_concurrent: int = 3,
max_iterations: int = 3,
) -> str:
"""将领域 prompt 与研究调度规范合并为完整的主 agent system_prompt。"""
separator = "\n\n" + "=" * 80 + "\n\n"
return separator.join([
domain_prompt.strip(),
RESEARCH_WORKFLOW_INSTRUCTIONS.strip(),
SUBAGENT_DELEGATION_INSTRUCTIONS.format(
max_concurrent_research_units=max_concurrent,
max_researcher_iterations=max_iterations,
).strip(),
])
def build_research_subagent(
model_override: str | None = None,
) -> dict:
"""创建标准 research-agent subagent 定义。"""
subagent = {
"name": "research-agent",
"description": "Conducts web research on a single focused topic.",
"system_prompt": RESEARCHER_INSTRUCTIONS.format(
date=datetime.now().strftime("%Y-%m-%d")
),
"tools": [tavily_search, think_tool],
}
if model_override:
subagent["model"] = model_override
return subagent
temperature=0.0 保证稳定性task() tool 是调度核心。
主 agent 调用 task(name="research-agent", prompt="..."),
框架在隔离的上下文窗口内运行 subagent(过滤掉 messages、todos、memory 等主 agent 状态),
返回结果后合并。这意味着 subagent 无法感知主 agent 的历史对话,
每次委派需在 prompt 中包含完整上下文。