Human-in-the-Loop через middleware: README.md

This commit is contained in:
2026-05-28 05:27:38 +00:00
parent de3cd66989
commit 3c967a7ced
@@ -1,123 +1,120 @@
# HumanintheLoop через Middleware # HumanintheLoop Agent via Middleware
## Описание проекта This repository contains a minimal example of an **LLM agent** that pauses every time it wants to call an external tool and asks the user for confirmation (`approve` or `reject`).
В этом проекте реализован агент на базе LangChain, который использует **HumanInTheLoopMiddleware** для ручного подтверждения вызовов инструментов. Каждый раз, когда агент планирует использовать инструмент (например, `get_weather`), он останавливается и выводит в терминал сообщение с просьбой подтвердить действие. Пользователь вводит одно из решений (`approve`, `reject` или `edit`) и только после этого выполнение возобновляется. The pause is implemented with LangChains builtin `HumanInTheLoopMiddleware`, which automatically generates the prompt, captures the user input, and resumes execution via a `Command`.
> **Преимущество**: Middleware сам формирует запрос на подтверждение, обрабатывает ответ и управляет переходом к следующему шагу через `Command(resume={…})`. Это упрощает интеграцию Human‑in‑the‑Loop по сравнению с ручным использованием `interrupt_before=['tools']`. > **Why use middleware?**
> Unlike the `interrupt_before=['tools']` approach that requires manual handling of interruptions, the middleware handles everything internally: it creates the confirmation request, processes the response, and resumes the agent with the chosen decision.
## Структура проекта
```
├── solution.py # Основной скрипт, реализующий агента
└── README.md # Текущий файл
```
--- ---
## Установка зависимостей ## 📦 Installation
```bash ```bash
# Создайте виртуальное окружение (рекомендуется) # Create a virtual environment (optional but recommended)
python -m venv .venv python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate source .venv/bin/activate # Windows: .venv\Scripts\activate
# Установите необходимые библиотеки # Install required packages
pip install langchain langgraph langchain-community openai pip install langchain langgraph openai rich
``` ```
> **Важно** > **OpenAI API key**
> * Если у вас нет ключа OpenAI, замените `OpenAI` на любой другой LLM (например, `DummyLLM`, который возвращает фиксированный ответ). > The example uses an OpenAI model. Set your key in the environment:
> * Для работы с `HumanInTheLoopMiddleware` требуется версия LangChain ≥ 0.2 и LangGraph ≥ 0.1.
```bash
export OPENAI_API_KEY="sk-…"
```
--- ---
## Запуск проекта ## 📁 Project Structure
| File | Purpose |
|------|---------|
| `solution.py` | Main script that creates the agent, defines a simple tool (`get_weather`), and runs an interactive loop. |
> The repository contains only one Python file for clarity.
---
## 🚀 Running the Example
```bash ```bash
python solution.py python solution.py
``` ```
### Что происходит при запуске? You will see something like:
1. Инициализируется LLM (по умолчанию OpenAI).
2. Создаётся инструмент `get_weather`.
3. Агент создаётся с Middleware, который перехватывает вызовы инструмента и запрашивает подтверждение у пользователя.
4. В терминале выводятся сообщения вида:
``` ```
[HumanInTheLoop] Подтвердите вызов инструмента: User: What's the weather in London?
- get_weather Agent: (pauses) Подтвердите вызов инструмента get_weather
Введите решение (approve/reject/edit): - approve
- reject
Your choice:
``` ```
5. После ввода решения агент продолжает работу. Type `approve` to let the agent call the tool, or `reject` to skip it.
After your decision, the agent continues its reasoning and eventually returns a final answer.
--- ---
## Пример использования ## 🛠️ Customizing
```bash ### Changing the Tool
$ python solution.py
> Какую погоду в Москве сегодня?
[HumanInTheLoop] Подтвердите вызов инструмента: Replace the `get_weather` function with any other LangChain tool:
- get_weather
Введите решение (approve/reject/edit): approve
Ответ агента: Сегодня в Москве солнечно, температура 22°C.
```
Если пользователь введёт `reject`, агент отменит вызов и попытается найти другой способ ответа. В случае `edit` можно изменить параметры запроса к инструменту.
---
## Как добавить собственный инструмент
1. Определите функцию‑инструмент:
```python ```python
def get_time(location: str) -> str: @tool
# Возвращает текущее время в указанном месте def get_time() -> str:
"""Return current UTC time."""
return datetime.utcnow().isoformat()
``` ```
2. Добавьте её в список `tools` при создании агента и настройте Middleware: Add it to the `tools` list when creating the agent.
### Adjusting Middleware Settings
- **Interrupt on specific decisions**
```python
interrupt_on={
"get_weather": {"allowed_decisions": ["approve", "reject"]} # no edit option
}
```
- **Custom prompt prefix**
```python
description_prefix="Please confirm the tool call:"
```
### Using a Different LLM
Swap `llm` for any LangChain-compatible model (e.g., GPT4o, Claude, etc.):
```python ```python
agent = create_agent( from langchain_openai import ChatOpenAI
model=llm, llm = ChatOpenAI(model_name="gpt-4o-mini")
tools=[get_weather, get_time],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={"get_time": True},
description_prefix="Подтвердите вызов инструмента",
),
],
)
``` ```
--- ---
## Тестирование ## 📖 Example Interaction
Для быстрой проверки можно использовать `DummyLLM`, который всегда возвращает один и тот же ответ. Это удобно, если у вас нет доступа к OpenAI. ```
User: Tell me the weather in Paris.
```python Agent: (pauses) Подтвердите вызов инструмента get_weather
class DummyLLM: - approve
def __call__(self, *args, **kwargs): - reject
return "dummy response" Your choice: approve
Agent: The current temperature in Paris is 18°C with clear skies.
Final answer: Its sunny and mild in Paris today.
``` ```
--- ---
## FAQ ## 📜 License
| Вопрос | Ответ | This project is provided under the MIT license. Feel free to adapt it for your own experiments.
|--------|-------|
| Как отключить Human‑in‑theLoop? | Удалите Middleware из списка `middleware` при создании агента. |
| Можно ли задать только `approve` и `reject`, без `edit`? | Да, передайте в `interrupt_on`: `{"get_weather": {"allowed_decisions": ["approve", "reject"]}}`. |
| Что делать, если агент не сохраняет состояние после паузы? | Убедитесь, что вы передали `checkpointer=MemorySaver()` при создании агента. |
--- ---
## Лицензия
MIT © 2026