Chain-of-Thought (CoT) Prompting
Encourage step-by-step reasoning for complex problems.Zero-Shot CoT
Copy
from openai import OpenAI
def zero_shot_cot(problem: str) -> str:
"""Apply zero-shot chain-of-thought prompting."""
client = OpenAI()
prompt = f"""{problem}
Let's think step by step."""
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Usage
problem = """
If a train travels at 60 mph for 2 hours, then at 80 mph for 3 hours,
what is the average speed for the entire journey?
"""
solution = zero_shot_cot(problem)
print(solution)
Few-Shot CoT
Copy
from openai import OpenAI
def few_shot_cot(problem: str, examples: list[dict]) -> str:
"""Apply few-shot chain-of-thought with examples."""
client = OpenAI()
# Build prompt with examples
prompt_parts = []
for example in examples:
prompt_parts.append(f"Problem: {example['problem']}")
prompt_parts.append(f"Reasoning: {example['reasoning']}")
prompt_parts.append(f"Answer: {example['answer']}\n")
prompt_parts.append(f"Problem: {problem}")
prompt_parts.append("Reasoning:")
prompt = "\n".join(prompt_parts)
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Usage
examples = [
{
"problem": "Roger has 5 tennis balls. He buys 2 more cans of 3 balls each. How many does he have?",
"reasoning": "Roger started with 5 balls. 2 cans of 3 balls = 6 balls. 5 + 6 = 11 balls.",
"answer": "11"
},
{
"problem": "A store has 15 apples. If they sell 6 and receive 10 more, how many do they have?",
"reasoning": "Started with 15 apples. Sold 6, so 15 - 6 = 9. Received 10 more, so 9 + 10 = 19.",
"answer": "19"
}
]
problem = "A farmer has 23 cows. He sells 7 and buys 12 more. How many cows does he have?"
solution = few_shot_cot(problem, examples)
print(solution)
Self-Ask with CoT
Copy
from openai import OpenAI
def self_ask_cot(question: str) -> str:
"""Use self-ask prompting for multi-hop reasoning."""
client = OpenAI()
system = """You are a reasoning assistant that breaks down complex questions.
When given a question, identify if follow-up questions are needed to answer it.
Format your response as:
- Follow-up: <question> (if needed)
- Intermediate answer: <answer>
- Repeat until you can answer the original question
- Final answer: <answer>"""
prompt = f"""Question: {question}
Are follow-up questions needed here?"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": system},
{"role": "user", "content": prompt}
]
)
return response.choices[0].message.content
# Usage
question = """
Who was president of the United States when the first iPhone was released,
and what was that president's age at the time?
"""
answer = self_ask_cot(question)
print(answer)
Tree-of-Thought (ToT) Prompting
Explore multiple reasoning paths for complex problems.Copy
from openai import OpenAI
from dataclasses import dataclass
import json
@dataclass
class ThoughtNode:
"""A node in the thought tree."""
thought: str
evaluation: float
children: list = None
def __post_init__(self):
if self.children is None:
self.children = []
class TreeOfThought:
"""Implement Tree-of-Thought reasoning."""
def __init__(self, model: str = "gpt-4o"):
self.client = OpenAI()
self.model = model
def generate_thoughts(
self,
problem: str,
context: str = "",
num_thoughts: int = 3
) -> list[str]:
"""Generate multiple distinct thoughts/approaches."""
prompt = f"""Problem: {problem}
{f"Current progress: {context}" if context else ""}
Generate {num_thoughts} distinct approaches or next steps to solve this problem.
Each approach should be different and explore a unique angle.
Return as JSON: {{"thoughts": ["thought1", "thought2", ...]}}"""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
return data.get("thoughts", [])
def evaluate_thought(
self,
problem: str,
thought: str
) -> float:
"""Evaluate how promising a thought is (0-1 scale)."""
prompt = f"""Problem: {problem}
Proposed approach: {thought}
Evaluate this approach on a scale of 0.0 to 1.0:
- 1.0 = Definitely leads to the solution
- 0.5 = Might help, uncertain
- 0.0 = Dead end, won't help
Return JSON: {{"score": <float>, "reasoning": "<brief explanation>"}}"""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"}
)
data = json.loads(response.choices[0].message.content)
return data.get("score", 0.5)
def solve(
self,
problem: str,
depth: int = 3,
breadth: int = 3,
threshold: float = 0.3
) -> str:
"""Solve using tree-of-thought search."""
# Generate initial thoughts
initial_thoughts = self.generate_thoughts(problem, num_thoughts=breadth)
# Create root nodes
candidates = []
for thought in initial_thoughts:
score = self.evaluate_thought(problem, thought)
if score >= threshold:
candidates.append(ThoughtNode(thought=thought, evaluation=score))
# Explore best candidates
for _ in range(depth - 1):
if not candidates:
break
# Sort by evaluation and take top candidates
candidates.sort(key=lambda x: x.evaluation, reverse=True)
best = candidates[:breadth]
new_candidates = []
for node in best:
# Generate follow-up thoughts
follow_ups = self.generate_thoughts(
problem,
context=node.thought,
num_thoughts=breadth
)
for thought in follow_ups:
combined = f"{node.thought}\nThen: {thought}"
score = self.evaluate_thought(problem, combined)
if score >= threshold:
child = ThoughtNode(thought=combined, evaluation=score)
node.children.append(child)
new_candidates.append(child)
candidates = new_candidates
# Get best final thought
if candidates:
best = max(candidates, key=lambda x: x.evaluation)
return self._generate_final_answer(problem, best.thought)
return "Could not find a solution path."
def _generate_final_answer(self, problem: str, reasoning: str) -> str:
"""Generate final answer based on best reasoning path."""
prompt = f"""Problem: {problem}
Reasoning path:
{reasoning}
Based on this reasoning, provide the final answer."""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}]
)
return response.choices[0].message.content
# Usage
tot = TreeOfThought()
problem = """
You have 4 numbers: 2, 3, 4, 5
Using each number exactly once and any arithmetic operations (+, -, *, /),
create an expression that equals 24.
"""
solution = tot.solve(problem, depth=3, breadth=3)
print(solution)
ReAct (Reasoning + Acting)
Combine reasoning with tool use for complex tasks.Copy
from openai import OpenAI
import json
import re
class ReActAgent:
"""Agent using ReAct pattern for reasoning and action."""
def __init__(self, tools: dict, model: str = "gpt-4o"):
self.client = OpenAI()
self.model = model
self.tools = tools # name -> function mapping
self.tool_descriptions = self._format_tools()
def _format_tools(self) -> str:
"""Format tool descriptions for the prompt."""
lines = []
for name, func in self.tools.items():
doc = func.__doc__ or "No description"
lines.append(f"- {name}: {doc}")
return "\n".join(lines)
def run(self, task: str, max_steps: int = 10) -> str:
"""Run the ReAct loop."""
system = f"""You are an agent that solves tasks through reasoning and actions.
Available tools:
{self.tool_descriptions}
For each step, respond with exactly one of:
1. Thought: <your reasoning about what to do next>
2. Action: <tool_name>(<args>)
3. Answer: <final answer when task is complete>
Always start with a Thought, then take an Action if needed, observe the result,
and continue until you can provide the Answer."""
messages = [
{"role": "system", "content": system},
{"role": "user", "content": f"Task: {task}"}
]
trajectory = []
for step in range(max_steps):
response = self.client.chat.completions.create(
model=self.model,
messages=messages
)
output = response.choices[0].message.content.strip()
trajectory.append(output)
# Check for final answer
if output.startswith("Answer:"):
return output[7:].strip()
# Parse and execute action
if "Action:" in output:
action_match = re.search(r'Action:\s*(\w+)\((.*?)\)', output)
if action_match:
tool_name = action_match.group(1)
args_str = action_match.group(2)
# Execute tool
if tool_name in self.tools:
try:
# Parse arguments
if args_str:
args = [a.strip().strip('"\'') for a in args_str.split(",")]
result = self.tools[tool_name](*args)
else:
result = self.tools[tool_name]()
observation = f"Observation: {result}"
except Exception as e:
observation = f"Observation: Error - {str(e)}"
else:
observation = f"Observation: Unknown tool '{tool_name}'"
trajectory.append(observation)
messages.append({"role": "assistant", "content": output})
messages.append({"role": "user", "content": observation})
else:
messages.append({"role": "assistant", "content": output})
messages.append({
"role": "user",
"content": "Please format your action as: Action: tool_name(args)"
})
else:
messages.append({"role": "assistant", "content": output})
messages.append({
"role": "user",
"content": "Continue with your next thought or action."
})
return "Max steps reached. Trajectory:\n" + "\n".join(trajectory)
# Example tools
def search(query: str) -> str:
"""Search for information on the web."""
# Simulated search results
return f"Search results for '{query}': Found relevant information about the topic."
def calculate(expression: str) -> str:
"""Evaluate a mathematical expression."""
try:
result = eval(expression)
return str(result)
except Exception as e:
return f"Error: {e}"
def lookup(topic: str) -> str:
"""Look up a specific fact or definition."""
facts = {
"python": "Python is a high-level programming language created by Guido van Rossum.",
"earth radius": "Earth's radius is approximately 6,371 kilometers.",
}
return facts.get(topic.lower(), f"No information found for '{topic}'")
# Usage
agent = ReActAgent(tools={
"search": search,
"calculate": calculate,
"lookup": lookup
})
result = agent.run(
"What is the circumference of Earth? Calculate it using the radius."
)
print(result)
Self-Consistency
Generate multiple reasoning paths and select the most consistent answer.Copy
from openai import OpenAI
from collections import Counter
import json
class SelfConsistency:
"""Apply self-consistency decoding."""
def __init__(self, model: str = "gpt-4o"):
self.client = OpenAI()
self.model = model
def solve(
self,
problem: str,
num_samples: int = 5,
temperature: float = 0.7
) -> dict:
"""Solve using self-consistency."""
# Generate multiple reasoning paths
responses = []
prompt = f"""{problem}
Think through this step by step and provide your answer.
At the end, clearly state your final answer after "Final Answer:".
"""
for _ in range(num_samples):
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}],
temperature=temperature
)
text = response.choices[0].message.content
responses.append(text)
# Extract final answers
answers = []
for response in responses:
answer = self._extract_answer(response)
if answer:
answers.append(answer)
# Find most common answer
if answers:
counter = Counter(answers)
most_common = counter.most_common(1)[0]
return {
"answer": most_common[0],
"confidence": most_common[1] / len(answers),
"num_samples": num_samples,
"all_answers": dict(counter),
"sample_reasoning": responses[0]
}
return {
"answer": None,
"confidence": 0,
"num_samples": num_samples,
"error": "Could not extract consistent answer"
}
def _extract_answer(self, response: str) -> str:
"""Extract the final answer from a response."""
# Look for "Final Answer:" pattern
if "Final Answer:" in response:
answer = response.split("Final Answer:")[-1].strip()
# Clean up the answer
answer = answer.split("\n")[0].strip()
return answer
# Fallback: last line
lines = [l.strip() for l in response.split("\n") if l.strip()]
if lines:
return lines[-1]
return None
# Usage
sc = SelfConsistency()
problem = """
A farmer has 17 sheep. All but 9 run away. How many sheep are left?
"""
result = sc.solve(problem, num_samples=5)
print(f"Answer: {result['answer']}")
print(f"Confidence: {result['confidence']:.0%}")
print(f"Vote distribution: {result['all_answers']}")
Prompt Chaining
Break complex tasks into sequential steps.Copy
from openai import OpenAI
from dataclasses import dataclass
from typing import Callable, Any
@dataclass
class ChainStep:
"""A step in a prompt chain."""
name: str
prompt_template: str
parser: Callable[[str], Any] = None
class PromptChain:
"""Chain multiple prompts together."""
def __init__(self, model: str = "gpt-4o"):
self.client = OpenAI()
self.model = model
self.steps: list[ChainStep] = []
def add_step(
self,
name: str,
prompt_template: str,
parser: Callable[[str], Any] = None
):
"""Add a step to the chain."""
self.steps.append(ChainStep(
name=name,
prompt_template=prompt_template,
parser=parser
))
return self
def run(self, initial_input: dict) -> dict:
"""Run the prompt chain."""
context = initial_input.copy()
results = {}
for step in self.steps:
# Format prompt with current context
prompt = step.prompt_template.format(**context)
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}]
)
output = response.choices[0].message.content
# Parse if parser provided
if step.parser:
output = step.parser(output)
results[step.name] = output
context[step.name] = output
return results
# Usage: Research and summarization chain
chain = PromptChain()
chain.add_step(
name="outline",
prompt_template="""Create an outline for an article about: {topic}
Include 3-5 main sections with brief descriptions.
Format as a numbered list."""
)
chain.add_step(
name="draft",
prompt_template="""Based on this outline:
{outline}
Write a detailed first draft of the article about {topic}.
Expand each section with relevant information and examples."""
)
chain.add_step(
name="review",
prompt_template="""Review this draft and identify improvements:
{draft}
List:
1. Factual issues or gaps
2. Clarity improvements
3. Missing information
4. Structural suggestions"""
)
chain.add_step(
name="final",
prompt_template="""Improve this draft based on the review:
Original draft:
{draft}
Review feedback:
{review}
Write the improved final version."""
)
results = chain.run({"topic": "the future of renewable energy"})
print("Final article:")
print(results["final"])
Least-to-Most Prompting
Decompose complex problems into simpler subproblems.Copy
from openai import OpenAI
class LeastToMost:
"""Implement least-to-most prompting."""
def __init__(self, model: str = "gpt-4o"):
self.client = OpenAI()
self.model = model
def decompose(self, problem: str) -> list[str]:
"""Decompose problem into subproblems."""
prompt = f"""Problem: {problem}
Break this problem down into simpler subproblems that can be solved sequentially.
List them from simplest to most complex, where each builds on previous answers.
Format as a numbered list of subproblems."""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}]
)
text = response.choices[0].message.content
# Parse numbered list
subproblems = []
for line in text.split("\n"):
line = line.strip()
if line and line[0].isdigit():
# Remove number and punctuation
subproblem = line.lstrip("0123456789.):- ").strip()
if subproblem:
subproblems.append(subproblem)
return subproblems
def solve(self, problem: str) -> dict:
"""Solve using least-to-most approach."""
# Decompose
subproblems = self.decompose(problem)
# Solve sequentially
solutions = []
context = f"Original problem: {problem}\n\n"
for i, subproblem in enumerate(subproblems):
prompt = f"""{context}
Previous solutions:
{chr(10).join(f"- {s['subproblem']}: {s['solution']}" for s in solutions)}
Now solve: {subproblem}
Provide a clear, concise solution."""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": prompt}]
)
solution = response.choices[0].message.content
solutions.append({
"subproblem": subproblem,
"solution": solution
})
# Final synthesis
synthesis_prompt = f"""Original problem: {problem}
Solutions to subproblems:
{chr(10).join(f"{i+1}. {s['subproblem']}: {s['solution']}" for i, s in enumerate(solutions))}
Now provide the complete final answer to the original problem."""
response = self.client.chat.completions.create(
model=self.model,
messages=[{"role": "user", "content": synthesis_prompt}]
)
return {
"subproblems": subproblems,
"solutions": solutions,
"final_answer": response.choices[0].message.content
}
# Usage
l2m = LeastToMost()
problem = """
Design a system to recommend movies to users based on their watching history
and preferences. The system should handle millions of users and movies.
"""
result = l2m.solve(problem)
print("Subproblems:")
for i, sp in enumerate(result["subproblems"], 1):
print(f" {i}. {sp}")
print("\nFinal Answer:")
print(result["final_answer"])
Prompting Best Practices
- Choose the technique based on problem complexity
- Chain-of-Thought works well for math and logical reasoning
- Tree-of-Thought excels at creative problem-solving
- ReAct is ideal when external tools are needed
- Self-Consistency improves reliability for high-stakes answers
Practice Exercise
Build a reasoning system that:- Automatically selects the best prompting technique
- Implements at least 3 different techniques
- Evaluates and compares results across techniques
- Provides confidence scores for answers
- Supports custom tool integration
- Problem classification for technique selection
- Robust answer extraction
- Performance measurement
- Fallback strategies