Spring AI Alibaba ——人工介入(Human-in-the-Loop)
Spring AI Alibaba ——人工介入Human-in-the-Loop核心结论一句话先记住如果说 Agent 是个不知疲倦的打工人那HITLHuman-in-the-Loop人工介入就是给它配了一个“拥有一票否决权的主管”。大白话当 AI 打算干一些“危险动作”比如写文件、删数据库、发正式邮件时系统会自动按下暂停键把操作卡住等你人工看一眼。你点头了Approve它才继续干你觉得不行可以帮它改参数Edit或者直接打回重做Reject。在 Spring AI Alibaba 中这个机制底层依赖于检查点Checkpoint机制Agent 暂停时会把当前的脑图记忆存进硬盘或内存等你审批完再原封不动地取出来继续跑。一、 老板批奏折的三种决策Decision Types当 Agent 被拦截下来时你需要给它一个反馈系统内置了三种决策✅approve批准没毛病原样执行。比如生成的邮件内容很好直接发。✏️edit修改思路对了但细节有误我帮你改改参数再执行。比如邮件收件人填错了手动改对后发送。❌reject拒绝纯属胡扯打回去并告诉它为什么拒绝让它重新想。比如这封邮件语气太凶了重写。二、 怎么给危险工具挂上“审批流”基础配置配置大白话第一步必须要有记忆存储如MemorySaver不然暂停后 Agent 就失忆了第二步搞一个HumanInTheLoopHook告诉它遇到哪些工具需要卡住。配置中断代码示例import com.alibaba.cloud.ai.graph.agent.ReactAgent; import com.alibaba.cloud.ai.graph.agent.hook.hip.HumanInTheLoopHook; import com.alibaba.cloud.ai.graph.agent.hook.hip.ToolConfig; import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver; // ⭐ 1. 必须配置检查点保存器因为人工介入必须保存案发现场 MemorySaver memorySaver new MemorySaver(); // ⭐ 2. 核心创建人工介入 Hook指定哪些工具需要审批 HumanInTheLoopHook humanInTheLoopHook HumanInTheLoopHook.builder() // 发现它调用 write_file 工具时给我拦住 .approvalOn(write_file, ToolConfig.builder().description(文件写入操作需要审批).build()) // 发现它调用 execute_sql 时也拦住 .approvalOn(execute_sql, ToolConfig.builder().description(SQL执行操作需要审批).build()) .build(); // 3. 把 Hook 和 Saver 挂载到 Agent 身上 ReactAgent agent ReactAgent.builder() .name(approval_agent) .model(chatModel) .tools(writeFileTool, executeSqlTool, readDataTool) // 里面包含了各种工具 .hooks(List.of(humanInTheLoopHook)) // 注入审批流 .saver(memorySaver) // 注入记忆 .build();✋三、 怎么响应中断并给反馈完整生命周期大白话当你调用 Agent 发现它没返回答案而是返回了一个InterruptionMetadata这就说明“它被卡住了在等你批示”。1. 发现并查看中断响应中断示例import com.alibaba.cloud.ai.graph.RunnableConfig; import com.alibaba.cloud.ai.graph.NodeOutput; import com.alibaba.cloud.ai.graph.action.InterruptionMetadata; // ⭐ 必须提供 threadId不然系统不知道这是谁的会话 String threadId user-session-123; RunnableConfig config RunnableConfig.builder().threadId(threadId).build(); // 运行它 OptionalNodeOutput result agent.invokeAndGetOutput(删除数据库中的旧记录, config); // ⭐ 检查是不是被中断了 if (result.isPresent() result.get() instanceof InterruptionMetadata) { InterruptionMetadata interruptionMetadata (InterruptionMetadata) result.get(); // 把它打算干的坏事打印出来看看 ListInterruptionMetadata.ToolFeedback toolFeedbacks interruptionMetadata.toolFeedbacks(); for (InterruptionMetadata.ToolFeedback feedback : toolFeedbacks) { System.out.println(工具: feedback.getName()); System.out.println(参数: feedback.getArguments()); System.out.println(描述: feedback.getDescription()); } }2. 给出决策并恢复运行完整示例接上文import com.alibaba.cloud.ai.graph.agent.ReactAgent; import com.alibaba.cloud.ai.graph.agent.hook.hip.HumanInTheLoopHook; import com.alibaba.cloud.ai.graph.agent.hook.hip.ToolConfig; import com.alibaba.cloud.ai.graph.RunnableConfig; import com.alibaba.cloud.ai.graph.NodeOutput; import com.alibaba.cloud.ai.graph.action.InterruptionMetadata; import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver; public class HumanInTheLoopExample { public static void main(String[] args) throws Exception { // ... (此处省略前面初始化 Agent 和 Hook 的代码) ... String threadId user-session-001; RunnableConfig config RunnableConfig.builder().threadId(threadId).build(); // 第一次调用期望它被拦住 OptionalNodeOutput result agent.invokeAndGetOutput(帮我写一首100字左右的诗, config); if (result.isPresent() result.get() instanceof InterruptionMetadata interruptionMetadata) { System.out.println(检测到中断需要人工审批); // ⭐ 1. 模拟老板批奏折构建审批意见这里选择全部 APPROVED 批准 InterruptionMetadata.Builder feedbackBuilder InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); interruptionMetadata.toolFeedbacks().forEach(toolFeedback - { InterruptionMetadata.ToolFeedback approvedFeedback InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED) // 决策批准 .build(); feedbackBuilder.addToolFeedback(approvedFeedback); }); InterruptionMetadata approvalMetadata feedbackBuilder.build(); // ⭐ 2. 将圣旨反馈意见塞进 Config 里 RunnableConfig resumeConfig RunnableConfig.builder() .threadId(threadId) .addMetadata(RunnableConfig.HUMAN_FEEDBACK_METADATA_KEY, approvalMetadata) // 带着反馈意见 .build(); // 第二次调用带着老板的决定恢复执行(注意传的 input 是空串因为状态已经记在脑子里了) OptionalNodeOutput finalResult agent.invokeAndGetOutput(, resumeConfig); if (finalResult.isPresent()) { System.out.println(最终结果: finalResult.get()); } } } }️四、 终极复杂场景Workflow工作流里的连环套大白话有时候 Agent 不是单打独斗而是被嵌套在一个巨大的StateGraph图工作流里的一个小小节点。这时候怎么审批区别在于记忆Saver必须注册在工作流全局的CompileConfig上中断和恢复也是对着CompiledGraph发号施令。工作流嵌套审批代码// ... 省略 imports ... // 1. 创建工具和 Saver ToolCallback searchTool FunctionToolCallback.builder(search, (args) - 搜索结果...).build(); MemorySaver saver new MemorySaver(); // ⭐ 全局共享的 Saver // 2. 创建带审批 Hook 的 Agent ReactAgent qaAgent ReactAgent.builder() .name(qa_agent) .model(chatModel) .saver(saver) // Agent 要挂载 .hooks(HumanInTheLoopHook.builder() .approvalOn(search, ToolConfig.builder().description(搜索操作需审批).build()) .build()) .tools(searchTool).build(); // ... 省略 PreprocessorNode 和 ValidatorNode 的定义 ... // 3. 构建工作流 StateGraph workflow new StateGraph(keyStrategyFactory); workflow.addNode(preprocess, node_async(new PreprocessorNode())); workflow.addNode(validate, node_async(new ValidatorNode())); // ⭐ 把 Agent 作为一个 Node 塞进图里 workflow.addNode(qaAgent.name(), qaAgent.asNode(true, false)); // ... 省略连接边的代码 ... // 4. 编译工作流⭐ 关键必须在 CompileConfig 中注册检查点保存器 CompiledGraph compiledGraph workflow.compile(CompileConfig.builder() .saverConfig(SaverConfig.builder().register(saver).build()) .build()); // 5. 执行工作流并处理中断 String threadId workflow-hilt-001; MapString, Object input Map.of(input, 请解释量子计算); // 第一次调用 Graph OptionalNodeOutput nodeOutputOptional compiledGraph.invokeAndGetOutput(input, RunnableConfig.builder().threadId(threadId).build()); if (nodeOutputOptional.isPresent() nodeOutputOptional.get() instanceof InterruptionMetadata interruptionMetadata) { System.out.println(工作流被中断等待人工审核。中断节点: interruptionMetadata.node()); // ⭐ 构建同意的反馈同上 InterruptionMetadata.Builder feedbackBuilder InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); interruptionMetadata.toolFeedbacks().forEach(toolFeedback - { feedbackBuilder.addToolFeedback(InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED).build()); }); InterruptionMetadata approvalMetadata feedbackBuilder.build(); // 第二次调用恢复工作流执行 RunnableConfig resumableConfig RunnableConfig.builder() .threadId(threadId) // 必须是同一个线程 .addHumanFeedback(approvalMetadata) .build(); // 传入空 Map因为状态已保存在全局检查点中 nodeOutputOptional compiledGraph.invokeAndGetOutput(Map.of(), resumableConfig); }️五、 官方送你的“批奏折”快捷键 (HITLHelper)大白话每次遇到中断都要写一堆Builder去循环构建同意/拒绝太啰嗦了你可以封装一个HITLHelper实用工具类一键审批HITLHelper 工具类代码public class HITLHelper { /** 批准所有工具调用 */ public static InterruptionMetadata approveAll(InterruptionMetadata interruptionMetadata) { InterruptionMetadata.Builder builder InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); interruptionMetadata.toolFeedbacks().forEach(toolFeedback - { builder.addToolFeedback(InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED).build()); }); return builder.build(); } /** 拒绝所有工具调用并给出理由 */ public static InterruptionMetadata rejectAll(InterruptionMetadata interruptionMetadata, String reason) { InterruptionMetadata.Builder builder InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); interruptionMetadata.toolFeedbacks().forEach(toolFeedback - { builder.addToolFeedback(InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.REJECTED) .description(reason).build()); }); return builder.build(); } /** 修改特定工具的参数其他的统统批准 */ public static InterruptionMetadata editTool(InterruptionMetadata interruptionMetadata, String toolName, String newArguments) { InterruptionMetadata.Builder builder InterruptionMetadata.builder() .nodeId(interruptionMetadata.node()) .state(interruptionMetadata.state()); interruptionMetadata.toolFeedbacks().forEach(toolFeedback - { if (toolFeedback.getName().equals(toolName)) { builder.addToolFeedback(InterruptionMetadata.ToolFeedback.builder(toolFeedback) .arguments(newArguments) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.EDITED).build()); } else { builder.addToolFeedback(InterruptionMetadata.ToolFeedback.builder(toolFeedback) .result(InterruptionMetadata.ToolFeedback.FeedbackResult.APPROVED).build()); } }); return builder.build(); } } // 实际使用起来爽多了 InterruptionMetadata approvalMetadata HITLHelper.approveAll(interruptionMetadata); // 一键全过 InterruptionMetadata rejectMetadata HITLHelper.rejectAll(interruptionMetadata, 操作不安全); // 一键打回 InterruptionMetadata editMetadata HITLHelper.editTool(interruptionMetadata, execute_sql, {\query\: \SELECT * FROM records LIMIT 10\}); // 手动改个分页再跑️最佳实践避坑指南没脑子千万别审批必须使用检查点Saver否则恢复时找不到状态。话要说清楚配置ToolConfig时描述写清楚点不然人工审核的时候看着一团代码懵圈。不要落下任何一只手遇到多个并发的工具中断必须对每一个ToolFeedback都给出决策是杀是留。认准唯一单号恢复执行的时候threadId必须和之前中断的完全一致。处理死等最好加个超时机制不能让 Agent 等老板审批等一整天。终极秒记口诀智能 Agent 爱自由危险动作需防守加入 HITL 做拦截Saver 留存防弄丢Approve 批准任它走Edit 帮你修一修要是胡扯全 Reject批完奏折再回头

