嵌套 Agent、TeamAgent 与子图
复杂系统不应堆在一个超大 Graph 中。可以组合三类执行单元:
主 Graph
├─ 单 Agent
├─ TeamAgent
└─ Graph.asTask() 子图
1、TeamAgent 作为 Agent 节点
1.1 父 TeamAgent Graph 直接嵌套子 TeamAgent
TeamAgent 本身实现 Agent,因此可成为父 TeamAgent Graph 的 Activity。父 TeamTrace 和 TeamProtocol 会为子团队准备本次 Prompt:
TeamAgent devTeam = TeamAgent.of(null)
.name("dev_team")
.protocol(TeamProtocols.SEQUENTIAL)
.feedbackMode(false)
.agentAdd(coder, tester)
.outputKey("team.dev.result")
.build();
Agent reviewer = SimpleAgent.of(chatModel)
.name("reviewer")
.role("质量审核员")
.instruction("审核开发小组交付物:\n#{team.dev.result}")
.outputKey("review.result")
.build();
TeamAgent project = TeamAgent.of(null)
.name("project_graph")
.protocol(TeamProtocols.NONE)
.agentAdd(devTeam, reviewer)
.graphAdjuster(spec -> {
spec.addStart(Agent.ID_START).linkAdd(devTeam.name());
spec.addActivity(devTeam).linkAdd(reviewer.name());
spec.addActivity(reviewer).linkAdd(Agent.ID_END);
spec.addEnd(Agent.ID_END);
})
.build();
父 TeamTrace 记录 dev_team 和 reviewer;子 TeamTrace 记录 coder 和 tester:
TeamTrace projectTrace = project.getTrace(session);
TeamTrace devTrace = devTeam.getTrace(session);
团队名称必须稳定且避免冲突。默认 TraceKey 是 __ 加团队名称,TeamAgent 内部 Graph ID 也使用该 TraceKey,例如:
team.name = dev_team
trace.key = __dev_team
graph.id = __dev_team
1.2 独立业务 Graph 必须显式调用 TeamAgent
普通独立 Graph 没有父 TeamTrace,不能直接写 spec.addActivity(devTeam) 后期待业务 Context 自动变成团队 Prompt。应使用适配 Activity 明确输入、Session 和输出:
spec.addActivity("dev_team_step")
.task((ctx, node) -> {
AgentSession session = ctx.getAs(Agent.KEY_SESSION);
String requirement = ctx.getAs("input.requirement");
String result = devTeam.prompt(requirement)
.session(session)
.call()
.getContent();
ctx.put("team.dev.result", result);
})
.linkAdd("next");
此时 TeamAgent 仍负责自己的内部 Graph、TeamTrace 和结果收敛;外层业务 Graph 负责把业务数据映射成团队 Prompt。只有在父 TeamAgent 的内部 Graph 中,才适合把子 TeamAgent 直接作为 Agent 节点使用。
2、Graph.asTask() 确定性子图
Graph prepareGraph = Graph.create("prepare_graph", spec -> {
spec.addStart("prepare_start").linkAdd("normalize");
spec.addActivity("normalize")
.task((ctx, node) -> {
String input = ctx.getAs("input.raw");
ctx.put("input.normalized", input.trim());
})
.linkAdd("prepare_end");
spec.addEnd("prepare_end");
});
放入主图:
Graph mainGraph = Graph.create("main_graph", spec -> {
spec.addStart("start").linkAdd(prepareGraph.getId());
spec.addActivity(prepareGraph.asTask()).linkAdd("agent_step");
spec.addActivity("agent_step")
.task((ctx, node) -> {
AgentSession session = ctx.getAs(Agent.KEY_SESSION);
String prompt = ctx.getAs("input.normalized");
String result = analyst.prompt(prompt)
.session(session)
.call()
.getContent();
ctx.put("analysis.result", result);
})
.linkAdd("end");
spec.addEnd("end");
});
完整执行准备:
FlowContext context = FlowContext.of("main-001");
context.put("input.raw", " 分析迁移方案 ");
InMemoryAgentSession.of(context);
FlowEngine.newInstance().eval(mainGraph, context);
asTask() 直接持有 Graph,不要求预先注册。子图沿用父图的 Context、FlowEngine、Driver、FlowTrace 和执行步数。
3、通过 #graphId 引用子图
YAML/JSON 或按 ID 组合时可以使用:
.task("#prepare_graph")
被引用 Graph 必须先加载到同一个 FlowEngine:
engine.load(prepareGraph);
engine.load(mainGraph);
engine.eval("main_graph", context);
TeamAgent 内部使用 FlowEngine.newInstance(true) 创建简化引擎。该模式使用不可写的空 Graph/命名 Driver 注册表,不用于动态 load/unload,也不能依赖 #graphId 在内部解析注册式子图。在 graphAdjuster 中组合普通子图时,应使用直接持有 Graph 的 prepareGraph.asTask()。
4、两类嵌套的本质区别
| 维度 | TeamAgent 嵌套 | Graph 子图 |
|---|---|---|
| 目标 | 多 Agent 协作单元 | 确定性流程复用 |
| TeamTrace | 子团队有独立 TeamTrace | 不自动创建 |
| Prompt | 子团队有协议和 working memory | 不自动处理 |
| 输出 | 可用 TeamAgent outputKey | 子图自行写 Context |
| Context | 与父团队共享 Session Context | 与父图共享 Context |
| 停止/恢复 | 同时涉及 TeamTrace 和 FlowTrace | 主要由 FlowTrace 定位 |
5、ID 唯一性范围
Graph ID 应在以下范围保持唯一:
- 同一个 FlowEngine 的注册空间;
- 共享同一 FlowContext 的嵌套执行树。
它不是整个 JVM 的强制全局唯一,但复用 ID 会污染 FlowTrace 和网关临时状态。
Node ID 只需在所属 Graph 内唯一;Graph.asTask() 默认使用子图 ID 作为父图节点 ID,因此还要避免与父图节点重名。
6、停止和中断传播
asTask() 和 #graphId 都在同一执行交换器中运行:
- 子图正常到 End 后,父图继续;
- 子图
stop()会停止整个共享执行; - 子图
interrupt()会截断当前分支; - 恢复时按各自 Graph ID 的 FlowTrace 位置定位。
因此子图节点也必须满足幂等要求。
7、分层建议
主 Graph:业务阶段、权限和治理边界
TeamAgent:某阶段内的多 Agent 协作
子 Graph:可复用的确定性处理过程
单 Agent:边界清晰的认知任务
这种分层比一个超大 TeamAgent 更容易测试、观察、恢复和版本演进。