Module 1: Fundamentals of Prompt Engineering

2. Anatomy of a Prompt

Overview

A professional prompt isn't free text: it has identifiable components that the model processes differently. In this capsule you'll learn the 4 fundamental components (instruction, context, input, output format), how the model processes them, and how tokenization affects results. By the end, you'll be able to break down any prompt and diagnose what's missing or what's in the way.

Why it matters: Without understanding the anatomy, you can't improve prompts systematically. If a prompt fails, you don't know whether the problem is in the instruction, in the context, or in the output format. With a clear anatomy, you optimize piece by piece.


The 4 components of a professional prompt

1. Instruction

What it is: The task you want the model to perform. It must be explicit and actionable.

Vague example:

Do something with this text.

Explicit example:

Extract the named entities (people, organizations, locations) from the following text.
Return a list in JSON format: {"persons": [], "organizations": [], "locations": []}

Rule: The instruction answers "What should the model do?" with enough detail that it doesn't have to guess.

Useful instruction verbs:

  • Classify, categorize
  • Extract, identify
  • Summarize, condense
  • Translate, paraphrase
  • Generate, create
  • Analyze, evaluate
  • Compare, contrast
  • Answer, explain

2. Context

What it is: Extra information the model needs to perform the task correctly. It includes domain, constraints, definitions, and background.

Example without context:

Classify this ticket.

Example with context:

You are a support ticket classifier. The categories are: Billing, Technical, Account, Other.
Answer with one of the four categories only, nothing else.
Definitions:
- Billing: payment problems, invoices, charges
- Technical: errors, bugs, technical access problems
- Account: password changes, settings, permissions
- Other: anything that doesn't fit the above

Rule: The context answers "What does the model need to know to do this well?" and "What constraints must it respect?"

Types of context:

  • Domain: "You're in the context of an insurance company"
  • Definitions: "A 'critical incident' is defined as..."
  • Constraints: "Only use information from the provided document"
  • Background: "The user has already tried restarting their device"

3. Input

What it is: The data the model has to act on. The variable content that changes on every call.

Example:

[Instruction and context above]

User ticket:
"My March invoice never arrived and it's been 2 weeks. I need help urgently."

