team - TeamAgent 自由模式 (NONE 协议)
2026年1月15日 下午6:14:46
在默认情况下,TeamAgent 遵循预定义的团队协议(如 Leader 或 A2A 模式)。但在某些业务场景下,我们需要打破固定协议,自定义 Agent 之间的流转逻辑,例如 并行计算、条件分支或复杂的网关聚合。
自由模式(NONE 协议) 的核心特征是:不使用内置协作协议,通过 graphAdjuster 完全自主定义执行图(Graph),实现“手写”业务流。
协议常量 TeamProtocols.NONE,v3.8.4 后内置,旧版可直接使用:
public class NoneProtocol implements TeamProtocol {
@Override
public String name() { return "NONE"; }
public NoneProtocol(TeamAgentConfig config) { }
@Override
public void buildGraph(GraphSpec spec) { }
}
1、如何使用自由模式
通过指定 .protocol(TeamProtocols.NONE) 显式关闭内置编排引擎。
TeamAgent team = TeamAgent.of(chatModel)
.name("my_custom_team")
.protocol(TeamProtocols.NONE) // 切换为自由模式(或者用: NoneProtocol::new)
.graphAdjuster(spec -> {
// 在此处手绘执行图
})
.build();
2、自由模式的轨迹提取 (TeamTrace)
在自由模式下,由于框架不再代劳最终回答,我们需要从 TeamTrace 中手动提取或设置结果:
- 踪迹获取:通过 team.getTrace(session) 获取当前会话的协作轨迹。
- 节点回溯:通过 trace.getSteps() 遍历每个 Agent 的执行快照。
- 手动定论:如果在执行图的末尾生成了最终结论,可以使用 trace.setFinalAnswer(...) 显式标记,以便后续流程或 UI 展示。
3、示例:A/B 测试共识决策系统
下面的示例展示了如何利用 NONE 协议 编排一个并行分析团队:将测试指标同步分发给三位专家,并在汇聚节点(Parallel Gateway)完成多数票表决。
public class ABTestingDecisionGraphTest {
@Test
@DisplayName("测试 A/B 测试 Graph:验证并行节点执行与结果汇聚决策")
public void testABTestingDecisionProcess() throws Throwable {
ChatModel chatModel = LlmUtil.getChatModel();
// --- 1. 初始化专家角色 (利用 SimpleAgent 的 outputKey 自动回填能力) ---
Agent dataAnalyst = createExpert(chatModel, "data_analyst", "数据分析专家", "data_opinion");
Agent productManager = createExpert(chatModel, "product_manager", "产品经理", "product_opinion");
Agent engineeringLead = createExpert(chatModel, "engineering_lead", "工程负责人", "engineering_opinion");
TeamAgent team = TeamAgent.of(chatModel)
.name("ab_testing_team")
.protocol(TeamProtocols.NONE)
.graphAdjuster(spec -> {
// A. 入口指派:从 Supervisor 指向数据准备节点
spec.addStart(Agent.ID_START)
.linkAdd("test_result_input");
// B. 数据准备 (Activity):模拟从数据库/API 加载测试指标
spec.addActivity("test_result_input")
.title("准备测试数据")
.task((ctx, node) -> {
ctx.put("variant_a_conv", 15.2);
ctx.put("variant_b_conv", 18.7);
System.out.println(">>> [Node] 业务指标载入 Context");
})
.linkAdd("parallel_analysis");
// C. 并行分发 (Parallel):同时触发三个专家的异步分析
spec.addParallel("parallel_analysis").title("启动多维度并行分析")
.linkAdd(dataAnalyst.name())
.linkAdd(productManager.name())
.linkAdd(engineeringLead.name());
// D. 结果汇聚:所有专家处理完后,自动跳转至决策网关
spec.addActivity(dataAnalyst).linkAdd("decision_gateway");
spec.addActivity(productManager).linkAdd("decision_gateway");
spec.addActivity(engineeringLead).linkAdd("decision_gateway");
// E. 共识决策 (Parallel 汇聚):基于 Context 中的专家意见进行多数票表决
spec.addParallel("decision_gateway")
.title("多数票共识决策")
.task((ctx, node) -> {
// 提取由 SimpleAgent.outputKey 自动同步过来的结果
String d = ctx.getAs("data_opinion");
String p = ctx.getAs("product_opinion");
String e = ctx.getAs("engineering_opinion");
int approveCount = 0;
if (isApprove(d)) approveCount++;
if (isApprove(p)) approveCount++;
if (isApprove(e)) approveCount++;
String finalVerdict = (approveCount >= 2) ? "PROMOTED_B" : "RETAINED_A";
ctx.put("ab_test_decision", finalVerdict);
System.out.println(">>> [Decision] 赞成票: " + approveCount + ", 最终裁决: " + finalVerdict);
})
.linkAdd(Agent.ID_END);
spec.addEnd(Agent.ID_END);
})
.build();
// --- 2. 运行流程 ---
AgentSession session = InMemoryAgentSession.of("session_ab_test_01");
String query = "当前 A 转化率 15.2%, B 转化率 18.7%。请给出你的评估意见(approve/reject)。";
team.call(Prompt.of(query), session);
// --- 3. 结果验证 ---
// A. 验证业务 Activity 逻辑:数据是否成功写入上下文
Assertions.assertEquals(15.2, session.getSnapshot().getAs("variant_a_conv"), "数据加载节点未执行");
// B. 验证 Agent 参与轨迹:Trace 记录 AI 专家的交互足迹
TeamTrace trace = team.getTrace(session);
List<String> agentFootprints = trace.getSteps().stream()
.map(TeamTrace.TeamStep::getSource)
.collect(Collectors.toList());
System.out.println("AI 执行足迹: " + agentFootprints);
Assertions.assertTrue(agentFootprints.contains("data_analyst"), "Trace 记录缺失专家节点");
// C. 验证最终业务决策结果
String decision = session.getSnapshot().getAs("ab_test_decision");
Assertions.assertNotNull(decision, "决策结果未生成");
System.out.println("测试成功。最终结论: " + decision);
}
/**
* 构建专家 Agent,配置 outputKey 实现 Agent 输出与 Session Context 的自动映射
*/
private Agent createExpert(ChatModel chatModel, String name, String role, String outputKey) {
return SimpleAgent.of(chatModel)
.name(name)
.systemPrompt(SimpleSystemPrompt.builder()
.role(role)
.instruction("你负责评估 A/B 测试。如果 B 优于 A,回复 'approve',否则回复 'reject'。只输出单词。")
.build())
.outputKey(outputKey) // 重要:Agent 执行完后会自动将 Content 写入 Context[outputKey]
.chatOptions(o -> o.temperature(0.1F))
.build();
}
private boolean isApprove(String opinion) {
return opinion != null && opinion.toLowerCase().contains("approve");
}
}