远程丰月 發表於 2026-3-31 15:19:00

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

<h2 id="引言">引言</h2>
<p>在构建AI智能体应用时,我们经常面临一个关键挑战:如何让AI在执行某些敏感操作前获得人工确认?Spring AI Alibaba框架提供了强大的人工介入(Human-in-the-Loop)机制,让开发者能够精确控制AI工具的执行流程,在关键节点引入人工审批环节。</p>
<p>本文将通过一个完整的实战示例,详细介绍如何在Spring AI Alibaba应用中实现人工介入功能。</p>
<h2 id="什么是人工介入">什么是人工介入?</h2>
<p>人工介入是一种机制,它允许AI智能体在执行特定工具前暂停执行,等待人工审批后再继续。这种机制特别适用于:</p>
<ul>
<li><strong>敏感操作</strong>:如数据删除、资金转账等</li>
<li><strong>内容生成</strong>:如文章发布、诗歌创作等需要质量把控的场景</li>
<li><strong>权限控制</strong>:某些需要特定权限才能执行的操作</li>
<li><strong>审计要求</strong>:需要记录人工决策过程的场景</li>
</ul>
<h2 id="实战示例诗歌创作的人工审批">实战示例:诗歌创作的人工审批</h2>
<p>让我们通过一个具体的例子来理解人工介入Hook的使用。这个示例展示了如何让AI在创作诗歌前获得人工确认。</p>
<h3 id="1-项目依赖配置">1. 项目依赖配置</h3>
<p>首先,确保你的项目中包含了Spring AI Alibaba相关依赖:</p>
<pre><code class="language-xml">&lt;dependencies&gt;
      &lt;!-- Spring AI Alibaba Agent Framework --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;com.alibaba.cloud.ai&lt;/groupId&gt;
          &lt;artifactId&gt;spring-ai-alibaba-agent-framework&lt;/artifactId&gt;
          &lt;version&gt;1.1.2.0&lt;/version&gt;
      &lt;/dependency&gt;

      &lt;!-- DashScope ChatModel 支持(如果使用其他模型,请跳转 Spring AI 文档选择对应的 starter) --&gt;
      &lt;dependency&gt;
          &lt;groupId&gt;com.alibaba.cloud.ai&lt;/groupId&gt;
          &lt;artifactId&gt;spring-ai-alibaba-starter-dashscope&lt;/artifactId&gt;
          &lt;version&gt;1.1.2.0&lt;/version&gt;
      &lt;/dependency&gt;
&lt;/dependencies&gt;
</code></pre>
<h3 id="2-代码实现解析">2. 代码实现解析</h3>
<h4 id="步骤1构建ai模型">步骤1:构建AI模型</h4>
<pre><code class="language-java">// 构建DashScope API对象
DashScopeApi dashScopeApi = DashScopeApi.builder()
      .apiKey(System.getenv("AliQwen_API"))
      .build();

// 创建聊天模型
ChatModel chatModel = DashScopeChatModel.builder()
      .dashScopeApi(dashScopeApi)
      .build();
</code></pre>
<h4 id="步骤2配置工具">步骤2:配置工具</h4>
<pre><code class="language-java">public class PoetTool implements BiFunction&lt;String, ToolContext, String&gt; {
        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();
        }

}
</code></pre>
<h4 id="步骤3构建带有hook的智能体">步骤3:构建带有Hook的智能体</h4>
<pre><code class="language-java">// 这里我们配置了poem工具需要人工审批,并提供了审批时的描述信息。
Map&lt;String, ToolConfig&gt; 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();
</code></pre>
<h4 id="步骤4创建会话配置">步骤4:创建会话配置</h4>
<pre><code class="language-java">String threadId = "user-session-001";
RunnableConfig config = RunnableConfig.builder()
    .threadId(threadId)
    .build();
</code></pre>
<h4 id="步骤5执行并处理中断">步骤5:执行并处理中断</h4>
<pre><code class="language-java">// 第一次调用 - 触发中断
Optional&lt;NodeOutput&gt; result = agent.invokeAndGetOutput(
    "帮我写一首100字左右的诗",
    config
);

