interrupt_on 参数配置哪些工具需要审批。
基本配置
interrupt_on 参数接收一个字典,用于映射工具名称到中断配置。每个工具可以配置为:
True:启用默认中断行为(允许批准、编辑、拒绝)False:禁用该工具的中断{"allowed_decisions": [...]}:自定义允许的决策
Copy
from langchain_core.tools import tool
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver
@tool
def delete_file(path: str) -> str:
"""Delete a file from the filesystem."""
return f"Deleted {path}"
@tool
def read_file(path: str) -> str:
"""Read a file from the filesystem."""
return f"Contents of {path}"
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""Send an email."""
return f"Sent email to {to}"
# 人在回路必须配置检查点
checkpointer = MemorySaver()
agent = create_deep_agent(
model="claude-sonnet-4-5-20250929",
tools=[delete_file, read_file, send_email],
interrupt_on={
"delete_file": True, # 默认:允许批准、编辑、拒绝
"read_file": False, # 不需要中断
"send_email": {"allowed_decisions": ["approve", "reject"]}, # 不允许编辑
},
checkpointer=checkpointer # 必须!
)
决策类型
allowed_decisions 列表控制人工在审查工具调用时可执行的操作:
"approve":按智能体原样执行工具"edit":在执行前修改工具参数"reject":跳过此次工具调用
Copy
interrupt_on = {
# 高风险操作:允许所有选项
"delete_file": {"allowed_decisions": ["approve", "edit", "reject"]},
# 中等风险:仅允许批准或拒绝
"write_file": {"allowed_decisions": ["approve", "reject"]},
# 必须执行:仅允许批准
"critical_operation": {"allowed_decisions": ["approve"]},
}
处理中断
当触发中断时,智能体会暂停执行并将控制权交还给您。检查返回结果中的中断信息,并按需处理。Copy
import uuid
from langgraph.types import Command
# 配置 thread_id 以持久化状态
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
# 调用智能体
result = agent.invoke({
"messages": [{"role": "user", "content": "Delete the file temp.txt"}]
}, config=config)
# 检查是否发生中断
if result.get("__interrupt__"):
# 提取中断信息
interrupts = result["__interrupt__"][0].value
action_requests = interrupts["action_requests"]
review_configs = interrupts["review_configs"]
# 构建工具名称到审批配置的映射
config_map = {cfg["action_name"]: cfg for cfg in review_configs}
# 向用户展示待审批的操作
for action in action_requests:
review_config = config_map[action["name"]]
print(f"Tool: {action['name']}")
print(f"Arguments: {action['args']}")
print(f"Allowed decisions: {review_config['allowed_decisions']}")
# 获取用户决策(与 action_requests 顺序一致)
decisions = [
{"type": "approve"} # 用户批准删除操作
]
# 携带决策恢复执行
result = agent.invoke(
Command(resume={"decisions": decisions}),
config=config # 必须使用相同的 config!
)
# 处理最终结果
print(result["messages"][-1]["content"])
多个工具调用
当智能体调用多个需要审批的工具时,所有中断会合并到同一次暂停中。必须按顺序为每个工具提供决策。Copy
config = {"configurable": {"thread_id": str(uuid.uuid4())}}
result = agent.invoke({
"messages": [{
"role": "user",
"content": "Delete temp.txt and send an email to admin@example.com"
}]
}, config=config)
if result.get("__interrupt__"):
interrupts = result["__interrupt__"][0].value
action_requests = interrupts["action_requests"]
# 此处有两个工具需要审批
assert len(action_requests) == 2
# 按照 action_requests 的顺序提供决策
decisions = [
{"type": "approve"}, # 第一个工具:delete_file
{"type": "reject"} # 第二个工具:send_email
]
result = agent.invoke(
Command(resume={"decisions": decisions}),
config=config
)
编辑工具参数
当允许"edit" 决策时,可以在执行前修改工具参数:
Copy
if result.get("__interrupt__"):
interrupts = result["__interrupt__"][0].value
action_request = interrupts["action_requests"][0]
# 智能体给出的原始参数
print(action_request["args"]) # {"to": "everyone@company.com", ...}
# 用户决定修改收件人
decisions = [{
"type": "edit",
"edited_action": {
"name": action_request["name"], # 必须包含工具名称
"args": {"to": "team@company.com", "subject": "...", "body": "..."}
}
}]
result = agent.invoke(
Command(resume={"decisions": decisions}),
config=config
)
子智能体中的中断
每个子智能体都可以拥有自己的interrupt_on 配置,用于覆盖主智能体的设置:
Copy
agent = create_deep_agent(
tools=[delete_file, read_file],
interrupt_on={
"delete_file": True,
"read_file": False,
},
subagents=[{
"name": "file-manager",
"description": "Manages file operations",
"system_prompt": "You are a file management assistant.",
"tools": [delete_file, read_file],
"interrupt_on": {
# 重写配置:在子智能体中要求读取操作审批
"delete_file": True,
"read_file": True, # 与主智能体配置不同!
}
}],
checkpointer=checkpointer
)
__interrupt__,并使用 Command 携带决策恢复执行。
最佳实践
始终使用检查点
人在回路场景需要检查点来在中断与恢复之间持久化状态:Copy
from langgraph.checkpoint.memory import MemorySaver
checkpointer = MemorySaver()
agent = create_deep_agent(
tools=[...],
interrupt_on={...},
checkpointer=checkpointer # HITL 必须配置检查点
)
使用相同的线程 ID
恢复执行时必须使用包含相同thread_id 的配置:
Copy
# 第一次调用
config = {"configurable": {"thread_id": "my-thread"}}
result = agent.invoke(input, config=config)
# 恢复执行(仍然使用相同 config)
result = agent.invoke(Command(resume={...}), config=config)
决策顺序要与动作一致
decisions 列表必须与 action_requests 的顺序一一对应:
Copy
if result.get("__interrupt__"):
interrupts = result["__interrupt__"][0].value
action_requests = interrupts["action_requests"]
# 为每个 action 创建一个决策,保持顺序一致
decisions = []
for action in action_requests:
decision = get_user_decision(action) # 自定义逻辑
decisions.append(decision)
result = agent.invoke(
Command(resume={"decisions": decisions}),
config=config
)
根据风险分级配置
根据风险等级为不同工具配置不同的中断策略:Copy
interrupt_on = {
# 高风险:提供完整控制(批准、编辑、拒绝)
"delete_file": {"allowed_decisions": ["approve", "edit", "reject"]},
"send_email": {"allowed_decisions": ["approve", "edit", "reject"]},
# 中风险:不允许编辑
"write_file": {"allowed_decisions": ["approve", "reject"]},
# 低风险:无需中断
"read_file": False,
"list_files": False,
}
Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.