Human-in-the-Loop через middleware: README.md
This commit is contained in:
@@ -1,96 +1,123 @@
|
|||||||
# Human‑in‑the‑Loop via Middleware
|
# Human‑in‑the‑Loop через Middleware
|
||||||
|
|
||||||
## 📖 Описание
|
## Описание проекта
|
||||||
В этом проекте реализован агент на базе LangChain, который при каждом вызове инструмента останавливается и запрашивает подтверждение пользователя.
|
В этом проекте реализован агент на базе LangChain, который использует **HumanInTheLoopMiddleware** для ручного подтверждения вызовов инструментов. Каждый раз, когда агент планирует использовать инструмент (например, `get_weather`), он останавливается и выводит в терминал сообщение с просьбой подтвердить действие. Пользователь вводит одно из решений (`approve`, `reject` или `edit`) и только после этого выполнение возобновляется.
|
||||||
* **HumanInTheLoopMiddleware** автоматически формирует запрос к пользователю (в терминале) с описанием того, что планирует сделать агент.
|
|
||||||
* Пользователь вводит одно из решений: `approve`, `reject` или `edit`. После этого выполнение возобновляется через команду `Command(resume={"decisions": [...]})`.
|
|
||||||
|
|
||||||
Таким образом, пользователь всегда контролирует действия агента и может корректировать их в реальном времени.
|
> **Преимущество**: Middleware сам формирует запрос на подтверждение, обрабатывает ответ и управляет переходом к следующему шагу через `Command(resume={…})`. Это упрощает интеграцию Human‑in‑the‑Loop по сравнению с ручным использованием `interrupt_before=['tools']`.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
```
|
||||||
|
├── solution.py # Основной скрипт, реализующий агента
|
||||||
|
└── README.md # Текущий файл
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Установка зависимостей
|
||||||
|
|
||||||
## 📦 Установка зависимостей
|
|
||||||
```bash
|
```bash
|
||||||
# Создайте виртуальное окружение (рекомендовано)
|
# Создайте виртуальное окружение (рекомендуется)
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
|
|
||||||
# Установите зависимости из requirements.txt
|
# Установите необходимые библиотеки
|
||||||
pip install -r requirements.txt
|
pip install langchain langgraph langchain-community openai
|
||||||
```
|
```
|
||||||
|
|
||||||
`requirements.txt`
|
> **Важно**
|
||||||
```txt
|
> * Если у вас нет ключа OpenAI, замените `OpenAI` на любой другой LLM (например, `DummyLLM`, который возвращает фиксированный ответ).
|
||||||
langchain==0.2.*
|
> * Для работы с `HumanInTheLoopMiddleware` требуется версия LangChain ≥ 0.2 и LangGraph ≥ 0.1.
|
||||||
langgraph==0.1.*
|
|
||||||
openai==1.*
|
|
||||||
python-dotenv==1.*
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Важно**:
|
---
|
||||||
> * `checkpointer=MemorySaver()` нужен для сохранения состояния паузы, иначе агент не сможет возобновиться после подтверждения.
|
|
||||||
> * Убедитесь, что переменная окружения `OPENAI_API_KEY` установлена (или используйте `.env` файл).
|
|
||||||
|
|
||||||
## 🚀 Запуск файлов
|
## Запуск проекта
|
||||||
|
|
||||||
| Файл | Что делает | Как запустить |
|
|
||||||
|------|------------|---------------|
|
|
||||||
| `agent.py` | Создаёт агента с middleware и инструментом `get_weather`. | `python agent.py` |
|
|
||||||
| `run_agent.py` | Демонстрирует взаимодействие: задаётся вопрос, агент вызывает инструмент, пользователь подтверждает. | `python run_agent.py` |
|
|
||||||
|
|
||||||
### Пример запуска
|
|
||||||
```bash
|
```bash
|
||||||
# 1️⃣ Запустите агента
|
python solution.py
|
||||||
python agent.py
|
|
||||||
|
|
||||||
# 2️⃣ В другом терминале запустите сценарий взаимодействия
|
|
||||||
python run_agent.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🧪 Пример использования
|
### Что происходит при запуске?
|
||||||
|
|
||||||
```python
|
1. Инициализируется LLM (по умолчанию OpenAI).
|
||||||
from langchain.agents import create_agent
|
2. Создаётся инструмент `get_weather`.
|
||||||
from langgraph.checkpoint.memory import MemorySaver
|
3. Агент создаётся с Middleware, который перехватывает вызовы инструмента и запрашивает подтверждение у пользователя.
|
||||||
from langchain.agents.middleware import HumanInTheLoopMiddleware
|
4. В терминале выводятся сообщения вида:
|
||||||
|
|
||||||
# Инициализация памяти для сохранения состояния паузы
|
|
||||||
memory = MemorySaver()
|
|
||||||
|
|
||||||
agent = create_agent(
|
|
||||||
model=llm,
|
|
||||||
tools=[get_weather],
|
|
||||||
system_prompt="Ты полезный ассистент",
|
|
||||||
middleware=[
|
|
||||||
HumanInTheLoopMiddleware(
|
|
||||||
interrupt_on={
|
|
||||||
"get_weather": True, # разрешаем все решения: approve, edit, reject
|
|
||||||
},
|
|
||||||
description_prefix="Подтвердите вызов инструмента",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
checkpointer=memory,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Запрос к агенту
|
|
||||||
response = agent.run("Какая погода в Москве?")
|
|
||||||
print(response)
|
|
||||||
```
|
|
||||||
|
|
||||||
При выполнении агента вы увидите в терминале запрос вида:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
[HumanInTheLoop] Подтвердите вызов инструмента:
|
[HumanInTheLoop] Подтвердите вызов инструмента:
|
||||||
Agent wants to call tool 'get_weather' with arguments: {"location": "Moscow"}
|
- get_weather
|
||||||
Enter decision (approve/reject/edit):
|
Введите решение (approve/reject/edit):
|
||||||
```
|
```
|
||||||
|
|
||||||
Введите `approve`, и агент продолжит работу, возвращая результат.
|
5. После ввода решения агент продолжает работу.
|
||||||
Если ввести `reject` – запрос будет отменён, а если `edit` – можно изменить аргументы перед повторным вызовом.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 Дополнительные ресурсы
|
## Пример использования
|
||||||
|
|
||||||
* [Документация Human‑in‑the‑Loop — LangChain](https://docs.langchain.com/oss/python/langchain/human-in-the-loop)
|
```bash
|
||||||
* [LangGraph Checkpointing](https://langgraph.org/docs/checkpoints)
|
$ python solution.py
|
||||||
|
> Какую погоду в Москве сегодня?
|
||||||
|
|
||||||
|
[HumanInTheLoop] Подтвердите вызов инструмента:
|
||||||
|
- get_weather
|
||||||
|
Введите решение (approve/reject/edit): approve
|
||||||
|
|
||||||
|
Ответ агента: Сегодня в Москве солнечно, температура 22°C.
|
||||||
|
```
|
||||||
|
|
||||||
|
Если пользователь введёт `reject`, агент отменит вызов и попытается найти другой способ ответа. В случае `edit` можно изменить параметры запроса к инструменту.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Как добавить собственный инструмент
|
||||||
|
|
||||||
|
1. Определите функцию‑инструмент:
|
||||||
|
|
||||||
|
```python
|
||||||
|
def get_time(location: str) -> str:
|
||||||
|
# Возвращает текущее время в указанном месте
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Добавьте её в список `tools` при создании агента и настройте Middleware:
|
||||||
|
|
||||||
|
```python
|
||||||
|
agent = create_agent(
|
||||||
|
model=llm,
|
||||||
|
tools=[get_weather, get_time],
|
||||||
|
middleware=[
|
||||||
|
HumanInTheLoopMiddleware(
|
||||||
|
interrupt_on={"get_time": True},
|
||||||
|
description_prefix="Подтвердите вызов инструмента",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Тестирование
|
||||||
|
|
||||||
|
Для быстрой проверки можно использовать `DummyLLM`, который всегда возвращает один и тот же ответ. Это удобно, если у вас нет доступа к OpenAI.
|
||||||
|
|
||||||
|
```python
|
||||||
|
class DummyLLM:
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return "dummy response"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
| Вопрос | Ответ |
|
||||||
|
|--------|-------|
|
||||||
|
| Как отключить Human‑in‑the‑Loop? | Удалите Middleware из списка `middleware` при создании агента. |
|
||||||
|
| Можно ли задать только `approve` и `reject`, без `edit`? | Да, передайте в `interrupt_on`: `{"get_weather": {"allowed_decisions": ["approve", "reject"]}}`. |
|
||||||
|
| Что делать, если агент не сохраняет состояние после паузы? | Убедитесь, что вы передали `checkpointer=MemorySaver()` при создании агента. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT © 2026
|
||||||
Reference in New Issue
Block a user