Chain-of-Thought (CoT) is one of the most impactful prompting techniques. Instead of asking directly, ask the model to show its reasoning. Results are dramatically better.
Why It Works
Without CoT
Question: "I have 10 apples. I eat 3. My friend gives 5. How many now?"
Direct: "You have 12 apples"
✓ Correct but luck
Complex math:
"A train leaves A for B (200km) at 100 km/h. A car leaves B at 80 km/h.
When do they meet?"
Direct: "After 2 hours"
✗ Wrong! (Correct: 1.1 hours)
Model didn't think—it guessed pattern.
With CoT
"...When do they meet?
Let me think step by step."
Model:
"1. Train: 100 km/h from A
2. Car: 80 km/h from B
3. Combined approach: 180 km/h
4. Time to cover 200 km: 200/180 = 1.11 hours
They meet after ~1 hour 7 minutes"
✓ Correct!
Triggering "let me think" activates reasoning pathways.
Variants
Zero-Shot CoT (Simple)
# Without
"What is the answer to X?"
# With
"What is the answer to X? Let me think step by step:"
Improvement: +5-40% accuracy depending on task
Cost: More output tokens (but worth it)
Few-Shot CoT
prompt = """
Example 1:
Question: 2+2?
Thought: 2+2 = 4
Answer: 4
Example 2:
Question: 10+15?
Thought: 10+15 = 25
Answer: 25
New Question: 123+456?
Thought: [model thinks]
Answer: [model answers]
"""
Improvement: +10-50% vs zero-shot CoT
Cost: Longer prompt
Self-Consistency Decoding
Generate CoT multiple times, vote on answer:
def self_consistent_answer(question, num_tries=5):
answers = []
for i in range(num_tries):
response = llm(f"{question}\n\nLet me think:")
answer = extract_answer(response)
answers.append(answer)
# Voting
return max(set(answers), key=answers.count)
# Cost: 5× more tokens
# Quality: +5-15% accuracy
# Use only for critical decisions
Tree-of-Thought (ToT)
Explore multiple reasoning paths, not just linear:
Problem: Best chess strategy?
Thought 1: Attack king
├─ With knight
└─ With pawn
└─ Verdict: Pawn better
Thought 2: Defend
├─ With rook
└─ With bishop
[LLM evaluates which path most promising]
Cost: 10-100× more tokens
Rarely used (complex).
Extended Thinking (Claude, New)
response = client.messages.create(
model="claude-3-7-sonnet",
max_tokens=16000,
thinking={
"type": "enabled",
"budget_tokens": 10000 # internal thinking
},
messages=[{
"role": "user",
"content": "Complex math problem..."
}]
)
# Claude thinks internally (invisible)
# Output more precise than visible CoT
vs CoT: Internal thinking often better (+5-20% quality), same cost.
When CoT Helps
Complex math: ✅ CoT +40% improvement
Multi-step reasoning: ✅ CoT +30%
Code writing: ✅ CoT +25%
Logic puzzles: ✅ CoT +50%
Simple factual QA: ❌ CoT helps 0%, wastes tokens
Summarization: ❌ CoT creates filler text
Classification (label): ❌ CoT makes output longer
Sentiment analysis: ❌ Overkill
Empirical Results
GPT-4 on Complex Tasks
| Task | No CoT | CoT | Improvement |
|---|---|---|---|
| Math (SVAMP) | 67% | 92% | +25% |
| Code (MGSM) | 71% | 83% | +12% |
| Commonsense | 58% | 81% | +23% |
| Logic | 42% | 96% | +54% |
Cost-Benefit
Math problem (no CoT):
- Tokens: 200
- Accuracy: 65%
- Cost: €0.006
Math problem (with CoT):
- Tokens: 600
- Accuracy: 92%
- Cost: €0.018
Error cost comparison:
- Without: 35% error rate
- With: 8% error rate
- Value per error prevention: Worth it if critical!
Rule: If error is expensive (medicine, code) → use CoT always
If error is cheap (UI text) → usually skip CoT
Best Practices
# 1. Trigger correctly
wrong = "What is the answer?"
right = "Let me think step by step:"
# 2. Combine with few-shot
prompt = """
Example 1: [with CoT thinking]
Example 2: [with CoT thinking]
New question:
Let me think step by step:"""
# 3. Don't overdo examples
too_much = """Thought: Step 1... Step 2... [50 lines]"""
good = """Thought: First A, then B, then C"""
# 4. Structure for complex tasks
prompt = """
Analyze:
1. Given:
2. Find:
3. Solution:
"""
# 5. Use self-consistency for critical decisions
if critical_decision:
answer = self_consistent_answer(question, num_tries=5)
else:
answer = llm(question + "\nThinking:")
CoT is simple magic: +20-50% quality for +200-400 extra tokens. Standard best practice. Always use for reasoning tasks.
Sources and Links
- Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
- Large Language Models are Zero-Shot Reasoners
Advanced CoT Techniques
Least-to-Most Prompting (Breaking Down Hard Problems)
def least_to_most_prompt(problem):
"""Break hard problems into simpler subproblems."""
# Step 1: Identify subproblems
subproblem_prompt = f"""
Given this complex problem, what are the prerequisite simpler problems we need to solve first?
Problem: {problem}
Subproblems (ordered from simple to complex):"""
subproblems = llm(subproblem_prompt)
# Step 2: Solve each subproblem in order
solutions = []
for subproblem in parse_subproblems(subproblems):
solution_prompt = f"""
Solve this step:
{subproblem}
Solution:"""
solution = llm(solution_prompt)
solutions.append(solution)
# Step 3: Combine to solve original
combine_prompt = f"""
Using these solutions to subproblems:
{chr(10).join(solutions)}
Solve the original problem:
{problem}
Answer:"""
final_answer = llm(combine_prompt)
return final_answer
# Example: "Build a web server from scratch"
# Subproblems:
# 1. What is TCP/IP?
# 2. How do sockets work?
# 3. How do HTTP requests work?
# 4. How to parse HTTP?
# 5. How to send responses?
Effectiveness: +30-40% for highly complex problems
Plan-and-Solve (Explicit Planning Phase)
def plan_and_solve(task):
"""Explicit planning before solving."""
# Phase 1: Create plan
plan_prompt = f"""
Task: {task}
Create a detailed step-by-step plan. Don't solve yet, just outline:
1. ...
2. ...
3. ..."""
plan = llm(plan_prompt)
# Phase 2: Execute plan
solve_prompt = f"""
Here's the plan:
{plan}
Now execute it step-by-step:
Step 1:
Step 2:
..."""
solution = llm(solve_prompt)
return solution
# Improvement: +15-25% vs basic CoT
# Why: Separating planning from execution clarifies thinking
Contrastive CoT (Reasoning by Comparison)
def contrastive_cot(question):
"""Show both correct AND incorrect reasoning."""
prompt = f"""
Question: {question}
WRONG approach (and why it fails):
[Model thinks through a common wrong method]
CORRECT approach:
[Model thinks through right method]
Answer: """
response = llm(prompt)
return response
# Result: +10-20% accuracy
# Helps model avoid common traps
Cost-Benefit Analysis
When CoT is Worth It
def should_use_cot(task_type, error_cost, question_frequency):
"""Determine if CoT is economically justified."""
# Variables
tokens_without_cot = 200
tokens_with_cot = 600
accuracy_without = 0.70
accuracy_with = 0.92
token_cost = 0.001 # €0.001 per 1000 tokens
cost_per_question_without = tokens_without_cot * token_cost / 1000
cost_per_question_with = tokens_with_cot * token_cost / 1000
# Error cost
error_rate_without = 1 - accuracy_without
error_rate_with = 1 - accuracy_with
annual_volume = question_frequency * 365
# Annual cost breakdown
cost_tokens_without = cost_per_question_without * annual_volume
cost_tokens_with = cost_per_question_with * annual_volume
cost_errors_without = error_rate_without * annual_volume * error_cost
cost_errors_with = error_rate_with * annual_volume * error_cost
total_without = cost_tokens_without + cost_errors_without
total_with = cost_tokens_with + cost_errors_with
savings = total_without - total_with
print(f"Total annual cost (no CoT): €{total_without:.0f}")
print(f"Total annual cost (with CoT): €{total_with:.0f}")
print(f"Annual savings: €{savings:.0f}")
return savings > 0
# Example: 100 math questions/day, €50 cost per error
should_use_cot("math", error_cost=50, question_frequency=100)
# Result: YES (saves €6,570/year)
Per-Task Recommendation Matrix
| Task | CoT? | Reason | Token Cost |
|---|---|---|---|
| Math problem | ✅ YES | 40% accuracy gain | +400 |
| Write code | ✅ YES | 25% error reduction | +300 |
| Multiple-choice | ⚠️ MAYBE | Only for hard questions | +100 |
| Factual QA | ❌ NO | Wastes tokens | +200 |
| Summary | ❌ NO | Adds fluff | +150 |
| Classification | ❌ NO | Just label needed | +200 |
| Brainstorm | ✅ YES | More creative | +200 |
| Translation | ❌ NO | Direct better | +100 |
Prompt Structure for CoT Mastery
Structure 1: Step-by-Step Explicit
prompt = """
Problem: [problem]
Let me solve this step by step:
Step 1 - [specific action]:
Step 2 - [specific action]:
Step 3 - [specific action]:
Therefore, the answer is:"""
Structure 2: Show Your Work
prompt = """
Problem: [problem]
First, I'll identify what we know:
- [fact 1]
- [fact 2]
Next, I'll apply the relevant principle:
[principle]
Calculating:
[calculation shown]
Answer: [final answer]"""
Structure 3: Compare Approaches
prompt = """
Problem: [problem]
Approach 1 (Method A):
[reasoning]
Result: [answer]
Approach 2 (Method B):
[reasoning]
Result: [answer]
The better approach is [Method X] because [reason].
Final answer: [answer]"""
Pitfalls & Solutions
Pitfall 1: CoT Makes Model Verbose Without Improving Accuracy
# WRONG: Just asking for reasoning
prompt = "Solve: What's 15 × 8?"
# Result: "Let me think step by step. 15 × 8 equals... let me see... 15 times 8... [rambling]"
# May get wrong answer AFTER long explanation
# RIGHT: Structure the CoT
prompt = """
Calculate 15 × 8
Breaking it down:
15 × 8 = (10 + 5) × 8 = 80 + 40 = 120
Answer: 120"""
Pitfall 2: Too Much Reasoning Path Exploration
# WRONG: Exploring every possible path
prompt = "Solve this logic puzzle. Consider all possibilities."
# Result: Model explores 50 branches, gets lost
# RIGHT: Bounded reasoning
prompt = """
Solve this logic puzzle.
Evaluate the top 3 most likely approaches.
Pick the best one.
Answer:"""
Pitfall 3: CoT with Trained Models
# Models trained SPECIFICALLY for CoT (e.g., o1) sometimes perform worse
# when explicitly asked for CoT (they already do it internally)
# For extended thinking models:
# USE: Let them think internally
response = client.messages.create(
model="o1", # Already does deep reasoning
max_tokens=10000,
messages=[{"role": "user", "content": "Hard problem..."}]
)
# DON'T: Ask for explicit CoT (redundant)
# response = client.messages.create(
# model="o1",
# messages=[{"role": "user", "content": "Hard problem...\n\nThink step by step..."}]
# )
CoT in Production
class CoTProcessor:
def __init__(self, client, model="claude-3-5-sonnet"):
self.client = client
self.model = model
self.reasoning_tasks = [
"math", "logic", "code_analysis", "multi-step"
]
def should_use_cot(self, task_type):
return task_type in self.reasoning_tasks
def process(self, question, task_type):
if self.should_use_cot(task_type):
prompt = f"{question}\n\nLet me think step by step:"
else:
prompt = question
response = self.client.messages.create(
model=self.model,
max_tokens=2000,
messages=[{"role": "user", "content": prompt}]
)
return {
"answer": response.content[0].text,
"used_cot": self.should_use_cot(task_type),
"tokens": response.usage.output_tokens
}
# Usage
processor = CoTProcessor(client)
result = processor.process(
"If A > B and B > C, is A > C?",
task_type="logic"
)
Combining CoT with Other Techniques
CoT + Few-Shot + Self-Consistency (Maximum Quality)
def premium_reasoning(question, critical=True):
"""Maximum quality reasoning for critical decisions."""
base_prompt = """
Example 1:
Q: 5 + 3 × 2?
Thought: PEMDAS — multiply first. 5 + (3 × 2) = 5 + 6 = 11
A: 11
Example 2:
Q: (5 + 3) × 2?
Thought: Parentheses first. (5 + 3) = 8. Then 8 × 2 = 16
A: 16
Q: {question}
Thought: """
if critical:
# Use self-consistency
answers = []
for i in range(3):
response = llm(base_prompt.format(question=question))
answer = extract_final_answer(response)
answers.append(answer)
final_answer = max(set(answers), key=answers.count)
confidence = answers.count(final_answer) / len(answers)
else:
response = llm(base_prompt.format(question=question))
final_answer = extract_final_answer(response)
confidence = 1.0
return {
"answer": final_answer,
"confidence": confidence,
"uses_cot": True,
"uses_fewshot": True,
"uses_consistency": critical
}
Cost vs Benefit:
- Basic CoT: +3× tokens, +30% quality
- CoT + Few-shot: +5× tokens, +50% quality
- CoT + Few-shot + Consistency: +9× tokens, +60% quality (critical only)
Use premium reasoning when:
- Decision affects people's lives (medicine, finance)
- Irreversible consequences
- High monetary value
- Legal/compliance critical
