SKILL.md 技能文档
能力目标
把一段需要多步操作的子任务整体交给一个独立子智能体执行,主智能体只拿回一条精炼结论;并能验证隔离真的生效、知道该往委派说明里打包什么、判断某个子任务值不值得委派。
前置
- 已能用
create_deep_agent构造智能体并读懂消息链(见 bootstrapping-deepagents-env)。 - 委派工具
task由框架自动注入,挂上子智能体列表即可用,不需要手写。
实操流程
写子任务要用的工具函数。文档字符串会作为工具说明喂给模型、决定它何时调用,必须写清楚:
def count_words(text: str) -> str: """Count words in the given text.""" return f"word_count={len(text.split())}"用普通字典定义子智能体,三个必填字段
name、description、system_prompt,可选tools与model:from deepagents import create_deep_agent, SubAgent analyzer_agent: SubAgent = { "name": "analyzer-agent", "description": ( "Analyzes a single text document: counts words and produces a short summary. " "Use this agent for any per-document analysis task." ), "system_prompt": ( "You analyze one document at a time. " "Use count_words to count words, then use summarize_local for a brief summary. " "Return a one-line conclusion only." ), "tools": [count_words, summarize_local], }类型标注可写可不写,写上能让编辑器帮你查字段名拼写。
挂进主智能体。主智能体定位是协调者,业务工具都放进子智能体里,并且系统提示必须明写「何时委派给谁」——不写这句主智能体不会凭空知道该用哪个子智能体:
agent = create_deep_agent( model=model, tools=[], system_prompt=( "You are a coordinator. When asked to analyze documents, " "delegate each document analysis to analyzer-agent, " "then ask merger-agent to combine the results." ), subagents=[analyzer_agent, merger_agent], )委派时把所有私有约束打包进委派说明。子智能体从一张白纸起跑,看不到主对话历史,委派说明是它唯一的信息通道。写在主对话里的预算上限、用户偏好、业务规则,不打包就等于让它靠默认值瞎猜:
# 好:Recommend 3 stocks ... Budget limit per stock: $5,000 (内部规则编号). # 坏:Pick 3 stocks for portfolio.需要在主子之间传大块数据时走文件,不要塞进委派说明。文件状态双向穿透委派边界:主智能体
write_file写的文件子智能体读得到、子智能体的改写也会合并回主智能体,而消息仍然隔离:# 主智能体 write_file /shared.txt → 委派子智能体读它并改写 → 主智能体 read_file 取回要做能力与成本分层,就给子智能体单独配模型。该字段接受模型名字符串或已构造的模型对象:
sub_model = ChatOpenAI(model="qwen-turbo", base_url=..., api_key=..., temperature=0) sentiment_agent: SubAgent = { "name": "sentiment-analyzer", "description": "Analyzes the sentiment of text (positive/negative/neutral). ...", "system_prompt": "You are a concise sentiment analyzer ...", "model": sub_model, "tools": [analyze_sentiment], }
校验回路
- 数主智能体消息链里
task的调用次数与参数:参数是description(这次子任务干什么)加subagent_type(派给谁,值等于子智能体字典的name)。调用次数 >0 说明路由成立。 - 数收口比:子智能体内部跑了 N 次工具调用,主智能体因这次委派只新增 1 条工具消息。这个 N→1 是框架固定行为,与子智能体内部做了多少步无关。
- 验输入侧隔离:在主对话里埋一个模型推断不出来的锚点字符串,委派后检查子智能体回传的内容里没有它。
- 验分层真的命中不同模型:用事件流拦截模型调用结束事件,从返回元数据里读实际命中的模型标识,再按事件里的智能体名字段区分是主脑还是子脑发起的。
- 量收益:同一任务跑「主智能体自己调工具」与「委派子智能体」两版,比主智能体最终的消息条数与字符总量。实测一次运行消息数降约 60%、字符数降约 71%(具体百分比随模型临场决定的工具调用次数浮动,关键是委派版主上下文恒为一条收口后的摘要)。
常见陷阱
- 委派说明写得模糊:后果不是路由到错的子智能体,而是主智能体判断不出该用谁、干脆自己做了,委派次数为 0,且不报任何错。描述的首要读者是做路由决策的主智能体,要具体到能和其他子智能体区分开。
- 忘了在委派说明里打包私有约束:子智能体会用一个自造的默认值继续跑。实测同一任务里,不打包时它用了一个比真实约束大十倍的预算上限。
- 以为规划状态会共享:消息、待办清单、结构化输出三项在启动子智能体时被剥掉,子智能体有自己独立的一份待办清单。文件状态不在剥除之列,这是唯一穿透的通道。剥除清单的具体成员随版本变化,以你本机装的版本源码里那个常量为准、直接导入打印比任何二手描述可靠。
- 想让子智能体再往下委派:子智能体的工具列表里没有
task,委派实际最多一层。 - 想手动构造子智能体的图:用 LangGraph 的预置反应式智能体构造器建独立图再注册;不要套用
create_deep_agent去建子图,会因通用型子智能体继承父工具与工具节点冲突抛ValueError。也不要裸实例化子智能体中间件,缺后端参数会抛TypeError——正确入口就是create_deep_agent(subagents=[...]),它替你补齐了后端与默认模型。 - 误以为委派是并行:委派是同步调用,主智能体在子智能体返回前什么都不做,两次委派是排队执行。要真并行得另走异步方案。
- 给琐碎子任务也委派:委派有固定开销(额外一轮推理加子智能体图初始化),同口径实测约 +2.6 秒。模型自己一步能答的任务不值得委派,实测这类任务模型也会正确判断不委派。
- 拿事件流的事件数去证明收口比:事件流里那些数字含逐 token 的流式片段,是事件口径不是消息口径。收口比要数消息里的工具消息条数。
适用范围与前置条件
- 已能用
create_deep_agent构造智能体并读懂消息链(见 bootstrapping-deepagents-env)。 - 委派工具
task由框架自动注入,挂上子智能体列表即可用,不需要手写。
怎么使用
使用步骤
写子任务要用的工具函数。文档字符串会作为工具说明喂给模型、决定它何时调用,必须写清楚:
def count_words(text: str) -> str: """Count words in the given text.""" return f"word_count={len(text.split())}"用普通字典定义子智能体,三个必填字段
name、description、system_prompt,可选tools与model:from deepagents import create_deep_agent, SubAgent analyzer_agent: SubAgent = { "name": "analyzer-agent", "description": ( "Analyzes a single text document: counts words and produces a short summary. " "Use this agent for any per-document analysis task." ), "system_prompt": ( "You analyze one document at a time. " "Use count_words to count words, then use summarize_local for a brief summary. " "Return a one-line conclusion only." ), "tools": [count_words, summarize_local], }类型标注可写可不写,写上能让编辑器帮你查字段名拼写。
挂进主智能体。主智能体定位是协调者,业务工具都放进子智能体里,并且系统提示必须明写「何时委派给谁」——不写这句主智能体不会凭空知道该用哪个子智能体:
agent = create_deep_agent( model=model, tools=[], system_prompt=( "You are a coordinator. When asked to analyze documents, " "delegate each document analysis to analyzer-agent, " "then ask merger-agent to combine the results." ), subagents=[analyzer_agent, merger_agent], )委派时把所有私有约束打包进委派说明。子智能体从一张白纸起跑,看不到主对话历史,委派说明是它唯一的信息通道。写在主对话里的预算上限、用户偏好、业务规则,不打包就等于让它靠默认值瞎猜:
# 好:Recommend 3 stocks ... Budget limit per stock: $5,000 (内部规则编号). # 坏:Pick 3 stocks for portfolio.需要在主子之间传大块数据时走文件,不要塞进委派说明。文件状态双向穿透委派边界:主智能体
write_file写的文件子智能体读得到、子智能体的改写也会合并回主智能体,而消息仍然隔离:# 主智能体 write_file /shared.txt → 委派子智能体读它并改写 → 主智能体 read_file 取回要做能力与成本分层,就给子智能体单独配模型。该字段接受模型名字符串或已构造的模型对象:
sub_model = ChatOpenAI(model="qwen-turbo", base_url=..., api_key=..., temperature=0) sentiment_agent: SubAgent = { "name": "sentiment-analyzer", "description": "Analyzes the sentiment of text (positive/negative/neutral). ...", "system_prompt": "You are a concise sentiment analyzer ...", "model": sub_model, "tools": [analyze_sentiment], }