Agent执行链路设计
一、介绍
本节基于上一节对 AI Agent 执行链路的分析(即循环处理模式,使用 for 循环不断判断任务完成状态,进行分析、自主规划、执行和结果验证),结合对应的 AutoAgentTest 测试代码,使用规则树(Rule Tree)来设计可执行链路节点。规则树允许动态扩展,后续可加入其他 AI Agent 执行策略(如固定步骤策略、响应式策略等),实现多策略融合。
二、流程设计
如图,Auto Ai Agent 动态多轮会话执行流程图;

首先,为入口保留多种策略选择,以适应不同场景下的多类型 Agent 使用。后续将通过在 agent 配置表中增加策略选择属性来区分不同的调用。本节将首先实现一个 AutoAgent。
接着,重点在于上一节的 AutoAgentTest 中,设计了一套自动化执行方法,通过 for 循环处理任务。在这里,我们采用规则树,将执行过程拆分为多个节点,每个节点可以循环调用,从而增强整体的灵活性。
最后,在用户提问后的步骤执行完毕后,进入结束环节并生成结果。如果你已经对上一节有透彻的理解,那么这一节关于节点拆分的部分将更加容易理解。
三、工程实现
1. 工程结构

如图先实现 Auto(自动型)Agent 的流程:把 AutoAgentTest 拆解为可维护的节点。
节点划分:
- Root(根节点):负责数据加载与初始化。
- Step1 任务分析:解析目标与约束,生成可执行计划。
- Step2 精准执行:按计划调用工具/模型,产出阶段结果。
- Step3 质量监督:校验结果,发现偏差并回退/修正。
- Step4 执行总结:汇总输出、生成报告与可复用产物。
扩展说明:上述步骤为基线方案,不必拘泥。如参考一线厂商的更优实践,可新增或重排步骤,形成一套可升级的执行流程。与我们使用过的部分 Agent 一样,版本可迭代;付费版本通常提供更强的能力与更细颗粒度的控制。
2. 修改说明
数据表结构调整: 在 ai_agent_flow_config 表中新增以下字段:
client_name:用于标识对话客户端名称。client_type:用于区分不同类型的对话客户端。
上述字段主要用于 AutoAgent 在调度过程中区分不同类型的客户端。与此同时,需要同步修改相关程序中的 DAO、PO、Mapper 层,以保持数据访问的一致性。
仓储接口扩展: 在 IAgentRepository 中新增方法:queryAiAgentClientFlowConfig(String aiAgentId)该方法用于查询指定 Agent 下所配置的 Client 节点,便于业务逻辑获取对应的客户端配置。
**领域模型调整:**在 domain agent model 模型中,针对 valobj 下的枚举类型,单独新增一个 enums 包,用于集中存放和管理枚举类。此调整将提升枚举的可维护性和代码结构的清晰度。
执行实体扩展: 新增 ExecuteCommandEntity 实体类,作为执行 Agent 请求的载体,主要包含以下属性:aiAgentId、message、sessionId、maxStep该实体用于封装执行过程中所需的核心参数。
执行流程实现: 新增 execute 执行包,以 规则树 的方式实现执行过程,包含以下节点:
RootNodeStep1AnalyzerNodeStep2PrecisionExecutorNodeStep3QualitySupervisorNodeStep4LogExecutionSummaryNode
各节点依序执行,分别负责解析、精确执行、质量监督以及日志总结,确保执行过程规范化与可追溯。具体实现可参考现有工程代码。
3. 库表修改

