理解 LangGraph Subagent 的 ID 关联机制
在 LangGraph/DeepAgents 中,主 agent 委派 subagent 执行任务时,通过一个精巧的 ID 关联机制来追踪整个生命周期。本文用最简洁的方式说明这个机制。
核心概念
一句话概括:task 工具调用的 id 就是 subagent 的身份标识,用来关联整个生命周期。
完整流程
步骤 1:主 agent 决定委派任务
主 agent 调用 task 工具,生成一个唯一的 tool_call_id:
python
{
"type": "updates",
"ns": (), # 主 agent,ns 为空
"data": {
"model_request": {
"messages": [
AIMessage(
tool_calls=[{
"name": "task", # task 工具
"args": {
"subagent_type": "researcher",
"description": "Research AI safety"
},
"id": "call_abc123" # ← 这个 ID 是关键
}]
)
]
}
}
}
关键信息:id: "call_abc123" 是这个 subagent 的唯一标识。
步骤 2:Subagent 执行中
Subagent 启动后,其所有事件都通过 ns (namespace) 携带这个 ID:
python
# Subagent 的所有事件
{
"type": "updates", # 或 "messages"
"ns": ("tools:call_abc123",), # tools: + tool_call_id
"data": {
"model_request": {...},
# 或其他节点数据
}
}
# Subagent 的 token 流
{
"type": "messages",
"ns": ("tools:call_abc123",),
"data": (
AIMessageChunk(content="Researching..."),
{...}
)
}
# Subagent 内部的工具调用
{
"type": "updates",
"ns": ("tools:call_abc123",),
"data": {
"model_request": {
"messages": [
AIMessage(tool_calls=[{
"name": "web_search",
"id": "call_xyz789" # 这是 subagent 内部的工具 ID
}])
]
}
}
}
关键信息:ns = ("tools:{tool_call_id}",) 标识事件来自哪个 subagent。
步骤 3:Subagent 结束,结果返回
Subagent 执行完毕后,结果通过 ToolMessage 返回给主 agent,通过 tool_call_id 关联:
python
{
"type": "updates",
"ns": (), # 回到主 agent
"data": {
"tools": {
"messages": [
ToolMessage(
content="## AI Safety Report\n\n...", # subagent 的输出
tool_call_id="call_abc123", # ← 对应步骤 1 的 ID
name="task"
)
]
}
}
}
关键信息:tool_call_id 对应回步骤 1 中的 task 工具调用。
时序图
text
┌─────────────────────────────────────────────────────────────────────┐
│ 主 Agent │
│ │
│ ① model_request: AIMessage(tool_calls=[task(id="call_abc123")]) │
│ │ │
│ │ tool_call_id = "call_abc123" │
│ ▼ │
├─────────────────────────────────────────────────────────────────────┤
│ Subagent (researcher) │
│ │
│ ns = ("tools:call_abc123",) │
│ │
│ ② model_request: "I'll research AI safety..." │
│ tools: ToolMessage(web_search result) │
│ model_request: "Based on my research..." │
│ │ │
│ │ tool_call_id = "call_abc123" │
│ ▼ │
├─────────────────────────────────────────────────────────────────────┤
│ 主 Agent │
│ │
│ ③ tools: ToolMessage(tool_call_id="call_abc123", content="...") │
│ model_request: "Here's the report..." │
│ │
└─────────────────────────────────────────────────────────────────────┘
ID 关联表
| 步骤 | 事件类型 | ns | 关键 ID |
|---|---|---|---|
| 1. 委派 | updates |
() |
tool_calls[0].id = "call_abc123" |
| 2. 执行 | 所有 subagent 事件 | ("tools:call_abc123",) |
通过 ns 识别 |
| 3. 结束 | updates |
() |
ToolMessage.tool_call_id = "call_abc123" |
前端渲染应用
理解这个 ID 关联机制后,前端可以这样处理:
typescript
// 状态管理
interface SubagentInfo {
id: string; // tool_call_id
type: string; // subagent_type
description: string;
status: "pending" | "running" | "complete";
result?: string;
}
// 处理事件
function handleEvent(event: StreamPart) {
// 1. 检测 subagent 启动
if (event.type === "updates" && !event.ns.length) {
const toolCalls = event.data.model_request?.messages?.[0]?.tool_calls;
toolCalls?.forEach(tc => {
if (tc.name === "task") {
subagents[tc.id] = {
id: tc.id,
type: tc.args.subagent_type,
description: tc.args.description,
status: "running"
};
}
});
}
// 2. 识别 subagent 事件
if (event.ns.length && event.ns[0].startsWith("tools:")) {
const subagentId = event.ns[0].split(":")[1];
// 将事件路由到对应的 subagent UI 组件
renderSubagentEvent(subagentId, event);
}
// 3. 检测 subagent 结束
if (event.type === "updates" && event.data.tools) {
event.data.tools.messages.forEach(msg => {
if (msg.name === "task" && subagents[msg.tool_call_id]) {
subagents[msg.tool_call_id].status = "complete";
subagents[msg.tool_call_id].result = msg.content;
}
});
}
}
总结
| 要点 | 说明 |
|---|---|
| 启动 | 主 agent 调用 task 工具,生成 tool_call_id |
| 标识 | Subagent 事件通过 ns = ("tools:{id}",) 标识来源 |
| 关联 | 结果通过 ToolMessage.tool_call_id 关联回去 |
| 用途 | 前端通过 ID 将事件路由到正确的 UI 组件 |
这个机制确保了在多个 subagent 并行执行时,每个事件都能准确归属到对应的 subagent,实现精细化的 UI 渲染。
评论
欢迎留下反馈,评论发布后会立即显示。