在进入正式的subagent学习之前,其实有必要对messages和response做一个说明。
messages 是一个列表结构,表示传递给模型的上下文信息,每一项都包含 role(角色,如 user / assistant / system)和 content(具体内容)。例如 messages[0] 就代表用户当前输入的一句话。在调试器中看到的 0 = {...},本质上就是这个列表中的第一个元素,即你发给模型的请求内容。

而 response 则是模型返回的结果,通常是一个结构化对象而不是简单字符串。它包含了模型 ID、唯一请求 ID,以及最关键的 content 字段。不同于传统接口直接返回文本,一些模型(如 qwen3.5-plus)会以“块”的形式返回内容,比如 ThinkingBlock(思考过程)和 TextBlock(最终回答)。此外,调试器中看到的 special variables 和 function variables 并不是业务数据,它们只是 Python 对象自带的底层属性和方法(如 __class__、append 等),主要用于调试和内部机制,一般不需要关注。

我们仍然从核心函数agent_loop开始,其实与之前的tools_use不同的是,这里多了对于task的处理过程,也就是如果模型返回一个 tool_use block 且 block.name == "task" 时,代码不会像普通工具那样直接调用 TOOL_HANDLERS,而是进入特殊分支:提取 block.input["prompt"],然后调用 run_subagent(...)。这意味着,模型不是要执行某个具体功能(比如读文件、查数据),而是希望再启动一个新的子 Agent 来完成一个子任务。本质上,这是一种“把复杂问题拆成更小问题再解决”的机制。
可以先看一下这个task,task需要prompt和description这两个属性,这正是上面的函数所input的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| # -- Subagent: fresh context, filtered tools, summary-only return -- def run_subagent(prompt: str) -> str: sub_messages = [{"role": "user", "content": prompt}] # fresh context for _ in range(30): # safety limit response = client.messages.create( model=MODEL, system=SUBAGENT_SYSTEM, messages=sub_messages, tools=CHILD_TOOLS, max_tokens=8000, ) sub_messages.append({"role": "assistant", "content": response.content}) if response.stop_reason != "tool_use": break results = [] for block in response.content: if block.type == "tool_use": handler = TOOL_HANDLERS.get(block.name) output = handler(**block.input) if handler else f"Unknown tool: {block.name}" results.append({"type": "tool_result", "tool_use_id": block.id, "content": str(output)[:50000]}) sub_messages.append({"role": "user", "content": results}) # Only the final text returns to the parent -- child context is discarded return "".join(b.text for b in response.content if hasattr(b, "text")) or "(no summary)"
|
看一下subagent,我们可以看到agent_loop其实是相似的,不太一样的可能就是调用的tools是CHILD_TOOLS。
1 2 3 4 5
| # -- Parent tools: base tools + task dispatcher -- PARENT_TOOLS = CHILD_TOOLS + [ {"name": "task", "description": "Spawn a subagent with fresh context. It shares the filesystem but not conversation history.", "input_schema": {"type": "object", "properties": {"prompt": {"type": "string"}, "description": {"type": "string", "description": "Short description of the task"}}, "required": ["prompt"]}}, ]
|
主agent可以看到其实是有一个task的,而subagent没有,这样的话可以避免无限subagent。
1 2 3
| return "".join(b.text for b in response.content if hasattr(b, "text")) or "(no summary)"
|
当subagent执行完之后,会将text作为output,加入到result,最终作为messages进入agent_loop。
其实感觉就是把subagent作为一个tool去使用。
上下文隔离
其实就是说subagent的messages不会去进入到主agent的message。
