Agent设计模式学习(基于langchain4j实现)(8) - 非AI智能体

上节继续,前面讨论的这个AI招聘示例,并非所有环节都需要AI参与,比如:HR、经理、团队对简历分别做出评价后,【计算平均分】以及【根据平均分更新状态(比如:平均分低于0.8则拒绝)】,这2个环节完全可以用代码实现,以节省大模型算力成本。 这时候,就不需要使用类似下面的AgentServices来构建
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 }
ScoreAggregator

虽然这个类也加了@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 }
StatusUpdate

 

完整的串起来,示例如下:

 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 }
_8_Non_AI_Agents

注意: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生成

 08_non_ai_diagram_simple

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

08_non_ai_diagram_detail

 

文中示例代码:

https://github.com/yjmyzz/agentic_turoial_with_langchain4j

 

参考:

Building Effective AI Agents \ Anthropic

[译] AI Workflow & AI Agent:架构、模式与工程建议(Anthropic,2024)

Agents and Agentic AI | LangChain4j

posted @ 2026-01-31 18:44  菩提树下的杨过  阅读(0)  评论(0)    收藏  举报