对于新应用,我们推荐使用事件流—这是 Deep Agents v0.6 中引入的类型化投影 API。事件流为每个投影(子代理、消息、工具调用、值)提供独立的迭代器,因此您可以独立消费它们,而不是基于
stream_mode 块进行分支处理。- 流式获取子代理进度—在子代理并行运行时跟踪其执行过程。
- 流式获取 LLM 令牌—从主代理和每个子代理流式获取令牌。
- 流式获取工具调用—查看子代理执行过程中的工具调用和结果。
- 流式获取自定义更新—从子代理节点内部发出用户定义的信号。
启用子图流式传输
Deep Agents 使用 LangGraph 的子图流式传输来呈现子代理执行过程中的事件。要接收子代理事件,请在流式传输时启用stream_subgraphs。
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "google-genai:gemini-3.6-flash",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "openai:gpt-5.5",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "openrouter:openrouter:z-ai/glm-5.2",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "fireworks:accounts/fireworks/models/glm-5p2",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "baseten:zai-org/GLM-5.2",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "ollama:north-mini-code-1.0",
systemPrompt: "你是一个有用的研究助手",
subagents: [
{
name: "researcher",
description: "深入研究某个主题",
systemPrompt: "你是一位细致的研究员。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "研究量子计算的进展" },
],
},
{
streamMode: "updates",
subgraphs: true,
},
)) {
if (namespace.length > 0) {
// 子代理事件 - namespace 标识了事件来源
console.log(`[subagent: ${namespace.join("|")}]`);
} else {
// 主代理事件
console.log("[main agent]");
}
console.log(chunk);
}
命名空间
当启用subgraphs 时,每个流式事件都包含一个命名空间,用于标识产生它的代理。命名空间是节点名称和任务 ID 的路径,代表了代理的层级结构。
| 命名空间 | 来源 |
|---|---|
() (空) | 主代理 |
("tools:abc123",) | 由主代理的 task 工具调用 abc123 生成的子代理 |
("tools:abc123", "model_request:def456") | 子代理内部的模型请求节点 |
for await (const [namespace, chunk] of await agent.stream(
{ messages: [{ role: "user", content: "Plan my vacation" }] },
{ streamMode: "updates", subgraphs: true },
)) {
// 检查此事件是否来自子代理
const isSubagent = namespace.some((segment: string) =>
segment.startsWith("tools:"),
);
if (isSubagent) {
// 从命名空间中提取工具调用 ID
const toolCallId = namespace
.find((s: string) => s.startsWith("tools:"))
?.split(":")[1];
console.log(`子代理 ${toolCallId}:`, chunk);
} else {
console.log("主代理:", chunk);
}
}
子代理进度
使用stream_mode="updates" 在每一步完成时跟踪子代理进度。这对于显示哪些子代理处于活动状态以及它们已完成的工作非常有用。
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "google-genai:gemini-3.6-flash",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "openai:gpt-5.5",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "openrouter:openrouter:z-ai/glm-5.2",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "fireworks:accounts/fireworks/models/glm-5p2",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "baseten:zai-org/GLM-5.2",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
import { createDeepAgent } from "deepagents";
const agent = createDeepAgent({
model: "ollama:north-mini-code-1.0",
systemPrompt:
"你是一个没有研究知识的项目协调者。" +
"对于每个用户请求,你必须调用 task() 工具," +
"并将 subagent_type 设置为 researcher。永远不要自己回答研究问题。" +
"将最终回复保持在一句话以内。",
subagents: [
{
name: "researcher",
description: "深入研究主题",
systemPrompt:
"你是一个细致的研究员。研究给定的主题 " +
"并在2-3句话内提供简洁的总结。",
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Write a short summary about AI safety" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
// 主代理更新(命名空间为空)
if (namespace.length === 0) {
for (const [nodeName, data] of Object.entries(chunk)) {
if (nodeName === "tools") {
// 返回给主代理的子代理结果
for (const msg of (data as any).messages ?? []) {
if (msg.type === "tool") {
console.log(`\n子代理完成: ${msg.name}`);
console.log(` 结果: ${String(msg.content).slice(0, 200)}...`);
}
}
} else {
console.log(`[主代理] 步骤: ${nodeName}`);
}
}
}
// 子代理更新(命名空间非空)
else {
for (const [nodeName] of Object.entries(chunk)) {
console.log(` [${namespace[0]}] 步骤: ${nodeName}`);
}
}
}
Output
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_request
[tools:call_def456] step: model_request
[tools:call_def456] step: model_request
Subagent complete: task
Result: # Comprehensive Report on AI Safety...
Main agent step: model_request
LLM 令牌
使用stream_mode="messages" 流式传输来自主代理和各个子代理的单独令牌。每个消息事件都包含标识源代理的元数据。
let currentSource = "";
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "Research quantum computing advances",
},
],
},
{ streamMode: "messages", subgraphs: true },
)) {
const [message] = chunk;
// 检查此事件是否来自子代理(命名空间包含 "tools:")
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
// 来自子代理的令牌
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
if (subagentNs !== currentSource) {
process.stdout.write(`\n\n--- [子代理: ${subagentNs}] ---\n`);
currentSource = subagentNs;
}
if (message.text) {
process.stdout.write(message.text);
}
} else {
// 来自主代理的令牌
if ("main" !== currentSource) {
process.stdout.write(`\n\n--- [主代理] ---\n`);
currentSource = "main";
}
if (message.text) {
process.stdout.write(message.text);
}
}
}
process.stdout.write("\n");
工具调用
当子代理使用工具时,您可以流式传输工具调用事件以显示每个子代理正在执行的操作。工具调用块会出现在messages 流模式中。
import { AIMessageChunk, ToolMessage } from "langchain";
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "研究近期的量子计算进展",
},
],
},
{ streamMode: "messages", subgraphs: true },
)) {
const [message] = chunk;
// 识别来源:主进程或子代理的命名空间段
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
const source = isSubagent
? namespace.find((s: string) => s.startsWith("tools:"))!
: "main";
// 工具调用数据块(流式工具调用)
if (AIMessageChunk.isInstance(message) && message.tool_call_chunks?.length) {
for (const tc of message.tool_call_chunks) {
if (tc.name) {
console.log(`\n[${source}] 工具调用:${tc.name}`);
}
// 参数以数据块形式流式传输 - 增量写入
if (tc.args) {
process.stdout.write(tc.args);
}
}
}
// 工具执行结果
if (ToolMessage.isInstance(message)) {
console.log(
`\n[${source}] 工具结果 [${message.name}]: ${message.text?.slice(0, 150)}`,
);
}
// 常规AI内容(跳过工具调用消息)
if (
AIMessageChunk.isInstance(message) &&
message.text &&
!message.tool_call_chunks?.length
) {
process.stdout.write(message.text);
}
}
process.stdout.write("\n");
自定义更新
在子代理工具内部使用config.writer 来发出自定义进度事件:
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "google-genai:gemini-3.6-flash",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "openai:gpt-5.5",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "anthropic:claude-sonnet-4-6",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "openrouter:openrouter:z-ai/glm-5.2",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "fireworks:accounts/fireworks/models/glm-5p2",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "baseten:zai-org/GLM-5.2",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
import { createDeepAgent } from "deepagents";
import { tool, type ToolRuntime } from "langchain";
import { z } from "zod";
/**
* 一个通过 config.writer 发送自定义进度事件的工具。
* writer 将数据发送到 “custom” 流模式。
*/
const analyzeData = tool(
async ({ topic }: { topic: string }, config: ToolRuntime) => {
const writer = config.writer;
writer?.({ status: "starting", topic, progress: 0 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "analyzing", progress: 50 });
await new Promise((r) => setTimeout(r, 500));
writer?.({ status: "complete", progress: 100 });
return `对“${topic}”的分析结果:客户情绪85%为正面,主要驱动因素是产品质量和支持响应时间。`;
},
{
name: "analyze_data",
description:
"对给定主题运行数据分析。" +
"此工具执行实际的分析并发送进度更新。" +
"对于任何分析请求,你必须调用此工具。",
schema: z.object({
topic: z.string().describe("要分析的主题或主题"),
}),
},
);
const agent = createDeepAgent({
model: "ollama:north-mini-code-1.0",
systemPrompt:
"你是一个协调员。对于任何分析请求,你必须使用任务工具" +
"委托给分析师子智能体。切勿尝试直接回答。" +
"收到结果后,用一句话总结。",
subagents: [
{
name: "analyst",
description: "执行数据分析并实时跟踪进度",
systemPrompt:
"你是一个数据分析师。对于每个分析请求,你必须调用" +
"analyze_data 工具。不要使用任何其他工具。" +
"分析完成后,请报告结果。",
tools: [analyzeData],
},
],
});
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析客户满意度趋势",
},
],
},
{ streamMode: "custom", subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
if (isSubagent) {
const subagentNs = namespace.find((s: string) => s.startsWith("tools:"))!;
console.log(`[${subagentNs}]`, chunk);
} else {
console.log("[main]", chunk);
}
}
Output
[tools:call_abc123] { status: 'fetching', progress: 0 }
[tools:call_abc123] { status: 'analyzing', progress: 50 }
[tools:call_abc123] { status: 'complete', progress: 100 }
流式传输多种模式
组合多种流模式以获得代理执行的完整视图:// 跳过内部中间件步骤 - 仅显示有意义的节点名称
const INTERESTING_NODES = new Set(["model", "tools"]);
let lastSource = "";
let midLine = false; // 当我们写入了令牌但没有结尾换行符时为 true
for await (const [namespace, mode, data] of await agent.stream(
{
messages: [
{
role: "user",
content: "分析远程工作对团队生产力的影响",
},
],
},
{ streamMode: ["updates", "messages", "custom"], subgraphs: true },
)) {
const isSubagent = namespace.some((s: string) => s.startsWith("tools:"));
const source = isSubagent ? "子代理" : "主代理";
if (mode === "updates") {
for (const nodeName of Object.keys(data)) {
if (!INTERESTING_NODES.has(nodeName)) continue;
if (midLine) {
process.stdout.write("\n");
midLine = false;
}
console.log(`[${source}] step: ${nodeName}`);
}
} else if (mode === "messages") {
const [message] = data;
if (message.text) {
// 当来源变化时打印标题
if (source !== lastSource) {
if (midLine) {
process.stdout.write("\n");
midLine = false;
}
process.stdout.write(`\n[${source}] `);
lastSource = source;
}
process.stdout.write(message.text);
midLine = true;
}
} else if (mode === "custom") {
if (midLine) {
process.stdout.write("\n");
midLine = false;
}
console.log(`[${source}] custom event:`, data);
}
}
process.stdout.write("\n");
常见模式
跟踪子代理生命周期
监控子代理何时启动、运行和完成:function getToolCalls(message: unknown): Array<{
id?: string;
name?: string;
args?: Record<string, unknown>;
}> {
if (!message || typeof message !== "object") {
return [];
}
const record = message as Record<string, unknown>;
const toolCalls = record.tool_calls ?? record.toolCalls;
return Array.isArray(toolCalls)
? (toolCalls as Array<{
id?: string;
name?: string;
args?: Record<string, unknown>;
}>)
: [];
}
const activeSubagents = new Map<
string,
{ type?: string; description?: string; status: string }
>();
for await (const [namespace, chunk] of await agent.stream(
{
messages: [
{ role: "user", content: "Research the latest AI safety developments" },
],
},
{ streamMode: "updates", subgraphs: true },
)) {
for (const [nodeName, data] of Object.entries(chunk)) {
// ─── 阶段1:检测子代理启动 ────────────────────────
// 当主代理发出任务工具调用时,说明已生成一个子代理。
if (namespace.length === 0) {
for (const msg of (data as { messages?: unknown[] }).messages ?? []) {
for (const tc of getToolCalls(msg)) {
if (tc.name === "task" && tc.id) {
activeSubagents.set(tc.id, {
type: tc.args?.subagent_type as string | undefined,
description: String(tc.args?.description ?? "").slice(0, 80),
status: "pending",
});
console.log(
`[lifecycle] PENDING → subagent "${tc.args?.subagent_type}" (${tc.id})`,
);
}
}
}
}
// ─── 阶段2:检测子代理运行中 ─────────────────────────
// 当我们从 "tools:UUID" 命名空间接收到事件时,
// 表示该子代理正在执行中。
if (namespace.length > 0 && namespace[0].startsWith("tools:")) {
const pregelId = namespace[0].split(":")[1];
// 检查是否有任何待处理的子代理需要标记为运行中。
// 注意:pregel 任务 ID 与 tool_call_id 不同,
// 因此我们在收到第一个子代理事件时将任何待处理的子代理标记为运行中。
let markedRunning = false;
for (const [, sub] of activeSubagents) {
if (sub.status === "pending") {
sub.status = "running";
markedRunning = true;
console.log(
`[lifecycle] RUNNING → subagent "${sub.type}" (pregel: ${pregelId})`,
);
break;
}
}
if (!markedRunning && activeSubagents.size === 0) {
activeSubagents.set(pregelId, {
type: "researcher",
status: "running",
});
console.log(
`[lifecycle] RUNNING → subagent "researcher" (pregel: ${pregelId})`,
);
}
}
// ─── 阶段3:检测子代理完成 ──────────────────────
// 当主代理的 tools 节点返回一个工具消息时,
// 表示子代理已完成并返回了其结果。
if (namespace.length === 0 && nodeName === "tools") {
for (const msg of (data as { messages?: Array<Record<string, unknown>> })
.messages ?? []) {
if (msg.type === "tool") {
const toolCallId = String(msg.tool_call_id ?? msg.toolCallId ?? "");
const subagent = activeSubagents.get(toolCallId);
if (subagent) {
subagent.status = "complete";
console.log(
`[lifecycle] COMPLETE → subagent "${subagent.type}" (${toolCallId})`,
);
console.log(
` 结果预览: ${String(msg.content).slice(0, 120)}...`,
);
}
}
}
}
}
}
// 打印最终状态
console.log("\n--- 子代理最终状态 ---");
for (const [id, sub] of activeSubagents) {
console.log(` ${sub.type}: ${sub.status}`);
}
相关内容
- 子代理— 使用 Deep Agents 配置和使用子代理
- 前端流式传输— 使用
useStream为 Deep Agents 构建 React UI - LangChain 事件流— 使用 LangChain 代理的通用流式概念
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

