Prompt Engineering Mastery: Advanced Techniques for GPT-4
Prompt Engineering Mastery: Advanced Techniques for GPT-4
After extensive work with GPT-4 since its March release, I’ve compiled advanced prompt engineering techniques that consistently produce better results. These patterns go beyond the basics and address real production challenges.
The Structured Thinking Framework
Chain of Thought with Explicit Steps
def create_reasoning_prompt(problem: str, domain: str) -> str:
"""Create a prompt that guides explicit reasoning."""
return f"""You are an expert in {domain}. Solve the following problem using a structured approach.
Problem: {problem}
Please follow these steps:
1. **Understanding**: Restate the problem in your own words to confirm understanding.
2. **Decomposition**: Break down the problem into smaller, manageable parts.
3. **Analysis**: Analyze each part, identifying key factors and constraints.
4. **Synthesis**: Combine insights from each part into a cohesive solution.
5. **Validation**: Check your solution against the original requirements.
6. **Conclusion**: Provide a clear, actionable answer.
Work through each step explicitly before providing your final answer."""
# Example usage
prompt = create_reasoning_prompt(
problem="Design a caching strategy for an API with 10,000 RPM that serves both real-time and historical data",
domain="distributed systems"
)
Multi-Persona Analysis
def multi_perspective_prompt(topic: str, perspectives: list) -> str:
"""Generate analysis from multiple expert perspectives."""
perspective_instructions = "\n".join([
f"- **{p['role']}**: Consider {p['focus']}"
for p in perspectives
])
return f"""Analyze the following topic from multiple expert perspectives:
Topic: {topic}
Consider these viewpoints:
{perspective_instructions}
For each perspective:
1. Identify key concerns and priorities
2. Highlight potential benefits and risks
3. Suggest specific recommendations
Finally, synthesize these perspectives into a balanced recommendation that addresses the concerns of all stakeholders."""
# Example
perspectives = [
{"role": "Security Engineer", "focus": "vulnerabilities, data protection, compliance"},
{"role": "Product Manager", "focus": "user experience, time to market, feature value"},
{"role": "DevOps Engineer", "focus": "deployment, monitoring, operational overhead"},
{"role": "Cost Analyst", "focus": "budget, ROI, resource efficiency"}
]
prompt = multi_perspective_prompt(
"Implementing a microservices architecture for our monolithic application",
perspectives
)
Context Optimization Techniques
Structured Context Windows
With GPT-4’s 8K and 32K context windows, organization matters.
from dataclasses import dataclass
from typing import List, Optional
import tiktoken
@dataclass
class ContextSection:
name: str
content: str
priority: int # 1 = highest
max_tokens: Optional[int] = None
class ContextManager:
def __init__(self, model: str = "gpt-4", max_tokens: int = 8000):
self.model = model
self.max_tokens = max_tokens
self.encoding = tiktoken.encoding_for_model(model)
self.sections: List[ContextSection] = []
def add_section(self, section: ContextSection):
"""Add a context section."""
self.sections.append(section)
def count_tokens(self, text: str) -> int:
"""Count tokens in text."""
return len(self.encoding.encode(text))
def build_context(self, reserve_for_response: int = 1000) -> str:
"""Build optimized context within token limits."""
available_tokens = self.max_tokens - reserve_for_response
# Sort by priority
sorted_sections = sorted(self.sections, key=lambda x: x.priority)
context_parts = []
used_tokens = 0
for section in sorted_sections:
content = section.content
# Truncate if necessary
if section.max_tokens:
tokens = self.encoding.encode(content)
if len(tokens) > section.max_tokens:
tokens = tokens[:section.max_tokens]
content = self.encoding.decode(tokens) + "..."
section_text = f"\n### {section.name.upper()} ###\n{content}\n"
section_tokens = self.count_tokens(section_text)
if used_tokens + section_tokens <= available_tokens:
context_parts.append(section_text)
used_tokens += section_tokens
else:
# Try to fit partial content
remaining = available_tokens - used_tokens - 50 # Buffer
if remaining > 100: # Worth including
tokens = self.encoding.encode(content)[:remaining]
truncated = self.encoding.decode(tokens)
context_parts.append(f"\n### {section.name.upper()} (truncated) ###\n{truncated}...\n")
break
return "".join(context_parts)
# Usage
context_mgr = ContextManager(max_tokens=8000)
context_mgr.add_section(ContextSection(
name="System Requirements",
content=requirements_doc,
priority=1,
max_tokens=1000
))
context_mgr.add_section(ContextSection(
name="Current Implementation",
content=source_code,
priority=2,
max_tokens=3000
))
context_mgr.add_section(ContextSection(
name="Test Cases",
content=test_file,
priority=3
))
optimized_context = context_mgr.build_context()
Dynamic Few-Shot Selection
from typing import List, Tuple
import numpy as np
class DynamicFewShotSelector:
def __init__(self, embedding_client, examples: List[dict]):
"""
Initialize with example pairs.
examples = [{"input": "...", "output": "...", "embedding": [...]}]
"""
self.client = embedding_client
self.examples = examples
# Pre-compute embeddings if not provided
for ex in self.examples:
if "embedding" not in ex:
ex["embedding"] = self._get_embedding(ex["input"])
def _get_embedding(self, text: str) -> list:
"""Get embedding for text."""
response = self.client.embeddings.create(
model="text-embedding-ada-002",
input=text
)
return response.data[0].embedding
def _cosine_similarity(self, a: list, b: list) -> float:
"""Calculate cosine similarity."""
a, b = np.array(a), np.array(b)
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
def select_examples(self, query: str, n: int = 3) -> List[dict]:
"""Select the n most relevant examples for the query."""
query_embedding = self._get_embedding(query)
# Calculate similarities
similarities = []
for ex in self.examples:
sim = self._cosine_similarity(query_embedding, ex["embedding"])
similarities.append((sim, ex))
# Sort by similarity and return top n
similarities.sort(key=lambda x: x[0], reverse=True)
return [ex for _, ex in similarities[:n]]
def build_few_shot_prompt(
self,
query: str,
n_examples: int = 3,
instruction: str = ""
) -> str:
"""Build a prompt with dynamically selected examples."""
examples = self.select_examples(query, n_examples)
prompt_parts = []
if instruction:
prompt_parts.append(instruction)
prompt_parts.append("")
prompt_parts.append("Here are some examples:")
prompt_parts.append("")
for i, ex in enumerate(examples, 1):
prompt_parts.append(f"Example {i}:")
prompt_parts.append(f"Input: {ex['input']}")
prompt_parts.append(f"Output: {ex['output']}")
prompt_parts.append("")
prompt_parts.append("Now, please process the following:")
prompt_parts.append(f"Input: {query}")
prompt_parts.append("Output:")
return "\n".join(prompt_parts)
# Usage
selector = DynamicFewShotSelector(openai_client, training_examples)
prompt = selector.build_few_shot_prompt(
query=user_input,
n_examples=3,
instruction="Convert natural language queries to SQL."
)
Output Control Patterns
Structured JSON Output
import json
from typing import Type
from pydantic import BaseModel
def create_json_extraction_prompt(
content: str,
schema: Type[BaseModel],
examples: list = None
) -> str:
"""Create a prompt for structured JSON extraction."""
schema_json = json.dumps(schema.model_json_schema(), indent=2)
prompt = f"""Extract information from the following content and return it as valid JSON matching this schema:
```json
{schema_json}
Important:
-
Return ONLY valid JSON, no additional text
-
Use null for missing optional fields
-
Ensure all required fields are present
-
Follow the exact field names and types """
if examples: prompt += “\n\nExamples:\n” for ex in examples: prompt += f”\nInput: {ex[‘input’]}\nOutput: {json.dumps(ex[‘output’])}\n”
prompt += f”\n\nContent to extract from:\n{content}\n\nJSON Output:”
return prompt
Example schema
from pydantic import BaseModel, Field from typing import List, Optional
class ContactInfo(BaseModel): name: str = Field(description=“Full name of the person”) email: Optional[str] = Field(description=“Email address if available”) phone: Optional[str] = Field(description=“Phone number if available”) company: Optional[str] = Field(description=“Company name if mentioned”) role: Optional[str] = Field(description=“Job title or role”)
prompt = create_json_extraction_prompt( content=email_text, schema=ContactInfo )
### Confidence Scoring
```python
def prompt_with_confidence(query: str, task_description: str) -> str:
"""Create a prompt that includes confidence scoring."""
return f"""{task_description}
Query: {query}
Please provide your response in the following format:
1. **Answer**: Your direct answer to the query
2. **Confidence**: Rate your confidence (0-100%) with justification
3. **Caveats**: Any important limitations or assumptions
4. **Alternatives**: If confidence is below 80%, suggest alternative interpretations
Be honest about uncertainty. It's better to express low confidence than to provide a confident but incorrect answer."""
# Usage
prompt = prompt_with_confidence(
query="What was the revenue impact of our Q3 marketing campaign?",
task_description="You are a business analyst assistant. Analyze the provided data and answer questions."
)
Error Recovery Patterns
Self-Correction Prompt
def self_correction_prompt(
original_query: str,
initial_response: str,
error_description: str
) -> str:
"""Create a prompt for self-correction."""
return f"""I previously attempted to answer a query but made an error. Please help me correct it.
Original Query: {original_query}
My Initial Response:
{initial_response}
Error/Issue Identified: {error_description}
Please:
1. Identify what went wrong in my initial response
2. Explain the correct approach
3. Provide a corrected response
Focus on learning from the error and ensuring the correction is accurate."""
# Usage example
correction_prompt = self_correction_prompt(
original_query="Calculate the compound interest for $10,000 at 5% for 3 years",
initial_response="$10,000 * 0.05 * 3 = $1,500 interest",
error_description="Used simple interest formula instead of compound interest"
)
Conclusion
Advanced prompt engineering is about creating structured, clear communication with GPT-4. These techniques help produce more reliable, consistent outputs. The key principles are:
- Structure your requests clearly and explicitly
- Provide relevant context efficiently within token limits
- Use examples that match the query type
- Control outputs with schemas and formats
- Build in error recovery mechanisms
Experiment with these patterns and adapt them to your specific use cases.