系列篇章💥
目录
前言
在第19篇文章中,我们学习了顺序工作流,它将多个 Agent 按固定顺序串联执行。但在实际业务场景中,往往需要反复迭代才能完成任务:
场景 1:代码审查
AI 生成代码 → 人工审查 → 发现问题 → 重新生成 → 再次审查...
问题:
- 需要迭代多少次?❓
- 什么时候停止?❓
- 如果一直达不到要求怎么办?❓
场景 2:内容创作
AI 写文章 → 编辑审核 → 修改建议 → 重写 → 再审...
挑战:
- 质量评估标准如何量化?❓
- 如何避免无限循环?❓
这就是循环工作流的价值所在!
什么是循环工作流?
循环工作流(Loop Workflow)是一种带有退出条件的迭代执行模式,它让多个 Agent 反复执行,直到满足某个条件或达到最大迭代次数。
┌─────────────┐
│ 初始化状态 │
└──────┬──────┘
│
▼
┌─────────────┐
│ Agent A │ ←───┐
└──────┬──────┘ │
│ │
▼ │
┌─────────────┐ │
│ Agent B │ │
└──────┬──────┘ │
│ │
▼ │
┌─────────────┐ │
│ 退出条件判断 │ │
└──┬──────┬───┘ │
│ │ │
YES NO ────────┘
│
▼
┌─────────────┐
│ 输出结果 │
└─────────────┘
核心优势
✅ 自我修正:根据反馈不断优化结果
✅ 自动化迭代:无需人工干预的持续改进
✅ 质量保证:通过明确的退出条件确保结果达标
✅ 灵活控制:最大迭代次数防止无限循环
一、循环工作流的核心概念
1.1 三大核心组件
① 子代理列表(Sub Agents)
循环工作流由多个 Agent 组成,它们会按顺序重复执行:
CvReviewer cvReviewer = AgenticServices.agentBuilder(CvReviewer.class)
.chatModel(openAiChatModel)
.outputKey("cvReview") // 评审结果
.build();
ScoredCvTailor scoredCvTailor = AgenticServices.agentBuilder(ScoredCvTailor.class)
.chatModel(openAiChatModel)
.outputKey("cv") // 优化后的简历
.build();
// 循环执行顺序:cvReviewer → scoredCvTailor → cvReviewer → scoredCvTailor → ...
执行流程:
第1轮:cvReviewer(初始简历) → scoredCvTailor(优化)
第2轮:cvReviewer(优化后简历) → scoredCvTailor(再优化)
第3轮:cvReviewer(再优化后简历) → scoredCvTailor(最终版本)
...
② 退出条件(Exit Condition)
退出条件是循环工作流的灵魂,它决定了何时停止迭代:
.exitCondition(agenticScope -> {
CvReview review = (CvReview) agenticScope.readState("cvReview");
System.out.println("检查退出条件,评分=" + review.score);
return review.score > 0.8; // 评分超过 0.8 就停止
})
常见退出条件:
- ✅ 质量评分达到阈值(如 score > 0.8)
- ✅ 特定关键词出现(如 “PASS”、“APPROVED”)
- ✅ 连续两次迭代结果差异小于某个值
- ✅ 外部 API 返回成功标志
③ 最大迭代次数(Max Iterations)
这是安全保护机制,防止退出条件永远无法满足导致死循环:
.maxIterations(3) // 最多迭代 3 次
为什么需要?
- 🛡️ 防止 AI 永远无法达到理想状态
- 🛡️ 避免无限消耗 Token 和费用
- 🛡️ 保证程序最终会终止
二、实战案例:简历评审与优化循环
2.1 业务场景
我们要构建一个智能简历优化系统:
输入:
- 原始简历(master_cv.txt)
- 职位描述(job_description_backend.txt)
处理流程:
1. 评审员(CvReviewer):根据职位描述评审简历,给出评分和反馈
2. 优化器(ScoredCvTailor):根据评审反馈优化简历
3. 重复步骤 1-2,直到评分 > 0.8 或达到最大迭代次数
输出:
- 优化后的简历
- 完整的评审历史
2.2 定义 Agent 接口
① 简历评审器(CvReviewer)
package com.langchain4j.agentic._03_loop_workflow;
import com.langchain4j.domain.CvReview;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
/**
* 简历评审器接口 - 根据职位描述评审简历,给出评分和反馈
*/
public interface CvReviewer {
@Agent("根据特定指令评审简历,给出反馈和评分。考虑简历与职位的匹配程度")
@SystemMessage("""
你是以下职位的招聘经理:
{{jobDescription}}
你需要评审申请人的简历,并决定从众多申请人中邀请谁参加现场面试。
你会给每份简历一个评分和反馈(包括优点和缺点)。
你可以忽略缺少地址和占位符等内容。
""")
@UserMessage("""
请评审这份简历:{{cv}}
""")
CvReview reviewCv(@V("cv") String cv, @V("jobDescription") String jobDescription);
}
关键点:
- 返回类型是
CvReview(结构化输出),包含score和feedback - SystemMessage 定义了角色和评审标准
- UserMessage 传入待评审的简历
② 带评分的简历优化器(ScoredCvTailor)
package com.langchain4j.agentic._03_loop_workflow;
import com.langchain4j.domain.CvReview;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
/**
* 带评分的简历定制器接口 - 根据评审反馈定制简历
*/
public interface ScoredCvTailor {
@Agent("根据特定指令定制简历")
@SystemMessage("""
以下是一份需要根据特定职位描述、反馈或其他指令进行定制的简历。
你可以优化简历以满足要求,但不要虚构事实。
如果删除不相关的内容能使简历更好地符合指令,可以删除。
目标是让申请人获得面试机会,并能够在面试中展现简历中的能力。
当前简历:{{cv}}
""")
@UserMessage("""
以下是定制简历的指令和反馈:
(再次强调,不要发明原始简历中不存在的事实。
如果申请人不适合,突出其现有特征中最匹配的部分,但不要编造事实)
评审结果:{{cvReview}}
""")
String tailorCv(@V("cv") String cv, @V("cvReview") CvReview cvReview);
}
关键点:
- 接收两个参数:当前简历
cv和评审结果cvReview - 根据评审反馈进行针对性优化
- 强调"不要虚构事实",保持真实性
③ 评审结果数据结构(CvReview)
package com.langchain4j.domain;
import dev.langchain4j.model.output.structured.Description;
/**
* 简历评审结果类 - 存储简历评审的评分和反馈信息
*/
public class CvReview {
@Description("邀请该候选人参加面试的可能性评分,范围从 0 到 1")
public double score;
@Description("对简历的反馈,包括优点、需要改进的地方、缺失的技能、警示信号等")
public String feedback;
public CvReview() {} // 反序列化需要无参构造函数
public CvReview(double score, String feedback) {
this.score = score;
this.feedback = feedback;
}
@Override
public String toString() {
return "\n简历评审: " +
" - 评分 = " + score +
"\n- 反馈 = \"" + feedback + "\"\n";
}
}
关键点:
- 使用
@Description注解指导 AI 生成结构化输出 score字段用于退出条件判断feedback字段用于指导下一次优化
2.3 构建循环工作流(基础版)
完整代码
package com.langchain4j;
import com.langchain4j.agentic._03_loop_workflow.CvReviewer;
import com.langchain4j.agentic._03_loop_workflow.ScoredCvTailor;
import com.langchain4j.domain.CvReview;
import com.langchain4j.util.StringLoader;
import dev.langchain4j.agentic.AgenticServices;
import dev.langchain4j.agentic.UntypedAgent;
import dev.langchain4j.model.openai.OpenAiChatModel;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Map;
@SpringBootTest
public class _03_LoopWorkflowTest {
@Autowired
private OpenAiChatModel openAiChatModel;
/**
* 测试无类型代理的循环工作流
* 使用 UntypedAgent 创建循环工作流,通过 Map 传递参数
*/
@Test
public void testLoop() throws Exception {
// 1. 创建子代理
CvReviewer cvReviewer = AgenticServices.agentBuilder(CvReviewer.class)
.chatModel(openAiChatModel)
.outputKey("cvReview") // 评审结果存入 AgenticScope
.build();
ScoredCvTailor scoredCvTailor = AgenticServices.agentBuilder(ScoredCvTailor.class)
.chatModel(openAiChatModel)
.outputKey("cv") // 优化后的简历存入 AgenticScope
.build();
// 2. 构建循环工作流
UntypedAgent reviewedCvGenerator = AgenticServices
.loopBuilder()
.subAgents(cvReviewer, scoredCvTailor) // 按顺序循环执行
.outputKey("cv") // 最终输出优化后的简历
.exitCondition(agenticScope -> {
CvReview review = (CvReview) agenticScope.readState("cvReview");
System.out.println("检查退出条件,评分=" + review.score);
return review.score > 0.8; // 评分超过 0.8 就停止
})
.maxIterations(3) // 最多迭代 3 次,防止死循环
.build();
// 3. 加载输入数据
String masterCv = StringLoader.loadFromResource("/documents/master_cv.txt");
String jobDescription = StringLoader.loadFromResource("/documents/job_description_backend.txt");
// 4. 准备参数
Map<String, Object> arguments = Map.of(
"cv", masterCv, // 从原始简历开始
"jobDescription", jobDescription
);
// 5. 调用工作流
String tailoredCv = (String) reviewedCvGenerator.invoke(arguments);
// 6. 输出结果
System.out.println("=== 评审后的简历(无类型) ===");
System.out.println(tailoredCv);
}
}
代码解析
关键步骤拆解:
① 创建子代理
CvReviewer cvReviewer = AgenticServices.agentBuilder(CvReviewer.class)
.chatModel(openAiChatModel)
.outputKey("cvReview") // 这会在每次迭代中更新,为下一次定制提供新的反馈
.build();
作用:
outputKey("cvReview"):将评审结果存入AgenticScope- 每次迭代都会更新这个值,供下一轮的
ScoredCvTailor使用
② 构建循环工作流
UntypedAgent reviewedCvGenerator = AgenticServices
.loopBuilder()
.subAgents(cvReviewer, scoredCvTailor) // 可以添加任意数量的子代理,顺序很重要
.outputKey("cv") // 这是我们想要观察的最终输出(改进后的简历)
.exitCondition(agenticScope -> {
CvReview review = (CvReview) agenticScope.readState("cvReview");
System.out.println("检查退出条件,评分=" + review.score);
return review.score > 0.8;
})
.maxIterations(3) // 安全措施,避免无限循环
.build();
参数说明:
subAgents():指定循环执行的 Agent 列表outputKey("cv"):指定最终输出的键名exitCondition():退出条件,每次迭代后都会检查maxIterations(3):最大迭代次数
③ 调用工作流
Map<String, Object> arguments = Map.of(
"cv", masterCv, // 从主简历开始,它会被持续改进
"jobDescription", jobDescription
);
String tailoredCv = (String) reviewedCvGenerator.invoke(arguments);
注意:
- 使用
UntypedAgent时,需要通过Map传递参数 - 返回值需要强制转换为对应类型
2.4 运行效果
检查退出条件,评分=0.0
检查退出条件,评分=0.3
检查退出条件,评分=0.8
=== 评审后的简历(无类型) ===
John Doe
后端开发工程师
个人简介
热衷于构建可扩展后端系统的软件工程师,拥有分布式系统和微服务架构的专业知识...
工作经历
- 设计并实现了基于 Spring Boot 的微服务架构...
- 领导了数据库优化项目,将查询性能提升了 40%...
技能
- 精通 Java、Spring Boot、微服务架构...
- 熟悉 Docker、Kubernetes、CI/CD...
执行过程分析:
第1轮:
- CvReviewer 评分:0.0(完全不匹配)
- ScoredCvTailor 根据反馈优化简历
第2轮:
- CvReviewer 评分:0.3(有所改进,但仍不足)
- ScoredCvTailor 继续优化
第3轮:
- CvReviewer 评分:0.8(达到阈值,退出循环)
- 输出最终优化后的简历
三、高级用法:追踪迭代历史
3.1 问题:如何获取完整的评审历史?
在基础版中,我们只能看到最终的简历和最后一次评审。但有时我们需要:
- 📊 查看每一次迭代的评分变化趋势
- 📝 对比不同版本的优化内容
- 🔍 分析 AI 的决策过程
3.2 解决方案:自定义输出处理器
@Test
public void testLoopWithHistory() throws Exception {
// 1. 创建子代理(与之前相同)
CvReviewer cvReviewer = AgenticServices.agentBuilder(CvReviewer.class)
.chatModel(openAiChatModel)
.outputKey("cvReview")
.build();
ScoredCvTailor scoredCvTailor = AgenticServices.agentBuilder(ScoredCvTailor.class)
.chatModel(openAiChatModel)
.outputKey("cv")
.build();
// 2. 创建历史记录列表
List<CvReview> reviewHistory = new ArrayList<>();
// 3. 构建循环工作流(增强版)
UntypedAgent reviewedCvGenerator = AgenticServices
.loopBuilder()
.subAgents(cvReviewer, scoredCvTailor)
.outputKey("cvAndReview") // 自定义输出键
.output(agenticScope -> {
// 自定义输出处理器:提取简历和最终评审
Map<String, Object> cvAndReview = Map.of(
"cv", agenticScope.readState("cv"),
"finalReview", agenticScope.readState("cvReview")
);
return cvAndReview;
})
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
reviewHistory.add(review); // ⭐ 捕获每次迭代的评审结果
System.out.println("退出检查,评分=" + review.score);
return review.score >= 0.8;
})
.maxIterations(3)
.build();
// 4. 加载输入数据
String masterCv = StringLoader.loadFromResource("/documents/master_cv.txt");
String fluteJobDescription = "我们正在寻找一位热情的长笛老师加入我们的音乐学院。";
// 5. 准备参数
Map<String, Object> arguments = Map.of(
"cv", masterCv,
"jobDescription", fluteJobDescription
);
// 6. 调用工作流
Map<String, Object> cvAndReview = (Map<String, Object>) reviewedCvGenerator.invoke(arguments);
// 7. 输出结果
System.out.println("=== 长笛老师的评审后简历 ===");
System.out.println(cvAndReview.get("cv"));
// 8. 检查最终评审
CvReview review = (CvReview) cvAndReview.get("finalReview");
System.out.println("=== 长笛老师的最终评审 ===");
System.out.println("简历" + (review.score >= 0.8 ? "通过" : "未通过") + ",评分=" + review.score);
System.out.println("最终反馈:" + review.feedback);
// 9. 输出完整评审历史
System.out.println("=== 长笛老师的完整评审历史 ===");
for (int i = 0; i < reviewHistory.size(); i++) {
System.out.println("第 " + (i + 1) + " 轮:" + reviewHistory.get(i));
}
}
3.3 运行效果
退出检查,评分=0.0
退出检查,评分=0.3
退出检查,评分=0.4
=== 长笛老师的评审后简历 ===
John Doe
音乐教育爱好者
个人简介
充满热情的音乐爱好者,具备良好的沟通能力和教学经验...
=== 长笛老师的最终评审 ===
简历未通过,评分=0.4
最终反馈:John Doe 展示了强大的软技能和指导经验,但缺乏正式的音乐培训...
=== 长笛老师的完整评审历史 ===
第 1 轮:
简历评审: - 评分 = 0.0
- 反馈 = "这份简历不适合我们音乐学院的长笛老师职位,完全没有音乐相关背景..."
第 2 轮:
简历评审: - 评分 = 0.3
- 反馈 = "John 的简历展示了强大的软技能,如沟通、耐心和适应能力,这些在教学角色中很重要。然而,缺乏正式的音乐培训..."
第 3 轮:
简历评审: - 评分 = 0.4
- 反馈 = "John Doe 展示了强大的软技能和指导经验,但仍然没有音乐资质..."
关键改进:
- ✅
reviewHistory列表记录了每次迭代的评审结果 - ✅
.output()方法自定义了输出格式 - ✅ 可以看到评分的变化趋势(0.0 → 0.3 → 0.4)
四、核心机制深度解析
4.1 AgenticScope 状态管理
AgenticScope 是循环工作流的共享状态容器,它在整个迭代过程中持续存在。
工作原理
初始化阶段:
AgenticScope {
"cv": "原始简历内容",
"jobDescription": "职位描述"
}
第1轮迭代后:
AgenticScope {
"cv": "优化后的简历 v1",
"jobDescription": "职位描述",
"cvReview": { score: 0.0, feedback: "..." } // 新增
}
第2轮迭代后:
AgenticScope {
"cv": "优化后的简历 v2", // 更新
"jobDescription": "职位描述",
"cvReview": { score: 0.3, feedback: "..." } // 更新
}
第3轮迭代后:
AgenticScope {
"cv": "优化后的简历 v3", // 更新
"jobDescription": "职位描述",
"cvReview": { score: 0.8, feedback: "..." } // 更新
}
读取和写入状态
// 读取状态
CvReview review = (CvReview) agenticScope.readState("cvReview");
String cv = (String) agenticScope.readState("cv");
// 写入状态(通常由 outputKey 自动完成)
// 当 Agent 执行完成后,结果会自动存入 AgenticScope
4.2 退出条件的执行时机
重要:退出条件在每次 Agent 调用后都会检查,而不仅仅是在整个循环结束后。
执行顺序:
1. 执行 cvReviewer
2. 检查退出条件 ❌ 不满足
3. 执行 scoredCvTailor
4. 检查退出条件 ❌ 不满足
5. 执行 cvReviewer(第2轮)
6. 检查退出条件 ❌ 不满足
7. 执行 scoredCvTailor(第2轮)
8. 检查退出条件 ✅ 满足,退出循环
验证方法:
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
System.out.println("退出检查,评分=" + review.score); // 每次都会打印
return review.score >= 0.8;
})
输出:
退出检查,评分=0.0 // cvReviewer 执行后
退出检查,评分=0.0 // scoredCvTailor 执行后(cvReview 未更新)
退出检查,评分=0.3 // cvReviewer 执行后
退出检查,评分=0.3 // scoredCvTailor 执行后
退出检查,评分=0.8 // cvReviewer 执行后,满足条件,退出
4.3 最大迭代次数的计算
maxIterations(3) 表示最多执行 3 轮完整的循环。
计算方式:
1 轮循环 = 所有子 Agent 各执行一次
如果有 2 个子 Agent:
- maxIterations(3) = 最多执行 6 次 Agent 调用(2 × 3)
示例:
.loopBuilder()
.subAgents(agentA, agentB, agentC) // 3 个子 Agent
.maxIterations(3) // 最多 3 轮
.build();
// 最多执行次数:3 × 3 = 9 次 Agent 调用
五、常见问题与避坑指南
5.1 问题 1:退出条件永远无法满足(死循环)
症状:
退出检查,评分=0.2
退出检查,评分=0.3
退出检查,评分=0.3
退出检查,评分=0.3
...(一直循环)
原因:
- AI 无法达到设定的质量标准
- 退出条件设置过高(如 score > 0.95)
- Agent 陷入局部最优
解决方案:
// ✅ 方案 1:设置合理的 maxIterations
.maxIterations(3) // 最多迭代 3 次
// ✅ 方案 2:降低退出条件阈值
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
return review.score >= 0.6; // 从 0.8 降低到 0.6
})
// ✅ 方案 3:添加超时控制
.timeout(Duration.ofMinutes(5)) // 最多执行 5 分钟
5.2 问题 2:无法访问中间结果
症状:
// 只能获取最终结果,看不到迭代过程
String result = (String) workflow.invoke(arguments);
解决方案:
// ✅ 使用 .output() 自定义输出处理器
.output(agenticScope -> {
Map<String, Object> result = Map.of(
"cv", agenticScope.readState("cv"),
"finalReview", agenticScope.readState("cvReview"),
"allReviews", reviewHistory // 包含完整历史
);
return result;
})
5.3 问题 3:参数传递失败
症状:
Exception: Parameter 'cv' not found in AgenticScope
原因:
- 初始参数中没有提供必需的键
- outputKey 配置错误
解决方案:
// ✅ 确保初始参数包含所有必需的键
Map<String, Object> arguments = Map.of(
"cv", masterCv, // 必须提供
"jobDescription", jobDescription // 必须提供
);
// ✅ 确保 outputKey 与 Agent 的参数名匹配
.outputKey("cv") // 对应 @V("cv") String cv
5.4 问题 4:评分停滞不前
症状:
第1轮:评分=0.3
第2轮:评分=0.3
第3轮:评分=0.3
原因:
- AI 无法找到进一步优化的方向
- 反馈不够具体
解决方案:
// ✅ 方案 1:提供更详细的反馈要求
@SystemMessage("""
请给出具体的改进建议,包括:
1. 缺少哪些关键技能
2. 哪些经历需要强调
3. 哪些内容应该删除
""")
// ✅ 方案 2:增加迭代次数
.maxIterations(5) // 从 3 增加到 5
// ✅ 方案 3:调整评分标准
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
// 如果连续两次评分相同,提前退出
if (reviewHistory.size() >= 2) {
CvReview lastReview = reviewHistory.get(reviewHistory.size() - 2);
if (lastReview.score == review.score) {
return true; // 评分停滞,提前退出
}
}
return review.score >= 0.8;
})
六、适用场景与性能分析
6.1 适用场景
| 场景 | 说明 | 示例 |
|---|---|---|
| 代码生成与审查 | 反复迭代直到代码质量达标 | AI 写代码 → 静态检查 → 修复 → 再检查 |
| 内容创作 | 多次修改直到满足编辑标准 | AI 写文章 → 编辑审核 → 修改 → 再审 |
| 数据清洗 | 持续优化直到数据质量合格 | AI 清洗数据 → 验证规则 → 修正 → 再验证 |
| 设计优化 | 根据反馈不断改进设计方案 | AI 设计 UI → 用户测试 → 改进 → 再测试 |
| 翻译校对 | 多轮校对直到翻译质量达标 | AI 翻译 → 人工评分 → 修改 → 再评分 |
6.2 不适用场景
❌ 简单任务:一次性就能完成,不需要迭代
❌ 实时性要求高:循环迭代会增加延迟
❌ 成本敏感:多次迭代会消耗更多 Token
❌ 无法量化质量:没有明确的退出条件
6.3 性能对比
| 指标 | 顺序工作流 | 循环工作流 |
|---|---|---|
| 执行次数 | 固定(N 个 Agent 执行 N 次) | 动态(取决于退出条件) |
| 延迟 | 低(一次性执行) | 高(可能多次迭代) |
| 成本 | 可控(已知执行次数) | 不可控(取决于迭代次数) |
| 质量 | 一般(无自我修正) | 高(持续优化) |
| 复杂度 | 低 | 中(需要设计退出条件) |
七、最佳实践
7.1 设计退出条件
原则:
- 可量化:使用数值评分、布尔值等明确指标
- 可达性:确保 AI 有能力达到该标准
- 容错性:设置最大迭代次数作为兜底
示例:
// ✅ 好的退出条件
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
return review.score >= 0.8; // 明确的数值阈值
})
// ❌ 不好的退出条件
.exitCondition(scope -> {
// 模糊的判断标准
String cv = (String) scope.readState("cv");
return cv.contains("perfect"); // AI 可能永远不会生成这个词
})
7.2 设置最大迭代次数
建议:
- 📌 对于简单任务:
maxIterations(2-3) - 📌 对于中等复杂任务:
maxIterations(5-7) - 📌 对于复杂任务:
maxIterations(10+)+ 超时控制
.loopBuilder()
.subAgents(cvReviewer, scoredCvTailor)
.maxIterations(3) // 简单任务,3 次足够
.timeout(Duration.ofMinutes(5)) // 超时保护
.build();
7.3 记录迭代历史
价值:
- 📊 分析 AI 的优化轨迹
- 🐛 调试问题时追溯原因
- 📈 评估工作流的效果
List<CvReview> reviewHistory = new ArrayList<>();
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
reviewHistory.add(review); // 记录每次迭代
return review.score >= 0.8;
})
7.4 提供清晰的反馈
原则:
- 📝 反馈要具体,指出具体问题
- 🎯 给出明确的改进方向
- ⚖️ 平衡正面和负面反馈
示例:
@SystemMessage("""
请给出具体的改进建议,包括:
1. 缺少哪些关键技能(列举具体技术名称)
2. 哪些经历需要强调(指出具体项目)
3. 哪些内容应该删除(说明原因)
同时也要指出简历的优点,鼓励候选人。
""")
八、进阶技巧
8.1 动态调整退出条件
根据任务难度动态调整阈值:
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
String jobDescription = (String) scope.readState("jobDescription");
// 根据职位描述的难度调整阈值
double threshold = jobDescription.contains("高级") ? 0.9 : 0.7;
return review.score >= threshold;
})
8.2 结合并行工作流
在循环内部使用并行工作流加速执行:
// 伪代码示例
ParallelAgent parallelAgent = AgenticServices.parallelBuilder()
.subAgents(reviewer1, reviewer2, reviewer3) // 三个评审员并行
.aggregator((results) -> {
// 合并三个评审结果,取平均分
double avgScore = results.stream()
.mapToDouble(r -> r.score)
.average()
.orElse(0.0);
return new CvReview(avgScore, "综合评审");
})
.build();
.loopBuilder()
.subAgents(parallelAgent, scoredCvTailor) // 并行评审 + 优化
.exitCondition(scope -> ...)
.build();
8.3 多条件退出
组合多个退出条件:
.exitCondition(scope -> {
CvReview review = (CvReview) scope.readState("cvReview");
// 条件 1:评分达标
boolean scoreMet = review.score >= 0.8;
// 条件 2:反馈中包含关键词
boolean feedbackPositive = review.feedback.contains("推荐");
// 条件 3:迭代次数达到上限
boolean maxIterReached = reviewHistory.size() >= 5;
// 满足任一条件就退出
return scoreMet || feedbackPositive || maxIterReached;
})
九、结语
本文深入讲解了循环工作流的三大核心组件——子代理列表、退出条件与最大迭代次数,通过简历评审→优化的迭代实战,完整演示了"自动迭代直到质量达标"的设计模式。循环工作流的精髓在于以量化指标驱动自我修正:退出条件让系统知道何时停止,最大迭代次数提供安全兜底,迭代历史则让优化过程透明可追溯。至此,你已经掌握了顺序、循环两种基础编排模式,下一篇我们将学习并行工作流,看如何让多个 Agent 同时执行,将任务效率提升数倍。敬请期待!

🎯🔖更多专栏系列文章:AI大模型提示工程完全指南、AI大模型探索之路(零基础入门)、AI大模型预训练微调进阶、AI大模型开源精选实践、AI大模型Spring AI开发实战🔥🔥🔥 其他专栏可以查看博客主页
🔔 关于作者:资深程序老猿,10年+架构经验,现专注 AIGC 探索与实践。
👍 若文章对你有所触动,恳请点赞 ⭐ 关注 ⭐ 收藏!AI 浪潮已至,愿与你同行。
你同行。
672

被折叠的 条评论
为什么被折叠?



