Agentic Design Pattern: Chain Of Thought

Written by

in


    """
Pattern 002: Chain-of-Thought (CoT)

Description:
    Agent breaks down complex problems into intermediate reasoning steps.
    CoT prompting encourages the model to explain its reasoning process
    step-by-step before arriving at a final answer.

Variants:
    - Zero-shot CoT: "Let's think step by step..."
    - Few-shot CoT: Provides examples with reasoning steps
    - Auto-CoT: Automatically generates reasoning examples

Use Cases:
    - Mathematical reasoning
    - Logical puzzles
    - Complex analysis tasks
    - Multi-step problem solving

LangChain Implementation:
    Uses structured prompts and output parsers to ensure step-by-step reasoning.
"""

import os
from typing import List, Dict, Any
from dotenv import load_dotenv

from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI
from langchain.chains import LLMChain

# Load environment variables
load_dotenv()


# Few-shot examples demonstrating Chain-of-Thought reasoning
COT_EXAMPLES = [
    {
        "question": "Roger has 5 tennis balls. He buys 2 more cans of tennis balls. Each can has 3 tennis balls. How many tennis balls does he have now?",
        "reasoning": """Let me think step by step:
1. Roger starts with 5 tennis balls
2. He buys 2 cans of tennis balls
3. Each can contains 3 tennis balls
4. So he gets 2 × 3 = 6 new tennis balls
5. Total tennis balls = 5 (original) + 6 (new) = 11

Therefore, Roger has 11 tennis balls now.""",
        "answer": "11"
    },
    {
        "question": "If it takes 5 machines 5 minutes to make 5 widgets, how long would it take 100 machines to make 100 widgets?",
        "reasoning": """Let me think step by step:
1. 5 machines make 5 widgets in 5 minutes
2. This means each machine makes 1 widget in 5 minutes
3. The machines work in parallel (simultaneously)
4. So 100 machines working in parallel would still take 5 minutes
5. In 5 minutes, 100 machines would make 100 widgets (1 widget per machine)

Therefore, it would take 5 minutes.""",
        "answer": "5 minutes"
    }
]


class ChainOfThoughtAgent:
    """Agent that uses Chain-of-Thought reasoning."""
    
    def __init__(self, model_name: str = "gpt-3.5-turbo", temperature: float = 0):
        """Initialize the Chain-of-Thought agent."""
        self.llm = ChatOpenAI(
            model=model_name,
            temperature=temperature,
            api_key=os.getenv("OPENAI_API_KEY")
        )
    
    def zero_shot_cot(self, question: str) -> Dict[str, str]:
        """
        Zero-shot Chain-of-Thought: Uses "Let's think step by step" prompt.
        
        Args:
            question: The question to answer
            
        Returns:
            Dictionary with reasoning and answer
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", "You are a helpful assistant that solves problems step-by-step."),
            ("human", "{question}\n\nLet's think step by step:")
        ])
        
        chain = prompt | self.llm | StrOutputParser()
        
        reasoning = chain.invoke({"question": question})
        
        # Extract final answer
        answer_prompt = ChatPromptTemplate.from_messages([
            ("system", "Based on the reasoning provided, give only the final answer concisely."),
            ("human", "Reasoning:\n{reasoning}\n\nFinal answer:")
        ])
        
        answer_chain = answer_prompt | self.llm | StrOutputParser()
        answer = answer_chain.invoke({"reasoning": reasoning})
        
        return {
            "question": question,
            "reasoning": reasoning,
            "answer": answer.strip()
        }
    
    def few_shot_cot(self, question: str, examples: List[Dict] = None) -> Dict[str, str]:
        """
        Few-shot Chain-of-Thought: Provides examples with reasoning steps.
        
        Args:
            question: The question to answer
            examples: List of example question-reasoning-answer triplets
            
        Returns:
            Dictionary with reasoning and answer
        """
        if examples is None:
            examples = COT_EXAMPLES
        
        # Create few-shot prompt template
        example_prompt = ChatPromptTemplate.from_messages([
            ("human", "{question}"),
            ("ai", "{reasoning}\n\nAnswer: {answer}")
        ])
        
        few_shot_prompt = FewShotChatMessagePromptTemplate(
            example_prompt=example_prompt,
            examples=examples
        )
        
        final_prompt = ChatPromptTemplate.from_messages([
            ("system", "You are a helpful assistant that solves problems step-by-step. Show your reasoning process clearly."),
            few_shot_prompt,
            ("human", "{question}")
        ])
        
        chain = final_prompt | self.llm | StrOutputParser()
        
        response = chain.invoke({"question": question})
        
        # Parse response to separate reasoning and answer
        lines = response.strip().split('\n')
        answer_line = [line for line in lines if line.strip().startswith("Answer:")]
        
        if answer_line:
            answer = answer_line[0].replace("Answer:", "").strip()
            reasoning = response.replace(answer_line[0], "").strip()
        else:
            # If no explicit answer line, last line is the answer
            reasoning = '\n'.join(lines[:-1])
            answer = lines[-1].strip()
        
        return {
            "question": question,
            "reasoning": reasoning,
            "answer": answer
        }
    
    def auto_cot(self, question: str) -> Dict[str, str]:
        """
        Auto-CoT: Automatically generates reasoning with structured steps.
        
        Args:
            question: The question to answer
            
        Returns:
            Dictionary with reasoning and answer
        """
        prompt = ChatPromptTemplate.from_messages([
            ("system", """You are a helpful assistant that solves problems systematically.