相关新闻

直流母线电压恢复的二次控制策略 直流微网中采用虚拟压降补偿 并联双向Buck-boost研究(Simulink仿真实现)

直流母线电压恢复的二次控制策略 直流微网中采用虚拟压降补偿 并联双向Buck-boost研究(Simulink仿真实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 &#x1f381…

2026/6/23 4:36:44阅读更多 →
用GLM-5.1构建智能体工作流的内容付费系统

用GLM-5.1构建智能体工作流的内容付费系统

1. 项目概述:为什么一个“内容付费系统”值得用 GLM-5.1 重做?智谱突然上线 GLM-5.1,不是一次常规迭代,而是一次能力边界的实质性突破。我盯着文档里那句“单次任务中持续、自主地工作长达 8 小时”,反复看了三遍——这…

2026/6/23 4:36:44阅读更多 →
React Hooks 闭包陷阱与依赖治理:从状态陈旧到渲染优化的工程化解法

React Hooks 闭包陷阱与依赖治理:从状态陈旧到渲染优化的工程化解法

React Hooks 闭包陷阱与依赖治理:从状态陈旧到渲染优化的工程化解法一、状态陈旧与无限重渲染:Hooks 在复杂场景下的隐秘陷阱 React Hooks 自 16.8 版本引入以来,极大地简化了函数组件的状态管理。然而,当应用复杂度上升&#xff…

2026/6/23 4:36:44阅读更多 →
高效3D模型管理实战指南:Windows STL缩略图专业方案深度解析

高效3D模型管理实战指南:Windows STL缩略图专业方案深度解析

高效3D模型管理实战指南:Windows STL缩略图专业方案深度解析 【免费下载链接】STL-thumbnail Shellextension for Windows File Explorer to show STL thumbnails 项目地址: https://gitcode.com/gh_mirrors/st/STL-thumbnail 在3D设计和制造领域&#xff0c…

2026/6/23 6:07:31阅读更多 →
TradingAgents-CN:构建AI驱动的智能股票分析系统的创新一体化解决方案

TradingAgents-CN:构建AI驱动的智能股票分析系统的创新一体化解决方案

TradingAgents-CN:构建AI驱动的智能股票分析系统的创新一体化解决方案 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 在金融科技快速…

2026/6/23 6:07:31阅读更多 →
嵌入式硬件加密加速实战:LTC eDMA非阻塞API原理与应用

嵌入式硬件加密加速实战:LTC eDMA非阻塞API原理与应用

1. 项目概述在嵌入式系统里做数据加解密,尤其是AES、DES这类对称加密,CPU软算起来是真够呛。我最近在搞一个物联网网关项目,需要实时加密上传的传感器数据包,一开始用软件库跑AES-128,CPU占用率直接飙到30%以上&#x…

2026/6/23 6:07:31阅读更多 →
SSM 框架实战教程 搭建事务测试环境 61-68

SSM 框架实战教程 搭建事务测试环境 61-68

SSM 框架实战教程 搭建事务测试环境 61-68 一、参考资料 【尚硅谷最新版SSM教程,基于AI的全新ssm框架实战】 https://www.bilibili.com/video/BV14WtLeDEit/?p61&share_sourcecopy_web&vd_source855891859b2dc554eace9de3f28b4528 二、笔记总结 61、创建数…

2026/6/23 6:07:31阅读更多 →
林伽一 · AI 科技周报 |2026年6月第3周

林伽一 · AI 科技周报 |2026年6月第3周

一、一周头条1. SpaceX 以 600 亿美元全股票交易收购 CursorSpaceX 上市后股价飙升,正式行权收购 AI 编程初创公司 Cursor。这笔交易反映了 AI 编程助手市场的巨大潜力。2. Z AI 发布 GLM-5.2 开源模型在编程基准测试中与 GPT-5.5 和 Claude Opus 4.8 具有竞争力&am…

2026/6/23 6:07:31阅读更多 →
CodeWarrior ColdFire开发中pragma指令的实战应用与优化技巧

CodeWarrior ColdFire开发中pragma指令的实战应用与优化技巧

1. 项目概述与pragma指令核心价值如果你在嵌入式领域,尤其是使用Freescale(现NXP)ColdFire系列微控制器做过开发,那么对CodeWarrior这个经典的集成开发环境(IDE)一定不会陌生。在这个环境里,除了…

2026/6/23 6:02:30阅读更多 →
【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体

【人工智能】一文搞定到底什么是智能体 一文搞定到底什么是智能体【人工智能】一文搞定到底什么是智能体一. LM,WorkFlow,Agent分别有什么么不同二. Agent的思考过程是怎样的三. Agent的五个核心部分1)LLM2)Prompt3)Me…

