# Human‑in‑the‑Loop Middleware Demo This repository contains a minimal LangChain/​LangGraph example that demonstrates how to pause an agent whenever it wants to call a tool and ask the user for approval (`approve` / `reject`). The pausing logic is handled by **`HumanInTheLoopMiddleware`**, which automatically generates a prompt, receives the user’s decision, and resumes execution via a `Command(resume={…})`. > **Why this matters** – In many real‑world scenarios an LLM should not act autonomously. By inserting a human checkpoint you can keep control over every tool call, ensuring safety, compliance or simply giving the user a chance to correct mistakes. --- ## 📦 Installation ```bash # 1️⃣ Clone the repo git clone https://github.com/your‑org/human‑in‑the‑loop-demo.git cd human‑in‑the‑loop-demo # 2️⃣ Create a virtual environment (recommended) python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate # 3️⃣ Install dependencies pip install -r requirements.txt ``` > **Requirements** > * Python ≥ 3.10 > * `langchain` (>=0.2) > * `langgraph` (>=0.1) > * `openai` or any LLM provider you prefer The `requirements.txt` file contains the exact versions used for this demo. --- ## 📁 Project Structure ``` . ├── agent.py # Agent definition with HumanInTheLoopMiddleware ├── main.py # CLI entry point – runs the agent interactively ├── tools.py # Example tool(s) (e.g., get_weather) └── README.md # This file ``` --- ## 🚀 Running the Demo ### 1️⃣ Start the Agent ```bash python main.py ``` You will see a prompt like: ``` Assistant: What would you like to do? User: Tell me the weather in London. Assistant: (Thinking...) ``` When the agent decides to call `get_weather`, it pauses and prints: ``` Human-in-the-loop checkpoint: The assistant wants to execute tool 'get_weather' with arguments {'location': 'London'}. Please type one of the following decisions: approve / reject ``` Type **`approve`** to let the tool run, or **`reject`** to cancel it. After your decision, the agent continues: ``` Assistant: The weather in London is 18°C and sunny. ``` ### 2️⃣ Using a Different Tool If you want to test another tool (e.g., `get_time`), add it to `tools.py`, import it in `agent.py`, and adjust the middleware configuration accordingly. --- ## 📚 Example Usage ```python # main.py from agent import agent def run(): print("Welcome! Type 'exit' to quit.") while True: user_input = input("\nUser: ") if user_input.lower() == "exit": break response = agent.invoke({"input": user_input}) print(f"Assistant: {response['output']}") if __name__ == "__main__": run() ``` ```python # agent.py from langchain.agents import create_agent from langchain.agents.middleware import HumanInTheLoopMiddleware from langgraph.checkpoint.memory import MemorySaver from tools import get_weather # <-- your tool(s) memory = MemorySaver() agent = create_agent( model="gpt-4o-mini", # or any LLM you have access to tools=[get_weather], system_prompt="You are a helpful assistant.", middleware=[ HumanInTheLoopMiddleware( interrupt_on={"get_weather": True}, description_prefix="Please confirm the tool call:", ), ], checkpointer=memory, ) ``` ```python # tools.py from langchain.tools import BaseTool class GetWeather(BaseTool): name = "get_weather" description = "Returns current weather for a location." args_schema = ... # define your schema here def _run(self, location: str) -> str: # Dummy implementation – replace with real API call return f"The weather in {location} is 18°C and sunny." get_weather = GetWeather() ``` --- ## 🔧 Customization Tips | Feature | How to change | |---------|---------------| | **Allowed decisions** | `interrupt_on={"get_weather": {"allowed_decisions": ["approve", "reject"]}}` | | **Prompt prefix** | Change `description_prefix` in the middleware. | | **Tool list** | Add or remove tools in the `tools=[...]` array. | | **LLM model** | Pass a different model name or a custom LLM instance to `create_agent`. | --- ## 📜 License This project is licensed under the MIT License – see the [LICENSE](LICENSE) file for details. ---