Agent设计模式学习(基于langchain4j实现)(9) - 人机协同

经过前面的一系列流程,招聘来到了最重要的1个环节,AI虽然强大,但是不能完全代替人做决定,最终还是要Boss决策这个候选人的去留。从系统设计角度来说,整个AI智能体环节中,要预留人工干预的能力,也称为"人机协同"(human_in_the_loop)

 

示例代码

 1 @SpringBootApplication
 2 public class _9a_HumanInTheLoop_Simple_Validator {
 3 
 4     public static void main(String[] args) throws IOException {
 5         ConfigurableApplicationContext context = SpringApplication.run(AgentDesignPatternApplication.class, args);
 6         ChatModel model = context.getBean("ollamaChatModel", ChatModel.class);
 7         RagProvider ragProvider = context.getBean("ragProvider", RagProvider.class);
 8 
 9         // 3. 创建相关智能体
10         InterviewOrganizer interviewOrganizer = AgenticServices.agentBuilder(InterviewOrganizer.class)
11                 .chatModel(model)
12                 .tools(new OrganizingTools())
13                 .contentRetriever(ragProvider.loadHouseRulesRetriever())
14                 .build();
15 
16         EmailAssistant emailAssistant = AgenticServices.agentBuilder(EmailAssistant.class)
17                 .chatModel(model)
18                 .tools(new OrganizingTools())
19                 .build();
20 
21         HiringDecisionProposer decisionProposer = AgenticServices.agentBuilder(HiringDecisionProposer.class)
22                 .chatModel(model)
23                 .outputKey("modelDecision")
24                 .build();
25 
26         // 2. 定义人工验证环节
27         HumanInTheLoop humanValidator = AgenticServices.humanInTheLoopBuilder()
28                 .description("验证模型提出的招聘决策")
29                 .inputKey("modelDecision")
30                 .outputKey("finalDecision") // 由人工检查
31                 .requestWriter(request -> {
32                     System.out.println("AI招聘助手建议: " + request);
33                     System.out.println("请确认最终决定。");
34                     System.out.println("选项: 邀请现场面试 (I), 拒绝 (R), 暂缓 (H)");
35                     System.out.print("> "); // 在实际系统中需要输入验证和错误处理
36                 })
37                 .responseReader(() -> new Scanner(System.in).nextLine())
38                 .build();
39 
40         // 3. 将智能体链接成工作流
41         UntypedAgent hiringDecisionWorkflow = AgenticServices.sequenceBuilder()
42                 .subAgents(decisionProposer, humanValidator)
43                 .outputKey("finalDecision")
44                 .build();
45 
46         // 4. 准备输入参数
47         Map<String, Object> input = Map.of(
48                 "cvReview", new CvReview(0.85,
49                         """
50                                 技术能力强,但缺乏所需的React经验。
51                                 似乎是快速独立学习者。文化契合度良好。
52                                 工作许可可能存在潜在问题,但似乎可以解决。
53                                 薪资期望略高于计划预算。
54                                 决定继续进行现场面试。
55                                 """)
56         );
57 
58         System.out.println(input + "\n");
59 
60         // 5. 运行工作流
61         String finalDecision = (String) hiringDecisionWorkflow.invoke(input);
62 
63         System.out.println("\n=== 人工最终决定 ===");
64         System.out.println("(邀请现场面试 (I), 拒绝 (R), 暂缓 (H))\n");
65         System.out.println(finalDecision);
66 
67         UntypedAgent candidateResponder = AgenticServices
68                 .conditionalBuilder()
69                 .subAgents(agenticScope -> finalDecision.contains("I"), interviewOrganizer)
70                 .subAgents(agenticScope -> finalDecision.contains("R"), emailAssistant)
71                 .subAgents(agenticScope -> finalDecision.contains("H"), new HoldOnAssist())
72                 .build();
73 
74         String candidateContact = StringLoader.loadFromResource("/documents/candidate_contact.txt");
75         String jobDescription = StringLoader.loadFromResource("/documents/job_description_backend.txt");
76 
77 
78         Map<String, Object> arguments = Map.of(
79                 "candidateContact", candidateContact,
80                 "jobDescription", jobDescription
81         );
82 
83         // 6. 根据人工最终决定,进行下一步操作
84         candidateResponder.invoke(arguments);
85 
86         // 注意:人工参与和人工验证通常需要较长时间等待用户响应。
87         // 在这种情况下,建议使用异步智能体,这样它们不会阻塞工作流的其余部分,
88         // 这些部分可以在用户回答之前潜在执行。
89     }
90 }
_9a_HumanInTheLoop_Simple_Validator

解释一下:

27行,这里的 AgenticServices.humanInTheLoopBuilder() 表示这里需要人机协助,协助的方式由29行的 new Scanner(System.in).nextLine() 指定为终端控制台输入(也可以根据需要,换成其它方式,比如:读数据库,调用接口从其它系统获取)

67-71行,则是根据人工指令做出的响应(即前面学过过的条件工作流),如果输入H,则执行下面的Agent 

1 public class HoldOnAssist {
2 
3     @Agent(description = "招聘流程暂缓")
4     public void abort() {
5         System.out.println("招聘流程暂缓");
6     }
7 }
HoldOnAssist

 

输出日志

 1 {cvReview=
 2 CvReview:  - score = 0.85
 3 - feedback = "技术能力强,但缺乏所需的React经验。
 4 似乎是快速独立学习者。文化契合度良好。
 5 工作许可可能存在潜在问题,但似乎可以解决。
 6 薪资期望略高于计划预算。
 7 决定继续进行现场面试。
 8 "
 9 }
10 
11 AI招聘助手建议: **招聘理由汇总:**
12 
13 **优势:** 技术能力强,文化契合度良好,学习能力佳
14 
15 **风险:** 缺乏React经验,薪资略超预算,潜在工作许可问题  
16 
17 **建议:** 继续现场面试评估,面试后综合决定
18 请确认最终决定。
19 选项: 邀请现场面试 (I), 拒绝 (R), 暂缓 (H)
20 > H
21 
22 === 人工最终决定 ===
23 (邀请现场面试 (I), 拒绝 (R), 暂缓 (H))
24 
25 H
26 招聘流程暂缓
View Code

image

 

时序图(简化版) - AI生成

09_human_diagram_simple

时序图(详细版) - AI生成
09_human_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 19:13  菩提树下的杨过  阅读(7)  评论(0)    收藏  举报