主题
流式传输
流式输出深度智能体运行和子智能体执行的实时更新
TIP
对于新应用,我们推荐事件流式传输——Deep Agents v0.6 引入的类型化投影 API。事件流式传输为每个投影(子智能体、消息、工具调用、值)提供独立的迭代器,因此你可以独立消费它们,而不必根据 stream_mode 分块进行分支判断。
Deep Agents 构建在 LangGraph 的流式传输基础设施之上,并提供对子智能体流的原生支持。当深度智能体将工作委派给子智能体时,你可以独立地流式传输每个子智能体的更新——实时追踪进度、LLM token 和工具调用。
深度智能体流式传输可以实现的功能:
流式输出子智能体进度——在并行运行时追踪每个子智能体的执行。 *
流式输出 LLM token——从主智能体和每个子智能体流式输出 token。 *
流式输出工具调用——查看子智能体执行内部的工具调用和结果。 *
流式输出自定义更新——从子智能体节点内部发出用户定义的信号。
启用子图流式传输
Deep Agents 使用 LangGraph 的子图流式传输来呈现来自子智能体执行的事件。要接收子智能体事件,请在流式传输时启用 stream_subgraphs。
python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="google_genai:gemini-3.6-flash",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="openai:gpt-5.5",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="anthropic:claude-sonnet-5",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="openrouter:z-ai/glm-5.2",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/glm-5p2",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="baseten:zai-org/GLM-5.2",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="ollama:north-mini-code-1.0",
system_prompt="You are a helpful research assistant",
subagents=[
{
"name": "researcher",
"description": "Researches a topic in depth",
"system_prompt": "You are a thorough researcher.",
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="updates",
subgraphs=True,
):
if namespace:
# Subagent event - namespace identifies the source
print(f"[subagent: {namespace}]")
else:
# Main agent event
print("[main agent]")
print(data)命名空间
启用 subgraphs 后,每个流式传输事件都包含一个命名空间,用于标识产生它的智能体。命名空间是节点名称和任务 ID 的路径,表示智能体层级结构。
| 命名空间 | 来源 |
|---|---|
()(空) | 主智能体 |
("tools:abc123",) | 由主智能体的 task 工具调用 abc123 派生的子智能体 |
("tools:abc123", "model_request:def456") | 子智能体内部的模型请求节点 |
使用命名空间将事件路由到正确的 UI 组件:
python
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Plan my vacation"}]},
stream_mode="updates",
subgraphs=True,
):
# Check if this event came from a subagent
is_subagent = any(
segment.startswith("tools:") for segment in namespace
)
if is_subagent:
# Extract the tool call ID from the namespace
tool_call_id = next(
s.split(":")[1] for s in namespace if s.startswith("tools:")
)
print(f"Subagent {tool_call_id}: {data}")
else:
print(f"Main agent: {data}")子智能体进度
使用 stream_mode="updates" 在每个步骤完成时追踪子智能体进度。这对于展示哪些子智能体处于活动状态以及它们完成了哪些工作很有用。
python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="google_genai:gemini-3.6-flash",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="openai:gpt-5.5",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="anthropic:claude-sonnet-5",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="openrouter:z-ai/glm-5.2",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/glm-5p2",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="baseten:zai-org/GLM-5.2",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")python
from deepagents import create_deep_agent
agent = create_deep_agent(
model="ollama:north-mini-code-1.0",
system_prompt=(
"You are a project coordinator with no research knowledge. "
"For every user request, you must call the task() tool with "
"subagent_type set to researcher. Never answer research questions yourself. "
"Keep your final response to one sentence."
),
subagents=[
{
"name": "researcher",
"description": "Researches topics thoroughly",
"system_prompt": (
"You are a thorough researcher. Research the given topic "
"and provide a concise summary in 2-3 sentences."
),
},
],
)
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Write a short summary about AI safety"}]},
stream_mode="updates",
subgraphs=True,
):
# Main agent updates (empty namespace)
if not namespace:
for node_name, data in data.items():
if node_name == "tools":
# Subagent results returned to main agent
for msg in data.get("messages", []):
if msg.type == "tool":
print(f"\nSubagent complete: {msg.name}")
print(f" Result: {str(msg.content)[:200]}...")
else:
print(f"[main agent] step: {node_name}")
# Subagent updates (non-empty namespace)
else:
for node_name, data in data.items():
print(f" [{namespace[0]}] step: {node_name}")shell
[main agent] step: model_request
[tools:call_abc123] step: model_request
[tools:call_abc123] step: tools
[tools:call_abc123] step: model_request
Subagent complete: task
Result: ## AI Safety Report...
[main agent] step: model_requestLLM token
使用 stream_mode="messages" 从主智能体和子智能体流式传输单个 token。每个消息事件都包含标识来源智能体的元数据。
python
current_source = ""
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing advances"}]},
stream_mode="messages",
subgraphs=True,
):
token, metadata = data
# Check if this event came from a subagent (namespace contains "tools:")
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
# Token from a subagent
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
if subagent_ns != current_source:
print(f"\n\n--- [subagent: {subagent_ns}] ---")
current_source = subagent_ns
if token.content:
print(token.content, end="", flush=True)
else:
# Token from the main agent
if "main" != current_source:
print("\n\n--- [main agent] ---")
current_source = "main"
if token.content:
print(token.content, end="", flush=True)
print()工具调用
当子智能体使用工具时,你可以流式传输工具调用事件,以展示每个子智能体正在做什么。工具调用分块会出现在 messages 流模式中。
python
from langchain.messages import AIMessageChunk, ToolMessage
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research recent quantum computing advances"}]},
stream_mode="messages",
subgraphs=True,
):
token, metadata = data
# Identify source: "main" or the subagent namespace segment
is_subagent = any(s.startswith("tools:") for s in namespace)
source = next((s for s in namespace if s.startswith("tools:")), "main") if is_subagent else "main"
# Tool call chunks (streaming tool invocations)
if isinstance(token, AIMessageChunk) and token.tool_call_chunks:
for tc in token.tool_call_chunks:
if tc.get("name"):
print(f"\n[{source}] Tool call: {tc['name']}")
# Args stream in chunks - write them incrementally
if tc.get("args"):
print(tc["args"], end="", flush=True)
# Tool results
if isinstance(token, ToolMessage):
print(f"\n[{source}] Tool result [{token.name}]: {str(token.content)[:150]}")
# Regular AI content (skip tool call messages)
if (
isinstance(token, AIMessageChunk)
and token.content
and not token.tool_call_chunks
):
print(token.content, end="", flush=True)
print()自定义更新
在你的子智能体工具内使用 get_stream_writer 来发出自定义进度事件:
python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="google_genai:gemini-3.6-flash",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="openai:gpt-5.5",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="anthropic:claude-sonnet-5",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="openrouter:z-ai/glm-5.2",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="fireworks:accounts/fireworks/models/glm-5p2",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="baseten:zai-org/GLM-5.2",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)python
import time
from langchain.tools import tool
from langgraph.config import get_stream_writer
from deepagents import create_deep_agent
@tool
def analyze_data(topic: str) -> str:
"""Run a data analysis on a given topic.
This tool performs the actual analysis and emits progress updates.
You MUST call this tool for any analysis request.
"""
writer = get_stream_writer()
writer({"status": "starting", "topic": topic, "progress": 0})
time.sleep(0.5)
writer({"status": "analyzing", "progress": 50})
time.sleep(0.5)
writer({"status": "complete", "progress": 100})
return (
f'Analysis of "{topic}": Customer sentiment is 85% positive, '
"driven by product quality and support response times."
)
agent = create_deep_agent(
model="ollama:north-mini-code-1.0",
system_prompt=(
"You are a coordinator. For any analysis request, you MUST delegate "
"to the analyst subagent using the task tool. Never try to answer directly. "
"After receiving the result, summarize it in one sentence."
),
subagents=[
{
"name": "analyst",
"description": "Performs data analysis with real-time progress tracking",
"system_prompt": (
"You are a data analyst. You MUST call the analyze_data tool "
"for every analysis request. Do not use any other tools. "
"After the analysis completes, report the result."
),
"tools": [analyze_data],
},
],
)
custom_event_count = 0
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze customer satisfaction trends"}]},
stream_mode="custom",
subgraphs=True,
):
custom_event_count += 1
is_subagent = any(s.startswith("tools:") for s in namespace)
if is_subagent:
subagent_ns = next(s for s in namespace if s.startswith("tools:"))
print(f"[{subagent_ns}]", data)
else:
print("[main]", data)shell
[tools:call_abc123] {'status': 'starting', 'topic': 'customer satisfaction trends', 'progress': 0}
[tools:call_abc123] {'status': 'analyzing', 'progress': 50}
[tools:call_abc123] {'status': 'complete', 'progress': 100}流式输出多种模式
组合多个流模式以获得智能体执行的全貌:
python
# Skip internal middleware steps - only show meaningful node names
INTERESTING_NODES = {"model", "tools"}
last_source = ""
mid_line = False # True when we've written tokens without a trailing newline
for namespace, mode, data in agent.stream(
{"messages": [{"role": "user", "content": "Analyze the impact of remote work on team productivity"}]},
stream_mode=["updates", "messages", "custom"],
subgraphs=True,
):
is_subagent = any(s.startswith("tools:") for s in namespace)
source = "subagent" if is_subagent else "main"
if mode == "updates":
for node_name in data:
if node_name not in INTERESTING_NODES:
continue
if mid_line:
print()
mid_line = False
print(f"[{source}] step: {node_name}")
elif mode == "messages":
token, metadata = data
if token.content:
# Print a header when the source changes
if source != last_source:
if mid_line:
print()
mid_line = False
print(f"\n[{source}] ", end="")
last_source = source
print(token.content, end="", flush=True)
mid_line = True
elif mode == "custom":
if mid_line:
print()
mid_line = False
print(f"[{source}] custom event:", data)
print()常见模式
追踪子智能体生命周期
监控子智能体何时启动、运行和完成:
python
active_subagents = {}
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research the latest AI safety developments"}]},
stream_mode="updates",
subgraphs=True,
):
for node_name, data in data.items():
# ─── Phase 1: Detect subagent starting ────────────────────────
# When the main agent's model node contains task tool calls,
# a subagent has been spawned.
if not namespace and node_name == "model":
for msg in data.get("messages", []):
for tc in getattr(msg, "tool_calls", []):
if tc["name"] == "task":
active_subagents[tc["id"]] = {
"type": tc["args"].get("subagent_type"),
"description": tc["args"].get("description", "")[:80],
"status": "pending",
}
print(
f'[lifecycle] PENDING → subagent "{tc["args"].get("subagent_type")}" '
f'({tc["id"]})'
)
# ─── Phase 2: Detect subagent running ─────────────────────────
# When we receive events from a tools:UUID namespace, that
# subagent is actively executing.
if namespace and namespace[0].startswith("tools:"):
pregel_id = namespace[0].split(":")[1]
# Check if any pending subagent needs to be marked running.
# Note: the pregel task ID differs from the tool_call_id,
# so we mark any pending subagent as running on first subagent event.
for sub_id, sub in active_subagents.items():
if sub["status"] == "pending":
sub["status"] = "running"
print(
f'[lifecycle] RUNNING → subagent "{sub["type"]}" '
f"(pregel: {pregel_id})"
)
break
# ─── Phase 3: Detect subagent completing ──────────────────────
# When the main agent's tools node returns a tool message,
# the subagent has completed and returned its result.
if not namespace and node_name == "tools":
for msg in data.get("messages", []):
if msg.type == "tool":
sub = active_subagents.get(msg.tool_call_id)
if sub:
sub["status"] = "complete"
print(
f'[lifecycle] COMPLETE → subagent "{sub["type"]}" '
f"({msg.tool_call_id})"
)
print(f" Result preview: {str(msg.content)[:120]}...")
# Print final state
print("\n--- Final subagent states ---")
for sub_id, sub in active_subagents.items():
print(f" {sub['type']}: {sub['status']}")处理人在回路中断
当配置了 interrupt_on 时,updates 流可能包含 __interrupt__ 条目,它们会暂停执行以等待人工批准。通过检查更新分块中的 __interrupt__ 键来检测它们。使用与 .invoke() 相同的扁平 {"decisions": [...]} 负载来恢复:
python
from langchain_core.utils.uuid import uuid7
config = {"configurable": {"thread_id": str(uuid7())}}
for mode, data in agent.stream(
{"messages": [{"role": "user", "content": "Delete temp.txt"}]},
stream_mode=["messages", "updates"],
config=config,
):
if mode == "updates" and isinstance(data, dict):
if "__interrupt__" in data:
for interrupt_obj in data["__interrupt__"]:
print(f"Approval needed: {interrupt_obj.value}")有关完整的流式恢复循环模式,请参阅人在回路:使用流式传输处理中断。
流分块形状
在 subgraphs=True 时,分块形状取决于你是传入一个流模式还是多个:
stream_mode | 分块形状 |
|---|---|
单个模式(例如 "updates") | (namespace, data) |
多个模式(例如 ["messages", "updates"]) | (namespace, mode, data) |
在没有 subgraphs 的情况下,单个模式直接产生 data,多个模式则产生 (mode, data)。
python
# Single mode + subgraphs
for namespace, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing"}]},
stream_mode="updates",
subgraphs=True,
):
print(namespace) # () for main agent, ("tools:<id>",) for subagent
print(data)
# Multiple modes + subgraphs
for namespace, mode, data in agent.stream(
{"messages": [{"role": "user", "content": "Research quantum computing"}]},
stream_mode=["updates", "messages", "custom"],
subgraphs=True,
):
print(mode) # "updates", "messages", or "custom"
print(namespace) # () for main agent, ("tools:<id>",) for subagent
print(data)LangGraph 1.1 及更高版本还支持统一的 version="v2" StreamPart 字典格式。请参阅流输出格式(v2)。本页的 Deep Agents 示例使用元组格式,这与 Deep Agents 当前依赖的 LangGraph 版本相匹配。
相关
- 人在回路——为敏感工具操作配置审批工作流
- 子智能体——在 Deep Agents 中配置和使用子智能体
- 前端流式传输——使用
useStream为 Deep Agents 构建 React UI - LangChain 事件流式传输——LangChain 智能体的通用流式传输概念