Обновить README.md
This commit is contained in:
@@ -1,148 +1,86 @@
|
|||||||
# Human‑in‑the‑Loop Middleware Demo
|
# Human‑in‑the‑Loop Agent with LangGraph
|
||||||
|
|
||||||
This repository contains a minimal FastAPI application that demonstrates how to implement a **Human‑in‑the‑Loop (HITL)** mechanism using custom middleware.
|
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 middleware allows you to pause the processing of an incoming request and resume it later, which is useful for scenarios where a human operator needs to review or approve data before the LLM generates a final response.
|
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.
|
||||||
|
|
||||||
> **TL;DR** – Send a request with `X-HITL-Interrupt: true` to pause.
|
> **⚠️ Prerequisites** – The example uses OpenAI‑compatible APIs.
|
||||||
> Then send another request with `X-HITL-Resume: <request-id>` to resume processing.
|
> Make sure you have an API key set in the environment variable `OPENAI_API_KEY`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Installation
|
## 📦 Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1️⃣ Clone the repo
|
# 1️⃣ Clone the repo (or copy solution.py into a new folder)
|
||||||
git clone https://github.com/yourname/hitl-middleware-demo.git
|
git clone https://github.com/your-username/hitl-langgraph.git
|
||||||
cd hitl-middleware-demo
|
cd hitl-langgraph
|
||||||
|
|
||||||
# 2️⃣ Create a virtual environment (recommended)
|
# 2️⃣ Create and activate a virtual environment (optional but recommended)
|
||||||
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
|
# 3️⃣ Install dependencies
|
||||||
pip install -r requirements.txt
|
pip install --upgrade pip
|
||||||
|
pip install langchain-openai langgraph langchain-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
> **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.
|
||||||
> * `fastapi` – Web framework.
|
|
||||||
> * `uvicorn[standard]` – ASGI server.
|
|
||||||
> * `langchain` – LLM wrapper (OpenAI).
|
|
||||||
> * `qdrant-client` – Vector store client.
|
|
||||||
> * `rich` – Pretty console output.
|
|
||||||
|
|
||||||
If you don't have a Qdrant instance running locally, install it via Docker:
|
---
|
||||||
|
|
||||||
|
## 🚀 Running the Agent
|
||||||
|
|
||||||
|
The main logic is in `solution.py`.
|
||||||
|
Run it directly:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 6333:6333 qdrant/qdrant
|
python solution.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### What Happens?
|
||||||
|
|
||||||
|
1. The agent starts a conversation.
|
||||||
|
2. When it decides to call the `get_weather` tool, the execution pauses.
|
||||||
|
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.
|
||||||
|
- `reject`: the agent receives a `ToolMessage` indicating rejection and can decide what to do next.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Running the Application
|
## 🔧 Example Interaction
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
uvicorn solution:app --reload
|
$ python solution.py
|
||||||
|
Agent: Какую погоду вы хотите узнать?
|
||||||
|
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 API will be available at `http://127.0.0.1:8000`.
|
If you type `reject`, the agent will receive a rejection message and can, for example, ask for clarification.
|
||||||
|
|
||||||
### Endpoints
|
|
||||||
|
|
||||||
| Method | Path | Description |
|
|
||||||
|--------|------|-------------|
|
|
||||||
| `POST /process` | Accepts a JSON body with a `text` field. The request is processed by the HITL middleware and forwarded to an OpenAI LLM via LangChain. |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📄 Example Usage
|
## 📁 Project Structure
|
||||||
|
|
||||||
Below are curl examples that illustrate how to interrupt and resume a request.
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
### 1️⃣ Send a request that will be **interrupted**
|
| `solution.py` | Full implementation of the HITL agent. |
|
||||||
|
| `README.md` | This documentation file. |
|
||||||
```bash
|
|
||||||
curl -X POST http://127.0.0.1:8000/process \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "X-HITL-Interrupt: true" \
|
|
||||||
-d '{"text":"Explain quantum entanglement."}'
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response (queued)**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "queued",
|
|
||||||
"request_id": "abcd1234"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> The middleware stores the request in memory and returns a `request_id` that can be used to resume later.
|
|
||||||
|
|
||||||
### 2️⃣ Resume the queued request
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -X POST http://127.0.0.1:8000/process \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-H "X-HITL-Resume: abcd1234" \
|
|
||||||
-d '{"text":"Explain quantum entanglement."}'
|
|
||||||
```
|
|
||||||
|
|
||||||
**Response (processed)**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "completed",
|
|
||||||
"response": "Quantum entanglement is a physical phenomenon..."
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
> The LLM processes the text and returns the answer.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 How It Works
|
## 🛠️ Customization
|
||||||
|
|
||||||
1. **Middleware (`HumanInLoopMiddleware`)**
|
- **Add more tools** – Decorate any function with `@tool` and add it to the `tools=[...]` list.
|
||||||
* Checks for `X-HITL-Interrupt` or `X-HITL-Resume` headers.
|
- **Change prompt** – Edit `system_prompt` in `create_react_agent`.
|
||||||
* If interrupted, stores the request body in a dictionary keyed by a generated UUID.
|
- **Persist memory** – Replace `MemorySaver()` with a file‑based or database checkpoint if you need persistence across runs.
|
||||||
* If resumed, retrieves the stored body and forwards it to the downstream route.
|
|
||||||
|
|
||||||
2. **Route (`/process`)**
|
|
||||||
* Receives the text payload.
|
|
||||||
* Calls `llm.invoke()` from LangChain to generate a response.
|
|
||||||
* Returns the LLM output in JSON.
|
|
||||||
|
|
||||||
3. **Qdrant**
|
|
||||||
* The example includes an initialized Qdrant client, but it is not used in this minimal demo.
|
|
||||||
* In a real-world scenario you could store embeddings or metadata there.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📦 Project Structure
|
## 📜 License
|
||||||
|
|
||||||
```
|
MIT © 2026. Feel free to fork and adapt for your own projects!
|
||||||
.
|
|
||||||
├── solution.py # Main FastAPI app with HITL middleware
|
|
||||||
├── requirements.txt # Python dependencies
|
|
||||||
└── README.md # This file
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Customization
|
|
||||||
|
|
||||||
- **LLM** – Replace `OpenAI(api_key="YOUR_OPENAI_API_KEY")` with another provider supported by LangChain.
|
|
||||||
- **Storage** – Swap the in‑memory dict for Redis, PostgreSQL, or any persistence layer to survive restarts.
|
|
||||||
- **Security** – Add authentication/authorization headers before allowing resume operations.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Use Cases
|
|
||||||
|
|
||||||
- **Content moderation** – Pause a request until a human moderator approves it.
|
|
||||||
- **Legal review** – Let lawyers vet LLM outputs before they are sent to clients.
|
|
||||||
- **Data privacy** – Inspect sensitive data for compliance before processing.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Happy hacking! 🚀
|
|
||||||
Reference in New Issue
Block a user