添加 client_name、client_type 字段,以及对应的枚举值,以及代码中增加 AiClientTypeEnumVO 枚举类,匹配这里配置的枚举类型。
4. 增加查询 - 客户端端类型
方法:cn.cactusli.ai.infrastructure.adapter.repository.AgentRepository#queryAiAgentClientFlowConfig
@Override
public Map<String, AiAgentClientFlowConfigVO> queryAiAgentClientFlowConfig(String aiAgentId) {
if (aiAgentId == null || aiAgentId.trim().isEmpty()) {
return Map.of();
}
try {
// 根据智能体ID查询流程配置列表
List<AiAgentFlowConfig> flowConfigs = aiAgentFlowConfigDao.queryByAgentId(aiAgentId);
if (flowConfigs == null || flowConfigs.isEmpty()) {
return Map.of();
}
// 转换为Map结构,key为clientId,value为AiAgentClientFlowConfigVO
Map<String, AiAgentClientFlowConfigVO> result = new HashMap<>();
for (AiAgentFlowConfig flowConfig : flowConfigs) {
AiAgentClientFlowConfigVO configVO = AiAgentClientFlowConfigVO.builder()
.clientId(flowConfig.getClientId())
.clientName(flowConfig.getClientName())
.clientType(flowConfig.getClientType())
.sequence(flowConfig.getSequence())
.build();
result.put(flowConfig.getClientType(), configVO);
}
return result;
} catch (NumberFormatException e) {
log.error("Invalid aiAgentId format: {}", aiAgentId, e);
return Map.of();
} catch (Exception e) {
log.error("Query ai agent client flow config failed, aiAgentId: {}", aiAgentId, e);
return Map.of();
}
}在系统中增加一个查询客户端类型的接口,用于在 Agent 执行过程中,获取可参考的 Client 节点。
- 接口设计
返回结果为Map<String, Object>结构:- key:客户端类型(
client_type) - value:对应的客户端配置对象
- key:客户端类型(
- 用途
该接口将作为 Agent 执行逻辑中的辅助能力,支持根据不同的客户端类型动态选择可用节点,增强调度的灵活性与可扩展性。
5. 节点流程 - AutoAgent
5.1 RootNode - 数据加载节点
@Slf4j
@Service("executeRootNode")
public class RootNode extends AbstractExecuteSupport {
@Resource
private Step1AnalyzerNode step1AnalyzerNode;
@Override
protected String doApply(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
log.info("=== 动态多轮执行测试开始 ====");
log.info("用户输入: {}", requestParameter.getMessage());
log.info("最大执行步数: {}", requestParameter.getMaxStep());
log.info("会话ID: {}", requestParameter.getSessionId());
Map<String, AiAgentClientFlowConfigVO> aiAgentClientFlowConfigVOMap = repository.queryAiAgentClientFlowConfig(requestParameter.getAiAgentId());
// 客户端对话组
dynamicContext.setAiAgentClientFlowConfigVOMap(aiAgentClientFlowConfigVOMap);
// 上下文信息
dynamicContext.setExecutionHistory(new StringBuilder());
// 当前任务信息
dynamicContext.setCurrentTask(requestParameter.getMessage());
// 最大任务步骤
dynamicContext.setMaxStep(requestParameter.getMaxStep());
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> get(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
return step1AnalyzerNode;
}
}- 第一个操作节点,加载数据。并把数据填充到上下文中。
5.2 Step1AnalyzerNode - 任务分析节点
@Slf4j
@Service
public class Step1AnalyzerNode extends AbstractExecuteSupport {
@Override
protected String doApply(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
log.info("\n🎯 === 执行第 {} 步 ===", dynamicContext.getStep());
// 第一阶段:任务分析
log.info("\n📊 阶段1: 任务状态分析");
String analysisPrompt = String.format("""
**原始用户需求:** %s
**当前执行步骤:** 第 %d 步 (最大 %d 步)
**历史执行记录:**
%s
**当前任务:** %s
请分析当前任务状态,评估执行进度,并制定下一步策略。
""",
requestParameter.getMessage(),
dynamicContext.getStep(),
dynamicContext.getMaxStep(),
!dynamicContext.getExecutionHistory().isEmpty() ? dynamicContext.getExecutionHistory().toString() : "[首次执行]",
dynamicContext.getCurrentTask()
);
// 获取对话客户端
AiAgentClientFlowConfigVO aiAgentClientFlowConfigVO = dynamicContext.getAiAgentClientFlowConfigVOMap().get(AiClientTypeEnumVO.TASK_ANALYZER_CLIENT.getCode());
ChatClient chatClient = getChatClientByClientId(aiAgentClientFlowConfigVO.getClientId());
String analysisResult = chatClient
.prompt(analysisPrompt)
.advisors(a -> a
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, requestParameter.getSessionId())
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 1024))
.call().content();
assert analysisResult != null;
parseAnalysisResult(dynamicContext.getStep(), analysisResult);
// 将分析结果保存到动态上下文中,供下一步使用
dynamicContext.setValue("analysisResult", analysisResult);
// 检查是否已完成
if (analysisResult.contains("任务状态: COMPLETED") ||
analysisResult.contains("完成度评估: 100%")) {
dynamicContext.setCompleted(true);
log.info("✅ 任务分析显示已完成!");
return router(requestParameter, dynamicContext);
}
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> get(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 如果任务已完成或达到最大步数,进入总结阶段
if (dynamicContext.isCompleted() || dynamicContext.getStep() > dynamicContext.getMaxStep()) {
return getBean("step4LogExecutionSummaryNode");
}
// 否则继续执行下一步
return getBean("step2PrecisionExecutorNode");
}
private void parseAnalysisResult(int step, String analysisResult) {
log.info("\n📊 === 第 {} 步分析结果 ===", step);
String[] lines = analysisResult.split("\n");
String currentSection = "";
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) continue;
if (line.contains("任务状态分析:")) {
currentSection = "status";
log.info("\n🎯 任务状态分析:");
continue;
} else if (line.contains("执行历史评估:")) {
currentSection = "history";
log.info("\n📈 执行历史评估:");
continue;
} else if (line.contains("下一步策略:")) {
currentSection = "strategy";
log.info("\n🚀 下一步策略:");
continue;
} else if (line.contains("完成度评估:")) {
currentSection = "progress";
String progress = line.substring(line.indexOf(":") + 1).trim();
log.info("\n📊 完成度评估: {}", progress);
continue;
} else if (line.contains("任务状态:")) {
currentSection = "task_status";
String status = line.substring(line.indexOf(":") + 1).trim();
if (status.equals("COMPLETED")) {
log.info("\n✅ 任务状态: 已完成");
} else {
log.info("\n🔄 任务状态: 继续执行");
}
continue;
}
switch (currentSection) {
case "status":
log.info(" 📋 {}", line);
break;
case "history":
log.info(" 📊 {}", line);
break;
case "strategy":
log.info(" 🎯 {}", line);
break;
default:
log.info(" 📝 {}", line);
break;
}
}
}
}AutoAgent 测试步骤提取
在 AutoAgentTest 的第一步中,将相关操作提取出来,之后逐步设置执行步骤。该操作的analysisPrompt部分依赖于大模型的能力,然而,由于某些模型上下文的 token 限制,可能导致性能瓶颈,甚至产生 幻觉(Hallucination)。因此,在这部分需要特别注意对模型的能力评估和测试。客户端对话与分析
接下来的步骤是启动客户端对话。使用chatClient进行对话操作,确保与客户端的互动能够顺利进行。对话完成后,调用parseAnalysisResult方法对结果进行解析,进而决定下一步执行的操作。这一步是 for 循环操作,进行多次执行,确保在每次循环中都能根据分析结果不断调整执行步骤。需要特别注意循环的终止条件和中断机制,避免无效或重复的执行。完成度检查与状态更新
在每次执行后,进行 完成度检查。如果通过analysisResult.contains("任务状态: COMPLETED")判断任务已经完成,则将dynamicContext.setCompleted(true)设置为true,标记该任务已完成。此时,系统会继续 路由后续节点,进入下一个执行阶段。
5.3 Step2PrecisionExecutorNode - 精准执行节点
@Slf4j
@Service
public class Step2PrecisionExecutorNode extends AbstractExecuteSupport {
@Override
protected String doApply(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
log.info("\n⚡ 阶段2: 精准任务执行");
// 从动态上下文中获取分析结果
String analysisResult = dynamicContext.getValue("analysisResult");
if (analysisResult == null || analysisResult.trim().isEmpty()) {
log.warn("⚠️ 分析结果为空,使用默认执行策略");
analysisResult = "执行当前任务步骤";
}
String executionPrompt = String.format("""
**分析师策略:** %s
**执行指令:** 根据上述分析师的策略,执行具体的任务步骤。
**执行要求:**
1. 严格按照策略执行
2. 使用必要的工具
3. 确保执行质量
4. 详细记录过程
**输出格式:**
执行目标: [明确的执行目标]
执行过程: [详细的执行步骤]
执行结果: [具体的执行成果]
质量检查: [自我质量评估]
""", analysisResult);
// 获取对话客户端
AiAgentClientFlowConfigVO aiAgentClientFlowConfigVO = dynamicContext.getAiAgentClientFlowConfigVOMap().get(AiClientTypeEnumVO.PRECISION_EXECUTOR_CLIENT.getCode());
ChatClient chatClient = getChatClientByClientId(aiAgentClientFlowConfigVO.getClientId());
String executionResult = chatClient
.prompt(executionPrompt)
.advisors(a -> a
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, requestParameter.getSessionId())
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 1024))
.call().content();
parseExecutionResult(dynamicContext.getStep(), executionResult);
// 将执行结果保存到动态上下文中,供下一步使用
dynamicContext.setValue("executionResult", executionResult);
// 更新执行历史
String stepSummary = String.format("""
=== 第 %d 步执行记录 ===
【分析阶段】%s
【执行阶段】%s
""", dynamicContext.getStep(), analysisResult, executionResult);
dynamicContext.getExecutionHistory().append(stepSummary);
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> get(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
return getBean("step3QualitySupervisorNode");
}
/**
* 解析执行结果
*/
private void parseExecutionResult(int step, String executionResult) {
log.info("\n⚡ === 第 {} 步执行结果 ===", step);
String[] lines = executionResult.split("\n");
String currentSection = "";
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) continue;
if (line.contains("执行目标:")) {
currentSection = "target";
log.info("\n🎯 执行目标:");
continue;
} else if (line.contains("执行过程:")) {
currentSection = "process";
log.info("\n🔧 执行过程:");
continue;
} else if (line.contains("执行结果:")) {
currentSection = "result";
log.info("\n📈 执行结果:");
continue;
} else if (line.contains("质量检查:")) {
currentSection = "quality";
log.info("\n🔍 质量检查:");
continue;
}
switch (currentSection) {
case "target":
log.info(" 🎯 {}", line);
break;
case "process":
log.info(" ⚙️ {}", line);
break;
case "result":
log.info(" 📊 {}", line);
break;
case "quality":
log.info(" ✅ {}", line);
break;
default:
log.info(" 📝 {}", line);
break;
}
}
}
}在这个节点,系统执行具体的任务步骤操作,同时通过
executionPrompt明确指定输出格式。完成这一步骤后,开始对话操作,并获取executionResult结果。根据获取的结果,系统会确定执行目标、执行过程、执行结果和质量检查,并输出相应的内容。后续的输出可以传递给前端页面进行展示。
记录完
stepSummary后,系统将路由到下一个节点,即step3QualitySupervisorNode。
5.4 Step3QualitySupervisorNode - 质量监督节点
@Slf4j
@Service
public class Step3QualitySupervisorNode extends AbstractExecuteSupport {
@Override
protected String doApply(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 第三阶段:质量监督
log.info("\n🔍 阶段3: 质量监督检查");
// 从动态上下文中获取执行结果
String executionResult = dynamicContext.getValue("executionResult");
if (executionResult == null || executionResult.trim().isEmpty()) {
log.warn("⚠️ 执行结果为空,跳过质量监督");
return "质量监督跳过";
}
String supervisionPrompt = String.format("""
**用户原始需求:** %s
**执行结果:** %s
**监督要求:** 请评估执行结果的质量,识别问题,并提供改进建议。
**输出格式:**
质量评估: [对执行结果的整体评估]
问题识别: [发现的问题和不足]
改进建议: [具体的改进建议]
质量评分: [1-10分的质量评分]
是否通过: [PASS/FAIL/OPTIMIZE]
""", requestParameter.getMessage(), executionResult);
// 获取对话客户端
AiAgentClientFlowConfigVO aiAgentClientFlowConfigVO = dynamicContext.getAiAgentClientFlowConfigVOMap().get(AiClientTypeEnumVO.QUALITY_SUPERVISOR_CLIENT.getCode());
ChatClient chatClient = getChatClientByClientId(aiAgentClientFlowConfigVO.getClientId());
String supervisionResult = chatClient
.prompt(supervisionPrompt)
.advisors(a -> a
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, requestParameter.getSessionId())
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 1024))
.call().content();
parseSupervisionResult(dynamicContext.getStep(), supervisionResult);
// 将监督结果保存到动态上下文中
dynamicContext.setValue("supervisionResult", supervisionResult);
// 根据监督结果决定是否需要重新执行
if (supervisionResult.contains("是否通过: FAIL")) {
log.info("❌ 质量检查未通过,需要重新执行");
dynamicContext.setCurrentTask("根据质量监督的建议重新执行任务");
} else if (supervisionResult.contains("是否通过: OPTIMIZE")) {
log.info("🔧 质量检查建议优化,继续改进");
dynamicContext.setCurrentTask("根据质量监督的建议优化执行结果");
} else {
log.info("✅ 质量检查通过");
dynamicContext.setCompleted(true);
}
// 更新执行历史
String stepSummary = String.format("""
=== 第 %d 步完整记录 ===
【分析阶段】%s
【执行阶段】%s
【监督阶段】%s
""", dynamicContext.getStep(),
dynamicContext.getValue("analysisResult"),
executionResult,
supervisionResult);
dynamicContext.getExecutionHistory().append(stepSummary);
// 增加步骤计数
dynamicContext.setStep(dynamicContext.getStep() + 1);
// 如果任务已完成或达到最大步数,进入总结阶段
if (dynamicContext.isCompleted() || dynamicContext.getStep() > dynamicContext.getMaxStep()) {
return router(requestParameter, dynamicContext);
}
// 否则继续下一轮执行,返回到Step1AnalyzerNode
return router(requestParameter, dynamicContext);
}
@Override
public StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> get(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
// 如果任务已完成或达到最大步数,进入总结阶段
if (dynamicContext.isCompleted() || dynamicContext.getStep() > dynamicContext.getMaxStep()) {
return getBean("step4LogExecutionSummaryNode");
}
// 否则返回到Step1AnalyzerNode进行下一轮分析
return getBean("step1AnalyzerNode");
}
/**
* 解析监督结果
*/
private void parseSupervisionResult(int step, String supervisionResult) {
log.info("\n🔍 === 第 {} 步监督结果 ===", step);
String[] lines = supervisionResult.split("\n");
String currentSection = "";
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) continue;
if (line.contains("质量评估:")) {
currentSection = "assessment";
log.info("\n📊 质量评估:");
continue;
} else if (line.contains("问题识别:")) {
currentSection = "issues";
log.info("\n⚠️ 问题识别:");
continue;
} else if (line.contains("改进建议:")) {
currentSection = "suggestions";
log.info("\n💡 改进建议:");
continue;
} else if (line.contains("质量评分:")) {
currentSection = "score";
String score = line.substring(line.indexOf(":") + 1).trim();
log.info("\n📊 质量评分: {}", score);
continue;
} else if (line.contains("是否通过:")) {
currentSection = "pass";
String status = line.substring(line.indexOf(":") + 1).trim();
if (status.equals("PASS")) {
log.info("\n✅ 检查结果: 通过");
} else if (status.equals("FAIL")) {
log.info("\n❌ 检查结果: 未通过");
} else {
log.info("\n🔧 检查结果: 需要优化");
}
continue;
}
switch (currentSection) {
case "assessment":
log.info(" 📋 {}", line);
break;
case "issues":
log.info(" ⚠️ {}", line);
break;
case "suggestions":
log.info(" 💡 {}", line);
break;
default:
log.info(" 📝 {}", line);
break;
}
}
}
}此节点的主要目的是检测整个过程生成内容的质量是否可靠。它会进行评分、与客户端进行对话、以及执行监督操作,之后更新历史步骤的
stepSummary。需要注意的是,完成路由操作后,
router会判断是否进入最终节点,或者是否需要返回step1AnalyzerNode继续执行。这一决策基于生成的内容是否已达到目标,并且是否超过了最大步骤限制。另外,
get方法中的路由操作会根据不同的类型来获取相应的bean对象。
5.5 Step4LogExecutionSummaryNode - 执行总结节点
@Slf4j
@Service
public class Step4LogExecutionSummaryNode extends AbstractExecuteSupport {
@Override
protected String doApply(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
log.info("\n📊 === 执行第 {} 步 ===", dynamicContext.getStep());
// 第四阶段:执行总结
log.info("\n📊 阶段4: 执行总结分析");
// 记录执行总结
logExecutionSummary(dynamicContext.getMaxStep(), dynamicContext.getExecutionHistory(), dynamicContext.isCompleted());
// 如果任务未完成,生成最终总结报告
if (!dynamicContext.isCompleted()) {
generateFinalReport(requestParameter, dynamicContext);
}
log.info("\n🏁 === 动态多轮执行测试结束 ====");
return "ai agent execution summary completed!";
}
@Override
public StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> get(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) throws Exception {
return defaultStrategyHandler;
}
/**
* 记录执行总结
*/
private void logExecutionSummary(int maxSteps, StringBuilder executionHistory, boolean isCompleted) {
log.info("\n📊 === 动态多轮执行总结 ====");
int actualSteps = Math.min(maxSteps, executionHistory.toString().split("=== 第").length - 1);
log.info("📈 总执行步数: {} 步", actualSteps);
if (isCompleted) {
log.info("✅ 任务完成状态: 已完成");
} else {
log.info("⏸️ 任务完成状态: 未完成(达到最大步数限制)");
}
// 计算执行效率
double efficiency = isCompleted ? 100.0 : (double) actualSteps / maxSteps * 100;
log.info("📊 执行效率: {:.1f}%", efficiency);
}
/**
* 生成最终总结报告
*/
private void generateFinalReport(ExecuteCommandEntity requestParameter, DefaultAutoAgentExecuteStrategyFactory.DynamicContext dynamicContext) {
try {
log.info("\n--- 生成未完成任务的总结报告 ---");
String summaryPrompt = String.format("""
请对以下未完成的任务执行过程进行总结分析:
**原始用户需求:** %s
**执行历史:**
%s
**分析要求:**
1. 总结已完成的工作内容
2. 分析未完成的原因
3. 提出完成剩余任务的建议
4. 评估整体执行效果
""",
requestParameter.getMessage(),
dynamicContext.getExecutionHistory().toString());
// 获取对话客户端 - 使用任务分析客户端进行总结
AiAgentClientFlowConfigVO aiAgentClientFlowConfigVO = dynamicContext.getAiAgentClientFlowConfigVOMap().get(AiClientTypeEnumVO.TASK_ANALYZER_CLIENT.getCode());
ChatClient chatClient = getChatClientByClientId(aiAgentClientFlowConfigVO.getClientId());
String summaryResult = chatClient
.prompt(summaryPrompt)
.advisors(a -> a
.param(CHAT_MEMORY_CONVERSATION_ID_KEY, requestParameter.getSessionId() + "-summary")
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 50))
.call().content();
logFinalReport(summaryResult);
// 将总结结果保存到动态上下文中
dynamicContext.setValue("finalSummary", summaryResult);
} catch (Exception e) {
log.error("生成最终总结报告时出现异常: {}", e.getMessage(), e);
}
}
/**
* 输出最终总结报告
*/
private void logFinalReport(String summaryResult) {
log.info("\n📋 === 最终总结报告 ===");
String[] lines = summaryResult.split("\n");
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) continue;
// 根据内容类型添加不同图标
if (line.contains("已完成") || line.contains("完成的工作")) {
log.info("✅ {}", line);
} else if (line.contains("未完成") || line.contains("原因")) {
log.info("❌ {}", line);
} else if (line.contains("建议") || line.contains("推荐")) {
log.info("💡 {}", line);
} else if (line.contains("评估") || line.contains("效果")) {
log.info("📊 {}", line);
} else {
log.info("📝 {}", line);
}
}
}
}- 最终总结产生结果的节点了,生成最终的报告。
四、测试验证
1. 导入数据

