系列文章

  1. 理解 AI Agent 的大脑:ReAct 模式从入门到实战
  2. AI Agent 的工具箱:深入理解 Tool Use 与 Spring AI Function Calling 实战
  3. AI Agent 的记忆力是怎么实现的——LangChain4j Memory 机制深度解析
  4. AI Agent 的记忆系统:从 ChatMemory 到持久化记忆的 Java 实战
  5. AI Agent 的规划大脑:从任务分解到自适应执行策略
  6. AI Agent 的灵魂对话:Prompt Engineering 系统提示词设计的艺术与工程
  7. AI Agent 的推理引擎:从 Chain-of-Thought 到推理模型的深度解析与 Java 实战
  8. 从零理解 RAG:检索增强生成完整指南
  9. Embedding 向量化的魔法:从文本到向量的数学之旅与 Java 实战
  10. AI Agent 的知识检索引擎:从向量搜索到智能检索策略的 Java 实战
  11. 让 AI 学会”说人话”——Spring AI 结构化输出实战
  12. MCP 模型上下文协议:AI 的万能接口与 MCP Server 实战
  13. 当 RAG 遇上知识图谱:GraphRAG 原理与 Java 实战
  14. 当 RAG 遇到 Agent:Agentic RAG 的架构设计与 Java 实战
  15. AI Agent 的流式响应与实时交互:从 SSE 到 WebSocket 的 Java 实战
  16. AI Agent 的工作流编排:从顺序链到自适应 DAG 的 Java 实战
  17. AI Agent 团队协作:多 Agent 系统架构设计与 Java 实战
  18. Agent 间如何对话:A2A 协议深度解析与 Java 实战
  19. Spring AI 核心架构全解析:从 ChatModel 到 Advisor Chain 的设计哲学
  20. AI Agent 的容错与韧性:从错误处理到生产级可靠性保障的 Java 实战
  21. AI Agent 的安全防线:Prompt 注入防御与生产级安全防护实战
  22. AI Agent 的可观测性:从链路追踪到成本监控的 Java 实战
  23. AI Agent 的自我反思与经验学习:从错误中进化的 Java 实战
  24. AI Agent 评估与优化:从基准测试到生产环境的质量守护实战
  25. AI Agent 的人机协作:从 Human-in-the-Loop 到渐进式自治的 Java 实战(本文)
  26. AI Agent 的上下文工程与 Token 预算管理实战
  27. AI Agent 的多模态感知:从图片理解到语音交互的 Java 实战

一个真实的翻车现场

2026 年初,某金融公司的风控 Agent 在凌晨 3 点自动冻结了 2000 个用户账户。原因是:Agent 检测到一组”异常交易模式”,按照预设规则执行了批量冻结。但实际上,那天是双十一预热活动的第一天,交易量暴增是正常行为。

这个 Agent 缺少什么?一个人类确认环节

如果在执行冻结前,Agent 能发一条消息给值班人员:”检测到 2000 个账户存在异常交易,建议冻结,是否确认?”——这一切就不会发生。

这就是 Human-in-the-Loop(HITL,人在回路中) 的核心价值:让 Agent 在关键时刻暂停,等人类确认后再继续。

在之前的系列文章中,我们讲了 Agent 的推理引擎(怎么思考)、工具箱(怎么行动)、规划大脑(怎么安排任务)、容错与韧性(怎么应对错误)。但这些都是 Agent “自己玩”的能力。今天这篇文章要回答一个更根本的问题:Agent 应该在什么时候停下来问人?


为什么 Agent 不能完全自主?

信任的三个阶段

想象你新招了一个助手。第一天,你会手把手教他每件事。一周后,你只在关键决策时确认。一个月后,你可能只看他提交的周报。

Agent 的信任建设也是一样的:

阶段一:完全监督(Fully Supervised) — Agent 的每个动作都需要人类确认。适合初期部署、高风险场景。

阶段二:关键审批(Critical Approval) — Agent 自行处理常规操作,只在高风险操作时请求确认。这是最常见的生产模式。

