Module 4: Chain-of-Thought and Reasoning
3. Manual CoT: Designing Reasoning Chains
Overview
Manual CoT (also called Few-Shot CoT) hands the model complete examples with explicit reasoning. Unlike Zero-Shot CoT, where you only add a phrase, here you carefully design the reasoning steps you want the model to imitate. The standard format: Input → Reasoning → Answer.
In this capsule you'll learn to design effective reasoning chains for math, logic, code debugging, text analysis, and business decisions.
Estimated time: 75-90 minutes
Why Is Manual CoT More Powerful than Zero-Shot?
Zero-Shot CoT switches on generic reasoning patterns. Manual CoT lets you:
- Specify the exact reasoning style you want
- Define the level of detail (step by step vs. logical leaps allowed)
- Establish the technical vocabulary appropriate to your domain
- Control the output format precisely
- Demonstrate how to handle special cases or edge cases
Tradeoff: Manual CoT takes more up-front design, but it produces more consistent, more controlled reasoning.
The Standard Format
The canonical Manual CoT format is:
Q: [question or problem]
A: [explicit step-by-step reasoning] ... Answer: [final answer]
Or in a more explicit labeled format:
Input: [problem]
Reasoning: [step 1] → [step 2] → ... → [step N]
Answer: [final answer]
The Anatomy of a Good Example
An effective Manual CoT example has these characteristics:
- Complexity similar to the real problem: Not too simple, not too different
- Complete reasoning: It shows every step, it doesn't skip important intermediate steps
- Consistent terminology: It uses the same terms the model will use when answering
- A clear answer: The final answer is unambiguous, in the expected format
- Appropriate length: 3-8 steps depending on the complexity of the domain
A Complete Example: Word Arithmetic
from openai import OpenAI
client = OpenAI()
MATH_WORD_COT_PROMPT = """Solve each math problem showing every reasoning step.
Q: A store has 120 shirts. On Monday it sold 35. On Tuesday it received a shipment of 50 and sold 28. How many shirts does it have now?
A: Let's go step by step.
At the start: 120 shirts.
Monday: sold 35 → 120 - 35 = 85 shirts.
Tuesday received: 85 + 50 = 135 shirts.
Tuesday sold: 135 - 28 = 107 shirts.
Answer: 107 shirts.
Q: Anna earns $2,400 a month. She pays $720 in rent (30%), $360 in food (15%), and saves 20%. How much is left after all of that?
A: Let's go step by step.
Monthly salary: $2,400.
Rent: 30% of 2400 = 0.30 × 2400 = $720.
Food: 15% of 2400 = 0.15 × 2400 = $360.
Savings: 20% of 2400 = 0.20 × 2400 = $480.
Total spent/saved: 720 + 360 + 480 = $1,560.
Money left: 2400 - 1560 = $840.
Answer: $840.
Q: {problem}
A:"""
def solve_math_word(problem: str) -> str:
"""Solves a word arithmetic problem with Manual CoT."""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "user",
"content": MATH_WORD_COT_PROMPT.format(problem=problem)
}
],
temperature=0,
max_tokens=600
)
return response.choices[0].message.content
if __name__ == "__main__":
problem = """
A project has 3 teams. Team A does 40% of the work.
Team B does twice as much as team C.
If team C does 12 hours of work, how many hours does the project have in total?
"""
print(solve_math_word(problem))
Example: Formal Logical Reasoning
LOGIC_COT_PROMPT = """Analyze the validity of each logical argument, identifying the premises and the conclusion.
Q: If it rains, then the ground is wet. The ground is wet. Is it raining?
A: Let's go step by step.
Premise 1: If it rains → ground wet. (P → Q)
Premise 2: Ground wet. (Q is true)
Can we conclude that it's raining? (Is P true?)
Analysis: Having Q true does NOT guarantee P. The ground can be wet from sprinklers, a spill, etc.
This is the fallacy of "affirming the consequent".
Answer: INVALID. You cannot conclude that it's raining just because the ground is wet.
Q: All mammals are warm-blooded. Dolphins are mammals. Are dolphins warm-blooded?
A: Let's go step by step.
Premise 1: ∀x: mammal(x) → warm_blooded(x). (Universal)
Premise 2: a dolphin is a mammal.
Desired conclusion: a dolphin is warm-blooded.
Analysis: We apply modus ponens. For x = dolphin: mammal(dolphin) is true (premise 2). Therefore warm_blooded(dolphin) is true by premise 1.
Answer: VALID. Dolphins are indeed warm-blooded. A correct argument by modus ponens.
Q: {argument}
A:"""
def analyze_argument(argument: str) -> str:
"""Analyzes the validity of a logical argument with Manual CoT."""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "user",
"content": LOGIC_COT_PROMPT.format(argument=argument)
}
],
temperature=0,
max_tokens=500
)
return response.choices[0].message.content
Example: Code Debugging
CODE_DEBUG_COT_PROMPT = """Debug the Python code by identifying the error, explaining why it happens, and proposing the fix.
Q:
```python
def calculate_average(numbers):
total = 0
for n in numbers:
total += n
return total / len(numbers)
print(calculate_average([]))
A: Let's go step by step. Execution trace:
- calculate_average is called with the empty list [].
- The loop doesn't run (empty list).
- total = 0.
- return 0 / len([]) → 0 / 0. Error: ZeroDivisionError: division by zero. Root cause: There's no check for an empty list. Fix:
def calculate_average(numbers):
if not numbers:
return 0 # Or raise ValueError("Empty list")
total = sum(numbers)
return total / len(numbers)
Answer: ZeroDivisionError from an empty list. Add an if not numbers check.
Q:
names = ["Anna", "Beth", "Carl"]
for i in range(len(names) + 1):
print(f"Hello, {names[i]}!")
A: Let's go step by step. Execution trace:
- names has 3 elements: indices 0, 1, 2.
- range(len(names) + 1) = range(4) = [0, 1, 2, 3].
- Iteration i=0: names[0] = "Anna" → OK.
- Iteration i=1: names[1] = "Beth" → OK.
- Iteration i=2: names[2] = "Carl" → OK.
- Iteration i=3: names[3] → IndexError: list index out of range.
Error: IndexError at i=3 because the highest valid index is 2.
Root cause: range uses an unnecessary
+ 1. Fix:
for i in range(len(names)): # Drop the + 1
print(f"Hello, {names[i]}!")
# Or better still:
for name in names:
print(f"Hello, {name}!")
Answer: IndexError from range(len+1). Change it to range(len(names)) or iterate directly.
Q: {code} A:"""
def debug_code(code: str) -> str: """Debugs Python code with Manual CoT.""" response = client.chat.completions.create( model="gpt-4o-mini", messages=[ { "role": "user", "content": CODE_DEBUG_COT_PROMPT.format(code=code) } ], temperature=0, max_tokens=700 ) return response.choices[0].message.content
---
## Example: Contextual Sentiment Analysis
CoT isn't only for math. It works for ambiguous classification:
```python
SENTIMENT_COT_PROMPT = """Classify the sentiment of the text (POSITIVE, NEGATIVE, NEUTRAL or MIXED) by reasoning about each element.
Q: "The hotel had an incredible view, but the rooms smelled of damp and the breakfast service was painfully slow."
A: Let's go step by step.
Element 1: "incredible view" → very positive (a standout sensory experience).
Element 2: "rooms smelled of damp" → very negative (an unpleasant sensory experience, directly hits comfort).
Element 3: "painfully slow breakfast service" → negative (hurts convenience).
Count: 1 positive vs. 2 negatives.
Weight: Damp in the rooms is a bigger problem than the view is a benefit.
Conclusion: The text is predominantly negative with one positive element.
Answer: MIXED (leaning NEGATIVE). Confidence: 0.75.
Q: "Delivered on time as always. Thanks."
A: Let's go step by step.
Element 1: "Delivered on time" → positive (meets the expectation).
Element 2: "as always" → reinforces the positive (consistency).
Element 3: "Thanks" → mildly positive (an expression of gratitude).
There are no negative elements.
Conclusion: Clearly positive text, though moderate (no exceptional enthusiasm).
Answer: POSITIVE. Confidence: 0.90.
Q: {text}
A:"""
def analyze_sentiment(text: str) -> dict:
"""Analyzes sentiment with explicit reasoning."""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "user",
"content": SENTIMENT_COT_PROMPT.format(text=text)
}
],
temperature=0,
max_tokens=400
)
output = response.choices[0].message.content
# Parse the structured result
import re
sentiment_match = re.search(
r'Answer:\s*(POSITIVE|NEGATIVE|NEUTRAL|MIXED)',
output, re.IGNORECASE
)
confidence_match = re.search(r'Confidence:\s*(0\.\d+|1\.0)', output)
return {
"reasoning": output,
"sentiment": sentiment_match.group(1) if sentiment_match else "UNKNOWN",
"confidence": float(confidence_match.group(1)) if confidence_match else None
}
Example: Business Decisions
DECISION_COT_PROMPT = """Analyze the business decision by evaluating the key factors step by step.
Q: A 10-person startup has $200K in the bank. They burn $40K/month. They're offered a $500K investment round with 20% dilution. The CEO estimates that with that money they could reach break-even in 12 months. Without the investment, they have 5 months of runway. Should they take the investment?
A: Let's go step by step.
Current situation: $200K cash / $40K burn = 5 months of runway.
Option A (Take the investment):
- Cash after the round: 200K + 500K = $700K.
- Runway: 700K / 40K = 17.5 months.
- Dilution: the CEO and the team lose 20% of their stake.
- Upside: 12 months to reach break-even; if they make it, the remaining 80% could be worth far more.
Option B (Don't take the investment):
- Only 5 months to become profitable or find another source of capital.
- High time pressure; sub-optimal decisions under pressure.
- No dilution, but a high risk of shutting down.
Risk analysis: With 5 months, if break-even isn't reached, the startup dies. With 17.5 months, there's room to pivot if needed.
Qualitative factors: Quality of the investors, terms of the deal, the CEO's confidence in the 12-month plan.
Answer: TAKE THE INVESTMENT. The risk of running out of money in 5 months outweighs the cost of 20% dilution, especially if the investors add strategic value.
Q: {situation}
A:"""
Designing Examples: Advanced Principles
Principle 1: Diversity of Reasoning Types
Your examples should cover the different "types" of problem the model may run into:
# For a QA system over legal contracts
EXAMPLES_LEGAL = [
{
"input": "Can the client cancel the contract if the supplier delivers 3 days late?",
"type": "direct_interpretation",
"reasoning": """
Look for the delay clause in the contract.
Clause 8.2: "Delays under 5 business days do not constitute a material breach."
3 days < 5 days → It is not a material breach under the clause.
With no material breach, the client cannot cancel without a penalty.
Answer: NO, they cannot cancel without a penalty. A 3-day delay is not a material breach under clause 8.2."""
},
{
"input": "The contract says 'prices subject to CPI adjustment'. CPI rose 8.5% this year. How much does the $10,000/month price go up?",
"type": "calculation_with_interpretation",
"reasoning": """
Adjustment clause: price subject to CPI (Consumer Price Index).
Current price: $10,000/month.
CPI change: 8.5%.
Calculation: 10,000 × 1.085 = $10,850/month.
Increase: $850/month.
Answer: The new price is $10,850/month. An increase of $850/month."""
}
]
Principle 2: Consistency in the Answer Format
# ❌ Inconsistent format across examples
bad_example = """
Q: What is 5 × 7?
A: 5 times 7 = 35
Q: What is 8 × 9?
A: Let's go step by step. 8 × 9 = 72.
Answer: seventy-two
"""
# ✅ Consistent format
good_example = """
Q: What is 5 × 7?
A: Step by step.
5 × 7 = 35.
Answer: 35.
Q: What is 8 × 9?
A: Step by step.
8 × 9 = 72.
Answer: 72.
"""
Principle 3: Representative Difficulty
def select_examples(example_pool: list[dict], new_problem: str) -> list[dict]:
"""
Selects the most representative examples for a new problem.
In production, you could use embeddings for similarity search.
For prototypes, manual selection is enough.
"""
# Simplified: select by problem type
# In production: use sentence embeddings + cosine similarity
detected_type = detect_type(new_problem)
examples_of_type = [e for e in example_pool if e["type"] == detected_type]
# Select 2-3 examples from different sub-types
return examples_of_type[:3]
def detect_type(problem: str) -> str:
"""Detects the problem type in order to select examples."""
keywords = {
"arithmetic": ["how much", "total", "average", "percentage", "$", "price"],
"logic": ["implies", "if...then", "therefore", "valid", "all", "some"],
"code": ["def ", "class ", "error", "bug", "function", "python", "javascript"],
"decision": ["should i", "should we", "best option", "advantages", "disadvantages"],
}
problem_lower = problem.lower()
for problem_type, kwords in keywords.items():
if any(kw in problem_lower for kw in kwords):
return problem_type
return "general"
Comparison: Zero-Shot CoT vs. Manual CoT
| Aspect | Zero-Shot CoT | Manual CoT |
|---|---|---|
| Design effort | Minimal | High |
| Tokens in the prompt | Few | Many (examples) |
| Format consistency | Medium | High |
| Control over the reasoning | Low | High |
| Generalization | High | Medium (depends on the examples) |
| Best for | Prototypes, general domains | Production, specific domains |
| Cost per call | Lower | Higher (more input tokens) |
How Many Examples You Need
The research suggests a curve of diminishing returns:
| Number of examples | Typical improvement | Token cost |
|---|---|---|
| 0 (Zero-Shot) | Baseline | 0 extra |
| 1 example | +10-15% | ~200-400 tokens |
| 2-3 examples | +20-30% | ~400-800 tokens |
| 4-5 examples | +30-35% | ~800-1500 tokens |
| 6-8 examples | +35-37% | ~1500-2500 tokens |
| > 8 examples | Minimal returns | Very expensive |
Practical recommendation: 2-3 well-designed examples are almost always enough.
Advanced Implementation with Pydantic
from pydantic import BaseModel, Field
from openai import OpenAI
from typing import Literal
client = OpenAI()
class CoTExample(BaseModel):
"""Structure for a Manual CoT example."""
input_problem: str = Field(description="The problem or question")
reasoning: str = Field(description="The reasoning steps")
answer: str = Field(description="The final answer")
type: str = Field(default="general", description="Category of the problem")
class ManualCoTEngine:
"""A configurable reasoning engine built on Manual CoT."""
def __init__(
self,
examples: list[CoTExample],
system_instruction: str = "You are an assistant that reasons step by step.",
max_tokens: int = 700
):
self.examples = examples
self.system_instruction = system_instruction
self.max_tokens = max_tokens
def build_prompt(self, problem: str, n_examples: int = 3) -> str:
"""Builds the prompt with the selected examples."""
# Take the first n_examples (or all of them if there are fewer)
selected_examples = self.examples[:n_examples]
parts = []
for ex in selected_examples:
parts.append(
f"Q: {ex.input_problem}\n"
f"A: {ex.reasoning}\n"
f"Answer: {ex.answer}"
)
examples_prompt = "\n\n".join(parts)
return f"""{examples_prompt}
Q: {problem}
A:"""
def solve(self, problem: str, n_examples: int = 3) -> dict:
"""Solves a problem using Manual CoT."""
prompt = self.build_prompt(problem, n_examples)
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": self.system_instruction},
{"role": "user", "content": prompt}
],
temperature=0,
max_tokens=self.max_tokens
)
output = response.choices[0].message.content
return {
"problem": problem,
"full_reasoning": output,
"tokens_used": response.usage.total_tokens,
"n_examples_used": n_examples
}
# Using the engine
if __name__ == "__main__":
math_examples = [
CoTExample(
input_problem="A coffee shop sells 150 cups/day at $3.50 each. Variable costs are $1.20/cup and fixed costs $200/day. What is the daily profit?",
reasoning="Revenue: 150 × 3.50 = $525.\nVariable costs: 150 × 1.20 = $180.\nFixed costs: $200.\nTotal costs: 180 + 200 = $380.\nProfit: 525 - 380 = $145.",
answer="$145",
type="financial"
),
CoTExample(
input_problem="How many days does a team of 4 people take to finish a task that one person would do in 20 days?",
reasoning="Total work: 1 task = 20 person-days.\nTeam capacity: 4 people/day.\nDays needed: 20 / 4 = 5 days.",
answer="5 days",
type="work"
)
]
engine = ManualCoTEngine(
examples=math_examples,
system_instruction="You are an expert in business math. Solve step by step."
)
result = engine.solve(
"A company has 3 salespeople. In one month they sold $45,000, $38,000 and $52,000 respectively. The commission is 6% of total sales. How much commission does each salesperson earn?"
)
print(result["full_reasoning"])
print(f"\nTokens used: {result['tokens_used']}")
Troubleshooting
Problem 1: The model doesn't follow the example format
Symptoms: The model gives the answer with no reasoning, or uses a different format.
# ❌ Cause: The examples are in a different language than the problem
bad_prompt = """
Q: ¿Cuánto es 5 + 3?
A: Paso a paso. 5 + 3 = 8. Respuesta: 8.
Q: What is 7 × 6?
A:""" # The model may answer in Spanish or without the format
# ✅ Fix: Same language and format in the examples and the problem
good_prompt = """
Q: What is 5 + 3?
A: Step by step. 5 + 3 = 8. Answer: 8.
Q: What is 7 × 6?
A:"""
Problem 2: The examples are too simple
Symptoms: The model follows the format but applies shallow reasoning to the real problem.
# ❌ An example that's far too simple for complex problems
unsuitable_example = """
Q: What is 2 + 2?
A: 2 + 2 = 4. Answer: 4.
Q: [Complex conditional probability problem]
A:"""
# The model "imitates" the simplicity of the example
# ✅ Examples of a difficulty similar to the real problem
suitable_example = """
Q: [Moderate probability problem]
A: [5-6 steps of reasoning with probabilities]
Q: [Complex conditional probability problem]
A:"""
Problem 3: Fabricated reasoning in the examples
Symptoms: There are errors in the examples you wrote and the model imitates them.
# CRITICAL: ALWAYS verify that your examples are correct
def verify_example(example: CoTExample) -> bool:
"""
Verifies that a CoT example is correct, using another LLM as the verifier.
"""
verification_prompt = f"""
Verify whether the following mathematical reasoning is correct.
Problem: {example.input_problem}
Reasoning: {example.reasoning}
Answer: {example.answer}
Is it correct? Reply CORRECT or INCORRECT.
If there's an error, explain what it is.
"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": verification_prompt}],
temperature=0,
max_tokens=200
)
result = response.choices[0].message.content.upper()
return "CORRECT" in result
Problem 4: Prompts that get too long from too many examples
Symptoms: High costs, high latency, or context errors.
# ✅ Compress the examples without losing the structure
def compress_example(example: CoTExample) -> str:
"""A compressed version of an example, for long prompts."""
# Condense the reasoning down to the key points
steps = example.reasoning.split('\n')
important_steps = [p for p in steps if p.strip() and '→' in p or '=' in p]
compressed_reasoning = ' → '.join(important_steps[:4])
return f"Q: {example.input_problem[:100]}\nA: {compressed_reasoning} Answer: {example.answer}"
Exercises
Exercise 1: Build an example for an age problem
Design a complete Manual CoT example for this type of problem: "Anna is twice Louis's age. In 5 years their ages will add up to 40. How old is each of them now?"
See solution
ages_example = CoTExample(
input_problem="Peter is three times Sophie's age. Three years ago, their ages added up to 22. How old are they now?",
reasoning="""Define the variables: Let S = Sophie's current age. Peter = 3S (three times).
Three years ago: Sophie was (S-3), Peter was (3S-3).
Equation: (S-3) + (3S-3) = 22
Simplify: 4S - 6 = 22
4S = 28
S = 7
Peter = 3 × 7 = 21.
Check: Three years ago: 4 + 18 = 22 ✓""",
answer="Sophie is 7, Peter is 21."
)
# Now the prompt for the Anna and Louis problem
AGES_PROMPT = f"""Solve the age problem step by step using algebra.
Q: {ages_example.input_problem}
A: {ages_example.reasoning}
Answer: {ages_example.answer}
Q: Anna is twice Louis's age. In 5 years their ages will add up to 40. How old is each of them now?
A:"""
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": AGES_PROMPT}],
temperature=0,
max_tokens=400
)
print(response.choices[0].message.content)
# Expected answer: Louis = 10, Anna = 20
Exercise 2: Few-shot CoT for urgency classification
Design 3 Manual CoT examples to classify support tickets as URGENT, NORMAL or LOW. Then test with 5 new tickets.
See solution
SUPPORT_COT_PROMPT = """Classify the urgency of each support ticket (URGENT, NORMAL, LOW) by reasoning about the impact.
Q: "The payment system is down. We haven't been able to process a single transaction for 2 hours."
A: Let's go step by step.
Operational impact: Payment system = core business function.
Duration: 2 hours of downtime.
Users affected: Everyone trying to pay → sales blocked.
Financial loss: High and growing by the minute.
Classification: Maximum revenue impact + many users affected.
Answer: URGENT.
Q: "The analytics dashboard isn't showing data from the last 48 hours."
A: Let's go step by step.
Operational impact: Analytics = reporting function, not core.
Duration: 48 hours without fresh data.
Users affected: Marketing/analytics team (internal, few users).
Financial loss: Delayed decisions, but operations aren't blocked.
Classification: Medium impact (it affects decisions but not critical operations).
Answer: NORMAL.
Q: "Could you change the color of the export button? The current blue doesn't match our brand."
A: Let's go step by step.
Operational impact: Cosmetic change, the export function still works.
User's urgency: "could you?" signals a non-urgent request.
Users affected: Personal/aesthetic preference.
Financial loss: None.
Classification: No functional or financial impact.
Answer: LOW.
Q: {ticket}
A:"""
test_tickets = [
"My password doesn't work and I have a presentation in 30 minutes",
"When will you add support for exporting to Excel?",
"The API is returning a 500 error for 30% of requests in production",
"The onboarding tutorial has a typo in step 3",
"The main server went down. Every user is seeing a 503 page",
]
for ticket in test_tickets:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": SUPPORT_COT_PROMPT.format(ticket=ticket)}],
temperature=0,
max_tokens=300
)
print(f"Ticket: {ticket[:50]}...")
print(f"Answer: {response.choices[0].message.content[-100:]}\n")
Exercise 3: Design CoT for data analysis
Create a Manual CoT prompt to analyze whether a sales figure is a statistical outlier given a dataset.
See solution
OUTLIER_COT_PROMPT = """Determine whether a value is a statistical outlier using the IQR method.
Q: Daily sales for the last 7 days: [120, 135, 128, 142, 118, 131, 890]. Is 890 an outlier?
A: Let's go step by step.
Sort the data: 118, 120, 128, 131, 135, 142, 890.
Compute the quartiles:
- Q1 (25th percentile): position 2 = 120.
- Q2 (median): position 4 = 131.
- Q3 (75th percentile): position 6 = 142.
Compute the IQR: IQR = Q3 - Q1 = 142 - 120 = 22.
Compute the bounds:
- Lower bound: Q1 - 1.5×IQR = 120 - 33 = 87.
- Upper bound: Q3 + 1.5×IQR = 142 + 33 = 175.
Check: Is 890 > 175? Yes. 890 >> 175.
Answer: YES, 890 is a statistical outlier (it exceeds the upper bound of 175 by a factor of ~5x).
Q: {data_and_value}
A:"""
Exercise 4: Compare the accuracy of Manual CoT vs. Zero-Shot CoT
Use the same 10 problems with both approaches and measure which is more accurate in your domain.
See solution
from openai import OpenAI
client = OpenAI()
# Design your own examples for whatever domain interests you
MANUAL_EXAMPLES = """
Q: [Example 1 relevant to your domain]
A: [Reasoning 1]
Answer: [A1]
Q: [Example 2, also relevant]
A: [Reasoning 2]
Answer: [A2]
"""
benchmark_problems = [
("Problem 1", "Answer 1"),
# ... 10 problems with known answers
]
def solve_manual_cot(p):
prompt = MANUAL_EXAMPLES + f"\nQ: {p}\nA:"
r = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": prompt}],
temperature=0, max_tokens=500
)
return r.choices[0].message.content
def solve_zero_shot_cot(p):
r = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"{p}\n\nLet's think step by step."}],
temperature=0, max_tokens=500
)
return r.choices[0].message.content
manual_ok = sum(
1 for p, correct in benchmark_problems
if correct in solve_manual_cot(p)
)
zero_ok = sum(
1 for p, correct in benchmark_problems
if correct in solve_zero_shot_cot(p)
)
n = len(benchmark_problems)
print(f"Manual CoT: {manual_ok}/{n} ({manual_ok/n:.0%})")
print(f"Zero-Shot CoT: {zero_ok}/{n} ({zero_ok/n:.0%})")
Exercise 5: Spot and fix a broken example
The following Manual CoT example has an error. Find it and fix it:
Q: A product costs $80 with a 25% discount. What is the original price?
A: Discounted price: $80.
Discount: 25%.
Original price = 80 + 25% = 80 + 20 = $100.
Answer: $100.
See solution
The error: The operation "80 + 25% of 80" is not the mathematically correct way to recover the original price.
Correct reasoning:
Discounted price: $80.
A 25% discount means that $80 represents 75% of the original price (100% - 25%).
Original price = 80 / 0.75 = $106.67.
Check: 106.67 × 0.25 = $26.67 of discount. 106.67 - 26.67 = $80 ✓.
Answer: $106.67.
The error is confusing "add the percentage of the discounted price" with the correct inverse operation. To go from a discounted price back to the original price you have to divide by (1 - discount).
# Corrected example
corrected_discount_example = CoTExample(
input_problem="A product costs $80 with a 25% discount. What is the original price?",
reasoning="""Discounted price: $80.
The percentage it represents: 100% - 25% = 75% of the original price.
Original price = 80 / 0.75 = 106.67.
Check: 106.67 × 0.25 = 26.67. 106.67 - 26.67 = 80 ✓""",
answer="$106.67"
)
Summary
- Manual CoT uses examples with explicit Reasoning + Answer to steer the model
- Standard format: Input → Step-by-step reasoning → Answer
- 2-3 examples are usually enough; more doesn't always help
- By domain: Math, logic, code, sentiment and business each need a different style
- Quality > quantity: Incorrect examples hurt performance; always verify them
- vs. Zero-Shot: More design effort, more consistency and control