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