Agent设计模式学习(基于langchain4j实现)(8) - 非AI智能体
AgenticServices.agentBuilder(XXX) .chatModel(model) .outputKey("xxx") .build();
先定义2个不需要AI参与的处理环节(也称非AI智能体)
1 /** 2 * 非AI智能体,将多个简历评审聚合成一个综合评审。 3 * 这演示了普通Java操作符如何作为一等智能体用于智能体工作流, 4 * 使它们能够与AI驱动的智能体互换使用。 5 */ 6 public class ScoreAggregator { 7 8 @Agent(description = "将HR/经理/团队评审聚合成综合评审", outputKey = "combinedCvReview") 9 public CvReview aggregate(@V("hrReview") CvReview hr, 10 @V("managerReview") CvReview mgr, 11 @V("teamMemberReview") CvReview team) { 12 13 System.out.println("ScoreAggregator被调用,参数:hrReview=" + hr + 14 ", managerReview=" + mgr + 15 ", teamMemberReview=" + team); 16 17 double avgScore = (hr.score + mgr.score + team.score) / 3.0; 18 19 String combinedFeedback = String.join("\n\n", 20 "HR评审: " + hr.feedback, 21 "经理评审: " + mgr.feedback, 22 "团队成员评审: " + team.feedback 23 ); 24 25 return new CvReview(avgScore, combinedFeedback); 26 } 27 }
虽然这个类也加了@Agent,表示这是1个智能体,但是并不需要LLM直接参与,所以得名”非AI智能体“。
1 /** 2 * 非AI智能体,根据评分更新申请状态。 3 * 这演示了普通Java操作符如何作为一等智能体用于智能体工作流, 4 * 使它们能够与AI驱动的智能体互换使用。 5 */ 6 public class StatusUpdate { 7 8 @Agent(description = "根据评分更新申请状态") 9 public void update(@V("combinedCvReview") CvReview aggregateCvReview) { 10 double score = aggregateCvReview.score; 11 System.out.println("StatusUpdate被调用,评分: " + score); 12 13 if (score >= 8.0) { 14 // 示例用的模拟数据库更新 15 System.out.println("申请状态更新为: 已邀请面试"); 16 } else { 17 // 示例用的模拟数据库更新 18 System.out.println("申请状态更新为: 已拒绝"); 19 } 20 } 21 }
完整的串起来,示例如下:
1 /** 2 * 这里展示如何在智能体工作流中使用非AI智能体(普通Java操作符)。 3 * 非AI智能体只是普通的方法,但可以像其他类型的智能体一样使用。 4 * 它们非常适合确定性的操作,如计算、数据转换和聚合,这些操作不需要LLM参与。 5 * 将更多步骤外包给非AI智能体,你的工作流将更快、更准确、更经济。 6 * 对于需要强制确定性执行的步骤,非AI智能体比工具更受青睐。 7 * 在这个例子中,我们希望评审者的综合评分是确定性计算的,而不是由LLM计算。 8 * 我们同样基于综合评分确定性地更新数据库中的申请状态。 9 * by 菩提树下的杨过(yjmyzz.cnblogs.com) 10 */ 11 @SpringBootApplication 12 public class _8_Non_AI_Agents { 13 14 public static void main(String[] args) throws IOException { 15 16 ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.class, args); 17 ChatModel model = context.getBean("ollamaChatModel", ChatModel.class); 18 19 // 2. 构建并行评审步骤的AI子智能体 20 HrCvReviewer hrReviewer = AgenticServices.agentBuilder(HrCvReviewer.class) 21 .chatModel(model) 22 .outputKey("hrReview") 23 .build(); 24 25 ManagerCvReviewer managerReviewer = AgenticServices.agentBuilder(ManagerCvReviewer.class) 26 .chatModel(model) 27 .outputKey("managerReview") 28 .build(); 29 30 TeamMemberCvReviewer teamReviewer = AgenticServices.agentBuilder(TeamMemberCvReviewer.class) 31 .chatModel(model) 32 .outputKey("teamMemberReview") 33 .build(); 34 35 // 3. 构建组合的并行智能体 36 var executor = Executors.newFixedThreadPool(3); // 保留引用以便后续关闭 37 38 UntypedAgent parallelReviewWorkflow = AgenticServices 39 .parallelBuilder() 40 .subAgents(hrReviewer, managerReviewer, teamReviewer) 41 .executor(executor) 42 .build(); 43 44 // 4. 构建包含非AI智能体的完整工作流 45 UntypedAgent collectFeedback = AgenticServices 46 .sequenceBuilder() 47 .subAgents( 48 parallelReviewWorkflow, 49 new ScoreAggregator(), // 非AI智能体不需要AgenticServices构建器。outputKey 'combinedCvReview' 已在类中定义 50 new StatusUpdate(), // 以'combinedCvReview'作为输入,不需要输出 51 AgenticServices.agentAction(agenticScope -> { // 添加非AI智能体的另一种方式,可以操作AgenticScope 52 CvReview review = (CvReview) agenticScope.readState("combinedCvReview"); 53 agenticScope.writeState("scoreAsPercentage", review.score * 100); // 当不同系统的智能体通信时,通常需要输出转换 54 }) 55 ) 56 .outputKey("scoreAsPercentage") // outputKey在ScoreAggregator.java中的非AI智能体注解中定义 57 .build(); 58 59 // 5. 加载输入数据 60 String candidateCv = StringLoader.loadFromResource("/documents/tailored_cv.txt"); 61 String candidateContact = StringLoader.loadFromResource("/documents/candidate_contact.txt"); 62 String hrRequirements = StringLoader.loadFromResource("/documents/hr_requirements.txt"); 63 String phoneInterviewNotes = StringLoader.loadFromResource("/documents/phone_interview_notes.txt"); 64 String jobDescription = StringLoader.loadFromResource("/documents/job_description_backend.txt"); 65 66 Map<String, Object> arguments = Map.of( 67 "candidateCv", candidateCv, 68 "candidateContact", candidateContact, 69 "hrRequirements", hrRequirements, 70 "phoneInterviewNotes", phoneInterviewNotes, 71 "jobDescription", jobDescription 72 ); 73 74 // 6. 调用工作流 75 double scoreAsPercentage = (double) collectFeedback.invoke(arguments); 76 executor.shutdown(); 77 78 System.out.println("=== 百分比形式的评分 ==="); 79 System.out.println(scoreAsPercentage); 80 // 从日志中我们可以看到,申请状态也已经相应更新 81 82 } 83 }
注意:49-54行,这里演示了2种创建”非AI智能体”的方式,一是直接new 对象,一种是直接 AgenticServices.agentAction(agenticScope -> {...});
输出:
---------------------------------
ScoreAggregator被调用,参数:hrReview=
CvReview: - score = 0.82
- feedback = "优点:简历清晰专业,联系方式完整。拥有比利时公民身份,合法工作许可。荷兰语母语水平,英语C1水平符合要求。工作履历稳定,无职业空白期,每段工作经历均超过1年。技术技能匹配度高,具有4年以上Java/Spring Boot开发经验,职责范围从单纯开发扩展到指导实习生,体现了成长。
不足之处:薪资期望75,000欧元略高于55,000-70,000欧元范围。可入职时间需要3个月通知,与理想的1-2个月入职时间存在差距。分布式系统经验有限,Kafka仅为基础水平。
技能评估:技术栈符合要求但深度不够,特别是分布式系统和现代微服务架构经验不足。指导他人的经验是加分项。
综合评估:候选人基础条件良好,技能匹配度较高,但薪资和入职时间需要进一步沟通。如果能协调薪资水平或缩短入职等待时间,建议进入面试环节。"
, managerReview=
CvReview: - score = 0.82
- feedback = "约翰·多伊是一位非常匹配的候选人。他在BrightPay Systems的工作经历特别出色,恰好满足职位的核心要求:具备Java/Spring Boot后端开发经验,成功完成SOAP到REST的API迁移,开发了定价工具系统,并取得了显著的量化成果(报价时间缩短35%)。地理位置理想,语言技能完全符合要求(荷兰语母语+英语C1)。技术栈匹配度高,包括PostgreSQL、CI/CD(GitHub Actions)、Docker等。个人项目展现了对Spring生态系统的深度理解。
主要不足包括:Kafka仅停留在概念验证阶段,缺乏生产级经验;对Kubernetes的实际应用经验不足;从金融科技角度来说,工作经验主要集中在定价工具开发,缺乏完整的支付与对账系统经验。但考虑到整体匹配度很高,这些不足完全可以通过培训和实践来弥补。建议邀请参加现场面试,重点评估其在支付系统架构设计方面的思维能力和学习潜力。"
, teamMemberReview=
CvReview: - score = 0.75
- feedback = "简历整体质量良好,展现了扎实的后端开发基础。优点:4年经验符合岗位要求,技术栈匹配(Java, Spring Boot, PostgreSQL),有具体量化成就(报价时间缩短35%),完成API现代化迁移,建立CI/CD流程,多语言能力突出。不足:Kafka只有基础水平且只是概念验证,个人项目描述过于简单,缺少测试经验(TDD、单元测试等),没有云平台经验(AWS/GCP/Azure),技术栈相对传统。需要改进:增加具体的技术实现细节,补充测试和云平台技能,完善项目描述。风险信号:涉及前端开发可能分散后端专业性,职业转换路径(机械工程→编程)需要进一步了解深度。"
StatusUpdate被调用,评分: 0.7966666666666665
申请状态更新为: 已拒绝
=== 百分比形式的评分 ===
79.66666666666666
--------------------------------------
时序图(简化版)-AI生成

时序图(详细版)-AI生成

文中示例代码:
https://github.com/yjmyzz/agentic_turoial_with_langchain4j
参考:
Building Effective AI Agents \ Anthropic
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
浙公网安备 33010602011771号