diff --git a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py index 44d2743..b38c635 100644 --- a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py +++ b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py @@ -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__":