Skip to content

Chain of Thought Examples

Chain of Thought (CoT) is a prompting technique that improves LLM reasoning by explicitly requesting step-by-step thinking before producing the final answer.

Overview

The ChainOfThought module automatically adds a "reasoning" field to any signature, encouraging the LLM to show its work:

from udspy import ChainOfThought, Signature, InputField, OutputField

class QA(Signature):
    """Answer questions."""
    question: str = InputField()
    answer: str = OutputField()

# Automatically adds reasoning step
cot = ChainOfThought(QA)
result = cot(question="What is 15 * 23?")

print(result.reasoning)  # Step-by-step calculation
print(result.answer)     # "345"

Basic Usage

Simple Question Answering

import udspy
from udspy import LM

lm = LM(model="gpt-4o-mini", api_key="your-key")
udspy.settings.configure(lm=lm)

class QA(Signature):
    """Answer questions clearly."""
    question: str = InputField()
    answer: str = OutputField()

predictor = ChainOfThought(QA)
result = predictor(question="What is the capital of France?")

print("Reasoning:", result.reasoning)
# "Let me recall the capital cities of European countries.
#  France is a major European nation, and its capital is Paris."

print("Answer:", result.answer)
# "Paris"

Math Problems

Chain of Thought excels at mathematical reasoning:

result = predictor(question="What is 17 * 24?")

print("Reasoning:", result.reasoning)
# "I'll break this down: 17 * 24 = 17 * 20 + 17 * 4 = 340 + 68 = 408"

print("Answer:", result.answer)
# "408"

Advanced Usage

Custom Reasoning Description

Customize how the reasoning field is described:

cot = ChainOfThought(
    QA,
    reasoning_description="Detailed mathematical proof with all intermediate steps"
)

result = cot(question="Prove that the sum of angles in a triangle is 180 degrees")

Multiple Output Fields

Chain of Thought works with signatures that have multiple outputs:

class Analysis(Signature):
    """Analyze text comprehensively."""
    text: str = InputField()
    summary: str = OutputField(description="Brief summary")
    sentiment: str = OutputField(description="Sentiment analysis")
    keywords: list[str] = OutputField(description="Key terms")

analyzer = ChainOfThought(Analysis)
result = analyzer(text="Long article text here...")

# Access all outputs plus reasoning
print(result.reasoning)   # Analysis process
print(result.summary)     # Summary
print(result.sentiment)   # Sentiment
print(result.keywords)    # Keywords

With Custom Model Parameters

# Use with specific model and temperature
cot = ChainOfThought(
    QA,
    model="gpt-4",
    temperature=0.0,  # Deterministic for math
)

result = cot(question="What is the square root of 144?")

Comparison: With vs Without CoT

Without Chain of Thought

from udspy import Predict

predictor = Predict(QA)
result = predictor(question="Why is the sky blue?")

print(result.answer)
# "The sky is blue due to Rayleigh scattering."

With Chain of Thought

cot_predictor = ChainOfThought(QA)
result = cot_predictor(question="Why is the sky blue?")

print(result.reasoning)
# "Let me explain the physics: Sunlight contains all colors. As it enters
#  the atmosphere, it interacts with air molecules. Blue light has shorter
#  wavelengths and scatters more than other colors (Rayleigh scattering).
#  This scattered blue light reaches our eyes from all directions."

print(result.answer)
# "The sky appears blue because blue light scatters more in the atmosphere
#  due to its shorter wavelength (Rayleigh scattering)."

Benefits: - More detailed and accurate answers - Shows the reasoning process - Better for complex or multi-step problems - Easier to verify correctness

Best Practices

1. Use for Complex Tasks

Chain of Thought shines for tasks requiring reasoning:

# Good use cases
- Math problems
- Logic puzzles
- Multi-step analysis
- Proof generation
- Planning tasks

# Less useful for
- Simple factual recall ("What is 2+2?")
- Classification without reasoning
- Direct information retrieval

2. Adjust Temperature

# For deterministic tasks (math, logic)
cot = ChainOfThought(QA, temperature=0.0)

# For creative reasoning
cot = ChainOfThought(QA, temperature=0.7)

3. Review Reasoning Quality

Always check if reasoning makes sense:

result = cot(question="Complex problem")

if "step" in result.reasoning.lower():
    print("✓ Good reasoning structure")

if len(result.reasoning) < 50:
    print("⚠ Reasoning might be too brief")

Real-World Examples

Code Review Reasoning

class CodeReview(Signature):
    """Review code for issues."""
    code: str = InputField()
    issues: list[str] = OutputField()
    severity: str = OutputField()

reviewer = ChainOfThought(CodeReview)
result = reviewer(code="""
def divide(a, b):
    return a / b
""")

print(result.reasoning)
# "Let me analyze this code:
#  1. No error handling for division by zero
#  2. No type checking
#  3. No documentation
#  These are significant issues."

print(result.issues)
# ["Division by zero not handled", "Missing type hints", "No docstring"]

print(result.severity)
# "High - can cause runtime errors"

Decision Making

class Decision(Signature):
    """Make informed decisions."""
    situation: str = InputField()
    options: list[str] = InputField()
    decision: str = OutputField()
    justification: str = OutputField()

decider = ChainOfThought(Decision)
result = decider(
    situation="Need to scale database, budget is tight",
    options=["Vertical scaling", "Horizontal scaling", "Managed service"]
)

print(result.reasoning)
# "Let me evaluate each option:
#  - Vertical: Quick but limited and expensive long-term
#  - Horizontal: Complex but scalable
#  - Managed: Higher cost but less maintenance
#  Given budget constraints..."

print(result.decision)
print(result.justification)

See the full example in the repository.