2026/6/22 6:01:42阅读更多 →
嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

嵌入式GUI控件实战:ROTARY、SCROLLBAR、SLIDER原理与应用

1. 嵌入式GUI控件:从原理到实战的深度解析在嵌入式系统开发中,图形用户界面(GUI)的设计与实现往往是项目从“能用”到“好用”的关键一跃。不同于资源充沛的PC或移动平台,嵌入式设备的GUI需要在有限的CPU性能、内存空间…

2026/6/23 1:55:32阅读更多 →
Google AI Studio 300美元额度的真相与实战指南

Google AI Studio 300美元额度的真相与实战指南

1. 这300美金不是“送钱”,而是Google埋下的第一道技术门槛 你看到标题里那个醒目的“$300美金”时,第一反应可能是:又一个免费额度?领完就完事?我亲手试过——这300美金根本不是红包,而是一张入场券&…

2026/6/23 5:55:37阅读更多 →
2026年京东云 618 活动 Hermes Agent/OpenClaw配置Token Plan新手必看指南

2026年京东云 618 活动 Hermes Agent/OpenClaw配置Token Plan新手必看指南

2026年京东云 618 活动 Hermes Agent/OpenClaw配置Token Plan新手必看指南。OpenClaw是开源的个人AI助手,Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流…

2026/6/23 0:00:38阅读更多 →
2026年北京电子沙盘制作公司深度评测:从技术选型到落地效果,谁在真正定义“数字+实体”的融合边界?

2026年北京电子沙盘制作公司深度评测:从技术选型到落地效果,谁在真正定义“数字+实体”的融合边界?

模块一:行业背景——百亿赛道爆发,北京市场的特殊性与选型困局2026年,电子沙盘行业已走过“要不要做”的讨论,进入“找谁做、怎么做”的深水区。据行业研究机构数据,2025年国内电子沙盘市场规模已突破85亿元&#xff0…

2026/6/23 0:00:38阅读更多 →
音视频场景下的 Java 开发者面试:技术与挑战

音视频场景下的 Java 开发者面试:技术与挑战

面试互联网大厂:从音视频场景看 Java 开发者的技能与挑战 在互联网大厂求职的面试中,Java 开发者往往需要面对严苛的技术问题。今天,我们将通过一位名叫燕双非的搞笑程序员与严肃的面试官之间的对话,看看在音视频场景下&#xff0…

2026/6/23 0:00:38阅读更多 →