Human-in-the-loop

Human-in-the-loop 是在 Agent 执行流程中引入人类判断点的模式,用于审批高风险操作、纠正错误决策、提供缺失信息。它是 Agent 安全性和可靠性的关键保障。

#type / concept #status / evergreen #tech / ai #tech / architecture

[!info] related notes

Human-in-the-loop

一句话定义

Human-in-the-loop (HITL) 是在 Agent 自主执行流程中嵌入人类判断点的模式,让人类在关键节点介入:审批高风险操作、纠正错误决策、提供模型无法获取的信息。

它解决什么问题

完全自主的 Agent 有三个风险:

  1. 不可逆的错误: Agent 误删数据、误发邮件、误扣款项
  2. 缺乏领域判断: 某些决策需要人类的经验和直觉
  3. 用户信任缺失: 用户不放心让 Agent 自己做所有事

HITL 不是”让 Agent 变笨”,而是在自主性和安全性之间找到平衡

核心原理

介入点类型

Agent 执行流程:

  ├─ [信息采集] → 用户提供缺失信息
  │   例: Agent 不确定用户要查哪个地区的数据

  ├─ [决策确认] → 用户确认 Agent 的计划
  │   例: Agent 说"我准备删除这 50 条记录,确认吗?"

  ├─ [审批检查] → 高风险操作必须审批
  │   例: 转账、删除、发布等不可逆操作

  ├─ [纠错介入] → 用户发现 Agent 方向错误
  │   例: Agent 搜索了错误的关键词

  └─ [结果验收] → 用户确认最终结果
      例: Agent 生成的报告是否满意

实现机制

HITL 的核心机制是中断 (Interrupt) + 恢复 (Resume)

Agent 运行中


遇到需要人类判断的节点


保存当前状态 (Checkpoint)


暂停执行,返回中间结果给前端


前端展示审批界面


用户做出决策 (批准/拒绝/修改)


恢复执行,携带用户的决策


继续 Agent 流程

LangGraph 的 Interrupt 机制

from langgraph.graph import StateGraph
from langgraph.checkpoint import MemorySaver

graph = StateGraph(AgentState)

# 在工具执行前中断
graph.add_node("execute_tool", execute_tool_node)
graph.add_interrupt_before("execute_tool")  # 执行前暂停

# 编译时启用 checkpoint
app = graph.compile(checkpointer=MemorySaver())

# 运行到中断点
result = app.invoke(input_data, config={"thread_id": "xxx"})

# 用户审批后恢复
app.resume(approval="approved", config={"thread_id": "xxx"})

在 React + Go + Python AI Service 架构中的位置

Python AI Service:
  Agent 遇到高风险工具调用
  → 保存 Checkpoint
  → 返回 interrupt 事件

Go 后端:
  收到 interrupt 事件
  → 通知前端需要审批
  → 等待用户决策

React 前端:
  展示 Human Approval UI
  → 用户点击"批准"或"拒绝"
  → 发送审批结果到后端

Go 后端:
  转发审批结果到 AI Service

Python AI Service:
  恢复执行,携带审批结果

典型工程实现

事件协议

// Agent 返回的中断事件
{
  "event": "interrupt",
  "data": {
    "interrupt_id": "int_001",
    "type": "approval_required",
    "tool_call": {
      "name": "delete_records",
      "arguments": {"record_ids": ["id_1", "id_2", "id_3"]}
    },
    "message": "即将删除 3 条记录,此操作不可撤销。",
    "options": ["approve", "reject", "modify"]
  }
}

// 用户的审批响应
{
  "event": "resume",
  "data": {
    "interrupt_id": "int_001",
    "decision": "approved",
    "modifications": null
  }
}

审批 UI 设计

function ApprovalCard({ interrupt }: { interrupt: InterruptEvent }) {
  return (
    <div className="approval-card">
      <h3>⚠️ 需要确认</h3>
      <p>{interrupt.message}</p>
      <pre>{JSON.stringify(interrupt.tool_call, null, 2)}</pre>
      <div className="actions">
        <button onClick={() => resume("approved")}>✅ 批准</button>
        <button onClick={() => resume("rejected")}>❌ 拒绝</button>
        <button onClick={() => resume("modified")}>✏️ 修改后执行</button>
      </div>
    </div>
  );
}

常见设计模式

1. 预定义审批点

在 Tool 定义中标记 requires_approval: true,Agent Runtime 自动在调用前中断。

2. 动态审批

根据参数动态判断是否需要审批(如金额 > 1000 需审批)。

3. 超时自动拒绝

用户长时间不响应,自动拒绝并通知 Agent。

4. 批量审批

多个低风险操作打包成一个审批请求。

常见坑

  1. 审批点太多: 每个操作都要审批,用户体验极差
  2. 审批点太少: 高风险操作没有人类把关
  3. 中断后状态丢失: 没有 Checkpoint,恢复时上下文丢失
  4. 审批界面信息不足: 用户看不到完整参数,无法做出判断
  5. 不做超时处理: 用户永远不响应,Agent 永远卡住

和其他概念的关系

总结

HITL 的核心是让 Agent 知道什么时候该问人。好的 HITL 设计既不会让 Agent 太自由(风险),也不会让 Agent 太受限(效率)。

参考资料

创建于 2026/6/30 更新于 2026/7/15