react - 人工介入(HITL)
2026年2月3日 下午8:39:13
在自动化程度极高的 AI Agent 应用中,人工介入(Human-In-The-Loop, HITL) 是确保业务安全与合规的最后一道防线。对于涉及资金退款、敏感数据删除或重要邮件发送等操作,我们需要在 Agent 执行前获得人类的明确许可,甚至允许人类修正 AI 的参数。
Solon AI 通过标准化的 HITLInterceptor,实现了 “任务探知 - 决策回填 - 断点续传” 的工业级管控流程。
1、核心原理:中断与延续
HITL 的本质是利用 ReAct 协议的生命周期钩子进行“切面管控”:
- 任务挂起: 当 Agent 尝试执行敏感工具时,拦截器会捕捉到这一动作,并将当前工具名、参数封装成
HITLTask快照存入 Session,随即通过trace.interrupt()中断执行。 - 断点续传: 当人类完成审批并回填
HITLDecision后,再次调用agent.call(session),拦截器会识别到决策指令,驱动流程从中断点继续运行。
2、核心组件说明
最新架构引入了四个核心类,实现了业务与 Agent 逻辑的彻底解耦:
HITL: 交互助手。提供 approve、submit 等静态 API。HITLTask: 任务快照。记录了“谁想调用哪个工具”以及“具体参数是什么”,供 UI 界面展示给审核员。HITLDecision: 决策实体。承载人类的最终裁决(批准、拒绝、跳过)及参数修正信息。HITLInterceptor: 管控引擎。负责监听 Action 阶段并执行拦截或决策分发。
3、快速接入
通过 HITLInterceptor 声明式地注册需要人工审核的工具。
- 关键准备示例
// 1. 定义并配置 HITL 拦截器
HITLInterceptor hitl = new HITLInterceptor()
// 快速注册敏感工具(触发时自动挂起)
.onSensitiveTool("refund_money", "delete_database")
// 自定义策略:例如只有退款金额超过 100 时才需要人工介入
.onTool("refund_money", (trace, args) -> {
double amount = Double.parseDouble(args.get("amount").toString());
return amount > 100 ? "大额退款需人工审核" : null;
});
// 2. 注入到 Agent
ReActAgent agent = ReActAgent.of(chatModel)
.defaultInterceptorAdd(hitl)
.build();
- HITL Web 控制器完整示例
@Controller
@Mapping("/ai/hitl")
public class HitlWebController {
// 1. 初始化带 HITL 拦截器的 Agent
private final ReActAgent agent = ReActAgent.of(LlmUtil.getChatModel())
.defaultInterceptorAdd(new HITLInterceptor()
.onSensitiveTool("transfer_money") // 只要调此工具就拦截
.onTool("send_msg", (trace, args) -> args.size() > 2 ? "复杂指令需审核" : null))
.build();
/**
* 执行/续传接口
* 无论初次提问还是审批后恢复,均调用此接口。不传 prompt 则视为“断点续传”
*/
@Post
@Mapping("call")
public Result call(String sid, String prompt) throws Throwable {
AgentSession session = InMemoryAgentSession.of(sid);
// 核心:调用 agent。如果是审批后恢复,prompt 传 null 即可
ReActResponse resp = agent.prompt(prompt).session(session).call();
// 检查是否被 HITL 拦截
if (resp.getTrace().isInterrupted()) {
return Result.failure(403, "审批拦截", HITL.getPendingTask(session));
}
return Result.succeed(resp.getContent());
}
/**
* 决策提交接口
* 由管理员或业务系统调用,提交批准、拒绝或修正参数
*/
@Post
@Mapping("submit")
public Result submit(String sid, int action, @Body Map<String, Object> args) {
AgentSession session = InMemoryAgentSession.of(sid);
HITLTask task = HITL.getPendingTask(session);
if (task == null) return Result.failure("任务不存在");
// 构建决策对象
HITLDecision decision = new HITLDecision().action(action).modifiedArgs(args);
if (action == HITLDecision.ACTION_REJECT) decision.comment("安全合规性拒绝");
// 回填决策,Agent 会在下一次 call 时识别并自动处理
HITL.submit(session, task.getToolName(), decision);
return Result.succeed("决策已提交,请重新请求 call 接口触发续传");
}
}
4、 业务闭环流程
人工介入在实际开发中分为三个标准阶段:
第一阶段:触发拦截
当用户发送“帮我退款 200 元”,Agent 推理出需要调用 refund_money。拦截器检测到触发条件,执行中断。
在 Controller 层,你可以探知到这个挂起的任务:
// 获取当前会话中被拦截的任务
HITLTask task = HITL.getPendingTask(session);
if (task != null) {
System.out.println("等待审批:" + task.getToolName());
System.out.println("AI 拟调用的参数:" + task.getArgs());
}
第二阶段:人工决策
审核员在管理后台看到任务快照后,通过 HITL 工具类提交决策。
- 批准并执行:
HITL.approve(session, "refund_money"); - 拒绝并终止:
HITL.reject(session, "refund_money", "理由:账户异常"); - 参数修正(人类发现 AI 填错了账号):
Map<String, Object> fixedArgs = Collections.singletonMap("account", "correct_888");
HITL.submit(session, "refund_money", HITLDecision.approve().modifiedArgs(fixedArgs));
第三阶段:恢复执行
业务系统再次调用 agent.call(session)(无需再次传入 Prompt)。此时拦截器会读取 HITLDecision:
- 如果是 Approve:拦截器自动替换/合并修正后的参数,执行工具并继续后续推理。
- 如果是 Reject:拦截器终止工具执行,将拒绝理由反馈给 Agent 产生最终回答。
- 如果是 Skip:跳过真实工具执行,返回一条“人工已处理”的观测结果给 Agent。