阶段三:完全自治(Full Autonomy) — Agent 自主决策,人类只在事后审计。适合已充分验证的低风险场景。

大多数企业 Agent 应该停留在阶段二,而不是盲目追求阶段三。原因很简单:错误的成本不对称。Agent 做对了 99 次节省的时间,可能抵不上第 100 次犯错造成的损失。

HITL 的三种模式

从技术实现角度看,HITL 有三种核心模式:

1. 审批型(Approval) — Agent 提出计划,人类批准或否决。典型场景:发送邮件、执行数据库变更、调用支付接口。

2. 纠正型(Correction) — Agent 执行后,人类可以纠正结果。典型场景:文本生成后人工修改、分类结果人工重新标注。

3. 升级型(Escalation) — Agent 遇到无法处理的情况,主动将任务转交给人类。典型场景:客服对话超出 Agent 能力范围、未知异常情况。

这三种模式不是互斥的。一个成熟的 Agent 系统通常同时使用多种模式,在不同环节应用不同的 HITL 策略。


企业级 HITL 架构设计

整体架构

一个完整的 HITL 系统包含以下组件:

1
2
3
4
5
6
7
8
9
10
11
12
┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│ AI Agent │────▶│ HITL 引擎 │────▶│ 通知渠道 │
│ (决策层) │ │ (规则评估) │ │ (钉钉/飞书/ │
│ │◀────│ │◀────│ 邮件/Web) │
└─────────────┘ └──────────────┘ └──────────────┘


┌──────────────┐
│ 审批存储 │
│ (审批记录、 │
│ 决策历史) │
└──────────────┘

核心流程是:

  1. Agent 在执行敏感操作前,调用 HITL 引擎
  2. HITL 引擎根据预定义规则判断是否需要审批
  3. 如果需要,通过通知渠道发送审批请求
  4. 人类做出决策(批准/否决/修改)
  5. 决策结果返回给 Agent,Agent 继续或调整执行

HITL 规则引擎

规则引擎是 HITL 系统的核心。它决定了哪些操作需要人工审批:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* HITL 规则定义
*/
public class HitlRule {
private String ruleId;
private String actionPattern; // 操作模式匹配(如 "delete.*", "payment.*")
private RiskLevel riskLevel; // LOW, MEDIUM, HIGH, CRITICAL
private ApprovalType approvalType; // NONE, SINGLE, DUAL(单人/双人审批)
private Duration timeout; // 审批超时时间
private String fallbackAction; // 超时后的回退动作(REJECT/PROCEED/ESCALATE)
}

/**
* 规则评估结果
*/
public class HitlDecision {
private boolean requiresApproval;
private ApprovalType approvalType;
private String approverId; // 指定审批人(可为空,表示任意审批人)
private String reason; // 为什么需要审批
private Duration timeout;
}

规则评估的关键在于精准判断。太宽松会让风险操作逃逸,太严格会拖慢 Agent 效率。一个实用的策略是基于操作的可逆性影响范围来分级:

级别 特征 示例 审批方式
LOW 可逆、影响范围小 更新用户昵称、添加标签 无需审批
MEDIUM 部分可逆、影响范围中等 修改订单状态、发送通知 自动审批 + 事后通知
HIGH 不可逆、影响范围大 删除数据、调用支付接口 实时审批
CRITICAL 不可逆、影响范围极大 批量操作、涉及资金/法律 双人审批

LangChain4j 实战:实现 HITL 工具拦截

LangChain4j 的工具调用机制天然适合实现 HITL。核心思路是:在 Tool 的执行逻辑中嵌入审批环节

基础实现:审批装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import dev.langchain4j.agent.tool.Tool;
import dev.langchain4j.service.MemoryId;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;

