diff --git a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/README.md b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/README.md index 3dd5efd..3d8694e 100644 --- a/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/README.md +++ b/solutions/69a86305c46fd26feae6bcaa_Human-in-the-Loop_через_middleware/README.md @@ -1,52 +1,80 @@ # 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. +A minimal LangChain project that demonstrates how to pause an agent before every tool call and let a user approve or reject the action via the terminal. --- -## 📦 Installation +## Table of Contents +- [Project Overview](#project-overview) +- [Prerequisites](#prerequisites) +- [Installation](#installation) +- [Running the Demo](#running-the-demo) + - [1️⃣ `main.py` – Interactive Agent](#1-mainpy---interactive-agent) + - [2️⃣ `tool_example.py` – Custom Tool](#2-tool_exempley---custom-tool) +- [Example Interaction](#example-interaction) +- [Project Structure](#project-structure) + +--- + +## Project Overview +The agent is created with **HumanInTheLoopMiddleware**. +When the agent wants to use a tool (e.g., `get_weather`), it pauses, prints a prompt in the terminal, and waits for user input: + +| Decision | Effect | +|----------|--------| +| `approve` | Tool call proceeds | +| `reject` | Tool call is skipped; the agent continues reasoning | +| `edit` | (Optional) User can modify the tool arguments before resuming | + +The middleware automatically handles the pause/resume logic via `Command(resume={"decisions": [...]})`. + +--- + +## Prerequisites +- Python 3.10+ +- A working OpenAI API key (or any LLM provider supported by LangChain) + +Set your key in an environment variable: ```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 +export OPENAI_API_KEY="sk-..." ``` --- -## 🚀 Running the Demo +## Installation -### 1️⃣ Start the Agent +1. **Clone the repo** + + ```bash + git clone https://github.com/yourusername/human-in-loop-demo.git + cd human-in-loop-demo + ``` + +2. **Create a virtual environment (optional but recommended)** + + ```bash + python -m venv .venv + source .venv/bin/activate # Windows: .venv\Scripts\activate + ``` + +3. **Install dependencies** + + ```bash + pip install -r requirements.txt + ``` + +> `requirements.txt` contains: +> ``` +> langchain==0.2.* +> langgraph==0.1.* +> python-dotenv # optional, for .env support +> ``` + +--- + +## Running the Demo + +### 1️⃣ `main.py` – Interactive Agent ```bash python main.py @@ -55,106 +83,55 @@ python main.py You will see a prompt like: ``` -Assistant: What would you like to do? +Agent: What would you like to know? User: Tell me the weather in London. -Assistant: (Thinking...) +Agent: (pausing) Would you like to call tool 'get_weather' with arguments {'location': 'London'}? [approve/reject/edit] +> ``` -When the agent decides to call `get_weather`, it pauses and prints: +Type `approve`, `reject`, or `edit` and press **Enter**. +If you choose `edit`, you’ll be prompted to modify the JSON arguments. -``` -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 -``` +### 2️⃣ `tool_example.py` – Custom Tool -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. +The demo includes a simple weather tool (`get_weather`). +You can add more tools by editing `tools/__init__.py` or creating new modules. --- -## 📚 Example Usage +## Example Interaction -```python -# main.py -from agent import agent +``` +$ python main.py +Agent: Hi! How can I help you today? +User: What's the weather in Paris? -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']}") +Agent: (pausing) Would you like to call tool 'get_weather' with arguments {'location': 'Paris'}? [approve/reject/edit] +> approve +Tool get_weather called. Result: "Sunny, 22°C" -if __name__ == "__main__": - run() +Agent: The current weather in Paris is Sunny, 22°C. +User: Thanks! ``` -```python -# agent.py -from langchain.agents import create_agent -from langchain.agents.middleware import HumanInTheLoopMiddleware -from langgraph.checkpoint.memory import MemorySaver +If you type `reject`, the agent will continue without calling the tool: -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() +Agent: (pausing) Would you like to call tool 'get_weather' with arguments {'location': 'Paris'}? [approve/reject/edit] +> reject +Agent: I couldn't retrieve the weather. Could you provide more details? ``` --- -## 🔧 Customization Tips +## Project Structure -| 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`. | +``` +human-in-loop-demo/ +├── main.py # Entry point – runs the interactive agent +├── tool_example.py # Example custom tool (get_weather) +├── requirements.txt # Dependencies +└── README.md # This file +``` ---- - -## 📜 License - -This project is licensed under the MIT License – see the [LICENSE](LICENSE) file for details. - ---- \ No newline at end of file +Feel free to extend the project by adding new tools, customizing prompts, or integrating a different LLM provider. Happy hacking! \ No newline at end of file