From 8a0b8b2ba801ebdd04d8e8386bba01795444a6cd Mon Sep 17 00:00:00 2001 From: Gaetan Hurel Date: Wed, 25 Jun 2025 15:48:07 +0200 Subject: [PATCH] add react vs custom --- react_vs_custom.md | 299 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) create mode 100644 react_vs_custom.md diff --git a/react_vs_custom.md b/react_vs_custom.md new file mode 100644 index 0000000..956e3b4 --- /dev/null +++ b/react_vs_custom.md @@ -0,0 +1,299 @@ +# ReAct Agent vs Custom StateGraph: Architectural Decision Guide + +This document explores the two main approaches for building LangGraph agents: using the prebuilt `create_react_agent` vs implementing a custom `StateGraph`. + +## TL;DR Recommendation + +**Use `create_react_agent` for most use cases**. Only migrate to custom `StateGraph` when you hit specific limitations of the ReAct pattern. + +## Option 1: `create_react_agent` (Current Implementation) + +### What it is +```python +# Simple 5-line agent creation +llm = init_chat_model("openai:gpt-4o-mini") +tools = [shell_tool, analyze_log_file] +agent = create_react_agent(llm, tools, prompt=system_prompt) +``` + +### Under the Hood +`create_react_agent` uses a predefined `StateGraph` with this structure: +``` +START → agent → tools → agent → END + ↑________________↓ +``` + +- **`agent` node**: LLM reasoning (decides what to do) +- **`tools` node**: Tool execution (acting) +- **Conditional loop**: Continues until final response + +### Advantages ✅ + +**Simplicity & Speed** +- Minimal code to get started +- Battle-tested ReAct pattern +- Automatic reasoning/acting cycles + +**Maintenance** +- Automatic updates with LangGraph improvements +- Less code to debug and maintain +- Well-documented pattern + +**Perfect for Standard Use Cases** +- Tool-based interactions +- Conversational interfaces +- Analysis workflows +- System administration tasks + +### Limitations ⚠️ + +- Fixed ReAct pattern only +- Limited state management +- No custom routing logic +- No parallel tool execution +- No complex workflow orchestration + +## Option 2: Custom StateGraph Implementation + +### What it looks like +```python +from typing import TypedDict, Annotated, Literal +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langchain_core.messages import BaseMessage + +class AgentState(TypedDict): + messages: Annotated[list[BaseMessage], add_messages] + current_task: str # "log_analysis", "shell_command", "general" + log_context: dict # Remember previous analyses + safety_mode: bool # Control dangerous commands + +def classify_request(state: AgentState) -> AgentState: + """Classify user request type""" + last_message = state["messages"][-1].content.lower() + + if any(word in last_message for word in ["log", "analyze", "error", "pattern"]): + state["current_task"] = "log_analysis" + elif any(word in last_message for word in ["command", "shell", "run", "execute"]): + state["current_task"] = "shell_command" + else: + state["current_task"] = "general" + + return state + +def route_request(state: AgentState) -> Literal["log_analyzer", "shell_executor", "general_chat"]: + """Route to appropriate node based on request type""" + return { + "log_analysis": "log_analyzer", + "shell_command": "shell_executor", + "general": "general_chat" + }[state["current_task"]] + +def analyze_logs_node(state: AgentState) -> AgentState: + """Specialized node for log analysis""" + llm = init_chat_model("openai:gpt-4o-mini") + + # Custom logic for log analysis + # - Parallel file processing + # - Context from previous analyses + # - Specialized prompting + + prompt = f"""You are a log analysis expert. + Previous context: {state.get("log_context", {})} + Use analyze_log_file tool for the requested analysis. + """ + + response = llm.invoke([HumanMessage(content=prompt)] + state["messages"][-3:]) + state["messages"].append(response) + + # Update context for future analyses + state["log_context"]["last_analysis"] = "completed" + + return state + +def execute_shell_node(state: AgentState) -> AgentState: + """Specialized node for shell commands with safety checks""" + llm = init_chat_model("openai:gpt-4o-mini") + + # Safety validation before execution + dangerous_commands = ["rm -rf", "sudo rm", "format", "dd if="] + last_message = state["messages"][-1].content.lower() + + if any(cmd in last_message for cmd in dangerous_commands): + state["messages"].append( + AIMessage(content="⚠️ Potentially dangerous command detected. Please confirm.") + ) + state["safety_mode"] = True + return state + + # Normal execution with ShellTool + # Custom logic for command validation and execution + + return state + +def general_chat_node(state: AgentState) -> AgentState: + """Handle general conversation""" + llm = init_chat_model("openai:gpt-4o-mini") + + prompt = """You are a helpful system administration assistant. + Provide guidance and suggestions for system debugging tasks. + """ + + response = llm.invoke([HumanMessage(content=prompt)] + state["messages"][-5:]) + state["messages"].append(response) + + return state + +def create_advanced_agent(): + """Create custom agent with StateGraph""" + + # Define workflow + workflow = StateGraph(AgentState) + + # Add nodes + workflow.add_node("classifier", classify_request) + workflow.add_node("log_analyzer", analyze_logs_node) + workflow.add_node("shell_executor", execute_shell_node) + workflow.add_node("general_chat", general_chat_node) + + # Define edges + workflow.add_edge(START, "classifier") + workflow.add_conditional_edges( + "classifier", + route_request, + { + "log_analyzer": "log_analyzer", + "shell_executor": "shell_executor", + "general_chat": "general_chat" + } + ) + + # All terminal nodes lead to END + workflow.add_edge("log_analyzer", END) + workflow.add_edge("shell_executor", END) + workflow.add_edge("general_chat", END) + + return workflow.compile() +``` + +### Advantages ✅ + +**Complete Control** +- Custom business logic +- Complex state management +- Advanced routing and validation +- Parallel processing capabilities + +**Specialized Workflows** +- Different handling per task type +- Memory between interactions +- Safety checks and validation +- Custom error handling + +**Performance Optimization** +- Optimized tool selection +- Reduced unnecessary LLM calls +- Parallel execution where possible + +### Disadvantages ❌ + +**Complexity** +- 50+ lines vs 5 lines +- More potential bugs +- Custom maintenance required + +**Development Time** +- Slower initial development +- More testing needed +- Complex debugging + +## Comparison Matrix + +| Aspect | `create_react_agent` | Custom `StateGraph` | +|--------|---------------------|-------------------| +| **Lines of Code** | ~5 | ~50+ | +| **Development Time** | Minutes | Hours/Days | +| **Flexibility** | ReAct pattern only | Complete freedom | +| **Maintenance** | Automatic | Manual | +| **Performance** | Good, optimized | Depends on implementation | +| **Debugging** | Limited visibility | Full control | +| **State Management** | Basic messages | Rich custom state | +| **Routing Logic** | Tool-based only | Custom conditional | +| **Parallel Execution** | No | Yes | +| **Safety Checks** | Tool-level only | Custom validation | +| **Use Cases Coverage** | 80% | 100% | + +## When to Use Each Approach + +### Stick with `create_react_agent` when: + +✅ **Tool-based interactions** (your current use case) +✅ **Standard conversational AI** +✅ **Rapid prototyping** +✅ **Simple reasoning/acting cycles** +✅ **Maintenance is a priority** +✅ **Team has limited LangGraph experience** + +### Migrate to Custom `StateGraph` when: + +🔄 **Complex business logic** required +🔄 **Multi-step workflows** with different paths +🔄 **Advanced state management** needed +🔄 **Parallel processing** requirements +🔄 **Custom validation/safety** logic +🔄 **Performance optimization** critical +🔄 **Specialized routing** based on context + +## Migration Strategy + +If you decide to eventually migrate to custom StateGraph: + +### Phase 1: Enhance Current Implementation +```python +# Add more sophisticated tools to your current setup +def create_enhanced_react_agent(): + tools = [ + shell_tool, + analyze_log_file, + safety_validator_tool, # New: safety checks + parallel_log_analyzer, # New: batch processing + context_manager_tool # New: conversation context + ] + return create_react_agent(llm, tools, enhanced_prompt) +``` + +### Phase 2: Hybrid Approach +```python +# Use create_react_agent for some tasks, custom StateGraph for others +def create_hybrid_agent(): + # Route complex workflows to custom graph + # Keep simple interactions with ReAct agent + pass +``` + +### Phase 3: Full Custom Implementation +- Implement complete StateGraph when requirements demand it + +## Recommendation for Your Project + +**Keep `create_react_agent` for now** because: + +1. ✅ Your use case (log analysis + shell commands) fits perfectly +2. ✅ Current implementation is clean and working +3. ✅ Maintenance overhead is minimal +4. ✅ Team can focus on improving tools rather than framework + +**Consider custom StateGraph later** if you need: +- Advanced workflow orchestration +- Complex state management between analyses +- Parallel processing of multiple log files +- Sophisticated safety validation +- Performance optimization for large-scale deployments + +## Conclusion + +Your current `create_react_agent` implementation is excellent for an MVP and likely covers 80% of system administration use cases. The ReAct pattern provides a solid foundation for tool-based AI interactions. + +Only migrate to custom StateGraph when you have specific requirements that the ReAct pattern cannot handle efficiently. Focus on enhancing your tools (`log_analyzer.py`, additional custom tools) rather than changing the underlying agent framework. + +**The best architecture is the one that solves your current problems without overengineering for hypothetical future needs.**