/**
* HITL 审批服务 — 拦截敏感工具调用
*/
@Service
public class ApprovalGateway {

private final ApprovalStore approvalStore;
private final NotificationService notificationService;
private final HitlRuleEngine ruleEngine;

/**
* 执行需要审批的操作
* Agent 调用此工具时,会触发审批流程
*/
@Tool("执行需要管理员审批的敏感操作。参数:action-操作描述, params-操作参数JSON, riskLevel-风险等级")
public String executeWithApproval(
String action,
String params,
String riskLevel) {

// 1. 评估是否需要审批
HitlDecision decision = ruleEngine.evaluate(action, params, RiskLevel.valueOf(riskLevel));

if (!decision.isRequiresApproval()) {
// 低风险操作,直接执行
return executeAction(action, params);
}

// 2. 创建审批请求
ApprovalRequest request = ApprovalRequest.builder()
.requestId(UUID.randomUUID().toString())
.action(action)
.params(params)
.riskLevel(riskLevel)
.createdAt(Instant.now())
.expiresAt(Instant.now().plus(decision.getTimeout()))
.status(ApprovalStatus.PENDING)
.build();

approvalStore.save(request);

// 3. 通知审批人
notificationService.notifyApprover(
decision.getApproverId(),
request
);

// 4. 返回挂起状态给 Agent
return String.format(
"操作 '%s' 已提交审批(ID: %s),等待管理员确认。预计超时时间:%s。请告知用户正在审批中。",
action, request.getRequestId(), decision.getTimeout()
);
}
}

Agent 接口定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 带 HITL 能力的 Agent 接口
*/
public interface HitlAgent {

@SystemMessage("""
你是一个企业级 AI 助手。你可以帮用户完成各种任务。

重要规则:
1. 涉及数据修改、删除、资金操作时,必须使用 executeWithApproval 工具
2. 只读查询(搜索、查看)可以直接执行
3. 如果用户要求的操作不在你的能力范围内,直接告知用户
4. 任何不确定的操作,宁可多问一句也不要擅自执行
""")
String chat(@MemoryId String sessionId, @UserMessage String message);
}

审批结果回调

审批不是同步等待的——审批人可能几分钟甚至几小时后才响应。我们需要一个异步回调机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/**
* 审批结果处理器
*/
@Component
public class ApprovalResultHandler {

private final AgentSessionManager sessionManager;
private final ChatLanguageModel model;

/**
* 审批通过后,继续执行操作
*/
public void onApproved(ApprovalRequest request) {
// 1. 执行原始操作
String result = executeAction(request.getAction(), request.getParams());

// 2. 恢复 Agent 会话,告知结果
AgentSession session = sessionManager.getSession(request.getSessionId());
String agentMessage = String.format(
"审批已通过(ID: %s)。操作执行结果:%s",
request.getRequestId(), result
);

// 3. 让 Agent 生成用户友好的回复
String response = model.generate(
List.of(
SystemMessage.from("将以下技术结果转化为用户友好的回复。"),
UserMessage.from(agentMessage)
)
).content().text();

// 4. 通过 WebSocket/消息队列推送给用户
session.sendMessage(response);
}

/**
* 审批被拒绝
*/
public void onRejected(ApprovalRequest request, String reason) {
AgentSession session = sessionManager.getSession(request.getSessionId());
String message = String.format(
"审批未通过(ID: %s)。原因:%s。请问您需要调整操作后重新提交吗?",
request.getRequestId(), reason
);
session.sendMessage(message);
}

/**
* 审批超时
*/
public void onTimeout(ApprovalRequest request) {
HitlRule rule = ruleEngine.getRule(request.getAction());
switch (rule.getFallbackAction()) {
case "REJECT":
onRejected(request, "审批超时,操作已自动拒绝");
break;
case "ESCALATE":
escalateToAdmin(request);
break;
case "PROCEED":
onApproved(request); // 低风险操作超时后自动放行
break;
}
}
}

LangChain4j 的 ChatMemory 与 HITL 状态管理

一个容易忽略的问题:当 Agent 等待审批时,对话还在继续。用户可能会问”那个操作审批了吗?”或者发送新的请求。

