Human-in-the-Loop через middleware: solution.py

This commit is contained in:
2026-05-28 05:40:26 +00:00
parent 44eee8bba3
commit a0ddc6f0ad
@@ -2,84 +2,89 @@
"""
Пример агента с Human-in-the-Loop через middleware.
Запускается из командной строки и демонстрирует работу интерактивного подтверждения вызова инструмента.
При каждом вызове инструмента агент останавливается,
выводит информацию и ожидает решения пользователя:
approve / reject (с возможностью указать причину отказа).
"""
from langgraph.prebuilt import create_react_agent
from langchain import ChatOpenAI
from langchain.tools import tool
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import Command, StateGraph
from langgraph.moderation import HumanInTheLoopMiddleware
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langchain.agents import create_react_agent
from langgraph.types import Command
# ------------------------------------------------------------
# 1. Определяем простой инструмент
# ------------------------------------------------------------
# 1. Модель LLM (замените на нужную модель и укажите ключ API)
llm = ChatOpenAI(
model="gpt-4o-mini", # пример модели, можно заменить
temperature=0.7,
)
# 2. Простой инструмент
@tool
def get_weather(city: str, date: str) -> str:
"""Возвращает погоду в городе на указанную дату."""
return f"Погода в {city} на {date}: солнечно 25°C."
# ------------------------------------------------------------
# 2. Создаём агент с HumanInTheLoopMiddleware
# ------------------------------------------------------------
# 3. Хранилище памяти для чекпоинтера
memory = MemorySaver()
# 4. Создание агента с HumanInTheLoopMiddleware
agent = create_react_agent(
tools=[get_weather],
llm=llm,
system_prompt="Ты полезный ассистент, отвечай точно.",
checkpointer=memory,
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={"get_weather": True}, # прерываем только при вызове get_weather
interrupt_on={"get_weather": True}, # прерывать на каждом вызове
description_prefix="Подтвердите вызов инструмента",
),
],
checkpointer=memory,
)
# ------------------------------------------------------------
# 3. Запускаем агент и обрабатываем интерактивный цикл
# ------------------------------------------------------------
def run_agent():
"""
Вводим сообщение от пользователя, запускаем агента,
обрабатываем прерывания и продолжаем работу до завершения.
Запускает агента, обрабатывает прерывания и выводит финальный ответ.
"""
# Инициализируем конфиг с thread_id
config = {"configurable": {"thread_id": "session-1"}}
# Запрашиваем ввод от пользователя
user_input = input("Введите запрос: ")
# Первый вызов агента
# Инициализируем запрос
result = agent.invoke(
{"messages": [{"role": "human", "content": user_input}]},
{"messages": [{"role": "human", "content": "Какая погода в Казани сегодня?"}]},
config=config,
)
# Цикл обработки прерываний
# Обрабатываем прерывания до тех пор, пока они не исчезнут
while "__interrupt__" in result:
interrupt_payload = result["__interrupt__"][0].value
action_requests = interrupt_payload.get("action_requests", [])
review_configs = interrupt_payload.get("review_configs", {})
decisions = []
for req in action_requests:
print("\nИнструмент:", req["name"])
print("Аргументы:", req["args"])
# Запрашиваем решение пользователя
decision = input("a=approve, r=reject: ").strip().lower()
if decision == "r":
reason = input("Причина отказа: ").strip()
decisions.append({"type": "reject", "message": reason})
for req in action_requests:
name = req.get("name")
args = req.get("args", {})
print("\nИнструмент:", name)
print("Аргументы:", args)
allowed = review_configs.get(name, {}).get(
"allowed_decisions", ["approve", "reject"]
)
print("Разрешённые решения:", allowed)
choice = input("a=approve, r=reject: ").strip().lower()
if choice == "r":
msg = input("Причина отказа: ")
decisions.append({"type": "reject", "message": msg})
else:
decisions.append({"type": "approve"})
# Возобновляем работу агента
# Возобновляем выполнение агента
result = agent.invoke(Command(resume={"decisions": decisions}), config=config)
# Выводим финальный ответ агента
final_message = result["messages"][-1]["content"]
print("\nОтвет агента:", final_message)
# Финальный ответ агента
final_answer = result["messages"][-1].content
print("\nОтвет агента:\n", final_answer)
if __name__ == "__main__":