|
| 1 | +--- |
| 2 | +title: "🦜🔗 LangGraph" |
| 3 | +description: "Build and train sophisticated AI agents using LangGraph with ART's reinforcement learning" |
| 4 | +--- |
| 5 | + |
| 6 | +# LangGraph Integration |
| 7 | + |
| 8 | +ART's LangGraph integration enables you to build sophisticated, multi-step AI agents that learn and improve through reinforcement training. By combining LangGraph's powerful agent framework with ART's training capabilities, you can create agents that reason, use tools, and adapt their behavior over time. |
| 9 | + |
| 10 | +## Why Use ART with LangGraph? |
| 11 | + |
| 12 | +LangGraph provides an excellent framework for building ReAct-style agents that can reason through complex tasks step-by-step. However, getting these agents to perform optimally often requires extensive prompt engineering and manual tuning. ART's integration with LangGraph addresses this by: |
| 13 | + |
| 14 | +- **Automatic behavior improvement**: Train your agents to get better at multi-step reasoning without manual prompt tuning |
| 15 | +- **Tool usage optimization**: Learn when and how to use tools more effectively through reinforcement learning |
| 16 | +- **Adaptive decision making**: Agents learn to make better choices about which actions to take in different situations |
| 17 | +- **Scalable training**: Train on diverse scenarios to build robust, generalizable agent behaviors |
| 18 | + |
| 19 | +## Key Features |
| 20 | + |
| 21 | +- **Seamless integration**: Drop-in replacement for LangGraph's LLM initialization |
| 22 | +- **Automatic logging**: Captures all agent interactions for training data generation |
| 23 | +- **Multi-step trajectory support**: Handles complex agent workflows with tool calls and reasoning steps |
| 24 | +- **RULER compatibility**: Use ART's general-purpose reward function to train agents without hand-crafted rewards |
| 25 | + |
| 26 | +## Basic Usage |
| 27 | + |
| 28 | +Here's how to integrate ART with your existing LangGraph agent: |
| 29 | + |
| 30 | +```python |
| 31 | +import art |
| 32 | +from art.langgraph import wrap_rollout, init_chat_model |
| 33 | +from art.local import LocalBackend |
| 34 | +from langgraph import create_react_agent |
| 35 | + |
| 36 | +# Define your tools |
| 37 | +def search_inbox(query: str) -> str: |
| 38 | + """Search for emails matching the query.""" |
| 39 | + # Your search implementation |
| 40 | + return f"Found emails matching: {query}" |
| 41 | + |
| 42 | +def read_email(email_id: str) -> str: |
| 43 | + """Read a specific email by ID.""" |
| 44 | + # Your email reading implementation |
| 45 | + return f"Email content for {email_id}" |
| 46 | + |
| 47 | +tools = [search_inbox, read_email] |
| 48 | + |
| 49 | +async def train_email_agent(): |
| 50 | + with LocalBackend() as backend: |
| 51 | + # Create your trainable model |
| 52 | + model = art.TrainableModel( |
| 53 | + name="email-agent-langgraph", |
| 54 | + project="email-search-agent", |
| 55 | + base_model="Qwen/Qwen2.5-7B-Instruct", |
| 56 | + ) |
| 57 | + |
| 58 | + await backend.register_model(model) |
| 59 | + |
| 60 | + # Define your rollout function |
| 61 | + @wrap_rollout(model) |
| 62 | + async def run_agent(scenario: str) -> art.Trajectory: |
| 63 | + # Create the LangGraph agent with ART's LLM wrapper |
| 64 | + agent = create_react_agent(init_chat_model(), tools) |
| 65 | + |
| 66 | + # Run the agent |
| 67 | + result = await agent.ainvoke({"messages": [("user", scenario)]}) |
| 68 | + |
| 69 | + # Return trajectory (automatically captured by wrap_rollout) |
| 70 | + return art.Trajectory() |
| 71 | + |
| 72 | + # Generate training data |
| 73 | + scenarios = [ |
| 74 | + "Find emails from John about the quarterly report", |
| 75 | + "Search for emails containing budget discussions from last week", |
| 76 | + "Find the latest email from Sarah and summarize it", |
| 77 | + ] |
| 78 | + |
| 79 | + for scenario in scenarios: |
| 80 | + await run_agent(scenario) |
| 81 | + |
| 82 | + # Start training with RULER |
| 83 | + await art.train(model, reward_function="ruler") |
| 84 | + |
| 85 | +if __name__ == "__main__": |
| 86 | + import asyncio |
| 87 | + asyncio.run(train_email_agent()) |
| 88 | +``` |
| 89 | + |
| 90 | +## How It Works |
| 91 | + |
| 92 | +The ART-LangGraph integration works through two main components: |
| 93 | + |
| 94 | +### 1. LLM Wrapper (`init_chat_model`) |
| 95 | + |
| 96 | +Replaces LangGraph's standard LLM initialization with ART's logging-enabled wrapper: |
| 97 | + |
| 98 | +```python |
| 99 | +# Standard LangGraph |
| 100 | +from langchain_openai import ChatOpenAI |
| 101 | +llm = ChatOpenAI(model="gpt-4") |
| 102 | + |
| 103 | +# With ART integration |
| 104 | +from art.langgraph import init_chat_model |
| 105 | +llm = init_chat_model() # Automatically uses your model's inference settings |
| 106 | +``` |
| 107 | + |
| 108 | +The wrapper captures all LLM interactions, including: |
| 109 | + |
| 110 | +- Input messages and prompts |
| 111 | +- Generated responses and tool calls |
| 112 | +- Tool execution results |
| 113 | +- Multi-step reasoning chains |
| 114 | + |
| 115 | +### 2. Rollout Wrapper (`wrap_rollout`) |
| 116 | + |
| 117 | +Automatically converts your agent execution into ART trajectories: |
| 118 | + |
| 119 | +```python |
| 120 | +@wrap_rollout(model) |
| 121 | +async def run_agent(scenario: str) -> art.Trajectory: |
| 122 | + # Your agent logic here |
| 123 | + agent = create_react_agent(init_chat_model(), tools) |
| 124 | + result = await agent.ainvoke({"messages": [("user", scenario)]}) |
| 125 | + return art.Trajectory() # Automatically populated from logs |
| 126 | +``` |
| 127 | + |
| 128 | +The wrapper: |
| 129 | + |
| 130 | +- Creates unique execution threads for each agent run |
| 131 | +- Logs all intermediate steps and tool calls |
| 132 | +- Converts LangGraph messages to ART's training format |
| 133 | +- Handles complex multi-turn conversations automatically |
| 134 | + |
| 135 | +## Advanced Example: Email Search Agent |
| 136 | + |
| 137 | +Here's a more complete example of training an email search agent: |
| 138 | + |
| 139 | +```python |
| 140 | +import art |
| 141 | +from art.langgraph import wrap_rollout, init_chat_model |
| 142 | +from art.local import LocalBackend |
| 143 | +from langgraph import create_react_agent |
| 144 | +from typing import List |
| 145 | + |
| 146 | +def search_inbox(query: str, limit: int = 5) -> str: |
| 147 | + """Search emails with improved functionality.""" |
| 148 | + # Simulate email search with realistic results |
| 149 | + results = [ |
| 150 | + f"Email {i }: Subject matching '{query }' from [email protected]" |
| 151 | + for i in range(min(limit, 3)) |
| 152 | + ] |
| 153 | + return "\n".join(results) if results else "No emails found." |
| 154 | + |
| 155 | +def read_email(email_id: str) -> str: |
| 156 | + """Read email with error handling.""" |
| 157 | + if not email_id.isdigit(): |
| 158 | + return "Error: Invalid email ID format" |
| 159 | + return f"Email {email_id}: [Email content here...]" |
| 160 | + |
| 161 | +def return_final_answer(answer: str) -> str: |
| 162 | + """Return the final answer to the user.""" |
| 163 | + return f"Final Answer: {answer}" |
| 164 | + |
| 165 | +tools = [search_inbox, read_email, return_final_answer] |
| 166 | + |
| 167 | +async def train_advanced_email_agent(): |
| 168 | + with LocalBackend() as backend: |
| 169 | + model = art.TrainableModel( |
| 170 | + name="advanced-email-agent", |
| 171 | + project="email-agents", |
| 172 | + base_model="Qwen/Qwen2.5-7B-Instruct", |
| 173 | + ) |
| 174 | + |
| 175 | + await backend.register_model(model) |
| 176 | + |
| 177 | + @wrap_rollout(model) |
| 178 | + async def run_email_agent(scenario: str) -> art.Trajectory: |
| 179 | + agent = create_react_agent(init_chat_model(), tools) |
| 180 | + |
| 181 | + result = await agent.ainvoke({ |
| 182 | + "messages": [("user", scenario)] |
| 183 | + }) |
| 184 | + |
| 185 | + return art.Trajectory() |
| 186 | + |
| 187 | + # Diverse training scenarios |
| 188 | + scenarios = [ |
| 189 | + "Find the most recent email from the finance team about Q4 budget", |
| 190 | + "Search for emails containing 'meeting' and summarize the key points", |
| 191 | + "Look for urgent emails from management and provide a brief overview", |
| 192 | + "Find emails about project deadlines and list them by priority", |
| 193 | + ] |
| 194 | + |
| 195 | + # Generate training trajectories |
| 196 | + for scenario in scenarios: |
| 197 | + trajectory = await run_email_agent(scenario) |
| 198 | + print(f"Generated trajectory for: {scenario}") |
| 199 | + |
| 200 | + # Train with RULER |
| 201 | + await art.train(model, reward_function="ruler") |
| 202 | + |
| 203 | +if __name__ == "__main__": |
| 204 | + import asyncio |
| 205 | + asyncio.run(train_advanced_email_agent()) |
| 206 | +``` |
| 207 | + |
| 208 | +## Best Practices |
| 209 | + |
| 210 | +### Agent Design |
| 211 | + |
| 212 | +- **Clear tool descriptions**: Ensure your tool functions have descriptive docstrings |
| 213 | +- **Error handling**: Include proper error handling in your tools for robust training |
| 214 | +- **Final answer pattern**: Use a dedicated tool for returning final answers to users |
| 215 | + |
| 216 | +### Training Data |
| 217 | + |
| 218 | +- **Diverse scenarios**: Create varied training scenarios that cover different use cases |
| 219 | +- **Realistic complexity**: Include both simple and complex multi-step tasks |
| 220 | +- **Edge cases**: Add scenarios that test error handling and edge cases |
| 221 | + |
| 222 | +### Performance Optimization |
| 223 | + |
| 224 | +- **Tool efficiency**: Optimize tool execution time since it affects training speed |
| 225 | +- **Batch generation**: Generate multiple trajectories efficiently using async patterns |
| 226 | +- **Resource management**: Monitor memory usage during long training runs |
| 227 | + |
| 228 | +The ART-LangGraph integration makes it straightforward to build and train sophisticated AI agents that improve their performance over time, turning your prototype agents into production-ready intelligent systems. |
0 commit comments