我们需要在 ChatMemory 中维护 HITL 状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* HITL 感知的 Memory 管理器
*/
@Component
public class HitlAwareMemoryManager {

private final Map<String, List<PendingApproval>> pendingApprovals = new ConcurrentHashMap<>();

/**
* 记录挂起的审批请求
*/
public void addPendingApproval(String sessionId, PendingApproval approval) {
pendingApprovals.computeIfAbsent(sessionId, k -> new ArrayList<>()).add(approval);
}

/**
* 构建包含 HITL 上下文的系统消息
*/
public String buildSystemContext(String sessionId) {
List<PendingApproval> pending = pendingApprovals.getOrDefault(sessionId, List.of());
if (pending.isEmpty()) return "";

StringBuilder sb = new StringBuilder("\n\n## 当前挂起的审批请求\n");
for (PendingApproval p : pending) {
sb.append(String.format(
"- [%s] 操作:%s,提交时间:%s,状态:%s\n",
p.getRequestId(), p.getAction(),
p.getCreatedAt(), p.getStatus()
));
}
sb.append("\n如果用户询问审批状态,请告知上述信息。");
return sb.toString();
}
}

Spring AI 实战:用 Advisor Chain 实现 HITL

Spring AI 的架构(在 核心架构全解析 中详细讲过)天然支持 HITL——通过 Advisor Chain 拦截工具调用。

Advisor 方式实现审批拦截

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import org.springframework.ai.chat.client.advisor.api.*;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.messages.Message;
import reactor.core.publisher.Flux;

/**
* HITL Advisor — 拦截敏感的工具调用请求
*
* 在 Advisor Chain 中的位置:
* QuestionAnswerAdvisor (RAG)
* → HitlAdvisor (审批拦截) ← 我们在这里
* → ToolCallingManager (执行工具)
*/
@Component
public class HitlAdvisor implements CallAroundAdvisor, StreamAroundAdvisor {

private final ApprovalGateway approvalGateway;
private final HitlRuleEngine ruleEngine;

@Override
public AdvisedResponse aroundCall(AdvisedRequest request, CallAroundAdvisorChain chain) {
// 1. 检查请求中是否包含敏感工具调用
List<ToolCall> toolCalls = extractToolCalls(request);

for (ToolCall toolCall : toolCalls) {
HitlDecision decision = ruleEngine.evaluate(
toolCall.name(), toolCall.arguments()
);

if (decision.isRequiresApproval()) {
// 2. 挂起工具执行,提交审批
String approvalId = approvalGateway.submitForApproval(toolCall, decision);

// 3. 替换工具调用结果为"等待审批"
Message approvalMessage = new AssistantMessage(
"⚠️ 该操作需要管理员审批(ID: " + approvalId + ")。"
+ "请等待审批结果,或联系管理员加速审批。"
);

// 4. 返回包装后的响应,跳过实际工具执行
ChatResponse blockedResponse = ChatResponse.builder()
.generations(List.of(new Generation(approvalMessage)))
.build();

return new AdvisedResponse(blockedResponse, request.adviseContext());
}
}

// 5. 非敏感操作,继续执行
return chain.nextAroundCall(request);
}

@Override
public String getName() {
return "HitlAdvisor";
}

@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 100; // 在 ToolCallingManager 之前执行
}
}

配置 Advisor Chain

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Configuration
public class AgentConfig {

@Bean
public ChatClient chatClient(
ChatModel chatModel,
HitlAdvisor hitlAdvisor,
QuestionAnswerAdvisor ragAdvisor) {

return ChatClient.builder(chatModel)
.defaultSystem("""
你是一个企业级 AI 助手。遵循以下规则:
1. 查询类操作直接执行
2. 修改类操作使用工具,系统会自动判断是否需要审批
3. 对用户保持友好和专业
""")
.defaultAdvisors(
ragAdvisor, // RAG 检索
hitlAdvisor // HITL 审批拦截
)
.build();
}
}

LangChain4j vs Spring AI 的 HITL 实现对比

维度 LangChain4j Spring AI
拦截机制 在 @Tool 方法内部实现 通过 Advisor Chain 拦截
侵入性 需要修改工具代码 零侵入,纯配置
灵活性 可以精确控制每个工具 基于规则引擎统一拦截
异步支持 需要手动实现 天然支持响应式
适用场景 少量敏感工具需要精细控制 大规模工具集需要统一治理

