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

This commit is contained in:
2026-05-28 05:44:17 +00:00
parent 51db484cf0
commit a4190d7713
@@ -1,139 +1,140 @@
# HumanintheLoop Agent via Middleware # HumanintheLoop Agent via Middleware (LangGraph)
This repository contains a minimal example of an LLM agent that pauses whenever it wants to call a tool and asks the user for approval before proceeding. This repository contains a minimal example of a **HumanintheLoop** agent built on top of LangGraph.
The core idea is to use **`HumanInTheLoopMiddleware`** from LangChain, which intercepts every tool invocation, prints a prompt with the action details, and waits for the user to respond (`approve`, `reject`, or optionally edit the request). 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.
> **Why this matters** In many realworld scenarios you want an LLM to ask for human confirmation before performing potentially sensitive actions (e.g., sending emails, accessing databases, calling external APIs). > ⚠️ The example uses OpenAIs API (or any compatible LLM). Make sure you have an API key set in the environment variable `OPENAI_API_KEY`.
--- ---
## Table of Contents ## Table of Contents
- [Project Structure](#project-structure) - [Features](#features)
- [Prerequisites](#prerequisites)
- [Installation](#installation) - [Installation](#installation)
- [Running the Agent](#running-the-agent) - [Running the Agent](#running-the-agent)
- [Interactive Mode](#interactive-mode) - [Interactive Demo (`solution.py`)](#interactive-demo-solutionpy)
- [Scripted Example](#scripted-example) - [Unit Tests (`tests/test_solution.py`)](#unit-tests-test_solutionpy)
- [Example Usage](#example-usage) - [Example Usage](#example-usage)
- [Extending the Agent](#extending-the-agent) - [License](#license)
--- ---
## Project Structure ## Features
| Feature | Description |
|---------|-------------|
| **HumanintheLoop** | 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 inmemory checkpoint (`MemorySaver`) to preserve state across interruptions. |
---
## Prerequisites
- Python 3.10+
- An OpenAI API key (or any compatible LLM endpoint)
```bash
export OPENAI_API_KEY="sk-..."
``` ```
├── solution.py # Main script with the agent implementation
└── README.md # This file
```
`solution.py` contains:
1. **LLM configuration** uses `ChatOpenAI`.
2. **A simple tool** (`get_weather`) that returns a fake weather string.
3. **Memory checkpoint** via `MemorySaver`.
4. **Agent creation** with `create_react_agent` and the middleware.
5. **Execution loop** that keeps asking for user input until the conversation ends.
--- ---
## Installation ## Installation
1. **Clone the repo** 1. **Clone the repository**
```bash ```bash
git clone https://github.com/your-username/human-in-the-loop-agent.git git clone https://github.com/yourusername/human-in-loop-langgraph.git
cd human-in-the-loop-agent cd human-in-loop-langgraph
``` ```
2. **Create a virtual environment (optional but recommended)** 2. **Create a virtual environment (optional but recommended)**
```bash ```bash
python -m venv .venv python -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate source .venv/bin/activate # On Windows: .venv\Scripts\activate
``` ```
3. **Install dependencies** 3. **Install dependencies**
```bash ```bash
pip install --upgrade pip pip install -r requirements.txt
pip install langchain langgraph openai
``` ```
4. **Set your OpenAI API key** *If you dont have a `requirements.txt`, create one with the following content:*
```bash ```text
export OPENAI_API_KEY="sk-..." langchain-openai>=0.2.0
# Windows: setx OPENAI_API_KEY "sk-..." langgraph>=0.1.0
``` ```
--- ---
## Running the Agent ## Running the Agent
### Interactive Mode ### Interactive Demo (`solution.py`)
Simply run the script: The main script demonstrates how to start the agent and handle interruptions.
```bash ```bash
python solution.py python solution.py
``` ```
You will see a prompt like: **What happens:**
``` 1. The user enters a prompt (e.g., “Whats the weather in Paris on 20241201?”).
Agent wants to call tool `get_weather` with arguments: 2. The agent processes the request, decides it needs to call `get_weather`, and pauses.
city = "Moscow" 3. The tool request is printed:
date = "2025-10-01"
Please type one of: approve / reject (or edit <new_args>) ```
> Tool requested: get_weather
``` Arguments: {'city': 'Paris', 'date': '2024-12-01'}
```
Type **`approve`** to let the agent proceed, or **`reject`** to stop it. 4. You are prompted to type `approve` or `reject`.
If you want to modify the arguments before approval, use `edit city=London date=2025-12-25`. 5. After your decision, the agent resumes and prints the final answer.
The conversation continues until the user types `stop` or the agent finishes its plan. ---
### Scripted Example ### Unit Tests (`tests/test_solution.py`)
You can also run a quick demo that automatically approves all calls: Run the test suite to verify that the interruption logic works as expected:
```bash ```bash
python - <<'PY' pytest tests/test_solution.py
from solution import agent, llm, memory
# Override middleware to autoapprove for demonstration
agent.middleware[0].interrupt_on = {"get_weather": False}
print(agent.run("What's the weather in New York tomorrow?"))
PY
``` ```
The tests simulate a user approving the tool call automatically and check that the final output contains the weather string.
--- ---
## Example Usage ## Example Usage
```bash Below is a quick snippet you can paste into a Python REPL or another script to see the agent in action:
$ python solution.py
User: What's the weather in Paris next Friday?
Agent wants to call tool `get_weather` with arguments:
city = "Paris"
date = "2025-10-06"
Please type one of: approve / reject (or edit <new_args>) ```python
> approve from solution import agent, memory # assuming solution.py defines them
Assistant: Погода в Париже на 2025‑10‑06: солнечно 25°C. # Start a new thread/session
User: Thank you! 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, youll see the same interruption prompt as described above.
## Extending the Agent
1. **Add more tools** decorate any function with `@tool` and add it to the `tools` list in `create_react_agent`.
2. **Change the interrupt policy** modify `interrupt_on` dict (e.g., `{ "get_weather": True, "send_email": False }`).
3. **Persist conversation state** replace `MemorySaver()` with a database checkpoint if you need longterm memory.
4. **Custom prompts** tweak `system_prompt` or add a custom `description_prefix`.
--- ---
Happy hacking! 🚀 ## License
MIT © 2026. Feel free to fork and adapt for your own projects.