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

简介: 本文详解 Spring AI Alibaba 人工介入 Hook 实战,通过 Human-in-the-Loop 实现 AI 智能体执行暂停、人工审批与流程恢复,让 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. 执行流程分析

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

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

高级特性

多工具审批

你可以为多个工具配置审批:

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. 执行结果

hitl.png

拓展

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

  1. SummarizationHook(消息压缩)

    当对话很长时,自动压缩对话历史,防止超出模型上下文限制

  2. ModelCallLimitHook(模型调用限制)

    防止Agent无限调用模型,控制成本

另外,我们也可以自定义Hook,这部分内容如果大家感兴趣的话,后面可以单独介绍一下下~

参考资料


目录
相关文章
|
10天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
11192 104
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
10天前
|
人工智能 IDE API
2026年国内 Codex 安装教程和使用教程:GPT-5.4 完整指南
Codex已进化为AI编程智能体,不仅能补全代码,更能理解项目、自动重构、执行任务。本文详解国内安装、GPT-5.4接入、cc-switch中转配置及实战开发流程,助你从零掌握“描述需求→AI实现”的新一代工程范式。(239字)
5827 136
|
8天前
|
人工智能 并行计算 Linux
本地私有化AI助手搭建指南:Ollama+Qwen3.5-27B+OpenClaw阿里云/本地部署流程
本文提供的全流程方案,从Ollama安装、Qwen3.5-27B部署,到OpenClaw全平台安装与模型对接,再到RTX 4090专属优化,覆盖了搭建过程的每一个关键环节,所有代码命令可直接复制执行。使用过程中,建议优先使用本地模型保障隐私,按需切换云端模型补充功能,同时注重显卡温度与显存占用监控,确保系统稳定运行。
2007 6
|
6天前
|
人工智能 自然语言处理 供应链
【最新】阿里云ClawHub Skill扫描:3万个AI Agent技能中的安全度量
阿里云扫描3万+AI Skill,发现AI检测引擎可识别80%+威胁,远高于传统引擎。
1409 3
|
7天前
|
人工智能 Linux API
离线AI部署终极手册:OpenClaw+Ollama本地模型匹配、全环境搭建与问题一站式解决
在本地私有化部署AI智能体,已成为隐私敏感、低成本、稳定运行的主流方案。OpenClaw作为轻量化可扩展Agent框架,搭配Ollama本地大模型运行工具,可实现完全离线、无API依赖、无流量费用的个人数字助理。但很多用户在实践中面临三大难题:**不知道自己硬件能跑什么模型、显存/内存频繁爆仓、Skills功能因模型不支持工具调用而失效**。
3389 7

热门文章

最新文章