🔥 0
0
Lesson 3 of 6 15 min +75 XP

Prompt Engineering for Devs

The difference between a mediocre AI feature and a great one is often just the prompt. This isn't about tricks - it's about clear communication.

Developer mindset:

Think of prompts like function signatures + documentation. Be explicit about inputs, outputs, and edge cases.

---

The System Prompt

The system prompt sets the rules before any user input. It's your most powerful tool.

Bad System Prompt

messages = [
    {"role": "system", "content": "You are helpful."},
    {"role": "user", "content": "Summarize this article..."}
]

Good System Prompt

messages = [
    {
        "role": "system",
        "content": """You are a content summarizer for a tech news app.

TASK: Summarize articles for busy developers.

RULES:
- Maximum 3 bullet points
- Each bullet under 20 words
- Focus on practical implications, not hype
- If the article is not tech-related, respond with "NOT_RELEVANT"

OUTPUT FORMAT:
- Bullet 1
- Bullet 2
- Bullet 3"""
    },
    {"role": "user", "content": "Summarize this article..."}
]

---

Anatomy of a Good System Prompt

ROLE "You are a [specific role] for [context]" TASK "Your job is to [specific action]" RULES / CONSTRAINTS "Always X, Never Y, If Z then..." OUTPUT FORMAT "Return JSON with fields: ...", "Use bullet points"

---

JSON Mode: Structured Outputs

When you need to parse the response in code, use JSON mode:

from openai import OpenAI
import json

client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",
            "content": """Extract product info from descriptions.
            Return JSON with: name, price, category, in_stock (boolean)"""
        },
        {
            "role": "user",
            "content": "The Nike Air Max 90 is available now for $150"
        }
    ],
    response_format={"type": "json_object"}  # Forces valid JSON
)

data = json.loads(response.choices[0].message.content)
print(data)
# {"name": "Nike Air Max 90", "price": 150, "category": "shoes", "in_stock": true}
Important:

When using JSON mode, you MUST mention "JSON" in your system prompt. Otherwise OpenAI may return an error.

---

Few-Shot Prompting

Show the model examples of what you want. This is the most effective technique for consistent outputs.

Zero-shot (No examples)

messages = [
    {
        "role": "system",
        "content": "Convert natural language to SQL."
    },
    {
        "role": "user",
        "content": "Show me all users who signed up last week"
    }
]
# Output might be inconsistent

Few-shot (With examples)

messages = [
    {
        "role": "system",
        "content": """Convert natural language to SQL for a users table.
        Table schema: users(id, email, name, created_at, plan)"""
    },
    # Example 1
    {
        "role": "user",
        "content": "Get all premium users"
    },
    {
        "role": "assistant",
        "content": "SELECT * FROM users WHERE plan = 'premium';"
    },
    # Example 2
    {
        "role": "user",
        "content": "Count users by plan"
    },
    {
        "role": "assistant",
        "content": "SELECT plan, COUNT(*) FROM users GROUP BY plan;"
    },
    # Actual query
    {
        "role": "user",
        "content": "Show me all users who signed up last week"
    }
]
# Output: SELECT * FROM users WHERE created_at >= NOW() - INTERVAL '7 days';
Zero-shot

No examples. Works for simple tasks.

Few-shot

2-5 examples. Best for structured outputs.

Many-shot

10+ examples. When precision is critical.

---

Chain-of-Thought Prompting

For complex reasoning, ask the model to think step-by-step:

messages = [
    {
        "role": "system",
        "content": """You are a code reviewer. When reviewing code:
        1. First, identify what the code is trying to do
        2. Then, list any bugs or issues
        3. Then, suggest improvements
        4. Finally, give an overall rating (1-5)

        Think through each step before giving your final answer."""
    },
    {
        "role": "user",
        "content": """Review this code:
        def get_user(id):
            user = db.query(f"SELECT * FROM users WHERE id = {id}")
            return user"""
    }
]

The model will now explain its reasoning, catching issues it might miss with a direct response (like the SQL injection vulnerability above).

---

Practical Template: API Endpoint Prompt

Here's a reusable template for backend tasks:

def create_system_prompt(task: str, output_schema: dict, rules: list[str]) -> str:
    return f"""You are a backend service component.

TASK: {task}

OUTPUT: Return valid JSON matching this schema:
{json.dumps(output_schema, indent=2)}

RULES:
{chr(10).join(f"- {rule}" for rule in rules)}

If you cannot complete the task, return:
{{"error": "reason"}}
"""

# Usage
prompt = create_system_prompt(
    task="Extract action items from meeting notes",
    output_schema={
        "action_items": [{"task": "string", "assignee": "string", "due": "string"}]
    },
    rules=[
        "Only include explicit action items, not general discussion",
        "If no assignee mentioned, use 'unassigned'",
        "If no due date mentioned, use 'no date'"
    ]
)

---

Common Mistakes

Too Vague
"Summarize this"

How long? What format? What to focus on?

Specific
"Summarize in 3 bullets, max 15 words each, focus on key decisions"
No Error Handling
"Extract the price"

What if there's no price?

With Fallback
"Extract the price. If not found, return null"

---

Prompt Testing Checklist

Before deploying a prompt to production:

  • Test edge cases - empty input, very long input, garbage input
  • Test adversarial input - "ignore previous instructions and..."
  • Verify output format - does it always return valid JSON?
  • Check consistency - run the same input 5 times, are outputs similar?
  • Measure tokens - is the prompt too long? Can you trim it?

Key Takeaways

  • Structure your system prompt - role, task, rules, output format
  • Use JSON mode - when you need to parse outputs programmatically
  • Few-shot examples work - 2-5 examples dramatically improve consistency
  • Handle edge cases - always tell the model what to do when things go wrong

Next up: Embeddings & Vector Search - how to search by meaning, not just keywords.

🧠 Quick Quiz

Test your understanding of this lesson.

1

What is the purpose of a system prompt?

2

What is few-shot prompting?

3

When should you use JSON mode?

Calling LLM APIs