Tag: patterns

  • Agentic Design Pattern: React

    
        """
    Pattern 001: ReAct (Reasoning + Acting)
    
    Description:
        Agent alternates between reasoning about the task and taking actions.
        The ReAct pattern combines reasoning traces with task-specific actions,
        allowing the agent to reason about what to do and then take actions.
    
    Components:
        - Thought: Agent reasons about current state
        - Action: Agent takes an action (e.g., tool use)
        - Observation: Agent observes the result
        - Loop continues until task is complete
    
    Use Cases:
        - Question answering with external knowledge
        - Task completion requiring multiple steps
        - Interactive problem solving
    
    LangChain Implementation:
        Uses LangChain's AgentExecutor with structured tools and ReAct prompt template.
    """
    
    import os
    from typing import List, Optional
    from dotenv import load_dotenv
    
    from langchain.agents import AgentExecutor, create_react_agent
    from langchain.tools import Tool
    from langchain_core.prompts import PromptTemplate
    from langchain_openai import ChatOpenAI
    
    # Load environment variables
    load_dotenv()
    
    
    # Define example tools
    def calculator(expression: str) -> str:
        """Evaluates a mathematical expression."""
        try:
            # Safe evaluation for demo purposes
            result = eval(expression, {"__builtins__": {}}, {})
            return f"Result: {result}"
        except Exception as e:
            return f"Error: {str(e)}"
    
    
    def search_tool(query: str) -> str:
        """Simulates a search tool that retrieves information."""
        # Simulated search results
        knowledge_base = {
            "capital of france": "Paris",
            "population of tokyo": "approximately 14 million",
            "height of mount everest": "8,848.86 meters (29,031.7 feet)",
            "speed of light": "299,792,458 meters per second",
            "boiling point of water": "100°C (212°F) at sea level",
        }
        
        query_lower = query.lower()
        for key, value in knowledge_base.items():
            if key in query_lower:
                return f"Search result: {value}"
        
        return f"Search result: Information about '{query}' not found in knowledge base."
    
    
    def get_current_date() -> str:
        """Returns the current date."""
        from datetime import datetime
        return f"Current date: {datetime.now().strftime('%Y-%m-%d')}"
    
    
    # Create tools list
    tools = [
        Tool(
            name="Calculator",
            func=calculator,
            description="Useful for performing mathematical calculations. Input should be a valid mathematical expression."
        ),
        Tool(
            name="Search",
            func=search_tool,
            description="Useful for searching factual information. Input should be a search query."
        ),
        Tool(
            name="GetDate",
            func=get_current_date,
            description="Returns the current date. No input required."
        )
    ]
    
    
    # ReAct prompt template
    REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:
    
    {tools}
    
    Use the following format:
    
    Question: the input question you must answer
    Thought: you should always think about what to do
    Action: the action to take, should be one of [{tool_names}]
    Action Input: the input to the action
    Observation: the result of the action
    ... (this Thought/Action/Action Input/Observation can repeat N times)
    Thought: I now know the final answer
    Final Answer: the final answer to the original input question
    
    Begin!
    
    Question: {input}
    Thought: {agent_scratchpad}
    """
    
    
    def create_react_agent_system():
        """Creates a ReAct agent using LangChain."""
        
        # Initialize LLM
        llm = ChatOpenAI(
            model="gpt-3.5-turbo",
            temperature=0,
            api_key=os.getenv("OPENAI_API_KEY")
        )
        
        # Create prompt template
        prompt = PromptTemplate.from_template(REACT_PROMPT)
        
        # Create agent
        agent = create_react_agent(
            llm=llm,
            tools=tools,
            prompt=prompt
        )
        
        # Create agent executor
        agent_executor = AgentExecutor(
            agent=agent,
            tools=tools,
            verbose=True,
            max_iterations=10,
            handle_parsing_errors=True
        )
        
        return agent_executor
    
    
    def demonstrate_react_pattern():
        """Demonstrates the ReAct pattern with various examples."""
        
        print("=" * 80)
        print("PATTERN 001: ReAct (Reasoning + Acting)")
        print("=" * 80)
        print()
        
        # Create the ReAct agent
        agent_executor = create_react_agent_system()
        
        # Test cases demonstrating ReAct pattern
        test_questions = [
            "What is the capital of France?",
            "What is 25 * 4 + 10?",
            "What is the population of Tokyo and what is 100 divided by that number in millions?",
            "What's today's date?",
        ]
        
        for i, question in enumerate(test_questions, 1):
            print(f"\n{'=' * 80}")
            print(f"Example {i}: {question}")
            print('=' * 80)
            
            try:
                result = agent_executor.invoke({"input": question})
                print(f"\n✓ Final Answer: {result['output']}")
            except Exception as e:
                print(f"\n✗ Error: {str(e)}")
            
            print()
        
        # Summary
        print("\n" + "=" * 80)
        print("REACT PATTERN DEMONSTRATION COMPLETE")
        print("=" * 80)
        print()
        print("Key Features Demonstrated:")
        print("1. Thought-Action-Observation loop")
        print("2. Tool selection and usage")
        print("3. Multi-step reasoning")
        print("4. Dynamic decision making")
        print("5. Interpretable reasoning traces")
        print()
        print("LangChain Components Used:")
        print("- AgentExecutor: Manages agent execution loop")
        print("- create_react_agent: Creates ReAct-style agent")
        print("- Tool: Wraps functions as agent tools")
        print("- PromptTemplate: Structures the ReAct prompt format")
        print("- ChatOpenAI: LLM for reasoning and action selection")
        print()
    
    
    if __name__ == "__main__":
        # Check for API key
        if not os.getenv("OPENAI_API_KEY"):
            print("Error: OPENAI_API_KEY not found in environment variables.")
            print("Please set it in your .env file or environment.")
            exit(1)
        
        demonstrate_react_pattern()
    
        

    Agentic Design Pattern: React

    Pattern 001: React – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the React pattern implementation.


    Pattern Description

    Pattern 001: ReAct (Reasoning + Acting)

    Description: Agent alternates between reasoning about the task and taking actions. The ReAct pattern combines reasoning traces with task-specific actions, allowing the agent to reason about what to do and then take actions.

    Components: – Thought: Agent reasons about current state – Action: Agent takes an action (e.g., tool use) – Observation: Agent observes the result – Loop continues until task is complete

    Use Cases: – Question answering with external knowledge – Task completion requiring multiple steps – Interactive problem solving

    LangChain Implementation: Uses LangChain’s AgentExecutor with structured tools and ReAct prompt template.


    File Statistics

    • Total Lines: 209
    • Classes: 0
    • Functions: 5
    • Constants: 1

    Module Documentation

    """
    Pattern 001: ReAct (Reasoning + Acting)
    
    Description:
        Agent alternates between reasoning about the task and taking actions.
        The ReAct pattern combines reasoning traces with task-specific actions,
        allowing the agent to reason about what to do and then take actions.
    
    Components:
        - Thought: Agent reasons about current state
        - Action: Agent takes an action (e.g., tool use)
        - Observation: Agent observes the result
        - Loop continues until task is complete
    
    Use Cases:
        - Question answering with external knowledge
        - Task completion requiring multiple steps
        - Interactive problem solving
    
    LangChain Implementation:
        Uses LangChain's AgentExecutor with structured tools and ReAct prompt template.
    """
    

    Purpose: This module implements the React pattern, providing a structured approach to agent design and implementation.


    Import Statements

    Standard Library Imports

    import datetime.datetime
    import langchain.agents.create_react_agent
    import langchain_core.prompts.PromptTemplate
    import os
    import typing.List
    import typing.Optional
    

    Purpose: Core Python functionality: – datetime.datetime: Date and time handling – langchain.agents.create_react_agent: Regular expression operations – langchain_core.prompts.PromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.List: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Optional: Type hints for better code documentation (List, Dict, Any, Optional)

    LangChain Imports

    from langchain.agents.AgentExecutor
    from langchain.tools.Tool
    from langchain_openai.ChatOpenAI
    

    Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows – Agents: Autonomous decision-making entities – Tools: Functions that agents can invoke

    Other Imports

    from dotenv.load_dotenv
    

    Purpose: Additional dependencies for specialized functionality.


    Module Constants

    REACT_PROMPT

    REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:
    

    Line 94: Module-level constant definition.


    Functions

    calculator(expression)

    Lines 38-45

    Purpose:

    Evaluates a mathematical expression.
    

    Parameters: – expression: Expression

    Returns: str

    search_tool(query)

    Lines 48-64

    Purpose:

    Simulates a search tool that retrieves information.
    

    Parameters: – query: Input query or question

    Returns: str

    get_current_date()

    Lines 67-70

    Purpose:

    Returns the current date.
    

    Returns: str

    create_react_agent_system()

    Lines 116-145

    Purpose:

    Creates a ReAct agent using LangChain.
    

    demonstrate_react_pattern()

    Lines 148-198

    Purpose:

    Demonstrates the ReAct pattern with various examples.
    

    Key Concepts Summary

    Pattern Overview

    The React pattern provides a structured approach to building AI agents with specific capabilities and behaviors. This implementation leverages LangChain’s composable components to create a robust and maintainable solution.

    Core Components

    1. Agent Class: Main implementation of the pattern logic
    2. Prompt Engineering: Carefully crafted prompts to guide LLM behavior
    3. Tool Integration: Optional tools for extended functionality
    4. Memory Management: State handling across interactions
    5. Output Parsing: Structured response processing

    When to Use

    ✅ Good for: – Scenarios requiring this specific pattern’s strengths – Applications needing structured agent behavior – Systems where explainability is important – Production environments requiring reliability

    ❌ Not ideal for: – Simple single-prompt tasks – Scenarios requiring different pattern characteristics – Resource-constrained environments (if computationally intensive)


    Best Practices Demonstrated

    1. Environment Configuration

    • ✅ Use .env files for API keys
    • ✅ Never hardcode credentials
    • ✅ Validate environment variables on startup

    2. Error Handling

    • ✅ Graceful degradation on failures
    • ✅ Informative error messages
    • ✅ Logging for debugging

    3. Prompt Engineering

    • ✅ Clear, specific instructions
    • ✅ Structured output formats
    • ✅ Few-shot examples when beneficial

    4. Code Organization

    • ✅ Separation of concerns (class-based design)
    • ✅ Type hints for clarity
    • ✅ Docstrings for documentation

    5. Performance Optimization

    • ✅ Appropriate temperature settings
    • ✅ Token budget management
    • ✅ Caching where applicable

    LangChain Components Used

    • ChatOpenAI: OpenAI model interface
    • Chains: Sequential component composition
    • Agents: Autonomous decision-making
    • Tools: External function calling

    Why LangChain? – Composable abstractions for LLM applications – Rich ecosystem of integrations – Production-ready patterns – Active community and development


    Execution Flow

    1. Initialize agent with configuration
       ↓
    2. Load environment and dependencies
       ↓
    3. Prepare prompt with input data
       ↓
    4. Invoke LLM through LangChain
       ↓
    5. Parse and validate response
       ↓
    6. Return formatted result
    

    Key Decision Points: – Model selection (temperature, model type) – Prompt structure (few-shot vs zero-shot) – Error handling strategy – Output format validation


    Performance Considerations

    Computational Cost

    • LLM Calls: Primary cost factor (based on tokens)
    • Latency: Depends on model and input size
    • Memory: Minimal for most patterns

    Optimization Strategies

    1. Prompt Optimization: Minimize tokens while maintaining clarity
    2. Caching: Cache repeated queries/responses
    3. Model Selection: Use smaller models when appropriate
    4. Batch Processing: Group similar requests
    5. Streaming: For long responses, stream tokens

    Cost Estimates (Approximate)

    • GPT-3.5-turbo: ~$0.002 per request
    • GPT-4: ~$0.03 per request
    • GPT-4-turbo: ~$0.01 per request

    Actual costs vary based on input/output token counts


    Common Pitfalls to Avoid

    1. Prompt Design Issues

    ❌ Vague or ambiguous instructions
    ✅ Clear, specific, testable prompts

    2. Error Handling

    ❌ Ignoring API errors or rate limits
    ✅ Implement retry logic and graceful degradation

    3. Token Management

    ❌ Exceeding model token limits
    ✅ Truncate inputs, chunk processing

    4. Security

    ❌ Exposing API keys in code
    ✅ Use environment variables

    5. Testing

    ❌ Only testing happy paths
    ✅ Test edge cases, failures, malformed inputs

    6. Cost Management

    ❌ Unmonitored API usage
    ✅ Implement budgets, alerts, and monitoring


    Further Improvements

    Production Enhancements

    1. Monitoring: Add logging, metrics, tracing
    2. Validation: Input/output schema validation
    3. Rate Limiting: Implement request throttling
    4. Caching: Redis or in-memory cache for responses
    5. Async Support: Non-blocking operations for scalability

    Feature Extensions

    1. Multi-Model Support: Switch between providers
    2. Fallback Models: Graceful degradation strategy
    3. Custom Tools: Domain-specific function calling
    4. Advanced Memory: Vector stores for long-term memory
    5. Evaluation: Automated testing and benchmarking

    Code Quality

    1. Testing: Unit tests, integration tests
    2. Documentation: API docs, usage examples
    3. Type Safety: Stricter type hints
    4. Configuration: Externalized config files

    Related Patterns

    • Pattern 002
    • Other Reasoning Patterns (001-011)

    Pattern Families: – Reasoning Patterns (001-011) – Multi-Agent Patterns (012-019) – Tool Use Patterns (020-025) – Memory Patterns (026-031) – And many more…


    Summary

    The React pattern provides a powerful approach to building AI agents with specific capabilities. This implementation demonstrates:

    ✅ Key Strengths: – Clean, maintainable code structure – LangChain integration for composability – Type hints and documentation – Production-ready patterns

    🎯 Best Use Cases: – Applications requiring this pattern’s characteristics – Systems needing structured agent behavior – Production environments requiring reliability

    📚 Learning Resources: – LangChain Documentation: https://python.langchain.com/ – Pattern Documentation: See related patterns – OpenAI API Reference: https://platform.openai.com/docs/


    File: 001_react.py
    Total Lines: 209
    Pattern Category: AI Agent Design Pattern #001


    Generated from actual implementation code
    For educational and reference purposes

  • Agentic Design Pattern: Reasoning + Action

    
    """
    Pattern 001: ReAct (Reasoning + Acting)
    
    Description:
        Agent alternates between reasoning about the task and taking actions.
        The ReAct pattern combines reasoning traces with task-specific actions,
        allowing the agent to reason about what to do and then take actions.
    
    Components:
        - Thought: Agent reasons about current state
        - Action: Agent takes an action (e.g., tool use)
        - Observation: Agent observes the result
        - Loop continues until task is complete
    
    Use Cases:
        - Question answering with external knowledge
        - Task completion requiring multiple steps
        - Interactive problem solving
    
    LangChain Implementation:
        Uses LangChain's AgentExecutor with structured tools and ReAct prompt template.
    """
    
    import os
    from typing import List, Optional
    from dotenv import load_dotenv
    
    from langchain.agents import AgentExecutor, create_react_agent
    from langchain.tools import Tool
    from langchain_core.prompts import PromptTemplate
    from langchain_openai import ChatOpenAI
    
    # Load environment variables
    load_dotenv()
    
    
    # Define example tools
    def calculator(expression: str) -> str:
        """Evaluates a mathematical expression."""
        try:
            # Safe evaluation for demo purposes
            result = eval(expression, {"__builtins__": {}}, {})
            return f"Result: {result}"
        except Exception as e:
            return f"Error: {str(e)}"
    
    
    def search_tool(query: str) -> str:
        """Simulates a search tool that retrieves information."""
        # Simulated search results
        knowledge_base = {
            "capital of france": "Paris",
            "population of tokyo": "approximately 14 million",
            "height of mount everest": "8,848.86 meters (29,031.7 feet)",
            "speed of light": "299,792,458 meters per second",
            "boiling point of water": "100°C (212°F) at sea level",
        }
        
        query_lower = query.lower()
        for key, value in knowledge_base.items():
            if key in query_lower:
                return f"Search result: {value}"
        
        return f"Search result: Information about '{query}' not found in knowledge base."
    
    
    def get_current_date() -> str:
        """Returns the current date."""
        from datetime import datetime
        return f"Current date: {datetime.now().strftime('%Y-%m-%d')}"
    
    
    # Create tools list
    tools = [
        Tool(
            name="Calculator",
            func=calculator,
            description="Useful for performing mathematical calculations. Input should be a valid mathematical expression."
        ),
        Tool(
            name="Search",
            func=search_tool,
            description="Useful for searching factual information. Input should be a search query."
        ),
        Tool(
            name="GetDate",
            func=get_current_date,
            description="Returns the current date. No input required."
        )
    ]
    
    
    # ReAct prompt template
    REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:
    
    {tools}
    
    Use the following format:
    
    Question: the input question you must answer
    Thought: you should always think about what to do
    Action: the action to take, should be one of [{tool_names}]
    Action Input: the input to the action
    Observation: the result of the action
    ... (this Thought/Action/Action Input/Observation can repeat N times)
    Thought: I now know the final answer
    Final Answer: the final answer to the original input question
    
    Begin!
    
    Question: {input}
    Thought: {agent_scratchpad}
    """
    
    
    def create_react_agent_system():
        """Creates a ReAct agent using LangChain."""
        
        # Initialize LLM
        llm = ChatOpenAI(
            model="gpt-3.5-turbo",
            temperature=0,
            api_key=os.getenv("OPENAI_API_KEY")
        )
        
        # Create prompt template
        prompt = PromptTemplate.from_template(REACT_PROMPT)
        
        # Create agent
        agent = create_react_agent(
            llm=llm,
            tools=tools,
            prompt=prompt
        )
        
        # Create agent executor
        agent_executor = AgentExecutor(
            agent=agent,
            tools=tools,
            verbose=True,
            max_iterations=10,
            handle_parsing_errors=True
        )
        
        return agent_executor
    
    
    def demonstrate_react_pattern():
        """Demonstrates the ReAct pattern with various examples."""
        
        print("=" * 80)
        print("PATTERN 001: ReAct (Reasoning + Acting)")
        print("=" * 80)
        print()
        
        # Create the ReAct agent
        agent_executor = create_react_agent_system()
        
        # Test cases demonstrating ReAct pattern
        test_questions = [
            "What is the capital of France?",
            "What is 25 * 4 + 10?",
            "What is the population of Tokyo and what is 100 divided by that number in millions?",
            "What's today's date?",
        ]
        
        for i, question in enumerate(test_questions, 1):
            print(f"\n{'=' * 80}")
            print(f"Example {i}: {question}")
            print('=' * 80)
            
            try:
                result = agent_executor.invoke({"input": question})
                print(f"\n✓ Final Answer: {result['output']}")
            except Exception as e:
                print(f"\n✗ Error: {str(e)}")
            
            print()
        
        # Summary
        print("\n" + "=" * 80)
        print("REACT PATTERN DEMONSTRATION COMPLETE")
        print("=" * 80)
        print()
        print("Key Features Demonstrated:")
        print("1. Thought-Action-Observation loop")
        print("2. Tool selection and usage")
        print("3. Multi-step reasoning")
        print("4. Dynamic decision making")
        print("5. Interpretable reasoning traces")
        print()
        print("LangChain Components Used:")
        print("- AgentExecutor: Manages agent execution loop")
        print("- create_react_agent: Creates ReAct-style agent")
        print("- Tool: Wraps functions as agent tools")
        print("- PromptTemplate: Structures the ReAct prompt format")
        print("- ChatOpenAI: LLM for reasoning and action selection")
        print()
    
    
    if __name__ == "__main__":
        # Check for API key
        if not os.getenv("OPENAI_API_KEY"):
            print("Error: OPENAI_API_KEY not found in environment variables.")
            print("Please set it in your .env file or environment.")
            exit(1)
        
        demonstrate_react_pattern()
    
    

    Agentic Design Pattern: Reasoning + Action

    Pattern 001: ReAct (Reasoning + Acting) – Line-by-Line Explanation

    Overview

    This document provides a detailed line-by-line explanation of the ReAct pattern implementation.


    Lines 1-22: Module Documentation

    """
    Pattern 001: ReAct (Reasoning + Acting)
    

    Explanation: Multi-line docstring that documents the pattern. This provides a comprehensive description of what the ReAct pattern is and how it works.

    Key Points: – ReAct stands for “Reasoning + Acting” – Combines reasoning traces with task-specific actions – Agent alternates between thinking and doing


    Lines 24-26: Import Standard Library

    import os
    from typing import List, Optional
    from dotenv import load_dotenv
    

    Line 24: import os – Imports the operating system module for environment variable access
    Line 25: from typing import List, Optional – Imports type hints for better code documentation
    Line 26: from dotenv import load_dotenv – Imports function to load environment variables from .env file


    Lines 28-31: Import LangChain Components

    from langchain.agents import AgentExecutor, create_react_agent
    from langchain.tools import Tool
    from langchain_core.prompts import PromptTemplate
    from langchain_openai import ChatOpenAI
    

    Line 28: Imports AgentExecutor (manages agent execution loop) and create_react_agent (factory function for ReAct agents)
    Line 29: Imports Tool class to wrap Python functions as agent tools
    Line 30: Imports PromptTemplate for creating structured prompts
    Line 31: Imports ChatOpenAI for LLM integration with OpenAI models


    Lines 33-34: Load Environment Variables

    # Load environment variables
    load_dotenv()
    

    Line 33: Comment explaining what the next line does
    Line 34: Calls load_dotenv() to load variables from .env file (like API keys)


    Lines 37-45: Calculator Tool Function

    def calculator(expression: str) -> str:
        """Evaluates a mathematical expression."""
        try:
            # Safe evaluation for demo purposes
            result = eval(expression, {"__builtins__": {}}, {})
            return f"Result: {result}"
        except Exception as e:
            return f"Error: {str(e)}"
    

    Line 37: Function definition – takes a mathematical expression string, returns string result
    Line 38: Docstring describing the function’s purpose
    Line 39: try block to catch errors during evaluation
    Line 40: Comment noting this is for demo (not production-safe)
    Line 41: eval() evaluates the expression with restricted builtins for safety
    – First argument: expression to evaluate – Second argument: empty __builtins__ dict for security – Third argument: empty local variables dict Line 42: Returns formatted result string
    Line 43: except catches any exceptions during evaluation
    Line 44: Returns error message if evaluation fails


    Lines 47-62: Search Tool Function

    def search_tool(query: str) -> str:
        """Simulates a search tool that retrieves information."""
        # Simulated search results
        knowledge_base = {
            "capital of france": "Paris",
            "population of tokyo": "approximately 14 million",
            "height of mount everest": "8,848.86 meters (29,031.7 feet)",
            "speed of light": "299,792,458 meters per second",
            "boiling point of water": "100°C (212°F) at sea level",
        }
    

    Line 47: Function definition for simulated search tool
    Line 48: Docstring explaining this simulates a search engine
    Line 49: Comment noting this is simulated data
    Lines 50-56: Dictionary containing factual knowledge for lookup – Key: search query phrase – Value: factual answer

        query_lower = query.lower()
        for key, value in knowledge_base.items():
            if key in query_lower:
                return f"Search result: {value}"
    
        return f"Search result: Information about '{query}' not found in knowledge base."
    

    Line 58: Convert query to lowercase for case-insensitive matching
    Line 59: Loop through each key-value pair in knowledge base
    Line 60: Check if the key is contained in the query
    Line 61: If match found, return the corresponding value
    Line 63: If no match found, return “not found” message


    Lines 65-69: Date Tool Function

    def get_current_date() -> str:
        """Returns the current date."""
        from datetime import datetime
        return f"Current date: {datetime.now().strftime('%Y-%m-%d')}"
    

    Line 65: Function definition – no parameters, returns string
    Line 66: Docstring
    Line 67: Import datetime module locally (only when function is called)
    Line 68: Gets current datetime, formats as YYYY-MM-DD, returns as formatted string


    Lines 72-92: Tools List Definition

    tools = [
        Tool(
            name="Calculator",
            func=calculator,
            description="Useful for performing mathematical calculations. Input should be a valid mathematical expression."
        ),
    

    Line 72: Creates list of Tool objects for the agent
    Lines 73-77: First tool – Calculator – Line 74: name="Calculator" – Name the agent will use to reference this tool – Line 75: func=calculator – Points to the calculator function defined earlier – Line 76: description=... – Tells the agent when/how to use this tool

        Tool(
            name="Search",
            func=search_tool,
            description="Useful for searching factual information. Input should be a search query."
        ),
        Tool(
            name="GetDate",
            func=get_current_date,
            description="Returns the current date. No input required."
        )
    ]
    

    Lines 78-82: Second tool – Search (similar structure)
    Lines 83-87: Third tool – GetDate (similar structure)
    Line 88: Closes the tools list


    Lines 95-112: ReAct Prompt Template

    REACT_PROMPT = """Answer the following questions as best you can. You have access to the following tools:
    
    {tools}
    
    Use the following format:
    
    Question: the input question you must answer
    Thought: you should always think about what to do
    Action: the action to take, should be one of [{tool_names}]
    Action Input: the input to the action
    Observation: the result of the action
    ... (this Thought/Action/Action Input/Observation can repeat N times)
    Thought: I now know the final answer
    Final Answer: the final answer to the original input question
    
    Begin!
    
    Question: {input}
    Thought: {agent_scratchpad}
    """
    

    Line 95: Defines the ReAct prompt template as a multi-line string
    Line 96: Instructions for the agent
    Line 98: {tools} – Placeholder that will be filled with tool descriptions
    Line 100: Tells agent to use specific format
    Lines 102-109: Defines the ReAct format: – Question: The task to solve – Thought: Agent’s reasoning about what to do – Action: Which tool to use – Action Input: What to pass to the tool – Observation: Tool’s output – Loop: Can repeat multiple times – Final Answer: Conclusion

    Line 111: {input} – Will be replaced with user’s question
    Line 112: {agent_scratchpad} – Will contain the agent’s working memory/history


    Lines 115-145: Agent Creation Function

    def create_react_agent_system():
        """Creates a ReAct agent using LangChain."""
    
        # Initialize LLM
        llm = ChatOpenAI(
            model="gpt-3.5-turbo",
            temperature=0,
            api_key=os.getenv("OPENAI_API_KEY")
        )
    

    Line 115: Function to create and configure the ReAct agent
    Line 116: Docstring
    Line 118: Comment
    Lines 119-123: Create ChatOpenAI instance – Line 120: Use GPT-3.5-turbo model – Line 121: Temperature=0 for deterministic outputs – Line 122: Get API key from environment variable

        # Create prompt template
        prompt = PromptTemplate.from_template(REACT_PROMPT)
    

    Lines 125-126: Convert the string template into a PromptTemplate object

        # Create agent
        agent = create_react_agent(
            llm=llm,
            tools=tools,
            prompt=prompt
        )
    

    Lines 128-133: Create the ReAct agent – Line 129: Pass the LLM instance – Line 130: Pass the list of tools – Line 131: Pass the prompt template

        # Create agent executor
        agent_executor = AgentExecutor(
            agent=agent,
            tools=tools,
            verbose=True,
            max_iterations=10,
            handle_parsing_errors=True
        )
    
        return agent_executor
    

    Lines 135-142: Wrap agent in AgentExecutor – Line 137: Pass the agent – Line 138: Pass tools again (executor needs direct access) – Line 139: verbose=True prints detailed execution steps – Line 140: max_iterations=10 prevents infinite loops – Line 141: handle_parsing_errors=True gracefully handles errors

    Line 144: Return the configured agent executor


    Lines 148-207: Demonstration Function

    def demonstrate_react_pattern():
        """Demonstrates the ReAct pattern with various examples."""
    
        print("=" * 80)
        print("PATTERN 001: ReAct (Reasoning + Acting)")
        print("=" * 80)
        print()
    

    Line 148: Main demonstration function
    Lines 151-154: Print header banner

        # Create the ReAct agent
        agent_executor = create_react_agent_system()
    
        # Test cases demonstrating ReAct pattern
        test_questions = [
            "What is the capital of France?",
            "What is 25 * 4 + 10?",
            "What is the population of Tokyo and what is 100 divided by that number in millions?",
            "What's today's date?",
        ]
    

    Lines 156-157: Create the agent system
    Lines 159-164: Define test questions that demonstrate different capabilities

        for i, question in enumerate(test_questions, 1):
            print(f"\n{'=' * 80}")
            print(f"Example {i}: {question}")
            print('=' * 80)
    
            try:
                result = agent_executor.invoke({"input": question})
                print(f"\n✓ Final Answer: {result['output']}")
            except Exception as e:
                print(f"\n✗ Error: {str(e)}")
    
            print()
    

    Line 166: Loop through questions with index starting at 1
    Lines 167-169: Print question header
    Lines 171-176: Try-except block to handle execution – Line 172: Invoke agent with question (returns dict with ‘output’ key) – Line 173: Print the final answer – Lines 174-175: Catch and print any errors

        # Summary
        print("\n" + "=" * 80)
        print("REACT PATTERN DEMONSTRATION COMPLETE")
        print("=" * 80)
        print()
        print("Key Features Demonstrated:")
        print("1. Thought-Action-Observation loop")
        print("2. Tool selection and usage")
        print("3. Multi-step reasoning")
        print("4. Dynamic decision making")
        print("5. Interpretable reasoning traces")
        print()
        print("LangChain Components Used:")
        print("- AgentExecutor: Manages agent execution loop")
        print("- create_react_agent: Creates ReAct-style agent")
        print("- Tool: Wraps functions as agent tools")
        print("- PromptTemplate: Structures the ReAct prompt format")
        print("- ChatOpenAI: LLM for reasoning and action selection")
        print()
    

    Lines 179-200: Print comprehensive summary of what was demonstrated


    Lines 202-210: Main Execution Block

    if __name__ == "__main__":
        # Check for API key
        if not os.getenv("OPENAI_API_KEY"):
            print("Error: OPENAI_API_KEY not found in environment variables.")
            print("Please set it in your .env file or environment.")
            exit(1)
    
        demonstrate_react_pattern()
    

    Line 202: Check if script is run directly (not imported)
    Lines 203-206: Validate API key exists – Line 204: Check if OPENAI_API_KEY environment variable is set – Lines 205-206: Print error message if not found – Line 207: Exit with error code 1

    Line 209: Run the demonstration function


    Key Concepts Summary

    1. ReAct Loop

    The agent repeatedly executes: Thought → Action → Observation until the task is complete.

    2. Tools

    Functions wrapped in LangChain’s Tool class that the agent can invoke.

    3. Prompt Template

    Structured format that guides the agent’s reasoning process.

    4. Agent Executor

    Manages the execution loop, tool calls, and error handling.

    5. LLM Integration

    Uses ChatOpenAI to power the reasoning and decision-making.


    Execution Flow

    1. User asks a question
    2. Agent thinks about what to do (Thought)
    3. Agent selects and invokes a tool (Action + Action Input)
    4. Tool executes and returns result (Observation)
    5. Steps 2-4 repeat as needed
    6. Agent provides final answer when task is complete

    Best Practices Demonstrated

    ✅ Type hints for better code documentation
    ✅ Error handling with try-except blocks
    ✅ Environment variables for sensitive data (API keys)
    ✅ Verbose mode for debugging and understanding
    ✅ Max iterations to prevent infinite loops
    ✅ Clear tool descriptions to guide agent behavior
    ✅ Comprehensive documentation with docstrings and comments


    Common Pitfalls to Avoid

    ❌ Don’t use eval() in production without proper sandboxing
    ❌ Don’t hardcode API keys in source code
    ❌ Don’t forget to set max_iterations
    ❌ Don’t make tool descriptions ambiguous
    ❌ Don’t ignore error handling


    Further Improvements

    • Add more sophisticated tools (web search, databases)
    • Implement custom tool error handling
    • Add tool result validation
    • Implement conversation memory
    • Add logging for production monitoring