4 human in loop中间件

LangChain 1.0 实战:Human-in-the-Loop 中间件详解 ------ 让 AI 更安全、更可控

作者 :AI 工程师
日期 :2026 年 3 月 26 日
关键词:LangChain、HumanInTheLoopMiddleware、人机协作、Agent 安全、MCP

在大模型智能体(Agent)日益普及的今天,如何确保其行为安全、合规、可审计 ,成为落地关键。LangChain 1.0 推出的 HumanInTheLoopMiddleware(人机协作中间件),正是解决这一问题的利器。

本文将深入介绍该中间件的原理、配置方式与实战技巧,助你构建高可信度的 AI 应用。


一、什么是 Human-in-the-Loop(HITL)?

Human-in-the-Loop(人机协作) 是一种在 AI 决策流程中引入人类监督的机制。当 Agent 尝试执行高风险操作 (如删除数据、发送邮件、修改配置)时,系统会自动暂停,等待人工审核后再继续。

✅ 典型场景:

  • 发送包含敏感信息的邮件
  • 执行 SQL 删除语句
  • 修改生产环境配置
  • 调用金融交易接口

LangChain 通过 HumanInTheLoopMiddleware 将 HITL 能力标准化,无缝集成到 Agent 工作流中。


二、核心能力:三种人工决策类型

当中间件触发中断后,人类可选择以下三种操作:

决策类型 说明 示例
✅ approve(批准) 按原参数执行工具调用 直接发送草稿邮件
✏️ edit(编辑) 修改工具参数后执行 修改收件人或正文后再发
❌ reject(拒绝) 取消操作,并反馈原因 拒绝发送,并要求重写

⚠️ 注意:是否允许 edit 取决于你在 interrupt_on 中的配置。


  1. 中断触发条件(interrupt_on)
    True:启用所有决策类型(approve/edit/reject)
    False:跳过审核
    字典形式:精细控制允许的决策类型
python 复制代码
HumanInTheLoopMiddleware(
            interrupt_on={
                "write_file": True, #写文件需要确认文件名和内容
                "execute_sql": True,# 执行SQL需要确认SQL语句
                "send_email": {
                    "allowed_decisions": ["approve", "edit", "reject"],
                    "description": "发送邮件需要确认收件人和内容"
                },
                "read_data": False,
            },
            description_prefix="敏感操作需要您的批准",
        )

三、快速上手:配置 HumanInTheLoopMiddleware

1. 简单的代码

python 复制代码
# -*- coding: utf-8 -*-
"""
agent_with_memory
Author: user
Date: 2026/3/16
Description:
"""
from langchain.agents import create_agent, AgentState
from langgraph.checkpoint.memory import InMemorySaver
from langchain_core.tools import tool
from langchain_community.callbacks import get_openai_callback
from langchain.chat_models import init_chat_model
from langchain.agents.middleware import HumanInTheLoopMiddleware
import os
from dotenv import load_dotenv
from langgraph.types import Command

load_dotenv(override=True)

model = init_chat_model(model="qwen2-72b", #
                        model_provider='openai',
                        api_key= os.getenv("api_key"),
                        base_url= os.getenv("base_url"),
                        temperature=0.3,
                        max_retries=4,
                        #max_tokens=10
                        )

# 1. 系统提示词
system_prompt = """你是多功能助手,可以执行写文件、执行SQL、发送邮件、读取数据等操作。"""

# 2. 定义工具
@tool
def write_file(filename: str, content: str) -> str:
    """写入文件"""
    with open(filename, "w", encoding="utf-8") as f:
        f.write(content)
    print("文件写入成功!")
    return f"已写入文件: {filename}"

@tool
def execute_sql(query: str) -> str:
    """执行 SQL 查询"""
    # 实际应用中连接数据库
    return f"执行 SQL: {query}"

@tool
def send_email(to: str, subject: str, body: str) -> str:
    """发送邮件"""
    return f"已发送邮件到 {to}"