选择建议:如果你只有几个关键工具需要审批(比如”发邮件”和”删数据”),LangChain4j 的方式更直接。如果你有几十个工具需要统一的审批策略,Spring AI 的 Advisor 方式更优雅。


信任校准与渐进式自治

信任分数模型

HITL 不应该是一个静态开关,而应该是一个动态调整的信任系统。随着 Agent 表现越来越好,它应该获得越来越多的自主权:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* 基于历史表现的信任分数计算器
*/
@Component
public class TrustScoreCalculator {

/**
* 计算某个工具的信任分数(0.0 ~ 1.0)
*
* 考量因素:
* 1. 历史成功率(权重 40%)
* 2. 审批通过率(权重 30%)
* 3. 用户纠正频率(权重 20%)
* 4. 连续成功次数(权重 10%,体现"近期表现")
*/
public double calculate(String toolName, String userId) {
ToolMetrics metrics = metricsStore.getMetrics(toolName, userId);

double successRate = metrics.getTotalCalls() > 0
? (double) metrics.getSuccessfulCalls() / metrics.getTotalCalls()
: 0.5; // 无历史数据时默认 0.5

double approvalRate = metrics.getApprovalRequests() > 0
? (double) metrics.getApprovedRequests() / metrics.getApprovalRequests()
: 1.0; // 从未需要审批说明风险低

double correctionRate = metrics.getUserCorrections() > 0
? 1.0 - (double) metrics.getUserCorrections() / metrics.getTotalCalls()
: 1.0;

double recentStreak = Math.min(metrics.getCurrentSuccessStreak() / 10.0, 1.0);

return successRate * 0.4
+ approvalRate * 0.3
+ correctionRate * 0.2
+ recentStreak * 0.1;
}

/**
* 根据信任分数决定审批策略
*/
public ApprovalStrategy getStrategy(String toolName, String userId) {
double trust = calculate(toolName, userId);

if (trust >= 0.95) {
return ApprovalStrategy.AUTO_PROCEED; // 自动放行
} else if (trust >= 0.80) {
return ApprovalStrategy.AUDIT_ONLY; // 执行后通知
} else if (trust >= 0.60) {
return ApprovalStrategy.SINGLE_APPROVAL; // 单人审批
} else {
return ApprovalStrategy.DUAL_APPROVAL; // 双人审批
}
}
}

渐进式自治的实际应用

以一个客服 Agent 为例,展示信任校准如何在实际中运作:

第 1 周(信任分 0.3):Agent 的每个回复都需要人工审核后才发送给客户。

第 1 个月(信任分 0.6):常见问题(FAQ)自动回复,复杂问题仍需审核。

第 3 个月(信任分 0.8):大部分对话自主处理,只在涉及退款、投诉升级时请求确认。

第 6 个月(信任分 0.95):全面自主,人工只做抽样质检。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* 渐进式自治策略应用
*/
@Component
public class ProgressiveAutonomy {

private final TrustScoreCalculator trustCalculator;

/**
* 决定客服 Agent 对某条消息的处理方式
*/
public ProcessingDecision decide(String sessionId, String userId, CustomerMessage message) {
double trust = trustCalculator.calculate("customer-service", userId);
MessageCategory category = classifyMessage(message);

return switch (category) {
case FAQ -> {
// FAQ 信任分超过 0.5 就自动回复
yield trust > 0.5
? ProcessingDecision.autoReply(generateFaqAnswer(message))
: ProcessingDecision.humanReview("FAQ 回复待审核");
}
case GENERAL_INQUIRY -> {
// 一般咨询信任分超过 0.7 自动回复
yield trust > 0.7
? ProcessingDecision.autoReply(generateAnswer(message))
: ProcessingDecision.humanReview("一般咨询待审核");
}
case COMPLAINT -> {
// 投诉永远需要审核,但信任分高时可以生成草稿
yield trust > 0.9
? ProcessingDecision.autoReplyWithAudit(generateComplaintResponse(message))
: ProcessingDecision.escalateToHuman("投诉升级");
}
case REFUND_REQUEST -> {
// 退款请求永远需要人工审批
yield ProcessingDecision.requiresApproval(
"退款请求",
generateRefundRecommendation(message)
);
}
};
}
}