将cn.cactusli.ai.test.spring.ai.AutoAgentTest 中 taskAnalyzerClient、precisionExecutorClient、qualitySupervisorClient 系统提示词放入数据库中。

- 添加创建文件
mcp应用的关联关系。
2. 测试功能
测试类:cn.cactusli.ai.test.domain.AutoAgentTest
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class AutoAgentTest {
@Resource
private DefaultArmoryStrategyFactory defaultArmoryStrategyFactory;
@Resource
private DefaultAutoAgentExecuteStrategyFactory defaultAutoAgentExecuteStrategyFactory;
@Resource
private ApplicationContext applicationContext;
@Before
public void init() throws Exception {
var armoryStrategyHandler =
defaultArmoryStrategyFactory.armoryStrategyHandler();
String apply = armoryStrategyHandler.apply(
ArmoryCommandEntity.builder()
.commandType(AiAgentEnumVO.AI_CLIENT.getCode())
.commandIdList(Arrays.asList("3101", "3102", "3103"))
.build(),
new DefaultArmoryStrategyFactory.DynamicContext());
ChatClient chatClient = (ChatClient) applicationContext.getBean(AiAgentEnumVO.AI_CLIENT.getBeanName("3101"));
log.info("客户端构建:{}", chatClient);
}
@Test
public void autoAgent() throws Exception {
StrategyHandler<ExecuteCommandEntity, DefaultAutoAgentExecuteStrategyFactory.DynamicContext, String> executeHandler
= defaultAutoAgentExecuteStrategyFactory.armoryStrategyHandler();
ExecuteCommandEntity executeCommandEntity = new ExecuteCommandEntity();
executeCommandEntity.setAiAgentId("3");
// executeCommandEntity.setMessage("你有哪些工具可以调用?");
executeCommandEntity.setMessage("搜索 Spring 技术项目列表。编写成一份文档,说明不同项目的适用场景。然后创建相应md文档。");
executeCommandEntity.setSessionId("session-id-" + System.currentTimeMillis());
executeCommandEntity.setMaxStep(2);
String apply = executeHandler.apply(executeCommandEntity, new DefaultAutoAgentExecuteStrategyFactory.DynamicContext());
log.info("测试结果:{}", apply);
}
}