智能体能自主决策任务的执行,但有时人工介入是必要的。LangChain提供了人工协作中间件支持智能体的人工介入功能。阅读本文您将获得:
- LangChain人工协作中断支持的决策类型
- LangChain人工协作如何配置中断
- LangChain人工协作如何响应中断
- LangChain人工协作的执行生命周期
- LangChain自定义人工协作逻辑
LangChain提供了人工协作HumanInTheLoopMiddleware中间件。 人工协作(Human-in-the-Loop,简称 HITL)中间件可让你在【智能体工具调用过程中】加入人工监督环节。当模型提出可能需要审核的操作(例如写入文件或执行SQL语句)时,该中间件能够暂停执行流程,等待人工决策。 其实现原理是通过可配置策略对每一次工具调用进行检查。若需要人工介入,中间件会触发【中断信号】以终止当前执行。此时,图状态会通过LangGraph的持久化层保存,确保执行流程可安全暂停,并在后续重新启动。 之后,人工决策将决定后续操作方向:该行动可按原计划批准执行("批准")、修改后再运行("编辑"),或结合反馈意见予以拒绝("拒绝")。
1、中断决策类型
人工协作中间件定义了三种内置的人工响应中断的方式:
| 决策类型 | 说明 | 示例场景 |
|---|---|---|
| ✅ 批准(approve) | 行动按原样获批并直接执行,无需修改 | 完全按照撰写内容发送邮件草稿 |
| ✏️ 编辑(edit) | 工具调用经修改后执行 | 发送邮件前修改收件人 |
| ❌ 拒绝(reject) | 工具调用被拒绝,且需在对话中添加拒绝说明 | 拒绝某封邮件草稿,并说明应如何重写 |
每种工具可用的决策类型,取决于你在 "interrupt_on"(中断触发条件)中配置的策略。当多个工具调用同时处于暂停状态时,每个行动都需要单独决策。决策的提供顺序必须与中断请求中行动的显示顺序一致。在编辑工具参数时,应谨慎修改。对原始参数进行大幅调整,可能会导致模型重新评估其执行思路,进而可能出现工具被多次执行或触发意外操作的情况。
2、配置中断
若要使用人工协作(HITL)功能,需在创建智能体时,将该中间件添加到智能体的中间件列表中。 你需要通过一种 "工具操作 - 决策类型" 映射关系来配置该中间件:为每种工具操作指定允许的决策类型。当某次工具调用与映射关系中的某一操作匹配时,中间件就会中断执行流程。
python
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model="gpt-4o",
tools=[write_file_tool, execute_sql_tool, read_data_tool],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"write_file": True, # All decisions (approve, edit, reject) allowed
"execute_sql": {"allowed_decisions": ["approve", "reject"]}, # No editing allowed
# Safe operation, no approval needed
"read_data": False,
},
# Prefix for interrupt messages - combined with tool name and args to form the full message
# e.g., "Tool execution pending approval: execute_sql with query='DELETE FROM...'"
# Individual tools can override this by specifying a "description" in their interrupt config
description_prefix="Tool execution pending approval",
),
],
# Human-in-the-loop requires checkpointing to handle interrupts.
# In production, use a persistent checkpointer like AsyncPostgresSaver.
checkpointer=InMemorySaver(),
)
必须配置一个检查点(checkpointer),以在中断期间持久化保存图状态(graph state)。在生产环境中,应使用具备持久化功能的检查点工具,例如AsyncPostgresSaver;若用于测试或原型开发,可使用InMemorySaver。调用智能体时,需传入包含线程ID(thread ID)的配置,使执行流程与对话线程相关联。
3、响应中断(Responding to Interrupts)
调用智能体后,智能体将持续运行,直至任务完成或触发中断。当某次工具调用与你在 "interrupt_on"(中断触发条件)中配置的策略相匹配时,中断即会被触发。在此情况下,调用结果中将包含一个 "interrupt" 字段,该字段内会列出需要审核的操作。之后,你可将这些操作呈现给审核人员,待获取决策意见后,即可恢复执行流程。
python
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command
from config import api_key, api_base
def init_model():
model = init_chat_model(
api_key = api_key,
base_url = api_base,
model = "Qwen/Qwen3-8B",
model_provider = "openai",
temperature = 0.7,
)
return model
@tool
def send_email(recipient: str, content: str) -> str:
"""Send an email to the specified recipient."""
return f"Email sent to {recipient} with content: {content}"
agent = create_agent(
model=init_model(),
tools=[send_email],
middleware=[HumanInTheLoopMiddleware(
interrupt_on={
# Require approval for sensitive operations
"send_email": True,
"delete_database": True,
# Auto-approve safe operations
"search": False,
})
],
# Persist the state across interrupts
checkpointer=InMemorySaver(),
)
# Human-in-the-loop requires a thread ID for persistence
config = {"configurable": {"thread_id": "001"}}
# Agent will pause and wait for approval before executing sensitive tools
result = agent.invoke(
{"messages": [{"role": "user", "content": "Send an email to the team, tell them we will be back in 2 hours"}]},
config=config
)
interrupts = result.get("__interrupt__", "No interrupt")
if interrupts != "No interrupt":
for interrupt in interrupts:
action_requests = interrupt.value.get("action_requests", [])
review_configs = interrupt.value.get("review_configs", [])
for action_request in action_requests:
tool_name = action_request['name']
tool_args = action_request['args']
msg = action_request['description']
print(msg)
print(f"需要审批的操作: {tool_name}")
print(f"操作参数: {tool_args}")
print("=" * 30 + "人工审批" + "=" * 40 )
human_decision = input("请输入您的审批意见(approve/reject/edit): ")
if human_decision == "approve":
# 批准
result = agent.invoke(
Command(resume={"decisions": [{"type": "approve"}]}),
config=config # Same thread ID to resume the paused conversation
)
print(result['messages'])
elif human_decision == "edit":
# 编辑
result = agent.invoke(
Command(resume={"decisions": [{"type": "edit", "edited_action": {
# Tool name to call. Will usually be the same as the original action.
"name": "send_email",
# Arguments to pass to the tool.
"args": {"recipient": "team@xxxx.com", "content": tool_args['content']},}
}]}),
config=config # Same thread ID to resume the paused conversation
)
print(result['messages'])
else:
# 拒绝
result = agent.invoke(
Command(resume={"decisions": [{"type": "reject", "message": "已拒绝执行发送邮件。"}]}),
config=config # Same thread ID to resume the paused conversation
)
print(result['messages'])
4、执行生命周期(Execution Lifecycle)
人工协作中间件定义了一个模型后钩子(after_model hook),此钩子会在模型生成响应之后、任何工具调用执行之前运行,具体流程如下:
- 智能体调用模型以生成响应。
- 中间件检查响应中是否包含工具调用。
- 若存在任何需要人工输入的调用,中间件会构建一个包含 "操作请求"(action_requests)和 "审核配置"(review_configs)的 HITL 请求(HITLRequest),并触发中断。
- 智能体等待人工决策。
- 根据HITL响应(HITLResponse)中的决策结果,中间件执行已批准(approved)或已编辑(edited)的调用,为已拒绝(rejected)的调用生成工具消息(ToolMessage),随后恢复执行流程。
5、自定义HITL逻辑
对于更具特殊性的工作流,你可以直接借助 "中断原语"(interrupt primitive)和 "中间件抽象层"(middleware abstraction)构建自定义HITL逻辑。 请先参考上文所述的 "执行生命周期",理解如何将中断功能集成到智能体的运行流程中。