Prompt Patterns for Developers

# Prompt Patterns for Developers

Most developers treat prompts like magic spells—type something vague, hope for lightning. That’s not engineering. That’s guessing.

After two years of building AI-powered features into production apps, I’ve learned that prompt engineering is really just API design for language models. The same principles apply: be explicit, handle edge cases, version your inputs, and test the outputs.

This article covers six prompt patterns I use daily. No hype. Just patterns that work.

## The Role Pattern: Define the Persona Explicitly

The most basic pattern, and the one most people get wrong. Don’t just say “you are a helpful assistant.” That’s useless. Define what the model should sound like and what it should know.

“`python
SYSTEM_PROMPT = “””You are a senior backend engineer reviewing code.
– Focus on performance, security, and maintainability
– Assume the codebase is Python/Django
– Never suggest premature optimization
– Point out specific line numbers when referencing issues
– Reply with actionable feedback, not general advice”””
“`

The key insight: specificity breeds quality. “Senior backend engineer” tells the model to use technical terminology. “Assume Python/Django” sets context without forcing you to repeat it. “Never suggest premature optimization” is a constraint that shapes every response.

You’ll notice I put constraints in the negative (“never,” “assume the codebase is”). Models often ignore positive instructions but respect negative constraints. Use both.

## Chain-of-Thought: Make the Model Show Work

When you need accurate reasoning—not just correct answers—ask the model to walk through its logic. This is chain-of-thought prompting, and it’s essential for anything beyond simple Q&A.

“`python
def analyze_code_with_cot(code_snippet: str) -> dict:
prompt = f”””Analyze this code for bugs. Show your reasoning step by step.

Code:
“`
{code_snippet}
“`

First, identify what the code is trying to do.
Second, trace the execution flow.
Third, list potential issues with specific line references.
Finally, rate severity (critical/high/medium/low).

Output your final answer in JSON format with keys: analysis, issues[], severity_rating”””

response = client.chat.completions.create(
model=”gpt-4o”,
messages=[
{“role”: “system”, “content”: “You are a code reviewer. Always show reasoning before giving final answers.”},
{“role”: “user”, “content”: prompt}
],
temperature=0.1 # Lower temperature for more consistent reasoning
)
return json.loads(response.choices[0].message.content)
“`

Three things make this work:

1. **Explicit steps** — “First, identify… Second, trace… Third, list…”
2. **Lower temperature** — 0.1 keeps the model focused rather than creative
3. **Structured output request** — asking for JSON forces the model to organize thoughts

The model won’t always follow your steps perfectly. But when it deviates, you’ll notice—and can adjust the prompt.

## Few-Shot Learning: Show, Don’t Just Tell

Sometimes explaining what you want takes more words than just showing an example. Few-shot learning means providing input-output pairs that demonstrate the pattern you want.

“`python
FEW_SHOT_EXAMPLES = “””
Example 1:
Input: “function to calculate fibonacci”
Output: “def fibonacci(n):\n if n <= 1:\n return n\n return fibonacci(n-1) + fibonacci(n-2)" Example 2: Input: "function to reverse a string" Output: "def reverse_string(s):\n return s[::-1]" Example 3: Input: "function to check if list is sorted" Output: "def is_sorted(lst):\n return all(lst[i] <= lst[i+1] for i in range(len(lst)-1))" """ prompt = f"""Given a function description, output only the Python code. {FEW_SHOT_EXAMPLES} Now generate for: Input: "function to find max value in dictionary" Output:""" ``` The model learns the format from examples. This is especially useful for: - Enforcing specific output formats - Getting consistent code style - Handling domain-specific transformations Three to five examples usually suffice. More than that and you're just adding token cost without improving quality. ## The Template Pattern: Parameterize Your Prompts Build prompts like you build functions—parameterize the variable parts. This makes prompts testable, versionable, and reusable. ```python def build_code_explanation_prompt(code: str, language: str, level: str) -> str:
“””Template for explaining code at different detail levels.”””
return f”””Explain this {language} code to a {level} developer.

Code:
“`{language}
{code}
“`

Requirements:
– Explain what each line does
– Highlight any potential issues
– Suggest improvements if any exist
– Use {level}-appropriate terminology”””

# Usage
explain_prompt = build_code_explanation_prompt(
code=”def foo(x): return x*2″,
language=”python”,
level=”junior”
)
“`

This pattern becomes powerful when you:

– A/B test prompts with different parameters
– Track which prompt versions perform better
– Build prompt libraries for your team

Store prompts in version control. Treat them like code, because they are.

## Structured Output: Force the Schema

Never parse free-text responses with regex if you can avoid it. Ask for structured output directly.

“`python
from pydantic import BaseModel

class CodeReview(BaseModel):
issues: list[dict] # [{“line”: 5, “severity”: “high”, “description”: “…”}]
suggestions: list[str]
overall_quality: str # “excellent”/”good”/”needs_work”

prompt = “””Review this code and return structured feedback.

Code:
“`python
def process_user_data(users):
for user in users:
print(user.name)
# missing error handling
“`”””

response = client.chat.completions.create(
model=”gpt-4o”,
messages=[{“role”: “user”, “content”: prompt}],
response_format={“type”: “json_object”} # Forces JSON
)

review = CodeReview.model_validate_json(response.choices[0].message.content)
“`

This works because:

– You define exactly what you need
– The model has less room to wander
– Pydantic validates the output automatically
– Your code becomes type-safe

Not all models support structured output. GPT-4o and Claude 3.5 support `response_format`. For other models, ask for JSON explicitly and parse carefully.

## The Iterative Refinement Pattern

First drafts are rarely final drafts. Build feedback loops into your prompts.

“`python
def refined_code_generation(initial_request: str, max_iterations: int = 3) -> str:
“””Generate code, then refine based on feedback.”””
current_code = generate_code(initial_request)

for i in range(max_iterations):
issues = check_code_quality(current_code)

if not issues:
return current_code

feedback_prompt = f”””The following code has issues:

Code:
“`python
{current_code}
“`

Issues found:
{chr(10).join(f”- {issue}” for issue in issues)}

Fix these issues while preserving the original functionality.”””

current_code = generate_code(feedback_prompt)

return current_code # Return best effort after max iterations
“`

This pattern mirrors how developers actually work:

1. Generate initial solution
2. Identify problems
3. Apply fixes
4. Repeat until acceptable

The loop prevents prompt bloat. Instead of stuffing every possible constraint into one prompt, you layer feedback.

## Key Takeaways

– Treat prompts as API design: be explicit, version them, test outputs
– Chain-of-thought works best with explicit step numbering and lower temperature
– Few-shot examples beat verbose instructions for format enforcement
– Parameterize prompts like functions—makes them reusable and testable
– Always request structured output when possible; parsing free text is fragile
– Build iterative refinement into prompts rather than cramming everything into one request

## Next Steps

1. **Audit your current prompts** — Pull whatever prompts you’re using and look for vagueness. Replace “helpful assistant” with actual role definitions.

2. **Pick one pattern to try** — If you’re not using structured output, start there. It’s the highest-impact change for production systems.

3. **Build a prompt library** — Create a shared repo or module for your team’s prompts. Version control them. Test the outputs.

4. **Measure, then optimize** — Track success rates on AI-generated outputs. If 30% of code suggestions fail, your prompt needs work—not the model.

Prompt engineering isn’t a magic skill. It’s engineering. Treat it accordingly.