找回密码
 立即注册
首页 业界区 业界 Spring AI Alibaba 人工介入实战|Human-in-the-Loop 让 ...

Spring AI Alibaba 人工介入实战|Human-in-the-Loop 让 AI 更可靠

孟清妍 5 小时前
引言

在构建AI智能体应用时,我们经常面临一个关键挑战:如何让AI在执行某些敏感操作前获得人工确认?Spring AI Alibaba框架提供了强大的人工介入(Human-in-the-Loop)机制,让开发者能够精确控制AI工具的执行流程,在关键节点引入人工审批环节。
本文将通过一个完整的实战示例,详细介绍如何在Spring AI Alibaba应用中实现人工介入功能。
什么是人工介入?

人工介入是一种机制,它允许AI智能体在执行特定工具前暂停执行,等待人工审批后再继续。这种机制特别适用于:

  • 敏感操作:如数据删除、资金转账等
  • 内容生成:如文章发布、诗歌创作等需要质量把控的场景
  • 权限控制:某些需要特定权限才能执行的操作
  • 审计要求:需要记录人工决策过程的场景
实战示例:诗歌创作的人工审批

让我们通过一个具体的例子来理解人工介入Hook的使用。这个示例展示了如何让AI在创作诗歌前获得人工确认。
1. 项目依赖配置

首先,确保你的项目中包含了Spring AI Alibaba相关依赖:
  1. <dependencies>
  2.       
  3.       <dependency>
  4.           <groupId>com.alibaba.cloud.ai</groupId>
  5.           spring-ai-alibaba-agent-framework</artifactId>
  6.           <version>1.1.2.0</version>
  7.       </dependency>
  8.       
  9.       <dependency>
  10.           <groupId>com.alibaba.cloud.ai</groupId>
  11.           spring-ai-alibaba-starter-dashscope</artifactId>
  12.           <version>1.1.2.0</version>
  13.       </dependency>
  14. </dependencies>
复制代码
2. 代码实现解析

步骤1:构建AI模型
  1. // 构建DashScope API对象
  2. DashScopeApi dashScopeApi = DashScopeApi.builder()
  3.         .apiKey(System.getenv("AliQwen_API"))
  4.         .build();
  5. // 创建聊天模型
  6. ChatModel chatModel = DashScopeChatModel.builder()
  7.         .dashScopeApi(dashScopeApi)
  8.         .build();
复制代码
步骤2:配置工具
  1. public class PoetTool implements BiFunction<String, ToolContext, String> {
  2.         public int count = 0;
  3.         public PoetTool() {
  4.         }
  5.         @Override
  6.         public String apply(
  7.                         @ToolParam(description = "The original user query that triggered this tool call") String originalUserQuery,
  8.                         ToolContext toolContext) {
  9.                 count++;
  10.                 System.out.println("Poet tool called : " + originalUserQuery);
  11.                 return "在城市的缝隙里,  \n" + "一束光悄悄发芽,  \n" + "穿过钢筋水泥的沉默,  \n" + "在风中轻轻说话。  \n" + "\n" + "夜色如墨,却不再黑,  \n"
  12.                                 + "星星点亮了每一个角落,  \n" + "我站在时间的边缘,  \n" + "等一朵云,轻轻落下";
  13.         }
  14.         public static ToolCallback createPoetToolCallback() {
  15.                 return FunctionToolCallback.builder("poem", new PoetTool())
  16.                                 .description("用来写诗的工具")
  17.                                 .inputType(String.class)
  18.                                 .build();
  19.         }
  20.         public static ToolCallback createPoetToolCallback(String name, PoetTool poetTool) {
  21.                 return FunctionToolCallback.builder(name, poetTool)
  22.                                 .description("用来写诗的工具")
  23.                                 .inputType(String.class)
  24.                                 .build();
  25.         }
  26. }
复制代码
步骤3:构建带有Hook的智能体
  1. // 这里我们配置了poem工具需要人工审批,并提供了审批时的描述信息。
  2. Map<String, ToolConfig> approvalOn = Map.of(
  3.     "poem", ToolConfig.builder()
  4.         .description("请确认诗歌工具执行")
  5.         .build()
  6. );
  7. ReactAgent agent = ReactAgent.builder()
  8.     .name("single_agent")
  9.     .model(chatModel)
  10.     .saver(new MemorySaver())  // 使用内存保存状态
  11.     .tools(List.of(createPoetToolCallback()))  // 添加诗歌创作工具
  12.     .hooks(HumanInTheLoopHook.builder()
  13.         .approvalOn(approvalOn)  // 添加人工介入Hook
  14.         .build())
  15.     .outputKey("article")
  16.     .build();
复制代码
步骤4:创建会话配置
  1. String threadId = "user-session-001";
  2. RunnableConfig config = RunnableConfig.builder()
  3.     .threadId(threadId)
  4.     .build();
