系列:00 索引 · 上一篇:07 Graph RAG · 下一篇:09 LangGraph
1. 行业常见问题
| 高风险动作 | 后果 |
|---|---|
| 自动提交计算任务(GPU/费用) | 成本失控 |
| 自动写入公共知识库 | 污染、合规 |
| 自动对外发送邮件/下单 | 不可撤销 |
| 全自动「定稿报告」 | 幻觉进入决策链 |
监管与科研场景常要求:关键节点必须有人确认或可追溯驳回。
段末注释:HITL(human-in-the-loop,人在回路)= 流程在指定节点暂停,等待人类输入后再继续。
2. 该技术如何解决
- 识别闸门点:submit、ingest、publish、pay
- 结构化待办:展示 plan 摘要、artifact 路径、approve/reject
- 持久化 state:LangGraph Checkpointer +
RunStore记录 HITL 元数据 - 代码层 enforcement:图上的
approved标志 且 Analyst 工具层的blocked_hitl
3. 核心原理
3.1 本仓库 full 流水线中的 HITL 位置
1 | sequence → literature → method_kb → planner → hitl_plan → analyst → reporter |
- Planner 产出
research_plan.v1(artifact 路径写入 state) - hitl_plan 节点:未批准则
RunStore.set_hitl_pending,stage=hitl_plan_pending - LangGraph interrupt:图在 analyst 前 挂起,等待 Web/CLI
resume - Analyst:即使图误放行,
execute_plan_steps(require_hitl=True)仍会blocked_hitl
3.2 三层职责(不要混在一处)
| 层 | 模块 | 职责 |
|---|---|---|
| 契约 | agent/uni/contracts/hitl.py |
HITLGate、HITLDecision 枚举 |
| 编排 | agent/orchestrator/graph.py |
hitl_plan 节点、interrupt_before |
| 持久化 | RunStore + SqliteSaver |
run 元数据 + 图 state 可恢复 |
| 执行阻断 | agent/analyst/artifacts.py |
未 approve 禁止 `submit_template_tool |
3.3 interrupt + resume(LangGraph 语义)
1 | app.stream(initial) → 跑到 analyst 前停止 → snap.next 非空 → hitl_pending 事件 |
thread_id = run_id,checkpoint 落盘 workspace/checkpoints.db。
4. 典型实现与代码示例
以下均来自本仓库 agent/orchestrator,示例目的是理解 框架怎么接 HITL,不是重写一套状态机。
4.1 闸门契约(跨 Web / CLI / 图共用)
1 | # agent/uni/contracts/hitl.py |
RunStore.set_hitl_pending / record_hitl_decision 用同一套 gate id,Web 工作台读 meta.json 里的 hitl 字段展示待办。
4.2 LangGraph:hitl_plan 节点 + interrupt 编译
1 | # agent/orchestrator/graph.py(节选) |
要点:
hitl_plan是图节点,不是 prompt 里写「请用户确认」interrupt_before=["analyst"]让 LangGraph 在 analyst 入口挂起,进程可退出get_checkpointer()用 SQLite,隔夜审批靠 checkpoint 恢复
4.3 执行层二次阻断(Analyst 提交 Argo)
1 | # agent/analyst/artifacts.py(节选) |
编排层传入 hitl_approved=bool(state.get("approved"))(见 node_analyst)。Prompt 约束不够,必须有工具层硬阻断。
4.4 Web / CLI:start → interrupt → resume
1 | # agent/orchestrator/streaming.py(节选) |
FastAPI 入口:POST /pipeline/start(SSE)→ POST /pipeline/{run_id}/resume(SSE),见 agent/uni/api/main.py。
4.5 工程验收(推荐)
在项目根目录执行,直接走 LangGraph + Checkpointer:
1 | # 步骤 1:启动 full 流水线,在 analyst 前 interrupt |
Web 等价路径:启动 uv run python -m agent.uni.api.main → 打开 /pipeline → 审批后点恢复。
4.6 与 Agent-10-09 的分工
| 主题 | 本文(08) | Agent-10-09 |
|---|---|---|
| 关注点 | 何时停、谁批准、如何 resume | 图怎么建、节点调哪个 Specialist |
| 关键 API | interrupt_before、Command(resume=True) |
StateGraph、build_pipeline |
| 状态字段 | approved、plan_artifact_path |
PipelineState 全字段 |
5. 替代方案与优缺点
| 方案 | 优点 | 缺点 |
|---|---|---|
| LangGraph interrupt + SqliteSaver(本仓库) | 与编排一体、可恢复 | 需理解 checkpoint/thread_id |
仅 RunStore 布尔位、无 interrupt |
实现简单 | 进程必须常驻或丢进度 |
| 外部 BPMN/Camunda | 企业审批成熟 | 与 LLM 步耦合重 |
| 仅 Analyst prompt「请勿提交」 | 零代码 | 不可审计、不可阻断 |
6. 自检题
- 本仓库为何在 图节点 hitl_plan 之外,Analyst 还要
blocked_hitl? thread_id为何等于run_id?换 run 不换 thread 会怎样?approve与reject在streaming._run_resume_pipeline_sync里如何影响approved与下游节点?
7. 延伸阅读
- LangGraph Human-in-the-loop
- 本仓库:
agent/orchestrator/graph.py、agent/orchestrator/streaming.py - 下一篇:Agent-10-09 多 Agent 编排与 LangGraph