学习资料:Datawhale《Deep Agents 实战》第五章:子 Agent 与上下文隔离
本章重点:
SubAgent、Context Quarantine、task()、SubAgentMiddleware、CompiledSubAgent、多 Agent 协作。
一、为什么需要 SubAgent?
上一章介绍了任务规划,通过write_todos将复杂任务拆解成多个子任务。
但任务拆解不代表上下文问题得到解决。
例如,让 Agent 完成一份技术调研报告,其中一个任务是搜索 LangGraph 的相关资料。这个过程可能涉及:
多次网络搜索,每次返回大量文本;
反复读取文档和保存中间结果;
比较不同来源的信息;
整理最终研究结论。
如果所有操作都由主 Agent 完成,搜索记录、工具返回和中间分析会不断堆积,导致上下文膨胀。
而主 Agent 实际上只需要知道最终的研究结论,不需要保留每次搜索的详细过程。
因此,Deep Agents 引入了SubAgent(子智能体)机制,将复杂子任务交给独立 Agent 执行。
1.1 核心思想:Context Quarantine
SubAgent 最重要的设计思想是Context Quarantine(上下文隔离)。
其执行流程:
用户提出复杂任务 | v 主 Agent 规划与任务分配 | | task() v SubAgent 独立上下文执行 | | 搜索、分析、工具调用 | 保存中间结果 v 返回精炼摘要 | v 主 Agent 整合结果并继续执行主 Agent 通过task工具委派任务,子 Agent 在独立上下文中完成工作,最后仅将结果返回主 Agent。
这里的隔离主要指对话上下文隔离,并不是所有资源完全隔离。使用共享 Backend 时,主、子 Agent 仍然可以共享文件。
1.2 什么情况下使用 SubAgent?
| 任务场景 | 是否适合 |
|---|---|
| 多轮搜索、文献调研 | 适合 |
| 复杂数据分析 | 适合 |
| 需要专用工具的任务 | 适合 |
| 多领域任务协作 | 适合 |
| 简单事实查询 | 没必要 |
| 必须由主 Agent 检查全部执行细节 | 不太适合 |
SubAgent 会增加模型调用和委派成本,所以并不是子任务越多越好。
二、如何定义 SubAgent?
Deep Agents 最常用的方式是通过 Python 字典定义子 Agent。
from deepagents import create_deep_agent research_subagent = { "name": "researcher", "description": "执行深度技术调研,搜索资料并整理结果", "system_prompt": """ 你是一名技术研究员。 1. 拆解研究问题 2. 搜索并交叉验证资料 3. 总结关键技术与局限 4. 返回500字以内的摘要 """, "tools": [internet_search], } agent = create_deep_agent( model=model, subagents=[research_subagent], )其中model和internet_search需要提前定义,示例主要展示 SubAgent 的配置方式。
2.1 关键配置字段
| 字段 | 作用 |
|---|---|
name | 子 Agent 唯一名称 |
description | 描述能力,供主 Agent 选择 |
system_prompt | 子 Agent 的独立指令 |
tools | 子 Agent 可使用的工具 |
model | 指定子 Agent 使用的模型 |
middleware | 配置专属中间件 |
skills | 指定独立技能目录 |
response_format | 定义结构化输出 |
permissions | 配置文件访问权限 |
前三个字段必填。
这里有几个容易忽略的细节:
第一,description决定任务路由。
主 Agent 需要根据描述判断调用哪个子 Agent。因此,描述应说明适用场景,而不是简单写成“负责研究”。
第二,system_prompt不继承主 Agent。
每个 SubAgent 都需要自己的系统提示词。
第三,tools默认继承,但显式指定后完全替换。
例如:
"tools": [internet_search]意味着该子 Agent 使用指定工具集,而不是在主 Agent 的工具列表上追加工具。
此外,skills和普通新增的middleware默认不继承,文件权限配置显式指定后也会整体替换父级规则,需要特别注意。
三、General-purpose:默认通用子 Agent
Deep Agents 默认提供一个名为general-purpose的子 Agent。
即使没有显式定义subagents,主 Agent 通常也可以通过task工具委派任务。
例如:
agent = create_deep_agent( model=model, tools=[internet_search], system_prompt="你是一名技术研究助手。", )主 Agent 可以发起类似调用:
task( subagent_type="general-purpose", description="整理 LangGraph 的核心架构特点" )默认通用子 Agent 可以继承主 Agent 显式配置的模型、工具和 Skills,但不会继承主 Agent 的自定义system_prompt。
3.1 子 Agent 的 Todo 规划能力
第四章介绍了TodoListMiddleware,它可以为 Agent 提供write_todos工具。
需要注意,主 Agent 启用了 Todo,并不代表 SubAgent 自动拥有 Todo。
在 Deep Agents v0.7 中,需要分别启用:
from langchain.agents.middleware import TodoListMiddleware agent = create_deep_agent( model=model, middleware=[TodoListMiddleware()], subagents=[ { "name": "general-purpose", "description": "执行需要规划的复杂任务", "system_prompt": "先制定计划,再执行任务。", "middleware": [TodoListMiddleware()], } ], )此时,主 Agent 和子 Agent 各自维护独立的 Todo 清单,不会自动共享任务状态。
可以理解为:
主 Agent 负责整体规划;
子 Agent 负责自己接收到的局部任务;
子 Agent 完成后向主 Agent 汇报结果。
这种设计使任务规划形成层次化结构。
四、CompiledSubAgent:复用 LangGraph 工作流
除了字典定义方式,Deep Agents 还支持CompiledSubAgent。
它允许将已有的 LangGraph 工作流包装为子 Agent。
from deepagents import create_deep_agent, CompiledSubAgent from langchain.agents import create_agent # 创建一个专用 Agent analysis_graph = create_agent( model=model, tools=[statistical_analysis], system_prompt="你是一名数据分析专家。", ) # 包装为子 Agent analysis_agent = CompiledSubAgent( name="data-analyzer", description="执行统计分析和结果解释", runnable=analysis_graph, ) agent = create_deep_agent( model=model, subagents=[analysis_agent], )示例中的statistical_analysis是应用自行定义的工具。
使用CompiledSubAgent时,底层图的 State 必须包含messages字段。
两种定义方式的区别:
| 对比 | 字典方式 | CompiledSubAgent |
|---|---|---|
| 配置难度 | 简单 | 相对复杂 |
| 适用场景 | 常规任务委派 | 复杂工作流 |
| 控制方式 | Prompt + Tools | LangGraph 图结构 |
| 分支与循环 | 依赖 Agent 自主执行 | 可以显式设计 |
普通研究、搜索、报告生成使用字典方式即可。
如果已有成熟的 LangGraph 工作流,或者任务涉及复杂分支和状态流转,则更适合CompiledSubAgent。
五、多 SubAgent 协作模式
实际项目中,可以定义多个专业 SubAgent,让主 Agent 承担任务协调工作。
例如,一个科研文献调研系统可以拆分为:
主 Agent 规划与协调 | +-------+-------+ | | | v v v researcher analyzer writer 文献检索 数据分析 报告撰写 | | | +-------+-------+ | v 主 Agent 整合最终结果对应配置:
subagents = [ { "name": "researcher", "description": "负责文献搜索和资料收集", "system_prompt": "收集资料,返回核心发现与来源。", "tools": [internet_search], }, { "name": "analyzer", "description": "负责分析研究结果与技术局限", "system_prompt": "提取关键发现并比较不同方法。", }, { "name": "writer", "description": "根据研究结果撰写技术报告", "system_prompt": "将分析结果整理成结构清晰的报告。", }, ] agent = create_deep_agent( model=model, subagents=subagents, )典型执行过程:
主 Agent 制定总体计划。
researcher搜集相关资料。analyzer分析研究结果。writer撰写报告。主 Agent 检查和整合最终内容。
这里需要注意,多个 SubAgent 并不意味着自动并行执行。
本章主要介绍同步任务委派。真正的异步委派与并行协作属于下一章的内容。
六、结构化输出:response_format
默认情况下,SubAgent 返回的是自由文本。
但对于需要程序化处理的任务,自由文本可能存在字段不一致、格式不稳定等问题。
Deep Agents 可以通过response_format指定 Pydantic 数据结构。
from pydantic import BaseModel, Field class ResearchResult(BaseModel): summary: str = Field(description="研究摘要") confidence: float = Field(description="置信度") sources: list[str] = Field(description="参考来源") research_subagent = { "name": "researcher", "description": "研究指定主题并返回结构化结果", "system_prompt": "完成研究并返回指定结构。", "response_format": ResearchResult, }此时,子 Agent 可以返回类似:
{ "summary": "LangGraph支持状态化工作流编排。", "confidence": 0.92, "sources": [ "https://docs.langchain.com/" ] }结构化输出的优势在于:
方便主 Agent 提取指定字段;
降低结果解析成本;
适合多 Agent 之间的信息传递;
便于后续数据存储和自动化处理。
这里的confidence是模型提供的数值,不应直接理解为经过统计校准的真实置信度。
七、SubAgent 的设计经验
结合本章内容,整理几个比较实用的原则。
7.1 description 要明确
不推荐:
"description": "负责搜索"推荐:
"description": ( "负责需要多次搜索、交叉验证和综合整理的" "复杂技术调研任务" )描述越具体,主 Agent 越容易正确选择子 Agent。
7.2 工具集遵循最小权限原则
研究型 Agent 通常只需要搜索和文件读取工具,没有必要配置邮件发送、文件删除等无关工具。
这既减少了工具选择的复杂度,也降低了误操作风险。
7.3 不同任务使用不同模型
简单信息提取可以使用轻量模型,复杂推理任务可以使用更强的模型。
这样能够在能力、延迟和成本之间进行权衡。
7.4 控制返回结果长度
上下文隔离是否有效,很大程度上取决于子 Agent 的返回内容。
如果子 Agent 把全部搜索记录和原始数据都返回给主 Agent,仍然会造成上下文膨胀。
更合理的做法是:
中间数据保存到文件,最终只返回摘要、关键发现和文件路径。
7.5 常见问题
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
| SubAgent 没被调用 | description 不明确 | 明确委派条件 |
| 调用了错误的 SubAgent | 多个描述高度相似 | 区分各自职责 |
| 主 Agent 上下文仍然膨胀 | 子 Agent 返回内容过长 | 精简摘要,原始数据写文件 |
| 子 Agent 无法使用 Todo | 没配置中间件 | 单独添加 TodoListMiddleware |
八、学习总结
本章最重要的收获,是理解 SubAgent 的目的并不只是把一个任务交给另一个模型执行,而是通过委派机制管理复杂任务的上下文和执行边界。
结合前面几章,可以建立一条比较清晰的技术主线:
第三章 Virtual Filesystem:解决大量中间信息如何存储。
第四章 Task Planning:解决复杂任务如何拆解和跟踪。
第五章 SubAgent:解决复杂子任务由谁执行,以及如何隔离执行上下文。
这三种机制结合后,Deep Agents 就可以将任务规划、局部执行和信息存储分开管理。
对于科研 Agent,我认为比较合适的场景是文献调研和实验结果分析:主 Agent 负责管理研究目标,专业子 Agent 分别处理文献检索、方法比较和数据分析,最后只返回关键结论。
但也需要认识到,SubAgent 本身并不保证研究结果正确。任务交接过程中仍可能出现信息遗漏、错误传播以及额外的 Token 开销,需要通过结果校验和合理的任务划分来控制。
总结:任务规划解决“做什么”,SubAgent 解决“谁来做”,Context Quarantine 解决“执行过程中产生的信息放在哪里”。
参考资料:
Datawhale:《Deep Agents 实战》第五章:子 Agent 与上下文隔离
标签:Deep AgentsLangChainLangGraphSubAgent多智能体Context Engineering