Disclosure: This post contains links to products I created. See details below.
I've written thousands of prompts across production systems — from internal tools at a major tech company to AI products used by thousands of developers. Most prompt engineering advice online is either too basic ("be specific!") or too theoretical to apply.
Here's what actually works, with real examples you can use today.
The Foundation: Structured Prompts Beat Clever Prompts
The single biggest improvement you can make to any prompt is adding structure. Not cleverness. Not jailbreaks. Structure.
Before (unstructured):
Help me review this code and find bugs and also suggest improvements
and make sure it follows best practices.
After (structured):
## Task
Review the following code for issues.
## Review Criteria
1. Bugs: logic errors, off-by-one, null handling
2. Security: injection risks, auth gaps, data exposure
3. Performance: unnecessary loops, missing indexes, N+1 queries
## Output Format
For each issue found:
- **Location**: file and line
- **Severity**: critical / warning / suggestion
- **Issue**: what's wrong
- **Fix**: recommended change
## Code
[paste code here]
The structured version consistently produces better results across every model I've tested. Why? Because you're reducing ambiguity. The model doesn't have to guess what "review" means or what format you want.
Technique 1: Role + Context + Task + Format
This is my go-to template for 80% of prompts:
You are a [ROLE] with expertise in [DOMAIN].
Context: [RELEVANT BACKGROUND]
Task: [SPECIFIC REQUEST]
Format: [HOW TO STRUCTURE THE RESPONSE]
Constraints: [WHAT TO AVOID OR LIMIT]
Real example for a database optimization prompt:
You are a senior database engineer with expertise in PostgreSQL performance tuning.
Context: We have a PostgreSQL 15 database handling 10M+ rows in the orders table.
Query response times have degraded from ~50ms to ~800ms over the past month.
Task: Analyze the following slow query and EXPLAIN ANALYZE output.
Suggest specific optimizations.
Format:
1. Root cause analysis (2-3 sentences)
2. Recommended indexes (with CREATE INDEX statements)
3. Query rewrite if applicable
4. Expected performance improvement
Constraints:
- Don't suggest adding read replicas (infrastructure change not approved)
- Solutions must work with our current PostgreSQL 15 setup
- Prioritize changes that don't require application code changes
Technique 2: Few-Shot With Edge Cases
Everyone knows about few-shot prompting. The trick most people miss: include edge cases in your examples.
## Task
Classify customer support tickets by priority.
## Examples
Input: "Can't log in to my account, getting 500 error"
Priority: HIGH
Reasoning: Account access blocked, server error indicates system issue
Input: "How do I change my notification preferences?"
Priority: LOW
Reasoning: Non-urgent feature question, self-service documentation available
Input: "I was charged twice for my subscription!!!"
Priority: HIGH
Reasoning: Billing error with financial impact, emotional urgency indicators
Input: "The dashboard loads slowly sometimes"
Priority: MEDIUM
Reasoning: Performance issue but intermittent, not blocking core functionality
Input: "I love your product, just wanted to say thanks"
Priority: LOW
Reasoning: Positive feedback, no action required (but flag for product team)
Notice the last two examples — they're edge cases. "Loads slowly sometimes" could go either way. "Just wanted to say thanks" isn't even a support request. Including these teaches the model your decision boundaries.
Technique 3: Chain of Thought With Checkpoints
For complex reasoning tasks, don't just say "think step by step." Give the model explicit checkpoints:
## Task
Determine if this API change is backward compatible.
## Analysis Steps
1. **Identify changes**: List every field, endpoint, or behavior that changed
2. **Classify each change**:
- Addition (new field/endpoint) → usually safe
- Modification (type change, rename) → usually breaking
- Removal → always breaking
3. **Check defaults**: Do new required fields have defaults?
4. **Check consumers**: Which clients would break? (list them)
5. **Verdict**: Compatible / Breaking / Compatible-with-caveats
Show your work for each step before giving the verdict.
The checkpoints prevent the model from jumping to conclusions. I've seen this reduce errors by ~40% on complex analysis tasks compared to open-ended "think step by step."
Technique 4: Negative Prompting
Tell the model what NOT to do. This is surprisingly effective:
## Task
Write a technical design document for a caching layer.
## Do NOT:
- Use buzzwords without defining them
- Suggest technologies without explaining trade-offs
- Skip failure modes and edge cases
- Write more than 2 pages
- Include implementation details (this is a design doc, not code)
## DO:
- Start with the problem statement (3 sentences max)
- Compare at least 2 approaches with pros/cons
- Address cache invalidation strategy explicitly
- Include a simple diagram (ASCII is fine)
- End with a clear recommendation and next steps
The "DO NOT" list is often more valuable than the "DO" list because it eliminates the most common failure modes.
Technique 5: Iterative Refinement Prompts
For tasks where quality matters, build in self-review:
## Task
Write a Python function that validates email addresses.
## Process
1. Write the initial implementation
2. Review your own code for:
- Edge cases (empty string, unicode, very long inputs)
- Security (ReDoS vulnerability in regex)
- Standards compliance (RFC 5322)
3. List any issues found
4. Write the final, corrected version
Show both versions so I can see what changed.
This consistently produces better code than single-pass generation. The model catches its own mistakes when you explicitly ask it to look.
Technique 6: Context Window Management
As prompts get complex, context window management becomes critical:
def build_prompt(task, context_items, max_context_tokens=2000):
"""
Prioritize context by relevance, not recency.
"""
# Score and rank context items
scored = [(item, relevance_score(item, task)) for item in context_items]
scored.sort(key=lambda x: x[1], reverse=True)
# Fill context budget
selected = []
token_count = 0
for item, score in scored:
item_tokens = count_tokens(item)
if token_count + item_tokens <= max_context_tokens:
selected.append(item)
token_count += item_tokens
return format_prompt(task, selected)
Key principle: relevant context beats more context. I've seen prompts perform worse when you add more information because the model gets distracted by irrelevant details.
The Meta-Lesson
After years of prompt engineering, here's what I keep coming back to: the best prompt is the one that makes the model's job easy.
Reduce ambiguity. Provide structure. Show examples. Set boundaries. That's it. No magic words, no secret techniques — just clear communication.
Resources
I've compiled my most effective prompts and patterns into reusable resources:
100 Advanced AI Prompts for Product Managers — 100 production-tested prompts covering product strategy, user research, competitive analysis, roadmap planning, and more. Each prompt includes the template, example output, and customization tips. ($5)
AI Agent Building Guide: 7 Real Systems — Goes deeper into how prompt engineering fits into full agent architectures, with real system designs. ($9)
Free AI Agent Deployment Checklist — A free checklist covering everything from prompt testing to production monitoring.
These are products I built based on my experience shipping AI systems. They're designed for practitioners, not beginners.
Recommended Tools
- Typeless — AI voice typing
- ElevenLabs — AI voice generation
What prompt engineering techniques have you found most effective? Drop your favorites in the comments — I'm always looking to learn from what others have discovered.
Top comments (0)