For each problem:
1. Break it down into clear steps
2. Number each step
3. Show your work clearly
4. Provide a final answer

Format your response as:
Step 1: [description]
Step 2: [description]
...
Final Answer: [answer]"""),
            ("human", "{question}")
        ])
        
        chain = prompt | self.llm | StrOutputParser()
        
        response = chain.invoke({"question": question})
        
        # Parse response
        lines = response.strip().split('\n')
        final_answer_line = [line for line in lines if "final answer" in line.lower()]
        
        if final_answer_line:
            answer = final_answer_line[0].split(':', 1)[-1].strip()
            reasoning = '\n'.join([line for line in lines if line not in final_answer_line])
        else:
            reasoning = response
            answer = "Unable to extract final answer"
        
        return {
            "question": question,
            "reasoning": reasoning,
            "answer": answer
        }


def demonstrate_cot_pattern():
    """Demonstrates the Chain-of-Thought pattern with various approaches."""
    
    print("=" * 80)
    print("PATTERN 002: Chain-of-Thought (CoT)")
    print("=" * 80)
    print()
    
    # Create CoT agent
    agent = ChainOfThoughtAgent()
    
    # Test questions
    test_questions = [
        "A farmer has 17 sheep and all but 9 die. How many sheep are left?",
        "If a train travels 120 km in 2 hours, how far will it travel in 5 hours at the same speed?",
        "Lisa has 10 apples. She gives 3 to her friend and buys 5 more. Her friend gives back 1 apple. How many apples does Lisa have now?"
    ]
    
    # Demonstrate Zero-shot CoT
    print("\n" + "=" * 80)
    print("ZERO-SHOT CHAIN-OF-THOUGHT")
    print("=" * 80)
    
    for i, question in enumerate(test_questions[:2], 1):
        print(f"\n{'- ' * 40}")
        print(f"Question {i}: {question}")
        print('- ' * 40)
        
        try:
            result = agent.zero_shot_cot(question)
            print(f"\nReasoning:\n{result['reasoning']}")
            print(f"\n✓ Answer: {result['answer']}")
        except Exception as e:
            print(f"\n✗ Error: {str(e)}")
    
    # Demonstrate Few-shot CoT
    print("\n\n" + "=" * 80)
    print("FEW-SHOT CHAIN-OF-THOUGHT")
    print("=" * 80)
    
    for i, question in enumerate(test_questions[1:], 1):
        print(f"\n{'- ' * 40}")
        print(f"Question {i}: {question}")
        print('- ' * 40)
        
        try:
            result = agent.few_shot_cot(question)
            print(f"\nReasoning:\n{result['reasoning']}")
            print(f"\n✓ Answer: {result['answer']}")
        except Exception as e:
            print(f"\n✗ Error: {str(e)}")
    
    # Demonstrate Auto-CoT
    print("\n\n" + "=" * 80)
    print("AUTO-COT (STRUCTURED STEPS)")
    print("=" * 80)
    
    question = test_questions[2]
    print(f"\n{'- ' * 40}")
    print(f"Question: {question}")
    print('- ' * 40)
    
    try:
        result = agent.auto_cot(question)
        print(f"\nReasoning:\n{result['reasoning']}")
        print(f"\n✓ Answer: {result['answer']}")
    except Exception as e:
        print(f"\n✗ Error: {str(e)}")
    
    # Summary
    print("\n\n" + "=" * 80)
    print("CHAIN-OF-THOUGHT PATTERN DEMONSTRATION COMPLETE")
    print("=" * 80)
    print()
    print("CoT Variants Demonstrated:")
    print("1. Zero-shot CoT: 'Let's think step by step' prompting")
    print("2. Few-shot CoT: Examples with reasoning provided")
    print("3. Auto-CoT: Structured step-by-step format")
    print()
    print("Key Benefits:")
    print("- Improved accuracy on complex tasks")
    print("- Transparent reasoning process")
    print("- Better error detection")
    print("- Enhanced interpretability")
    print()
    print("LangChain Components Used:")
    print("- ChatPromptTemplate: Structures prompts")
    print("- FewShotChatMessagePromptTemplate: Manages few-shot examples")
    print("- StrOutputParser: Parses LLM outputs")
    print("- Chain composition: Connects components")
    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_cot_pattern()

    

Agentic Design Pattern: Chain Of Thought

Pattern 002: Chain Of Thought – Line-by-Line Explanation

Overview

This document provides a detailed line-by-line explanation of the Chain Of Thought pattern implementation.


Pattern Description

Pattern 002: Chain-of-Thought (CoT)

Description: Agent breaks down complex problems into intermediate reasoning steps. CoT prompting encourages the model to explain its reasoning process step-by-step before arriving at a final answer.

Variants: – Zero-shot CoT: “Let’s think step by step…” – Few-shot CoT: Provides examples with reasoning steps – Auto-CoT: Automatically generates reasoning examples

Use Cases: – Mathematical reasoning – Logical puzzles – Complex analysis tasks – Multi-step problem solving

LangChain Implementation: Uses structured prompts and output parsers to ensure step-by-step reasoning.


File Statistics

  • Total Lines: 313
  • Classes: 1
  • Functions: 1
  • Constants: 1

Module Documentation

"""
Pattern 002: Chain-of-Thought (CoT)