复制代码
步骤5:执行并处理中断
  1. // 第一次调用 - 触发中断
  2. Optional<NodeOutput> result = agent.invokeAndGetOutput(
  3.     "帮我写一首100字左右的诗",
  4.     config
  5. );
  6. // 检查是否触发中断
  7. if (result.isPresent() && result.get() instanceof InterruptionMetadata) {
  8.     InterruptionMetadata interruptionMetadata = (InterruptionMetadata) result.get();
  9.    
  10.     System.out.println("检测到中断,需要人工审批");
  11.    
  12.     // 获取工具反馈信息
  13.     List<InterruptionMetadata.ToolFeedback> toolFeedbacks =
  14.         interruptionMetadata.toolFeedbacks();
  15.    
  16.     for (InterruptionMetadata.ToolFeedback feedback : toolFeedbacks) {
  17.         System.out.println("id: " + feedback.getId());
  18.         System.out.println("工具: " + feedback.getName());
  19.         System.out.println("参数: " + feedback.getArguments());
  20.         System.out.println("描述: " + feedback.getDescription());
  21.     }
  22.    
  23.     // 模拟人工决策(批准)
  24.     InterruptionMetadata.Builder feedbackBuilder = InterruptionMetadata.builder()
  25.         .nodeId(interruptionMetadata.node())
  26.         .state(interruptionMetadata.state());
  27.    
  28.     toolFeedbacks.forEach(toolFeedback -> {
  29.         InterruptionMetadata.ToolFeedback approvedFeedback =
  30.             InterruptionMetadata.ToolFeedback.builder(toolFeedback)
  31.                 .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED)
  32.                 .build();
  33.         feedbackBuilder.addToolFeedback(approvedFeedback);
  34.     });
  35.    
  36.     InterruptionMetadata approvalMetadata = feedbackBuilder.build();
  37.    
  38.     // 使用人工反馈恢复执行
  39.     RunnableConfig resumeConfig = RunnableConfig.builder()
  40.         .threadId(threadId)
  41.         .addMetadata(RunnableConfig.HUMAN_FEEDBACK_METADATA_KEY, approvalMetadata)
  42.         .build();
  43.    
  44.     Optional<NodeOutput> finalResult = agent.invokeAndGetOutput("", resumeConfig);
  45.    
  46.     if (finalResult.isPresent()) {
  47.         System.out.println("执行完成");
  48.         // 因为创建智能体的时候,指定了outputKey,所以这里我们直接获取
  49.         Object article = finalResult.get().state().data().get("article");
  50.         System.out.println("最终结果: " + article);
  51.     }
  52. }
复制代码
3. 执行流程分析

这个示例的执行流程如下:

  • 触发阶段:用户请求AI创作诗歌
  • 中断阶段:AI检测到poem工具需要人工审批,暂停执行
  • 审批阶段:系统展示工具信息,等待人工决策
  • 恢复阶段:人工批准后,AI继续执行并生成诗歌
  • 完成阶段:返回最终结果
高级特性

多工具审批

你可以为多个工具配置审批:
  1. Map<String, ToolConfig> approvalOn = Map.of(
  2.     "poem", ToolConfig.builder().description("诗歌创作工具").build(),
  3.     "delete", ToolConfig.builder().description("数据删除工具").build(),
  4.     "publish", ToolConfig.builder().description("内容发布工具").build()
  5. );
复制代码
审批结果类型

支持多种审批结果:

  • APPROVED:批准执行
  • REJECTED:拒绝执行
  • MODIFIED:修改参数后执行
最佳实践

1. 明确审批策略


  • 只为真正需要人工确认的工具配置审批
  • 提供清晰的审批描述信息
  • 考虑审批的时效性
2. 用户体验优化


  • 提供友好的审批界面
  • 支持批量审批操作
  • 记录审批历史便于审计
3. 错误处理
  1. try {
  2.     Optional<NodeOutput> result = agent.invokeAndGetOutput(request, config);
  3.     // 处理中断和结果
  4. } catch (GraphRunnerException e) {
  5.     // 处理执行异常
  6.     log.error("智能体执行失败", e);
  7. }
复制代码
4. 状态管理
  1. // 使用合适的Saver
  2. .saver(new MemorySaver())  // 内存存储,适合开发测试
  3. .saver(new RedisSaver())   // Redis存储,适合生产环境
  4. .saver(new DatabaseSaver()) // 数据库存储,适合需要持久化的场景
复制代码
5. 执行结果

1.png

拓展

Spring Ai Alibaba还为我们内置了几个其他的Hook

  • SummarizationHook(消息压缩)
    当对话很长时,自动压缩对话历史,防止超出模型上下文限制
  • ModelCallLimitHook(模型调用限制)
    防止Agent无限调用模型,控制成本
另外,我们也可以自定义Hook,这部分内容如果大家感兴趣的话,后面可以单独介绍一下下~
参考资料


  • HumanInTheLoopHook API文档

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册