一、本章介绍
当 AiApi、ChatModel 以及各类 Agent 完成初始化与装配之后,流程便进入到智能体工作流的编排阶段。在这一阶段,不同类型的 Agent 可以按照多种方式进行组合:例如,通过 LoopAgent 将多个 LlmAgent 组织为循环执行结构;或使用 ParallelAgent 实现多 Agent 的并行处理;随后再由 SequentialAgent 按顺序串联这些执行结果。
由于这些组合方式具备较高的灵活性和嵌套可能性,整体流程不再是单一路径。因此,需要引入专门的流转判断节点,对执行路径进行控制与分发,从而将各类节点有序衔接,确保整个工作流能够按照预期逻辑持续推进。
二、流程设计
如图,智能体装配中,AgentWorkflowNode 部分;

本节主要围绕 AgentWorkflowNode 向其他三类节点的流转机制展开设计,涉及的节点包括 LoopAgent、ParallelAgentNode 以及 SequentialAgentNode。整体执行路径最终会汇聚到 SequentialAgentNode,由其完成收尾处理,即以串行方式输出最终结果。
需要特别说明的是,在本节中仅关注上述三个节点之间的衔接与流转逻辑,具体的功能实现将放在后续章节中详细展开。
此外,还存在一种简化场景:流程中仅包含单个 LlmAgent,直接作为执行终点,而不再额外通过 SequentialAgentNode 进行封装。这种情况将在后续设计中进一步补充和扩展。
三、功能实现
1. 工程结构
本节主要设计 AgentWorkflowNode 在工作流中的流转逻辑,即如何根据配置进入不同类型的 Workflow 节点,并完成节点之间的衔接。
在设计过程中,可以结合 LoopAgentTest、ParallelAgentTest 和 SequentialAgentTest 进行对照分析,通过这些测试用例理解不同 Agent 组合方式下的执行路径,从而辅助完成本部分的流程设计。
2. 链路分析
agent-workflows:
- type: sequential
name: CodePipelineAgent
description: Executes a sequence of code writing, reviewing, and refactoring.
sub-agents:
- CodeWriterAgent
- CodeReviewerAgent
- CodeRefactorerAgent在实现层面,本部分编码需要严格依据
agent-workflows的配置进行驱动。其中,type用于标识三类智能体节点类型之一:LoopAgent、ParallelAgentNode 或 SequentialAgentNode。因此,首先需要由 AgentWorkflowNode 作为统一入口,对不同类型进行分发处理。在具体流转过程中,LoopAgent 与 ParallelAgentNode 之间存在较高的灵活性。这两类节点既可以单独出现,也可能相互嵌套或交替执行,例如从 LoopAgent 进入 ParallelAgentNode,或反向从 ParallelAgentNode 切入 LoopAgent。因此,在设计时不仅要处理节点之间的跳转关系,还需要考虑各自内部可能存在的循环与嵌套逻辑。
对于流程的收敛,通常由 SequentialAgentNode 作为终点更为合理。由于其本身具备顺序执行的特性,能够天然承担结果整合与收尾的职责。从配置角度看,将其作为最终节点,有助于简化整体结构,同时也更容易组合出多样化的执行路径。
需要注意的是,随着业务复杂度提升,工作流可能演化为更深层的嵌套结构。例如多个 SequentialAgentNode 串联,再嵌入 LoopAgent 与 ParallelAgentNode,形成多层组合。这类复杂链路虽然具备更强的表达能力,但也可能带来上下文膨胀的问题,增加模型产生偏差的风险。因此,在实际设计中,应在灵活性与可控性之间取得平衡,优先构建结构清晰、职责明确的执行链路,以获得更稳定的效果。
3. 核心模块
3.1 枚举定义
public enum AgentTypeEnum {
Loop("循环执行","loop","loopAgentNode"),
Parallel("并行执行","parallel","parallelAgentNode"),
Sequential("串行执行","sequential","sequentialAgentNode"),
;
private String name;
private String type;
private String node;
public static AgentTypeEnum fromType(String type) {
if (type == null) {
return null;
}
for (AgentTypeEnum value : values()) {
if (value.getType().equalsIgnoreCase(type)) {
return value;
}
}
return null;
}
}- 为了方便使用不同类型的流转操作,这里把几种类型定义枚举,并提供通过 yml 文件配置 agent 的 type 获取到对应的智能体。
3.2 主流转节点
@Slf4j
@Service
public class AgentWorkflowNode extends AbstractArmorySupport {
@Resource
private LoopAgentNode loopAgentNode;
@Resource
private ParallelAgentNode parallelAgentNode;
@Resource
private SequentialAgentNode sequentialAgentNode;
@Override
protected AiAgentRegisterVO doApply(ArmoryCommandEntity requestParameter, DefaultArmoryFactory.DynamicContext dynamicContext) throws Exception {
log.info("Ai Agent 装配操作 - AgentWorkflowNode");
AiAgentConfigTableVO aiAgentConfigTableVO = requestParameter.getAiAgentConfigTableVO();
List<AiAgentConfigTableVO.Module.AgentWorkflow> agentWorkflows = aiAgentConfigTableVO.getModule().getAgentWorkflows();
if (null == agentWorkflows || agentWorkflows.isEmpty()) {
throw new RuntimeException("agentWorkflows is null");
}
dynamicContext.setAgentWorkflows(agentWorkflows);
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<ArmoryCommandEntity, DefaultArmoryFactory.DynamicContext, AiAgentRegisterVO> get(ArmoryCommandEntity requestParameter, DefaultArmoryFactory.DynamicContext dynamicContext) throws Exception {
List<AiAgentConfigTableVO.Module.AgentWorkflow> agentWorkflows = dynamicContext.getAgentWorkflows();
AiAgentConfigTableVO.Module.AgentWorkflow agentWorkflow = agentWorkflows.get(0);
String type = agentWorkflow.getType();
AgentTypeEnum agentTypeEnum = AgentTypeEnum.fromType(type);
if (null == agentTypeEnum) {
throw new RuntimeException("agentWorkflow type is error!");
}
String node = agentTypeEnum.getNode();
return switch (node) {
case "loopAgentNode" -> loopAgentNode;
case "parallelAgentNode" -> parallelAgentNode;
case "sequentialAgentNode" -> sequentialAgentNode;
default -> defaultStrategyHandler;
};
}
}借助 AgentWorkflowNode 的分发能力,流程可以根据配置进入任意一种已支持的节点类型。
需要注意的是,当前仅允许在既定的类型范围内进行流转,一旦用户配置的节点类型不在枚举列表中,系统将直接抛出异常。例如,如果仅配置单一的 LlmAgent,而未使用 Loop、Parallel 或 Sequential 等结构进行封装,同样会触发错误。
这类场景将在后续版本中进一步优化支持。本阶段主要聚焦于基础流转机制的实现与理解。在掌握核心逻辑之后,也可以基于现有设计自行扩展更灵活的组合方式。
3.3 子流转节点
3.3.1 loop 循环
@Slf4j
@Service
public class LoopAgentNode extends AbstractArmorySupport {
@Override
public StrategyHandler<ArmoryCommandEntity, DefaultArmoryFactory.DynamicContext, AiAgentRegisterVO> get(ArmoryCommandEntity requestParameter, DefaultArmoryFactory.DynamicContext dynamicContext) throws Exception {
List<AiAgentConfigTableVO.Module.AgentWorkflow> agentWorkflows = dynamicContext.getAgentWorkflows();
if (null == agentWorkflows || agentWorkflows.isEmpty()) {
return defaultStrategyHandler;
}
AiAgentConfigTableVO.Module.AgentWorkflow agentWorkflow = agentWorkflows.get(0);
String type = agentWorkflow.getType();
AgentTypeEnum agentTypeEnum = AgentTypeEnum.fromType(type);
if (null == agentTypeEnum) {
throw new RuntimeException("agentWorkflow type is error!");
}
String node = agentTypeEnum.getNode();
return switch (node) {
case "parallelAgentNode" -> getBean("parallelAgentNode");
case "sequentialAgentNode" -> getBean("sequentialAgentNode");
default -> defaultStrategyHandler;
};
}
}- 进入 LoopAgentNode 可以流转到 parallelAgentNode、sequentialAgentNode
3.3.2 parallel 并行
@Slf4j
@Service
public class ParallelAgentNode extends AbstractArmorySupport {
@Override
public StrategyHandler<ArmoryCommandEntity, DefaultArmoryFactory.DynamicContext, AiAgentRegisterVO> get(ArmoryCommandEntity requestParameter, DefaultArmoryFactory.DynamicContext dynamicContext) throws Exception {
List<AiAgentConfigTableVO.Module.AgentWorkflow> agentWorkflows = dynamicContext.getAgentWorkflows();
if (null == agentWorkflows || agentWorkflows.isEmpty()) {
return defaultStrategyHandler;
}
AiAgentConfigTableVO.Module.AgentWorkflow agentWorkflow = agentWorkflows.get(0);
String type = agentWorkflow.getType();
AgentTypeEnum agentTypeEnum = AgentTypeEnum.fromType(type);
if (null == agentTypeEnum) {
throw new RuntimeException("agentWorkflow type is error!");
}
String node = agentTypeEnum.getNode();
return switch (node) {
case "loopAgentNode" -> getBean("loopAgentNode");
case "sequentialAgentNode" -> getBean("sequentialAgentNode");
default -> defaultStrategyHandler;
};
}
}- 进入 ParallelAgentNode 可以流转到 loopAgentNode、sequentialAgentNode
3.3.2 sequential 序列
@Slf4j
@Service
public class SequentialAgentNode extends AbstractArmorySupport {
@Override
public StrategyHandler<ArmoryCommandEntity, DefaultArmoryFactory.DynamicContext, AiAgentRegisterVO> get(ArmoryCommandEntity requestParameter, DefaultArmoryFactory.DynamicContext dynamicContext) throws Exception {
return runnerNode;
}
}- 这三个节点,主要先体现关于流转的操作,后续在讲解每个几点里的功能装配。
- 进入到 SequentialAgentNode 目前则只作为兜底,不在循环。后续我们在做一些复杂的扩展。