Appearance
Human-in-the-loop
HITL 在模型请求敏感工具时暂停 LangGraph 执行,把待执行 action 和允许的决定交给人工界面。恢复 时必须使用同一个 thread config,checkpointer 才能找到暂停前状态。
执行时序
前端类比
它类似可恢复的服务端 transaction approval:前端不是简单弹出 confirm 后继续本地函数,而是把 决定提交给持久化工作流,由服务端从 checkpoint 恢复。
Deep Agents 原生语义:interrupt_on/interruptOn 会配置 HumanInTheLoopMiddleware。 Middleware 在普通 tool call 执行前产生 LangGraph interrupt;Command(resume=...) 携带与 action 顺序对应的 decisions 恢复图。
配置审批策略
python
import os
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
agent = create_deep_agent(
model=os.environ["DEEPAGENTS_MODEL"],
checkpointer=MemorySaver(),
interrupt_on={
"read_file": False,
"write_file": {"allowed_decisions": ["approve", "reject"]},
"delete": {"allowed_decisions": ["approve", "edit", "reject"]},
},
)ts
import { createDeepAgent } from 'deepagents'
import { MemorySaver } from '@langchain/langgraph'
const model = process.env.DEEPAGENTS_MODEL
if (!model) throw new Error('DEEPAGENTS_MODEL is required')
const agent = createDeepAgent({
model,
checkpointer: new MemorySaver(),
interruptOn: {
read_file: false,
write_file: { allowedDecisions: ['approve', 'reject'] },
},
})内存 checkpointer 只适合教程。生产环境需要持久、并发安全并满足数据保留要求的实现。
读取 Interrupt 并恢复
Python v2 invoke 返回带 interrupts 和 value 的结果:
python
from uuid import uuid4
from langgraph.types import Command
config = {"configurable": {"thread_id": str(uuid4())}}
result = agent.invoke(
{"messages": [{"role": "user", "content": "删除临时草稿"}]},
config=config,
version="v2",
)
if result.interrupts:
request = result.interrupts[0].value
print(request["action_requests"])
print(request["review_configs"])
result = agent.invoke(
Command(
resume={
"decisions": [
{
"type": "reject",
"message": "无法确认文件归属,请不要重试删除。",
}
]
}
),
config=config,
version="v2",
)决定数量和顺序必须与 action_requests 对齐。edit 需要提供完整 edited_action/ editedAction,审批端必须再次验证修改后的工具名和参数。
TypeScript 使用 new Command({ resume: { decisions } }),并从 invoke 结果的 interrupt 数据读取待 审批 action。字段采用 camelCase,不能直接复制 Python snake_case。
三种决定
| 决定 | 语义 | UI 必须展示 |
|---|---|---|
| approve | 按原参数执行 | 工具名、完整参数、目标资源、影响 |
| edit | 用审批人修改后的 action 执行 | 原值与新值 diff、重新校验结果 |
| reject | 跳过工具并把原因反馈给模型 | 拒绝原因、是否禁止模型重试 |
Reject message 应明确后续行为。例如“不要重试删除,请改为只列出候选文件”,比“拒绝”更能避免 模型换一种参数重复请求。
Subagent 与 HITL
自定义 subagent 可以配置自己的 interrupt_on/interruptOn,并覆盖继承设置。审批界面必须 展示 action 来源和 subagent 名称,不能把所有请求都标成主 Agent。
Interpreter 内的 PTC 和动态 task 不一定经过普通 tool-call 路径。需要逐次审批的能力不应只靠 interpreter bridge 暴露;应把不可绕过规则放在工具、sandbox 或上层 LangGraph 节点。
HITL 不是安全隔离
- 审批人可能误判命令或参数。
- 已批准工具仍可能访问超出预期的数据。
- Checkpointer 保存状态,不限制工具权限。
- Prompt injection 可以诱导 Agent 构造看似合理的请求。
HITL 应叠加在最小工具权限、sandbox、认证、审计与幂等设计之上。