Rule: The input is what the user or the system provides on each request. It must be clearly delimited (for example, with labels like "Input:" or triple quotes ''').

How to delimit the input:

# Option 1: A label
prompt = f"""
Instruction: Classify the sentiment.

Input: {user_text}
"""

# Option 2: Triple quotes
prompt = f"""
Classify the sentiment of the following text:

'''{user_text}'''
"""

# Option 3: XML-style (works well with Claude)
prompt = f"""
Classify the sentiment of this text:

<text>
{user_text}
</text>
"""

Delimiting keeps the model from "blending" the input with the instruction (especially important if the input can itself contain instructions).


4. Output format

What it is: How the answer must be structured. JSON, a list, a paragraph, a table, and so on.

Example without a format:

Summarize this article.

Example with a format:

Summarize this article in exactly 3 bullet points.
Each bullet must be 15 words maximum.
Format:
- [point 1]
- [point 2]
- [point 3]

Rule: The output format reduces variability and makes the answer parseable by code. In production, you almost always need a structured format.

Common formats:

FormatWhen to use it
JSONData extraction, classification with metadata
Bullet listSummaries, brainstorming
Exact stringSimple classification (POSITIVE/NEGATIVE)
Markdown tableComparisons
CodeCode generation
Structured paragraphNarrative analysis

A complete integrated example

# A prompt with the 4 components made explicit, plus the full code

from openai import OpenAI
import json
import os
from dotenv import load_dotenv

load_dotenv()
client = OpenAI()

# The prompt's components, clearly identified
INSTRUCTION = """
Extract the named entities from the text.
Classify each one as PERSON, ORGANIZATION or LOCATION.
"""

CONTEXT = """
Rules:
- Only include entities that appear explicitly in the text
- If an entity is ambiguous, use the most likely category
- Don't invent entities that aren't in the text
- The same entity may appear several times: include it only once
"""

INPUT = "Maria Garcia works at Google in Mountain View. Yesterday she spoke with Juan Perez from Microsoft about the project."

OUTPUT_FORMAT = """
Respond with valid JSON and nothing else:
{
  "entities": [
    {"text": "...", "type": "PERSON|ORGANIZATION|LOCATION"}
  ]
}
"""

# The assembled prompt
prompt = f"""
## Instruction
{INSTRUCTION}

## Context
{CONTEXT}

## Input
{INPUT}

## Output Format
{OUTPUT_FORMAT}
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0  # Deterministic, for extraction
)

output = response.choices[0].message.content
print(output)

# Parse the JSON
data = json.loads(output)
print(f"Entities found: {len(data['entities'])}")
for e in data['entities']:
    print(f"  - {e['text']} ({e['type']})")

Expected output:

{
  "entities": [
    {"text": "Maria Garcia", "type": "PERSON"},
    {"text": "Google", "type": "ORGANIZATION"},
    {"text": "Mountain View", "type": "LOCATION"},
    {"text": "Juan Perez", "type": "PERSON"},
    {"text": "Microsoft", "type": "ORGANIZATION"}
  ]
}
Entities found: 5
  - Maria Garcia (PERSON)
  - Google (ORGANIZATION)
  - Mountain View (LOCATION)
  - Juan Perez (PERSON)
  - Microsoft (ORGANIZATION)

How the model processes each part

The model doesn't "read" the prompt the way a human does. It processes it as a sequence of tokens:

  1. Tokens: The text is split into subunits (words, parts of words, punctuation). "Extract" may be 1 token, "entities" may be 1-2 tokens.

  2. Order matters: The model processes left to right. The instruction at the start carries more "weight" than context at the end in some scenarios. That's why the recommended order is: Instruction → Context → Input → Output Format.

  3. Delimiters: Using labels like ## Instruction or Input: helps the model segment the prompt mentally. It isn't mandatory, but it improves consistency.

  4. Length: More context isn't always better. Irrelevant context can "dilute" the instruction. Only include what's necessary.

  5. Recency bias: LLMs tend to give more weight to what sits at the end of the prompt. That's why putting the output format last is a good practice — it's the last thing the model "sees" before generating.


Tokens and tokenization: the impact on results

What tokens are

LLMs don't process characters or whole words. They process tokens, which are fragments of text (typically 3-4 characters in English, 1-2 in Spanish).

Example:

  • "Prompt engineering" → ~3-4 tokens
  • "ingeniería de prompts" → ~4-5 tokens

The impact on results

  1. Context limit: Every model has a maximum number of tokens (e.g. 128K for GPT-4o). If your prompt + answer exceeds the limit, it gets truncated.

  2. Cost: Most APIs charge per token. A longer prompt = a higher cost per call.

  3. Latency: More tokens = more processing time. For real-time applications, that matters.

  4. Quality: In some cases, very long prompts with redundant information can degrade quality. "Signal vs noise".

Check the token count

import tiktoken
from openai import OpenAI

# Count tokens before calling
def count_tokens(text: str, model: str = "gpt-4o-mini") -> int:
    encoding = tiktoken.encoding_for_model(model)
    return len(encoding.encode(text))

# Example
prompt = """
Extract the named entities from the following text.
Respond with JSON: {"entities": [{"text": "...", "type": "PERSON|ORGANIZATION|LOCATION"}]}

Text: Maria Garcia works at Google.
"""

tokens = count_tokens(prompt)
print(f"Prompt tokens: {tokens}")
# Output: Prompt tokens: ~42

# Cost estimate (gpt-4o-mini: $0.15 per million input tokens)
cost_per_call = tokens * 0.15 / 1_000_000
print(f"Estimated cost: ${cost_per_call:.6f}")

Anatomy vs roles: the distinction

There's an important difference between the anatomy of a prompt (the components of the content) and roles (system/user/assistant, which are the structure of the API):

Anatomy (what the prompt says):

  • Instruction, Context, Input, Output Format

Roles (how it's organized in the API):

  • system: Instruction + Context (the contract)
  • user: Input + a repeat of the Output Format if needed
  • assistant: The history of answers
# Mapping anatomy → roles
response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {
            "role": "system",         # Instruction + Context
            "content": """
            You are a named entity extractor.
            Categories: PERSON, ORGANIZATION, LOCATION.
            Respond with valid JSON only.
            """
        },
        {
            "role": "user",           # Input + Output Format
            "content": """
            Text: Maria Garcia works at Google in Mountain View.
            
            Format: {"entities": [{"text": "...", "type": "..."}]}
            """
        }
    ],
    temperature=0
)

Comparison: a prompt without anatomy vs with anatomy

AspectWithout anatomyWith anatomy
ReproducibilityLow (every attempt is different)High (same structure, consistent results)
DebuggingHard (you don't know what to change)Easy (change one component, measure the impact)
EvaluationSubjective ("it looks good")Per component (is the instruction clear? is the format right?)
MaintenanceChaoticVersionable, documentable
CostNot optimizedOptimizable (token count per component)

Comparison: component ordering

# Order A: instruction first (recommended)
prompt_a = """
Classify the sentiment as POSITIVE or NEGATIVE.

Rules: One word only. No explanations.

Text: "I loved the product"
"""

# Order B: input first (less effective)
prompt_b = """
Text: "I loved the product"

Classify the sentiment as POSITIVE or NEGATIVE.
One word only.
"""

# On most models, order A is more consistent
# because the instruction comes before the input

How this connects to the project

In the Prompt Analyzer (capsule 08) you'll use the anatomy to:

  • Identify which components a given prompt has
  • Detect missing components (e.g. no output format)
  • Suggest specific improvements per component
  • Score the "quality" of a prompt by which components are present

Troubleshooting

Problem 1: the model ignores the output format

Cause: The output format is buried in a lot of text, or it isn't explicit enough.

Fix: Put the output format at the end, with concrete examples. Use phrases like "Respond ONLY with..." or "Mandatory format:" and add an example:

Mandatory format (don't include anything else):
{"result": "POSITIVE|NEGATIVE", "confidence": 0.0-1.0}

Example: {"result": "POSITIVE", "confidence": 0.95}

Problem 2: the model invents information that isn't in the input

Cause: Missing context that explicitly rules out invention.

Fix: Add this to the context:

IMPORTANT: Don't invent information.
If it isn't in the input, put "Not found" in that field.

Problem 3: inconsistent answers between calls

Cause: Temperature > 0, or an ambiguous instruction that allows multiple interpretations.

Fix: Use temperature=0 for deterministic tasks. Make the instruction more explicit, with examples of what you DO and DON'T want.


Problem 4: the model blends the context with the input

Cause: The input isn't clearly delimited.

Fix: Use explicit delimiters:

Instruction: Classify the sentiment.

Input (text to classify):
'''
I loved the product, I recommend it.
'''

Respond only with: POSITIVE, NEGATIVE or NEUTRAL

Problem 5: the prompt is too long and the model loses the thread

Cause: Excessive context that dilutes the instruction.

Fix: The principle of minimum useful context: include only what the model NEEDS to know for this specific task. Check the token count with tiktoken.


Exercises

Exercise 1: Identify the components

Given this prompt, identify the instruction, context, input and output format:

You are an assistant that summarizes articles. The summary must be 100 words maximum.
Only include facts from the article, not opinions.

Article: "Artificial intelligence is transforming the industry..."

Respond with: SUMMARY: [your summary here]
See solution
  • Instruction: "Summarize articles" (implicit in the role)
  • Context: 100 words maximum, facts only, no opinions
  • Input: The article between quotes
  • Output Format: "SUMMARY: [your summary here]"

Analysis: The instruction is implicit in the role (it isn't explicit as an action). To improve it: "Summarize the following article in 100 words maximum, including facts only."


Exercise 2: Fill in the missing components

This prompt fails frequently. Which components are missing?

Translate this into English: "Prompt engineering es fundamental."
See solution

Components present:

  • Instruction: ✅ "Translate... into English"
  • Input: ✅ The text between quotes

Missing components:

  • Context: It doesn't specify tone (formal/informal), dialect (UK/US), or whether there are technical terms that shouldn't be translated
  • Output Format: Just the translation? With the original? In quotes?

Improved prompt:

Translate the following text into English (US). Keep the tone professional.
If there are technical terms in Spanish that are used in English (e.g. "prompt engineering"), leave them untranslated.

Input: "Prompt engineering es fundamental."

Output: The translation only, without the original or any explanations.

Exercise 3: A prompt with a complete anatomy

Write a prompt with the 4 components for the following task: Extract the price, product and currency from e-commerce texts.

Example input: "The iPhone 15 Pro is available for $1,199 USD"

See solution
from openai import OpenAI
import json

client = OpenAI()

INSTRUCTION = "Extract price information from e-commerce texts."

CONTEXT = """
Extract exactly these fields:
- product: the product name
- price: a numeric value (without the currency symbol)
- currency: a 3-letter code (USD, EUR, MXN, etc.)

If a field isn't present, use null.
"""

INPUT = "The iPhone 15 Pro is available for $1,199 USD"

OUTPUT_FORMAT = """
Valid JSON, no extra text:
{"product": "...", "price": 0.0, "currency": "..."}
"""

prompt = f"""
## Instruction
{INSTRUCTION}

## Context
{CONTEXT}

## Input
{INPUT}

## Output Format
{OUTPUT_FORMAT}
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0
)

result = json.loads(response.choices[0].message.content)
print(result)
# {"product": "iPhone 15 Pro", "price": 1199.0, "currency": "USD"}

Exercise 4: Diagnose a failing prompt

This prompt produces inconsistent results. Identify the problem and fix it:

You are a marketing expert. Analyze this tweet and tell me whether it's good or bad for the brand.

Tweet: "Our product changed my life. #Recommended"
See solution

Problems identified:

  1. No output format: "tell me whether it's good or bad" is vague. Just one word? With an explanation? With a score?
  2. Insufficient context: What criteria define "good for the brand"? Authenticity? Reach? Sentiment?
  3. Ambiguous instruction: "Analyze" doesn't specify which aspects to analyze

Corrected prompt:

You are a social media marketing expert.

Evaluate the following tweet against these criteria:
- Authenticity: does it look genuine or paid?
- Sentiment: positive, neutral or negative for the brand?
- Reputational risk: is there any risk?

Tweet: "Our product changed my life. #Recommended"

Respond with JSON:
{
  "authenticity": "genuine|paid|ambiguous",
  "sentiment": "positive|neutral|negative",
  "reputational_risk": true|false,
  "recommendation": "amplify|ignore|reply"
}

Exercise 5: The difference order makes

Take this prompt and reorganize the components into the recommended order (Instruction → Context → Input → Output):

Input: "The meeting is on Tuesday, July 15 at 3pm in room B"

Return JSON with the fields: date, time, location.

Context: Extract meeting details from natural language text.

Instruction: Extract the details of the following meeting.
See solution
## Instruction
Extract the details of the following meeting.

## Context
Extract meeting details from natural language text.
If a field isn't present, use null.
Date format: YYYY-MM-DD. Time format: HH:MM (24h).

## Input
"The meeting is on Tuesday, July 15 at 3pm in room B"

## Output Format
Valid JSON:
{"date": "2025-07-15", "time": "15:00", "location": "room B"}

Extra improvements: An explicit format for date and time was added, plus the handling of null fields.


Exercise 6 (Advanced): A prompt with multiple inputs

Design a prompt that can process several tickets at once and return an array of classifications.

See solution
from openai import OpenAI
import json

client = OpenAI()

tickets = [
    "I can't access my account",
    "When does my order arrive?",
    "Duplicate charge on my invoice",
    "Hi, I need help with something"
]

# Build the ticket list for the prompt
tickets_formatted = "\n".join([f"{i+1}. {t}" for i, t in enumerate(tickets)])

prompt = f"""
## Instruction
Classify each support ticket into a category.

## Context
Available categories: TECHNICAL, ORDER, BILLING, GREETING, OTHER
One category per ticket. Only use the categories listed.

## Input
{tickets_formatted}

## Output Format
JSON with an array of objects:
[
  {{"id": 1, "category": "..."}},
  {{"id": 2, "category": "..."}}
]
Return exactly {len(tickets)} objects.
"""

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": prompt}],
    temperature=0
)

results = json.loads(response.choices[0].message.content)
for r in results:
    print(f"Ticket {r['id']}: {r['category']}")

# Expected output:
# Ticket 1: TECHNICAL
# Ticket 2: ORDER
# Ticket 3: BILLING
# Ticket 4: GREETING

Summary

  • 4 components: Instruction, Context, Input, Output Format
  • Instruction: What to do (explicit, actionable, with a clear verb)
  • Context: What to know, which constraints apply, domain definitions
  • Input: The data that varies per call, explicitly delimited
  • Output Format: The structure of the answer (JSON, string, list); at the end of the prompt
  • Tokens: They drive cost, latency, limits. Check them with tiktoken before production
  • Recommended order: Instruction → Context → Input → Output Format
  • Roles vs anatomy: Roles (system/user) are the structure of the API; the anatomy is the content

Further resources

  1. OpenAI Tokenizer — A visual tool for seeing how text gets tokenized
  2. tiktoken (Python) — OpenAI's library for counting tokens in code
  3. Anthropic Token Counting — How to count tokens for Claude
  4. OpenAI Prompt Engineering Guide — Strategies recommended by OpenAI
  5. Learn Prompting: Prompt Structure — An introductory guide to prompt structure
  6. Anthropic Prompt Design — How Claude processes prompts