Human-in-the-Loop через middleware: README.md
This commit is contained in:
@@ -1,140 +1,86 @@
|
|||||||
# Human‑in‑the‑Loop Agent via Middleware (LangGraph)
|
# Human‑in‑the‑Loop Agent with LangGraph
|
||||||
|
|
||||||
This repository contains a minimal example of a **Human‑in‑the‑Loop** agent built on top of LangGraph.
|
This repository contains a minimal example of a **Human‑in‑the‑Loop** (HITL) agent built on top of [LangGraph](https://github.com/langchain-ai/langgraph).
|
||||||
The agent pauses whenever it needs to call an external tool, prints the tool request and waits for a user decision (`approve` or `reject`). After the decision is supplied, execution resumes automatically.
|
The agent pauses whenever it needs to call an external tool, presents the tool output to the user and waits for a decision (`approve` or `reject`). After the decision is made the conversation continues automatically.
|
||||||
|
|
||||||
> ⚠️ The example uses OpenAI’s API (or any compatible LLM). Make sure you have an API key set in the environment variable `OPENAI_API_KEY`.
|
> **⚠️ Prerequisites** – The example uses OpenAI‑compatible APIs.
|
||||||
|
> Make sure you have an API key set in the environment variable `OPENAI_API_KEY`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Table of Contents
|
## 📦 Installation
|
||||||
|
|
||||||
- [Features](#features)
|
|
||||||
- [Prerequisites](#prerequisites)
|
|
||||||
- [Installation](#installation)
|
|
||||||
- [Running the Agent](#running-the-agent)
|
|
||||||
- [Interactive Demo (`solution.py`)](#interactive-demo-solutionpy)
|
|
||||||
- [Unit Tests (`tests/test_solution.py`)](#unit-tests-test_solutionpy)
|
|
||||||
- [Example Usage](#example-usage)
|
|
||||||
- [License](#license)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
| Feature | Description |
|
|
||||||
|---------|-------------|
|
|
||||||
| **Human‑in‑the‑Loop** | Agent stops before calling any tool, prints the request and waits for user input. |
|
|
||||||
| **Interrupts via `interrupt_before=["tools"]`** | Configurable interruption point in LangGraph. |
|
|
||||||
| **Tool Example** | Simple `get_weather(city, date)` function that returns a mock weather string. |
|
|
||||||
| **Checkpointing** | Uses an in‑memory checkpoint (`MemorySaver`) to preserve state across interruptions. |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Python 3.10+
|
|
||||||
- An OpenAI API key (or any compatible LLM endpoint)
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export OPENAI_API_KEY="sk-..."
|
# 1️⃣ Clone the repo (or copy solution.py into a new folder)
|
||||||
```
|
git clone https://github.com/your-username/hitl-langgraph.git
|
||||||
|
cd hitl-langgraph
|
||||||
|
|
||||||
---
|
# 2️⃣ Create and activate a virtual environment (optional but recommended)
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. **Clone the repository**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/yourusername/human-in-loop-langgraph.git
|
|
||||||
cd human-in-loop-langgraph
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Create a virtual environment (optional but recommended)**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
source .venv/bin/activate # Windows: .\.venv\Scripts\activate
|
||||||
|
|
||||||
|
# 3️⃣ Install dependencies
|
||||||
|
pip install --upgrade pip
|
||||||
|
pip install langchain-openai langgraph langchain-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
3. **Install dependencies**
|
> **Tip** – If you want to use a different LLM (e.g., Anthropic, Gemini), replace the `ChatOpenAI` import with the appropriate wrapper and adjust the model name.
|
||||||
|
|
||||||
```bash
|
|
||||||
pip install -r requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
*If you don’t have a `requirements.txt`, create one with the following content:*
|
|
||||||
|
|
||||||
```text
|
|
||||||
langchain-openai>=0.2.0
|
|
||||||
langgraph>=0.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Running the Agent
|
## 🚀 Running the Agent
|
||||||
|
|
||||||
### Interactive Demo (`solution.py`)
|
The main logic is in `solution.py`.
|
||||||
|
Run it directly:
|
||||||
The main script demonstrates how to start the agent and handle interruptions.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python solution.py
|
python solution.py
|
||||||
```
|
```
|
||||||
|
|
||||||
**What happens:**
|
### What Happens?
|
||||||
|
|
||||||
1. The user enters a prompt (e.g., “What’s the weather in Paris on 2024‑12‑01?”).
|
1. The agent starts a conversation.
|
||||||
2. The agent processes the request, decides it needs to call `get_weather`, and pauses.
|
2. When it decides to call the `get_weather` tool, the execution pauses.
|
||||||
3. The tool request is printed:
|
3. The tool output (e.g., `"Погода в Москва на 2024-05-28: солнечно 25°C."`) is printed to the console.
|
||||||
|
4. You are prompted to type **approve** or **reject**:
|
||||||
```
|
- `approve`: the agent resumes with the tool result as normal input.
|
||||||
Tool requested: get_weather
|
- `reject`: the agent receives a `ToolMessage` indicating rejection and can decide what to do next.
|
||||||
Arguments: {'city': 'Paris', 'date': '2024-12-01'}
|
|
||||||
```
|
|
||||||
|
|
||||||
4. You are prompted to type `approve` or `reject`.
|
|
||||||
5. After your decision, the agent resumes and prints the final answer.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Unit Tests (`tests/test_solution.py`)
|
## 🔧 Example Interaction
|
||||||
|
|
||||||
Run the test suite to verify that the interruption logic works as expected:
|
```text
|
||||||
|
$ python solution.py
|
||||||
```bash
|
Agent: Какую погоду вы хотите узнать?
|
||||||
pytest tests/test_solution.py
|
User: Москва на 2024-05-28
|
||||||
|
Agent (calling tool): get_weather(city='Москва', date='2024-05-28')
|
||||||
|
Tool output: Погода в Москва на 2024-05-28: солнечно 25°C.
|
||||||
|
Please type 'approve' or 'reject': approve
|
||||||
|
Agent: Спасибо! Как ещё могу помочь?
|
||||||
```
|
```
|
||||||
|
|
||||||
The tests simulate a user approving the tool call automatically and check that the final output contains the weather string.
|
If you type `reject`, the agent will receive a rejection message and can, for example, ask for clarification.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Example Usage
|
## 📁 Project Structure
|
||||||
|
|
||||||
Below is a quick snippet you can paste into a Python REPL or another script to see the agent in action:
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
```python
|
| `solution.py` | Full implementation of the HITL agent. |
|
||||||
from solution import agent, memory # assuming solution.py defines them
|
| `README.md` | This documentation file. |
|
||||||
|
|
||||||
# Start a new thread/session
|
|
||||||
config = {"configurable": {"thread_id": "demo-session"}}
|
|
||||||
|
|
||||||
# Invoke with a user message
|
|
||||||
response = agent.invoke(
|
|
||||||
{"messages": [{"role": "user", "content": "What's the weather in Tokyo on 2025-01-15?"}]},
|
|
||||||
config=config,
|
|
||||||
)
|
|
||||||
|
|
||||||
print("\nFinal response:")
|
|
||||||
print(response["messages"][-1]["content"])
|
|
||||||
```
|
|
||||||
|
|
||||||
When you run this, you’ll see the same interruption prompt as described above.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## License
|
## 🛠️ Customization
|
||||||
|
|
||||||
MIT © 2026. Feel free to fork and adapt for your own projects.
|
- **Add more tools** – Decorate any function with `@tool` and add it to the `tools=[...]` list.
|
||||||
|
- **Change prompt** – Edit `system_prompt` in `create_react_agent`.
|
||||||
|
- **Persist memory** – Replace `MemorySaver()` with a file‑based or database checkpoint if you need persistence across runs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📜 License
|
||||||
|
|
||||||
|
MIT © 2026. Feel free to fork and adapt for your own projects!
|
||||||
Reference in New Issue
Block a user