从上下文隔离到任务协作:SubAgent 的概念、创建与应用实践
从上下文隔离到任务协作:SubAgent 的概念、创建与应用实践
在构建复杂 Agent 应用时,主代理往往需要同时处理任务规划、工具调用、信息检索、数据分析和结果生成等工作。
如果所有任务都由一个 Agent 直接完成,容易出现以下问题:
- 上下文越来越长,导致上下文膨胀
- 大量工具调用记录干扰主任务
- 不同类型的任务彼此混杂
- 主代理难以专注于整体规划
- 复杂任务的执行效率和成功率下降
SubAgent 的出现,就是为了解决这些问题。
SubAgent 可以理解为由主 Agent 调用的专用子代理。它在相对独立的上下文中完成某个具体任务,最后只向主 Agent 返回整理后的关键信息。
一、SubAgent 是什么?
SubAgent 是主 Agent 的子代理,主要负责执行某一类具体任务。
主 Agent 不需要亲自完成所有工作,而是可以将复杂问题拆分为多个子任务,然后交给不同的 SubAgent 执行。
例如,一个“分析 DeepSeek 用户增长情况”的任务,可以被拆分为:
主 Agent:
负责理解问题、拆分任务和生成最终报告
网络搜索 SubAgent:
负责搜索 2024 年和 2025 年的用户数据
数据处理 SubAgent:
负责清洗和整理不同来源的数据
数值计算 SubAgent:
负责计算用户增长率
主 Agent:
负责整合各个 SubAgent 的结果
二、SubAgent 的核心价值
1. 上下文隔离
SubAgent 可以在独立上下文中完成任务。
主 Agent 不需要接收子任务执行过程中的全部信息,只需要接收最终提取出的关键结果。
例如,网络搜索 SubAgent 可能需要:
- 搜索多个网页
- 打开网页内容
- 阅读和筛选信息
- 对比多个数据来源
- 整理搜索结果
主 Agent 不一定需要看到所有网页和工具调用过程,只需要获得最终整理结果:
2024 年用户数量:A
2025 年用户数量:B
增长比例:C
数据来源:D
这种方式可以有效避免主 Agent 的上下文被大量中间信息污染。
2. 任务专业化
不同的 SubAgent 可以负责不同的专业领域。
| SubAgent | 主要职责 | 常用工具 |
|---|---|---|
| 网络搜索 SubAgent | 搜索和整理互联网信息 | Tavily、搜索 API |
| 数据库 SubAgent | 查询和处理数据库数据 | SQL、数据库工具 |
| 数值计算 SubAgent | 执行数学和统计计算 | 计算器、Python |
| 代码 SubAgent | 编写、检查和调试代码 | 代码执行工具 |
| 文档 SubAgent | 读取、分析和生成文档 | 文档处理工具 |
每个 SubAgent 都可以有独立的:
- 系统提示词
- 工具列表
- 模型配置
- 输出格式
- 中间件
- 状态处理逻辑
3. 提高执行效率和成功率
由于 SubAgent 专注于单一任务,因此能够减少任务之间的相互干扰。
与让一个 Agent 从头到尾处理所有工作相比,专业化的 SubAgent 更容易:
- 准确调用工具
- 遵守专用提示词
- 输出结构化结果
- 控制上下文长度
- 提高任务完成质量
三、Deep Agent 与 SubAgent 的协作逻辑
Deep Agent 通常充当系统中的主 Agent,负责高层次的规划和协调。
主 Agent 的主要职责:
- 理解用户需求
- 制定整体计划
- 拆分复杂任务
- 选择合适的 SubAgent
- 分派任务
- 整合子任务结果
- 生成最终回答
SubAgent 的主要职责:
- 接收具体任务
- 使用指定工具
- 在独立上下文中执行任务
- 整理和筛选结果
- 将关键结果返回主 Agent
四、SubAgent 的两种创建方式
SubAgent 主要有两种创建方法:
- Dictionary-based 基础创建
- CompiledSubAgent 自定义创建
五、Dictionary-based SubAgent
1. 基本结构
Dictionary-based 方式通过一个字典来描述 SubAgent。
internet_subagent = {
"name": "internet-agent",
"description": (
"Utilize online tools to search for information "
"on the internet"
),
"system_prompt": "You are a great Internet searcher",
"tools": [internet_search],
"model": model,
}
2. 配置字段
必填字段
| 字段 | 类型 | 说明 |
|---|---|---|
name | str | SubAgent 的名称 |
description | str | SubAgent 的职责描述 |
system_prompt | str | SubAgent 的系统提示词 |
tools | List | SubAgent 可以调用的工具列表 |
可选字段
| 字段 | 类型 | 说明 |
|---|---|---|
model | str | BaseChatModel | SubAgent 使用的模型 |
middleware | List[Middleware] | SubAgent 使用的中间件 |
interrupt_on | Dict[str, bool] | 配置工具调用是否支持中断 |
3. 创建工具
以 Tavily 网络搜索为例:
import os
from langchain_core.tools import tool
from tavily import TavilyClient
tavily_client = TavilyClient(
api_key=os.environ["TAVILY_API_KEY"]
)
@tool
def internet_search(query: str) -> str:
"""
Search the internet for relevant information.
"""
response = tavily_client.search(query)
return str(response)
其中:
@tool用于将函数声明为 LangChain 工具TAVILY_API_KEY从环境变量中读取 API Keyinternet_search是网络搜索 SubAgent 使用的工具
4. 配置 SubAgent
internet_subagent = {
"name": "internet-agent",
"description": (
"Utilize online tools to search for information "
"on the internet."
),
"system_prompt": (
"You are an expert internet researcher. "
"Search for reliable information and summarize "
"the key findings."
),
"tools": [internet_search],
"model": model,
}
description 的作用
description 不只是普通的文字说明,还可以帮助主 Agent 判断什么时候应该调用这个 SubAgent。
推荐写法:
"description": (
"Search the internet for up-to-date information "
"and summarize the most relevant findings."
)
不推荐写法:
"description": "A useful agent"
描述过于模糊时,主 Agent 可能无法准确判断该 SubAgent 的用途。
system_prompt 的作用
system_prompt 用于定义 SubAgent 的角色和行为方式。
例如:
"system_prompt": """
You are an expert internet researcher.
Search for reliable and up-to-date information.
Summarize the key findings clearly.
"""
一个好的系统提示词通常需要说明:
- SubAgent 的角色
- 需要完成的任务
- 工具的使用方式
- 结果的整理方式
- 输出格式和质量要求
5. 将 SubAgent 传入 Deep Agent
from deepagents import create_deep_agent
agent = create_deep_agent(
model=model,
subagents=[internet_subagent],
)
subagents 可以传入多个 SubAgent:
agent = create_deep_agent(
model=model,
subagents=[
internet_subagent,
database_subagent,
calculation_subagent,
],
)
六、CompiledSubAgent 自定义创建
1. 基本思路
CompiledSubAgent 的创建流程是:
使用 create_agent 创建独立代理
↓
将独立代理包装为 CompiledSubAgent
↓
传入 create_deep_agent
↓
由主 Agent 调用
相比字典方式,CompiledSubAgent 可以对代理内部逻辑进行更细致的控制。
2. 使用 create_agent 创建独立代理
from deepagents import create_deep_agent, CompiledSubAgent
from langchain.agents import create_agent
custom_graph = create_agent(
model=model,
tools=[internet_search],
prompt="You are a great Internet searcher.",
)
这里的 custom_graph 是一个已经配置完成的独立代理。
参数说明:
| 参数 | 说明 |
|---|---|
model | 代理使用的模型 |
tools | 代理可以调用的工具 |
prompt | 代理的系统提示词 |
3. 包装为 CompiledSubAgent
custom_subagent = CompiledSubAgent(
name="internet_search",
description=(
"A specialised agent for gathering information "
"via web searches"
),
runnable=custom_graph,
)
CompiledSubAgent 的核心字段:
| 字段 | 说明 |
|---|---|
name | SubAgent 的名称 |
description | SubAgent 的功能描述 |
runnable | 实际执行任务的代理对象 |
4. 传入 Deep Agent
agent = create_deep_agent(
model=model,
tools=[internet_search],
subagents=[custom_subagent],
)
完整调用关系:
七、SubAgent 的实际调用
可以使用 HumanMessage 向主 Agent 发送任务:
from langchain.messages import HumanMessage
res = agent.invoke(
{
"messages": [
HumanMessage(
content=(
"进行网络搜索获取数据,比对 DeepSeek 模型的用户使用量,"
"2024 到 2025 年增长了百分之多少?"
)
)
]
}
)
主 Agent 可能会产生类似的工具调用:
[
{
"name": "task",
"args": {
"description": (
"Conduct a comprehensive web search "
"to gather ..."
),
"subagent_type": "internet-agent",
},
"id": "call_...",
"type": "tool_call",
}
]
字段含义:
| 字段 | 含义 |
|---|---|
name | 被调用的工具名称 |
args | 工具调用参数 |
description | 分派给 SubAgent 的任务 |
subagent_type | 要调用的 SubAgent 类型 |
id | 本次调用的唯一标识 |
type | 调用类型 |
八、SubAgent 的应用场景
1. 适合使用 SubAgent
多步骤任务
数据搜索 → 信息提取 → 数据清洗 → 数值计算 → 报告生成
可以将每个阶段交给对应的 SubAgent,避免主 Agent 上下文变得混乱。
专业领域任务
当任务需要专用说明、工具或领域知识时,可以创建专用 SubAgent。
例如:
- 网络搜索
- 数据库查询
- 财务分析
- 法律检索
- 代码审查
- 文档解析
不同模型能力的任务
可以根据任务特点,为不同 SubAgent 配置不同模型。
search_subagent = {
"name": "search-agent",
"description": "负责搜索和整理资料",
"system_prompt": "你是一名专业的信息检索专家",
"tools": [internet_search],
"model": search_model,
}
calculation_subagent = {
"name": "calculation-agent",
"description": "负责执行数值计算",
"system_prompt": "你是一名严谨的数值计算专家",
"tools": [calculator],
"model": reasoning_model,
}
主 Agent 需要专注于规划
当主 Agent 只负责高层协调时,系统结构会更加清晰:
2. 不适合使用 SubAgent
简单的单步任务
例如:
- 回答简单问题
- 执行一次简单计算
- 查询单个数据
- 总结一小段文本
这些任务直接由主 Agent 完成即可。
后续步骤依赖完整中间信息
如果后续处理必须依赖前面所有中间过程,就不应简单地只返回摘要。
可以采用以下方案:
- 返回完整的结构化数据
- 保留关键中间结果
- 让主 Agent 参与关键步骤
- 只隔离不影响后续处理的部分
成本敏感的任务
使用 SubAgent 可能增加:
- 模型调用次数
- Token 消耗
- 工具调用次数
- 执行时间
- 系统维护成本
因此需要评估 SubAgent 带来的收益是否值得这些额外开销。
九、三种 SubAgent 类型对比
| 类型 | 创建方式 | 自定义能力 | 适用场景 |
|---|---|---|---|
| General-purpose SubAgent | 系统自动提供 | 一般 | 通用、临时任务 |
| Dictionary-based SubAgent | 使用字典配置 | 中等 | 简单、标准化任务 |
| CompiledSubAgent | 独立创建后包装 | 较强 | 复杂、高度定制化任务 |
十、如何选择 SubAgent 创建方式?
可以按照以下思路进行选择:
推荐原则
- 简单任务:直接由主 Agent 执行
- 简单专用任务:使用 Dictionary-based
- 复杂专用任务:使用 CompiledSubAgent
- 通用临时任务:使用 General-purpose SubAgent
- 强依赖中间信息的任务:谨慎进行上下文隔离
- 成本敏感任务:先评估调用收益和额外开销
十一、最佳实践
1. 清晰描述 SubAgent 职责
"description": (
"Search the internet for reliable information "
"and summarize the key findings."
)
不要使用过于模糊的描述:
"description": "A useful agent"
2. 让 SubAgent 返回结构化结果
推荐让 SubAgent 返回清晰、紧凑的结果:
{
"topic": "DeepSeek 用户增长",
"data_2024": "...",
"data_2025": "...",
"growth_rate": "...",
"sources": [...]
}
这样主 Agent 更容易继续处理。
3. 控制返回内容
SubAgent 的目标不是返回所有过程信息,而是返回对主任务有用的结果。
原始工具结果
↓
SubAgent 筛选和整理
↓
结构化关键信息
↓
主 Agent
4. 为不同任务选择合适模型
如果某个 SubAgent 负责复杂推理、专业分析或精确计算,可以为它单独指定更适合的模型。
5. 避免过度拆分
不是所有任务都需要 SubAgent。
如果一个任务只有一步操作,强行创建 SubAgent 可能会导致:
- 调用链变长
- 系统复杂度增加
- Token 消耗上升
- 执行时间增加
- 调试难度提高
十二、总结
SubAgent 的核心思想是:
将复杂任务中的局部工作交给专门的子代理,在独立上下文中完成任务,并将关键结果返回给主 Agent。
它主要带来三方面价值:
- 上下文隔离:避免主 Agent 被大量中间信息污染
- 任务专业化:让不同 SubAgent 负责不同领域和工具
- 高层协调:让主 Agent 专注于任务规划、协调和结果整合
SubAgent 的创建方式主要有两种:
Dictionary-based
→ 简单、标准化、配置方便
CompiledSubAgent
→ 灵活、自定义、适合复杂代理逻辑
最终,一个合理的 Agent 系统应该根据任务复杂度、上下文依赖、专业化需求和运行成本,决定是否使用 SubAgent,以及选择哪种创建方式。