Description:
    Agent breaks down complex problems into intermediate reasoning steps.
    CoT prompting encourages the model to explain its reasoning process
    step-by-step before arriving at a final answer.

Variants:
    - Zero-shot CoT: "Let's think step by step..."
    - Few-shot CoT: Provides examples with reasoning steps
    - Auto-CoT: Automatically generates reasoning examples

Use Cases:
    - Mathematical reasoning
    - Logical puzzles
    - Complex analysis tasks
    - Multi-step problem solving

LangChain Implementation:
    Uses structured prompts and output parsers to ensure step-by-step reasoning.
"""

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


Import Statements

Standard Library Imports

import langchain_core.output_parsers.StrOutputParser
import langchain_core.prompts.ChatPromptTemplate
import langchain_core.prompts.FewShotChatMessagePromptTemplate
import os
import typing.Any
import typing.Dict
import typing.List

Purpose: Core Python functionality: – langchain_core.output_parsers.StrOutputParser: Regular expression operations – langchain_core.prompts.ChatPromptTemplate: Regular expression operations – langchain_core.prompts.FewShotChatMessagePromptTemplate: Regular expression operations – os: Environment variable access and system operations – typing.Any: Type hints for better code documentation (List, Dict, Any, Optional) – typing.Dict: Type hints for better code documentation (List, Dict, Any, Optional) – typing.List: Type hints for better code documentation (List, Dict, Any, Optional)

LangChain Imports

from langchain.chains.LLMChain
from langchain_openai.ChatOpenAI

Purpose: LangChain framework components: – LLM Interface: Wrapper for OpenAI models – Chains: Composable building blocks for complex workflows

Other Imports

from dotenv.load_dotenv

Purpose: Additional dependencies for specialized functionality.


Module Constants

COT_EXAMPLES

COT_EXAMPLES = [

Line 38: Module-level constant definition.


Classes

Class: ChainOfThoughtAgent

Lines 66-209

Purpose:

Agent that uses Chain-of-Thought reasoning.

Methods:

__init__(self, model_name, temperature)

Lines 69-75

Purpose:

Initialize the Chain-of-Thought agent.

Parameters: – model_name: Language model instance – temperature: Sampling temperature (0-1)

zero_shot_cot(self, question)

Lines 77-109

Purpose:

Zero-shot Chain-of-Thought: Uses "Let's think step by step" prompt.

Args:
    question: The question to answer

Returns:
    Dictionary with reasoning and answer

Parameters: – question: Question to answer

Returns: <ast.Subscript object at 0x000001A06D60E590>

few_shot_cot(self, question, examples)

Lines 111-162

Purpose:

Few-shot Chain-of-Thought: Provides examples with reasoning steps.

Args:
    question: The question to answer
    examples: List of example question-reasoning-answer triplets

Returns:
    Dictionary with reasoning and answer

Parameters: – question: Question to answer – examples: Examples

Returns: <ast.Subscript object at 0x000001A06D608810>

auto_cot(self, question)

Lines 164-209

Purpose:

Auto-CoT: Automatically generates reasoning with structured steps.

Args:
    question: The question to answer

Returns:
    Dictionary with reasoning and answer

Parameters: – question: Question to answer

Returns: <ast.Subscript object at 0x000001A06D5F7F50>


Functions

demonstrate_cot_pattern()

Lines 212-302

Purpose:

Demonstrates the Chain-of-Thought pattern with various approaches.

Key Concepts Summary

Pattern Overview

The Chain Of Thought 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

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 001
  • Pattern 003
  • 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 Chain Of Thought 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: 002_chain_of_thought.py
Total Lines: 313
Pattern Category: AI Agent Design Pattern #002


Generated from actual implementation code
For educational and reference purposes

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *