From 50009952660fe44fe4500e4c9721c3a0fc1c037d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=B8=D1=8F=20=D0=91=D0=B5=D1=80=D0=B4?= =?UTF-8?q?=D0=BD=D0=B8=D0=BA=D0=BE=D0=B2=D0=B0?= Date: Thu, 28 May 2026 05:44:16 +0000 Subject: [PATCH] =?UTF-8?q?Human-in-the-Loop=20=D1=87=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B7=20middleware:=20solution.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solution.py | 97 +++++++------------ 1 file changed, 35 insertions(+), 62 deletions(-) diff --git a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py index b38c635..86daec2 100644 --- a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py +++ b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/solution.py @@ -1,22 +1,17 @@ -# solution.py - +# -*- coding: utf-8 -*- """ -Пример агента с Human-in-the-Loop через middleware. -При каждом вызове инструмента агент останавливается, -выводит информацию и ожидает решения пользователя: -approve / reject (с возможностью указать причину отказа). +Пример агента с Human‑in‑the‑loop, реализованный в LangGraph. """ -from langchain import ChatOpenAI -from langchain.tools import tool +from langchain_openai import ChatOpenAI +from langgraph.prebuilt import create_react_agent from langgraph.checkpoint.memory import MemorySaver -from langchain.agents.middleware import HumanInTheLoopMiddleware -from langchain.agents import create_react_agent from langgraph.types import Command +from langchain.tools import tool -# 1. Модель LLM (замените на нужную модель и укажите ключ API) +# 1. Модель LLM (пример с OpenAI‑совместимым API) llm = ChatOpenAI( - model="gpt-4o-mini", # пример модели, можно заменить + model="gpt-4o-mini", # замените на нужную модель temperature=0.7, ) @@ -29,63 +24,41 @@ def get_weather(city: str, date: str) -> str: # 3. Хранилище памяти для чекпоинтера memory = MemorySaver() -# 4. Создание агента с HumanInTheLoopMiddleware +# 4. Создание агента с interrupt_before=["tools"] agent = create_react_agent( tools=[get_weather], - llm=llm, + model=llm, system_prompt="Ты полезный ассистент, отвечай точно.", checkpointer=memory, - middleware=[ - HumanInTheLoopMiddleware( - interrupt_on={"get_weather": True}, # прерывать на каждом вызове - description_prefix="Подтвердите вызов инструмента", - ), - ], + interrupt_before=["tools"], # включаем human‑in‑the‑loop ) -def run_agent(): - """ - Запускает агента, обрабатывает прерывания и выводит финальный ответ. - """ - config = {"configurable": {"thread_id": "session-1"}} - # Инициализируем запрос - result = agent.invoke( - {"messages": [{"role": "human", "content": "Какая погода в Казани сегодня?"}]}, - config=config, - ) +# 5. Запуск и цикл обработки прерываний +config = {"configurable": {"thread_id": "session-1"}} +result = agent.invoke( + {"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 = [] +while "__interrupt__" in result: + # Последнее сообщение содержит вызов инструмента + last_msg = result["messages"][-1] + tool_call = last_msg.tool_calls[0] # предполагаем один вызов + name = tool_call["name"] + args = tool_call.get("args", {}) + print(f"\nИнструмент: {name}") + print(f"Аргументы: {args}") - for req in action_requests: - name = req.get("name") - args = req.get("args", {}) - print("\nИнструмент:", name) - print("Аргументы:", args) + choice = input("a=approve, r=reject: ").strip().lower() + if choice == "r": + msg = input("Причина отказа: ") + decisions = [{"type": "reject", "message": msg}] + else: + decisions = [{"type": "approve"}] - allowed = review_configs.get(name, {}).get( - "allowed_decisions", ["approve", "reject"] - ) - print("Разрешённые решения:", allowed) + # Возобновляем выполнение + result = agent.invoke(Command(resume=decisions), config=config) - 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_answer = result["messages"][-1].content - print("\nОтвет агента:\n", final_answer) - - -if __name__ == "__main__": - run_agent() \ No newline at end of file +# 6. Финальный ответ +final_answer = result["messages"][-1].content +print("\nОтвет агента:\n", final_answer) \ No newline at end of file