@tool
def read_data(source: str) -> str:
    """读取数据(安全操作)"""
    return f"读取数据: {source}"



# 4. 添加记忆
checkpointer = InMemorySaver()

# 5. 创建 Agent
agent = create_agent(
    model=model,
    tools=[write_file, execute_sql,send_email,read_data],
    system_prompt=system_prompt,
    checkpointer=checkpointer,
    middleware=[
        HumanInTheLoopMiddleware(
            interrupt_on={
                "write_file": True, #写文件需要确认文件名和内容
                "execute_sql": True,# 执行SQL需要确认SQL语句
                "send_email": {
                    "allowed_decisions": ["approve", "edit", "reject"],
                    "description": "发送邮件需要确认收件人和内容"
                },
                "read_data": False,
            },
            description_prefix="敏感操作需要您的批准",
        ),
    ],
)

# 6. 运行对话
config = {"configurable": {"thread_id": "user-001"}}



# 初始调用
result = agent.invoke(
    {"messages": [{"role": "user", "content": "在文件 test.txt 中写入内容:Hello, World!"}]},
    config=config
)

# 中断后必须用 Command(resume=...) 恢复;HumanInTheLoopMiddleware 期望 HITLResponse:
# {"decisions": [{"type": "approve"|"edit"|"reject", ...}]}
# 不能传 {"decision": "approve"},否则 interrupt() 收不到决策,工具不会执行。
if result.get("__interrupt__"):
    print(f"等待审批: {result['__interrupt__']}")

    choice = input("批准? (y/n/e): ").lower().strip()

    if choice == "y":
        result = agent.invoke(
            Command(resume={"decisions": [{"type": "approve"}]}),
            config=config,
        )
    elif choice == "e":
        new_content = input("输入新的文件内容: ")
        result = agent.invoke(
            Command(
                resume={
                    "decisions": [
                        {
                            "type": "edit",
                            "edited_action": {
                                "name": "write_file",
                                "args": {
                                    "filename": "safe_test.txt",
                                    "content": new_content,
                                },
                            },
                        }
                    ]
                }
            ),
            config=config,
        )
    else:
        result = agent.invoke(
            Command(
                resume={
                    "decisions": [
                        {
                            "type": "reject",
                            "message": "用户拒绝执行 write_file",
                        }
                    ]
                }
            ),
            config=config,
        )

print(result['messages'][-1].content)

2 api接口对答题

相关推荐
4SAPI9 分钟前
多国产模型混合调度与企业级治理生产选型指南:4SAPI、硅基流动与 OpenRouter 的架构权衡
大数据·人工智能·架构·php
武子康13 分钟前
Cosmos Curator 总览:从一条样本的组成,选对数据处理入口
人工智能·后端·agent
XMAIPC_Robot22 分钟前
-40~85℃宽温实测:RK3588 机器人控制器硬件底座,长时间 SLAM 定位稳定性验证
人工智能·fpga开发·机器人·边缘计算·arm+fpga·rk3588+fpga
锋行天下42 分钟前
Langgraph 运行时上下文使用示例
人工智能
zandy10111 小时前
中电金信金融 AI 工程化实践:异构模型纳管、智能体治理与 AI 原生软件工厂
人工智能·金融
吴佳浩1 小时前
中小企业跑125B 大模型:显存装不下的时候,Strata 做了什么
人工智能·llm
学IT的周星星1 小时前
LangGraph:用「流程图」的方式编排 Agent
数据库·人工智能·大模型·llm·流程图·agent
NC 王炸1 小时前
不用 API Key,也能让网页调用 AI?Opera 把本地模型接进了浏览器
人工智能·浏览器扩展·ai 工具·本地 ai·opera·webai
锋行天下1 小时前
Langgraph 实现类似Langchain记忆上下文过长裁剪
人工智能·后端
不老刘1 小时前
Antigravity 的 New Worktree 模式:给 AI 代理一个安全的“平行工位”
人工智能·git·ai编程·antigravity