首页
关于这个博客
Search
1
Java 实现Google 账号单点登录(OAuth 2.0)全流程解析
1,421 阅读
2
Spring AI 无法获取大模型深度思考内容?解决方案来了
525 阅读
3
EasyExcel 实战:导出带图片的 Excel 完整方案
282 阅读
4
服务器遭遇 XMRig 挖矿程序入侵排查与清理全记录
265 阅读
5
微信小程序实现页面返回前确认弹窗:兼容左上角返回与右滑返回
219 阅读
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
登录
Search
标签搜索
Spring AI
java虚拟机
JVM
Spring AI Alibaba
Java
保姆级教程
SpringBoot
Spring
WebFlux
MCP
大模型
Agent Skills
Nginx
Agent
Ubuntu
Mysql
Apache POI
自定义starter
Mybatis
响应式编程
Luca Ju
累计撰写
51
篇文章
累计收到
2
条评论
首页
栏目
Java 核心
框架与中间件
数据库技术
开发工具与效率
问题排查与踩坑记录
程序员成长与思考
前端
页面
关于这个博客
搜索到
1
篇与
的结果
2026-03-16
Spring AI Alibaba 人工介入实战|Human-in-the-Loop 让 AI 更可靠
引言在构建AI智能体应用时,我们经常面临一个关键挑战:如何让AI在执行某些敏感操作前获得人工确认?Spring AI Alibaba框架提供了强大的人工介入(Human-in-the-Loop)机制,让开发者能够精确控制AI工具的执行流程,在关键节点引入人工审批环节。本文将通过一个完整的实战示例,详细介绍如何在Spring AI Alibaba应用中实现人工介入功能。什么是人工介入?人工介入是一种机制,它允许AI智能体在执行特定工具前暂停执行,等待人工审批后再继续。这种机制特别适用于:敏感操作:如数据删除、资金转账等内容生成:如文章发布、诗歌创作等需要质量把控的场景权限控制:某些需要特定权限才能执行的操作审计要求:需要记录人工决策过程的场景实战示例:诗歌创作的人工审批让我们通过一个具体的例子来理解人工介入Hook的使用。这个示例展示了如何让AI在创作诗歌前获得人工确认。1. 项目依赖配置首先,确保你的项目中包含了Spring AI Alibaba相关依赖:<dependencies> <!-- Spring AI Alibaba Agent Framework --> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-agent-framework</artifactId> <version>1.1.2.0</version> </dependency> <!-- DashScope ChatModel 支持(如果使用其他模型,请跳转 Spring AI 文档选择对应的 starter) --> <dependency> <groupId>com.alibaba.cloud.ai</groupId> <artifactId>spring-ai-alibaba-starter-dashscope</artifactId> <version>1.1.2.0</version> </dependency> </dependencies>2. 代码实现解析步骤1:构建AI模型// 构建DashScope API对象 DashScopeApi dashScopeApi = DashScopeApi.builder() .apiKey(System.getenv("AliQwen_API")) .build(); // 创建聊天模型 ChatModel chatModel = DashScopeChatModel.builder() .dashScopeApi(dashScopeApi) .build();步骤2:配置工具public class PoetTool implements BiFunction<String, ToolContext, String> { public int count = 0; public PoetTool() { } @Override public String apply( @ToolParam(description = "The original user query that triggered this tool call") String originalUserQuery, ToolContext toolContext) { count++; System.out.println("Poet tool called : " + originalUserQuery); return "在城市的缝隙里, \n" + "一束光悄悄发芽, \n" + "穿过钢筋水泥的沉默, \n" + "在风中轻轻说话。 \n" + "\n" + "夜色如墨,却不再黑, \n" + "星星点亮了每一个角落, \n" + "我站在时间的边缘, \n" + "等一朵云,轻轻落下"; } public static ToolCallback createPoetToolCallback() { return FunctionToolCallback.builder("poem", new PoetTool()) .description("用来写诗的工具") .inputType(String.class) .build(); } public static ToolCallback createPoetToolCallback(String name, PoetTool poetTool) { return FunctionToolCallback.builder(name, poetTool) .description("用来写诗的工具") .inputType(String.class) .build(); } }步骤3:构建带有Hook的智能体// 这里我们配置了poem工具需要人工审批,并提供了审批时的描述信息。 Map<String, ToolConfig> approvalOn = Map.of( "poem", ToolConfig.builder() .description("请确认诗歌工具执行") .build() ); ReactAgent agent = ReactAgent.builder() .name("single_agent") .model(chatModel) .saver(new MemorySaver()) // 使用内存保存状态 .tools(List.of(createPoetToolCallback())) // 添加诗歌创作工具 .hooks(HumanInTheLoopHook.builder() .approvalOn(approvalOn) // 添加人工介入Hook .build()) .outputKey("article") .build();步骤4:创建会话配置String threadId = "user-session-001"; RunnableConfig config = RunnableConfig.builder() .threadId(threadId) .build();步骤5:执行并处理中断// 第一次调用 - 触发中断 Optional<NodeOutput> result = agent.invokeAndGetOutput( "帮我写一首100字左右的诗", config ); // 检查是否触发中断 if (result.isPresent() && result.get() instanceof InterruptionMetadata) { InterruptionMetadata interruptionMetadata = (InterruptionMetadata) result.get(); System.out.println("检测到中断,需要人工审批"); // 获取工具反馈信息 List<InterruptionMetadata.ToolFeedback> toolFeedbacks = interruptionMetadata.toolFeedbacks(); for (InterruptionMetadata.ToolFeedback feedback : toolFeedbacks) { System.out.println("id: " + feedback.getId()); System.out.println("工具: " + feedback.getName()); System.out.println("参数: " + feedback.getArguments()); System.out.println("描述: " + feedback.getDescription()); } // 模拟人工决策(批准) InterruptionMetadata.Builder feedbackBuilder = InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); toolFeedbacks.forEach(toolFeedback -> { InterruptionMetadata.ToolFeedback approvedFeedback = InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED) .build(); feedbackBuilder.addToolFeedback(approvedFeedback); }); InterruptionMetadata approvalMetadata = feedbackBuilder.build(); // 使用人工反馈恢复执行 RunnableConfig resumeConfig = RunnableConfig.builder() .threadId(threadId) .addMetadata(RunnableConfig.HUMAN_FEEDBACK_METADATA_KEY, approvalMetadata) .build(); Optional<NodeOutput> finalResult = agent.invokeAndGetOutput("", resumeConfig); if (finalResult.isPresent()) { System.out.println("执行完成"); // 因为创建智能体的时候,指定了outputKey,所以这里我们直接获取 Object article = finalResult.get().state().data().get("article"); System.out.println("最终结果: " + article); } }3. 执行流程分析这个示例的执行流程如下:触发阶段:用户请求AI创作诗歌中断阶段:AI检测到poem工具需要人工审批,暂停执行审批阶段:系统展示工具信息,等待人工决策恢复阶段:人工批准后,AI继续执行并生成诗歌完成阶段:返回最终结果高级特性多工具审批你可以为多个工具配置审批:Map<String, ToolConfig> approvalOn = Map.of( "poem", ToolConfig.builder().description("诗歌创作工具").build(), "delete", ToolConfig.builder().description("数据删除工具").build(), "publish", ToolConfig.builder().description("内容发布工具").build() );审批结果类型支持多种审批结果:APPROVED:批准执行REJECTED:拒绝执行MODIFIED:修改参数后执行最佳实践1. 明确审批策略只为真正需要人工确认的工具配置审批提供清晰的审批描述信息考虑审批的时效性2. 用户体验优化提供友好的审批界面支持批量审批操作记录审批历史便于审计3. 错误处理try { Optional<NodeOutput> result = agent.invokeAndGetOutput(request, config); // 处理中断和结果 } catch (GraphRunnerException e) { // 处理执行异常 log.error("智能体执行失败", e); }4. 状态管理// 使用合适的Saver .saver(new MemorySaver()) // 内存存储,适合开发测试 .saver(new RedisSaver()) // Redis存储,适合生产环境 .saver(new DatabaseSaver()) // 数据库存储,适合需要持久化的场景5. 执行结果拓展Spring Ai Alibaba还为我们内置了几个其他的HookSummarizationHook(消息压缩)当对话很长时,自动压缩对话历史,防止超出模型上下文限制ModelCallLimitHook(模型调用限制)防止Agent无限调用模型,控制成本另外,我们也可以自定义Hook,这部分内容如果大家感兴趣的话,后面可以单独介绍一下下~参考资料HumanInTheLoopHook API文档
2026年03月16日
23 阅读
0 评论
1 点赞