生产级最佳实践

1. 审批超时处理

审批请求不应该无限等待。设置合理的超时和回退策略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Component
public class ApprovalTimeoutScheduler {

@Scheduled(fixedRate = 60_000) // 每分钟扫描一次
public void checkTimeouts() {
List<ApprovalRequest> expired = approvalStore.findExpired(Instant.now());

for (ApprovalRequest request : expired) {
HitlRule rule = ruleEngine.getRule(request.getAction());

switch (rule.getFallbackAction()) {
case "REJECT":
// 超时自动拒绝 — 最安全的策略
approvalResultHandler.onTimeout(request);
log.warn("审批超时自动拒绝: {}", request.getRequestId());
break;

case "ESCALATE":
// 升级到管理员 — 适合紧急但需要确认的操作
notificationService.escalateToAdmin(request);
log.warn("审批超时已升级: {}", request.getRequestId());
break;

case "PROCEED":
// 超时自动放行 — 仅适合低风险操作
approvalResultHandler.onApproved(request);
log.info("审批超时自动放行: {}", request.getRequestId());
break;
}
}
}
}

最佳实践:默认使用 REJECT 策略。宁可让 Agent 等待,也不要让未经审批的操作自动执行。

2. 批量操作的特殊处理

批量操作(比如”删除所有过期数据”)需要额外的安全机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Tool("批量操作工具,支持对多个实体执行统一操作")
public String batchOperation(String action, String entityType, String filter, int estimatedCount) {

// 批量操作的额外安全检查
if (estimatedCount > 100) {
// 大批量操作:需要预览 + 双人审批
BatchPreview preview = generatePreview(action, entityType, filter);
return String.format(
"⚠️ 检测到大批量操作(预计影响 %d 条记录)。\n" +
"预览结果:\n%s\n" +
"请确认后使用 executeWithApproval 提交审批。注意:此操作需要双人审批。",
estimatedCount, preview.toSummary()
);
}

if (estimatedCount > 10) {
// 中等批量:需要单人审批
return submitForApproval(action, entityType, filter, ApprovalType.SINGLE);
}

// 小批量:标准审批流程
return submitForApproval(action, entityType, filter, ApprovalType.SINGLE);
}

3. 审批人路由

不同的操作应该路由给不同的审批人:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@Component
public class ApproverRouter {

/**
* 根据操作类型和组织架构路由审批人
*/
public ApproverInfo route(String action, String department, RiskLevel riskLevel) {
return switch (riskLevel) {
case CRITICAL -> {
// 关键操作:部门负责人 + 安全团队双审
yield ApproverInfo.dualApproval(
orgService.getDepartmentHead(department),
securityTeam.getOnCallApprover()
);
}
case HIGH -> {
// 高风险操作:部门负责人
yield ApproverInfo.singleApproval(
orgService.getDepartmentHead(department)
);
}
case MEDIUM -> {
// 中等风险:团队 Lead
yield ApproverInfo.singleApproval(
orgService.getTeamLead(department)
);
}
case LOW -> {
// 低风险:任何有权限的人
yield ApproverInfo.anyApprover(
permissionService.getApproverPool(action)
);
}
};
}
}

4. 审批记录与审计

所有 HITL 决策都应该被完整记录,用于事后审计和信任分数计算:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Entity
@Table(name = "hitl_audit_log")
public class HitlAuditLog {

@Id
private String auditId;

private String requestId;
private String sessionId;
private String userId;
private String toolName;
private String action;
private String params; // 操作参数(加密存储)

private RiskLevel riskLevel;
private ApprovalType approvalType;
private String approverId;
private ApprovalStatus status; // PENDING / APPROVED / REJECTED / TIMEOUT

private String rejectionReason;
private Instant requestedAt;
private Instant decidedAt;
private Duration responseTime; // 审批响应时间

private String executionResult; // 操作执行结果
private boolean userCorrected; // 用户事后是否纠正了结果
}