// 检查是否触发中断
if (result.isPresent() &amp;&amp; result.get() instanceof InterruptionMetadata) {
    InterruptionMetadata interruptionMetadata = (InterruptionMetadata) result.get();
   
    System.out.println("检测到中断,需要人工审批");
   
    // 获取工具反馈信息
    List&lt;InterruptionMetadata.ToolFeedback&gt; 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 -&gt; {
      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&lt;NodeOutput&gt; finalResult = agent.invokeAndGetOutput("", resumeConfig);
   
    if (finalResult.isPresent()) {
      System.out.println("执行完成");
      // 因为创建智能体的时候,指定了outputKey,所以这里我们直接获取
      Object article = finalResult.get().state().data().get("article");
      System.out.println("最终结果: " + article);
    }
}
</code></pre>
<h3 id="3-执行流程分析">3. 执行流程分析</h3>
<p>这个示例的执行流程如下:</p>
<ol>
<li><strong>触发阶段</strong>:用户请求AI创作诗歌</li>
<li><strong>中断阶段</strong>:AI检测到<code>poem</code>工具需要人工审批,暂停执行</li>
<li><strong>审批阶段</strong>:系统展示工具信息,等待人工决策</li>
<li><strong>恢复阶段</strong>:人工批准后,AI继续执行并生成诗歌</li>
<li><strong>完成阶段</strong>:返回最终结果</li>
</ol>
<h2 id="高级特性">高级特性</h2>
<h3 id="多工具审批">多工具审批</h3>
<p>你可以为多个工具配置审批:</p>
<pre><code class="language-java">Map&lt;String, ToolConfig&gt; approvalOn = Map.of(
    "poem", ToolConfig.builder().description("诗歌创作工具").build(),
    "delete", ToolConfig.builder().description("数据删除工具").build(),
    "publish", ToolConfig.builder().description("内容发布工具").build()
);
</code></pre>
<h3 id="审批结果类型">审批结果类型</h3>
<p>支持多种审批结果:</p>
<ul>
<li><code>APPROVED</code>:批准执行</li>
<li><code>REJECTED</code>:拒绝执行</li>
<li><code>MODIFIED</code>:修改参数后执行</li>
</ul>
<h2 id="最佳实践">最佳实践</h2>
<h3 id="1-明确审批策略">1. 明确审批策略</h3>
<ul>
<li>只为真正需要人工确认的工具配置审批</li>
<li>提供清晰的审批描述信息</li>
<li>考虑审批的时效性</li>
</ul>
<h3 id="2-用户体验优化">2. 用户体验优化</h3>
<ul>
<li>提供友好的审批界面</li>
<li>支持批量审批操作</li>
<li>记录审批历史便于审计</li>
</ul>
<h3 id="3-错误处理">3. 错误处理</h3>
<pre><code class="language-java">try {
    Optional&lt;NodeOutput&gt; result = agent.invokeAndGetOutput(request, config);
    // 处理中断和结果
} catch (GraphRunnerException e) {
    // 处理执行异常
    log.error("智能体执行失败", e);
}
</code></pre>
<h3 id="4-状态管理">4. 状态管理</h3>
<pre><code class="language-java">// 使用合适的Saver
.saver(new MemorySaver())// 内存存储,适合开发测试
.saver(new RedisSaver())   // Redis存储,适合生产环境
.saver(new DatabaseSaver()) // 数据库存储,适合需要持久化的场景
</code></pre>
<h3 id="5-执行结果">5. 执行结果</h3>
<p><img alt="hitl" loading="lazy" src="https://img2024.cnblogs.com/blog/2047556/202603/2047556-20260331151801269-427191517.png" class="lazyload"></p>
<h2 id="拓展">拓展</h2>
<p>Spring Ai Alibaba还为我们内置了几个其他的Hook</p>
<ol>
<li>
<p>SummarizationHook(消息压缩)</p>
<p>当对话很长时,自动压缩对话历史,防止超出模型上下文限制</p>
</li>
<li>
<p>ModelCallLimitHook(模型调用限制)</p>
<p>防止Agent无限调用模型,控制成本</p>
</li>
</ol>
<p>另外,我们也可以自定义Hook,这部分内容如果大家感兴趣的话,后面可以单独介绍一下下~</p>
<h2 id="参考资料">参考资料</h2>
<ul>
<li>HumanInTheLoopHook API文档</li>
</ul>
<hr><br><br>
来源:https://www.cnblogs.com/jucunqi/p/19801759
頁: [1]
查看完整版本: Spring AI Alibaba 人工介入实战|Human-in-the-Loop 让 AI 更可靠