经过前面的一系列流程,招聘来到了最重要的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 }解释一下:
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 }输出日志:
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 招聘流程暂缓
时序图(简化版) - AI生成

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

文中示例代码:
https://github.com/yjmyzz/agentic_turoial_with_langchain4j
参考:
Building Effective AI Agents \ Anthropic
[译] AI Workflow & AI Agent:架构、模式与工程建议(Anthropic,2024)