HITL 的边界与局限性

不适合 HITL 的场景

HITL 不是万能药。以下场景应该谨慎使用:

1. 实时性要求极高的场景:高频交易、实时推荐。等待审批的延迟(哪怕几秒)会导致业务损失。

2. 规模极大的场景:每秒处理数千个请求的系统,无法为每个请求都申请人工审批。需要通过规则引擎批量处理。

3. 决策一致性要求极高的场景:如果人类审批者之间的判断标准不一致,HITL 反而会引入噪声。此时应该用确定性规则替代人工判断。

4. 人类疲劳问题:如果审批请求太多,审批人会进入”点击通过”模式,失去审查的意义。需要控制审批频率,引入批量审批和自动放行机制。

HITL 反模式

反模式一:万事皆审批。每个操作都要求审批,导致 Agent 比手动操作还慢。正确做法是基于风险分级,只审批高风险操作。

反模式二:审批即安全。以为有了审批流程就万事大吉,忽略了审批人可能不了解操作的上下文。正确做法是提供充分的上下文信息(操作预览、影响分析、历史记录)。

反模式三:静默放行。审批超时后自动放行高风险操作。正确做法是超时默认拒绝,除非明确配置了放行策略。


与系列文章的关联

HITL 不是孤立存在的,它与其他 Agent 能力紧密耦合:

  • **Tool Use**:HITL 拦截的是工具调用。理解 Tool Use 的机制是实现 HITL 的前提。
  • **记忆系统**:审批状态需要持久化存储,与 Agent 的记忆系统共享存储基础设施。
  • **工作流编排**:在 DAG 工作流中,HITL 是一种特殊的节点类型——暂停节点(Wait Node)。
  • **容错与韧性**:审批超时是一种特殊的故障模式,需要纳入容错策略。
  • **安全防线**:HITL 是安全防线的最后一道——即使 Agent 被注入恶意 Prompt,关键操作仍需人类确认。
  • **评估与优化**:审批记录是评估 Agent 质量的重要数据源——高拒绝率说明 Agent 的决策能力需要提升。

未来展望

HITL 正在从”被动审批”走向”主动协作”:

1. 智能审批推荐:Agent 不只提交操作请求,还附带风险分析、预期结果、替代方案,帮助审批人快速决策。

2. 上下文感知审批:审批系统自动拉取相关上下文(历史记录、类似操作的结果、用户画像),减少审批人的信息搜寻成本。

3. 预测性 HITL:通过分析 Agent 的历史行为,预测哪些操作可能需要审批,提前做好准备。

4. 多模态审批:审批不只是”点按钮”,还可以通过语音、手势甚至面部表情(在 AR/VR 场景中)进行。


总结

Human-in-the-Loop 不是 Agent 的”退步”,而是 Agent 走向成熟的标志。一个知道何时停下来问人的 Agent,比一个盲目自信的 Agent 更值得信赖。

核心要点回顾:

  1. 信任是渐进的:从完全监督到完全自治,Agent 的自主权应该随着信任的积累逐步提升。
  2. 风险分级是关键:不是所有操作都需要审批,基于可逆性和影响范围进行分级。
  3. LangChain4j 适合精细控制,Spring AI 适合统一治理——根据你的工具规模选择。
  4. 超时默认拒绝:宁可让 Agent 等待,也不要让未经审批的操作自动执行。
  5. 审批记录是金矿:它不仅是审计依据,更是优化 Agent 的数据来源。

在下一阶段的 Agent 发展中,HITL 将从”人类审核机器”的模式,演变为”人机共同决策”的模式。Agent 负责信息收集和方案生成,人类负责价值判断和最终决策。这才是 AI Agent 真正的归宿。


💡 系列导航:本文是 AI Agent 系列的第 25 篇。想了解 Agent 的推理机制?推荐阅读 推理引擎。想了解如何保障 Agent 的可靠性?推荐阅读 容错与韧性