"""
Pattern 77: ReAct (Reasoning + Acting) Pattern
Interleaves reasoning traces with task-specific actions.
"""
from typing import Dict, Any, List, Optional, Callable
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel
from enum import Enum
class StepType(str, Enum):
THOUGHT = "thought"
ACTION = "action"
OBSERVATION = "observation"
class ReActStep(BaseModel):
"""Represents a step in the ReAct cycle."""
type: StepType
content: str
step_number: int
class ReActPattern:
"""
ReAct Pattern - Reasoning and Acting in an interleaved manner.
The agent alternates between thinking about what to do and taking actions.
"""
def __init__(self, model_name: str = "gpt-4"):
self.llm = ChatOpenAI(model=model_name, temperature=0.7)
self.available_actions = self._define_actions()
self.trace: List[ReActStep] = []
def _define_actions(self) -> Dict[str, Callable]:
"""Define available actions the agent can take."""
return {
"search": lambda query: f"Search results for: {query}",
"calculate": lambda expr: f"Calculation result: {eval(expr)}",
"lookup": lambda term: f"Definition of {term}: [simulated lookup]",
"finish": lambda answer: f"Final Answer: {answer}"
}
def think(self, question: str, context: str = "") -> str:
"""Reasoning step - agent thinks about next action."""
prompt = ChatPromptTemplate.from_messages([
("system", """You are using the ReAct (Reasoning + Acting) pattern.
Think step-by-step about how to answer this question.
You can use these actions: {actions}
Context so far:
{context}
Provide your thought process about what to do next."""),
("human", "Question: {question}\n\nThought:")
])
chain = prompt | self.llm
response = chain.invoke({
"question": question,
"actions": ", ".join(self.available_actions.keys()),
"context": context or "No previous steps"
})
return response.content
def act(self, thought: str) -> tuple[str, str]:
"""Action step - agent takes an action based on reasoning."""
prompt = ChatPromptTemplate.from_messages([
("system", """Based on this thought, decide which action to take.
Available actions: {actions}
Thought: {thought}
Respond with: Action: [action_name]([argument])
For example: Action: search(quantum computing)"""),
("human", "What action should be taken?")
])
chain = prompt | self.llm
response = chain.invoke({
"thought": thought,
"actions": ", ".join(self.available_actions.keys())
})
# Parse action
action_str = response.content
action_name = "search"
action_arg = thought[:30]
if "Action:" in action_str:
try:
action_part = action_str.split("Action:")[1].strip()
action_name = action_part.split("(")[0].strip()
action_arg = action_part.split("(")[1].split(")")[0].strip()
except:
pass
return action_name, action_arg
def observe(self, action_name: str, action_arg: str) -> str:
"""Observation step - observe the result of the action."""
if action_name in self.available_actions:
try:
result = self.available_actions[action_name](action_arg)
return result
except Exception as e:
return f"Error executing {action_name}: {e}"
return f"Unknown action: {action_name}"
def run(self, question: str, max_steps: int = 5) -> Dict[str, Any]:
"""
Execute the ReAct pattern: Think -> Act -> Observe -> Repeat.
"""
self.trace = []
context = ""
final_answer = None
for step_num in range(max_steps):
# Step 1: Think (Reasoning)
thought = self.think(question, context)
self.trace.append(ReActStep(
type=StepType.THOUGHT,
content=thought,
step_number=step_num + 1
))
# Step 2: Act
action_name, action_arg = self.act(thought)
action_str = f"{action_name}({action_arg})"
self.trace.append(ReActStep(
type=StepType.ACTION,
content=action_str,
step_number=step_num + 1
))
# Check if we're done
if action_name == "finish":
final_answer = action_arg
break
# Step 3: Observe
observation = self.observe(action_name, action_arg)
self.trace.append(ReActStep(
type=StepType.OBSERVATION,
content=observation,
step_number=step_num + 1
))
# Update context
context += f"\nStep {step_num + 1}:\n Thought: {thought}\n Action: {action_str}\n Observation: {observation}"
return {
"question": question,
"trace": self.trace,
"final_answer": final_answer,
"total_steps": len(self.trace) // 3
}
def format_trace(self) -> str:
"""Format the trace for display."""
output = []
for step in self.trace:
prefix = {
StepType.THOUGHT: "💭 Thought",
StepType.ACTION: "⚡ Action",
StepType.OBSERVATION: "👁 Observation"
}[step.type]
output.append(f"{prefix} {step.step_number}: {step.content}")
return "\n".join(output)
# Example usage
if __name__ == "__main__":
agent = ReActPattern()
question = "What is 15% of 240?"
print("=== ReAct Pattern: Reasoning + Acting ===\n")
print(f"Question: {question}\n")
result = agent.run(question, max_steps=3)
print("=== Execution Trace ===\n")
print(agent.format_trace())
if result["final_answer"]:
print(f"\n=== Final Answer ===")
print(result["final_answer"])
Agentic Architecture Pattern: React
Pattern 77: 77 React – Line-by-Line Explanation
Overview
Pattern 77: ReAct (Reasoning + Acting) Pattern Interleaves reasoning traces with task-specific actions.
Code Structure Analysis
File Information
- Pattern Number: 77
- Pattern Name: 77 React
- File Path:
patterns\execution_control\77_react.py - Total Lines: 194
Detailed Code Explanation
Module Docstring
"""
Pattern 77: ReAct (Reasoning + Acting) Pattern
Interleaves reasoning traces with task-specific actions.
"""
Explanation: This module docstring describes the purpose and key features of the 77 React pattern.
Imports Section
from typing import Dict, Any, List, Optional, Callable
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel
from enum import Enum # First 20 imports shown
Explanation: The module imports necessary dependencies:
– from typing import Dict, Any, List, Optional, Callable: Type hints for better code documentation
– from langchain_core.prompts import ChatPromptTemplate: LangChain framework integration
– from langchain_openai import ChatOpenAI: LangChain framework integration
– from enum import Enum: Enumeration support for fixed sets of values
Enumerations
StepType (Line 13)
class StepType(Enum):
THOUGHT
ACTION
OBSERVATION
Purpose: No enum docstring.
Values:
– THOUGHT: Represents thought
– ACTION: Represents action
– OBSERVATION: Represents observation
Classes
StepType (Line 13)
Description: No class docstring.
ReActStep (Line 19)
Description: Represents a step in the ReAct cycle.
ReActPattern (Line 26)
Description: ReAct Pattern – Reasoning and Acting in an interleaved manner. The agent alternates between thinking about what to do and taking actions.
Methods:
__init__ (Line 32)
def __init__(self, model_name):
"""No method docstring."""
Purpose: No method docstring.
Parameters:
– self: Instance reference
– model_name: LLM model to use (e.g., “gpt-4”)
_define_actions (Line 37)
def _define_actions(self):
"""Define available actions the agent can take."""
Purpose: Define available actions the agent can take.
Parameters:
– self: Instance reference
think (Line 46)
def think(self, question, context):
"""Reasoning step - agent thinks about next action."""
Purpose: Reasoning step – agent thinks about next action.
Parameters:
– self: Instance reference
– question: Parameter for question
– context: Parameter for context
act (Line 70)
def act(self, thought):
"""Action step - agent takes an action based on reasoning."""
Purpose: Action step – agent takes an action based on reasoning.
Parameters:
– self: Instance reference
– thought: Parameter for thought
observe (Line 105)
def observe(self, action_name, action_arg):
"""Observation step - observe the result of the action."""
Purpose: Observation step – observe the result of the action.
Parameters:
– self: Instance reference
– action_name: Parameter for action_name
– action_arg: Parameter for action_arg
run (Line 115)
def run(self, question, max_steps):
"""Execute the ReAct pattern: Think -> Act -> Observe -> Repeat."""
Purpose: Execute the ReAct pattern: Think -> Act -> Observe -> Repeat.
Parameters:
– self: Instance reference
– question: Parameter for question
– max_steps: Parameter for max_steps
format_trace (Line 164)
def format_trace(self):
"""Format the trace for display."""
Purpose: Format the trace for display.
Parameters:
– self: Instance reference
Design Patterns Used
- Strategy Pattern: Different execution strategies for various scenarios
- State Pattern: Managing different states in the workflow
- Chain of Responsibility: Sequential processing through workflow nodes
- Observer Pattern: Tracking and monitoring pattern execution
- Factory Pattern: Creating instances with proper configuration
Usage Example
# Initialize the pattern
pattern = StepType(name="example", model_name="gpt-4")
# Configure and execute
result = pattern.execute(data={"key": "value"})
# Check results
print(result)
Key Concepts
- LLM Integration: Uses LangChain/OpenAI for intelligent decision-making
- Workflow Orchestration: LangGraph manages execution flow through nodes
- State Management: TypedDict defines workflow state structure
- Error Handling: Comprehensive error handling and fallback mechanisms
- Extensibility: Designed for easy customization and extension
Extension Points
This pattern can be extended by: 1. Adding custom workflow nodes 2. Implementing additional validation logic 3. Integrating with external services 4. Customizing LLM prompts and responses 5. Adding monitoring and logging capabilities
Leave a Reply