Skip to article frontmatterSkip to article content

人机交互

人机交互(Human-in-the-loop, HITL)指智能体为了向人类索要执行权限或额外信息而主动中断,并在获得人类回复后继续执行的过程。

LangGraph 特别开发了 HITL 中间件,用于人机交互。当触发人机交互时,HITL 中间件会中断程序执行,等待人类回复。在中断前,LangGraph 会将当前状态保存在检查点 checkpointer 中,直到中断结束,再将状态从检查点中恢复出来。

注意:本文只是演示 checkpoint 在人机交互过程中的作用,无所谓线程结束后记忆是否保持,因此使用 InMemorySaver。在生产环境中,请使用由数据库支持的检查点,例如:

  • SqliteSaver

  • PostgresSaver

  • MongoDBSaver

  • RedisSaver

import os
import uuid
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langchain_core.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command

# 加载模型配置
_ = load_dotenv()
# 配置大模型服务
llm = ChatOpenAI(
    api_key=os.getenv("DASHSCOPE_API_KEY"),
    base_url=os.getenv("DASHSCOPE_BASE_URL"),
    model="qwen3-coder-plus",
)

# 工具函数
@tool
def get_weather(city: str) -> str:
    """Get weather for a given city."""
    return f"It's always sunny in {city}!"

@tool
def add_numbers(a: float, b: float) -> float:
    """Add two numbers and return the sum."""
    return a + b

@tool
def calculate_bmi(weight_kg: float, height_m: float) -> float:
    """Calculate BMI given weight in kg and height in meters."""
    if height_m <= 0 or weight_kg <= 0:
        raise ValueError("height_m and weight_kg must be greater than 0.")
    return weight_kg / (height_m ** 2)

# 创建带工具调用的Agent
tool_agent = create_agent(
    model=llm,
    tools=[get_weather, add_numbers, calculate_bmi],
    middleware=[
        HumanInTheLoopMiddleware( 
            interrupt_on={
                # 无需触发人工审批
                "get_weather": False,
                # 需要审批,且允许approve,edit,reject三种审批类型
                "add_numbers": True,
                # 需要审批,允许approve,reject两种审批类型
                "calculate_bmi": {"allowed_decisions": ["approve", "reject"]},
            },
            description_prefix="Tool execution pending approval",
        ),
    ],
    checkpointer=InMemorySaver(),
    system_prompt="You are a helpful assistant",
)
# 运行Agent
config = {'configurable': {'thread_id': str(uuid.uuid4())}}
result = tool_agent.invoke(
    {"messages": [{
        "role": "user",
        "content": "我身高180cm,体重180斤,我的BMI是多少"
        # "content": "what is the weather in sf"
    }]},
    config=config,
)

# result['messages'][-1].content
result.get('__interrupt__')
[Interrupt(value={'action_requests': [{'name': 'calculate_bmi', 'args': {'height_m': 1.8, 'weight_kg': 90}, 'description': "Tool execution pending approval\n\nTool: calculate_bmi\nArgs: {'height_m': 1.8, 'weight_kg': 90}"}], 'review_configs': [{'action_name': 'calculate_bmi', 'allowed_decisions': ['approve', 'reject']}]}, id='b58dbd2802c1ff4f89a7504b20d5d229')]
# Resume with approval decision
result = tool_agent.invoke(
    Command(
        resume={"decisions": [{"type": "approve"}]}  # or "edit", "reject"
    ), 
    config=config
)

result['messages'][-1].content
'您的BMI是27.8。根据中国成人BMI标准,这属于超重范围(BMI ≥ 24为超重,≥ 28为肥胖)。建议您关注饮食健康和适量运动,如有需要可咨询医生或营养师以获得更专业的建议。'