# Human‑in‑the‑Loop 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`). The pause is implemented with LangChain’s built‑in `HumanInTheLoopMiddleware`, which automatically generates the prompt, captures the user input, and resumes execution via a `Command`. > **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. --- ## 📦 Installation ```bash # Create a virtual environment (optional but recommended) python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # Install required packages pip install langchain langgraph openai rich ``` > **OpenAI API key** > The example uses an OpenAI model. Set your key in the environment: ```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 python solution.py ``` You will see something like: ``` User: What's the weather in London? Agent: (pauses) Подтвердите вызов инструмента get_weather - approve - reject Your choice: ``` 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 ### Changing the Tool Replace the `get_weather` function with any other LangChain tool: ```python @tool def get_time() -> str: """Return current UTC time.""" return datetime.utcnow().isoformat() ``` 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., GPT‑4o, Claude, etc.): ```python from langchain_openai import ChatOpenAI llm = ChatOpenAI(model_name="gpt-4o-mini") ``` --- ## 📖 Example Interaction ``` User: Tell me the weather in Paris. Agent: (pauses) Подтвердите вызов инструмента get_weather - approve - reject Your choice: approve Agent: The current temperature in Paris is 18°C with clear skies. Final answer: It’s sunny and mild in Paris today. ``` --- ## 📜 License This project is provided under the MIT license. Feel free to adapt it for your own experiments. ---