Contents

Chapter 1

Prompt Engineering Patterns Guide

A practical reference for the most effective prompt patterns, when to

use them, and how to combine them for complex tasks.

Pattern Quick Reference

PatternBest ForComplexityToken Cost
Zero-shotSimple, well-defined tasksLowLow
Few-shotTasks where output format mattersMediumMedium
Chain-of-ThoughtReasoning, math, logicMediumHigh
Self-ConsistencyHigh-stakes reasoningHighVery High
ReActAgent tasks with toolsHighVariable
Tree-of-ThoughtComplex problem solvingVery HighVery High

1. Zero-Shot Prompting

Give the model a task with no examples. Works when the task is

unambiguous and the model has strong prior knowledge.

When to use: Classification, simple extraction, translation,

summarization of short texts.

When NOT to use: Tasks with specific output formats, domain-specific

terminology, or unusual conventions.

System: You are a sentiment classifier. Return exactly one word:
        positive, negative, or neutral.

User: "The new update completely broke my workflow. Unacceptable."

Key principle: The more specific your system message, the better

zero-shot works. Constrain the output format tightly.


2. Few-Shot Prompting

Provide 2-5 input/output examples before the actual task. The model

learns the pattern from examples rather than explicit instructions.

When to use: Custom output formats, domain-specific tasks,

tasks where "show don't tell" is easier.

When NOT to use: Tasks where examples would be too long (> 1K tokens

each), or where the pattern is trivially obvious.

Choosing Good Examples

1. Diverse: Cover different edge cases, not just the happy path

2. Representative: Match the distribution of real inputs

3. Correct: Wrong examples teach wrong patterns — double-check

4. Ordered: Put the most similar example to the expected input last

Common Mistake: Example Leakage

# BAD: The model will always output "Acme Corp" because all examples use it
Example 1: Input: "..." → {"company": "Acme Corp"}
Example 2: Input: "..." → {"company": "Acme Corp"}
Example 3: Input: "..." → {"company": "Acme Corp"}

# GOOD: Diverse examples prevent fixation on one pattern
Example 1: Input: "..." → {"company": "Northwind Inc"}
Example 2: Input: "..." → {"company": "DataCo"}
Example 3: Input: "..." → {"company": "StreamLine Labs"}

3. Chain-of-Thought (CoT)

Ask the model to show its reasoning step by step before giving

the final answer. Dramatically improves accuracy on reasoning tasks.

When to use: Math problems, multi-hop reasoning, logic puzzles,

complex analysis, any task where intermediate steps matter.

Two approaches:

System: Think step by step before answering.

User: If a store has 240 apples and sells 30% on Monday,
then receives a shipment of 50 on Tuesday, how many apples
does it have on Wednesday?

Zero-Shot CoT

Just add "Let's think step by step" to any prompt. Surprisingly

effective — often matches few-shot CoT performance.

CoT with Structured Output

For production use, separate the reasoning from the answer:

System: You solve math problems. Show your work in a <reasoning>
block, then give the final answer in a <answer> block.

User: ...

Expected output:
<reasoning>
Step 1: 240 × 0.30 = 72 apples sold
Step 2: 240 - 72 = 168 remaining after Monday
Step 3: 168 + 50 = 218 after Tuesday shipment
</reasoning>
<answer>218</answer>

Why this matters: You can programmatically extract just the

block while keeping the reasoning for debugging.


4. Self-Consistency

Run the same prompt multiple times (with temperature > 0), then

take the majority answer. Trades cost for accuracy.

When to use: High-stakes decisions, ambiguous inputs,

tasks where you need confidence calibration.

python
# Pseudocode for self-consistency
answers = []
for _ in range(5):
    response = llm.complete(prompt, temperature=0.7)
    answer = extract_answer(response)
    answers.append(answer)

final_answer = most_common(answers)
confidence = answers.count(final_answer) / len(answers)

Cost consideration: 5× the token cost. Use only when accuracy

is worth the expense (medical, financial, legal domains).


5. Role Prompting

Assign the model a specific persona or expertise. This activates

domain-specific knowledge and adjusts tone/depth.

Effective roles:

"You are a senior Python developer with 15 years of experience."
"You are a tax accountant specializing in small business filings."
"You are a cybersecurity analyst performing a threat assessment."

Ineffective roles:

"You are the world's best AI."  (too vague)
"You are an expert."  (at what?)
"You are helpful and harmless."  (default behavior anyway)

Combining with constraints:

You are a senior data engineer. You ONLY recommend solutions using:
- Python 3.10+
- Apache Spark 3.x
- Delta Lake
- Azure cloud services
If asked about other technologies, say "Outside my expertise area."

6. Output Format Control

The most impactful technique for production systems. If you don't

control the output format, you can't reliably parse the response.

JSON Mode

System: Return a JSON object with exactly these keys: name, age, city.
        Return ONLY the JSON object, no additional text.

Markdown Tables

System: Format your response as a markdown table with columns:
        | Feature | Status | Priority |

Structured Delimiters

System: Use these delimiters in your response:
        <analysis>Your analysis here</analysis>
        <recommendation>Your recommendation</recommendation>
        <confidence>0.0 to 1.0</confidence>

Anti-pattern: Hoping for the Best

# BAD: No format control → unparseable output
System: Analyze this data and give me the results.

# GOOD: Explicit format → reliable parsing
System: Analyze this data. Return a JSON object with:
- "findings": array of strings
- "severity": "low" | "medium" | "high"
- "confidence": float 0.0-1.0
Return ONLY the JSON. No markdown fences, no commentary.

7. Prompt Chaining

Break complex tasks into a pipeline of simpler prompts, where

each step's output feeds the next step's input.

Example: Document Analysis Pipeline

Step 1: Extract entities  →  list of entities
Step 2: Classify relationships  →  entity graph
Step 3: Summarize findings  →  executive summary
Step 4: Generate recommendations  →  action items

Advantages over one giant prompt:

  • Each step is testable independently
  • You can retry individual steps on failure
  • Different steps can use different models (cheap for extraction, expensive for reasoning)
  • Intermediate results are inspectable for debugging

Disadvantage: Higher total latency (steps run sequentially).


8. Negative Prompting

Tell the model what NOT to do. Surprisingly effective for preventing

common failure modes.

System: You summarize documents.

DO NOT:
- Start with "This document discusses..."
- Include your own opinions or editorializing
- Use the phrase "in conclusion"
- Add information not present in the source
- Use bullet points (write flowing paragraphs)

Combining Patterns: Decision Tree

Is the task simple and well-defined?
├── Yes → Zero-shot with format control
└── No
    ├── Does output format matter?
    │   ├── Yes → Few-shot (2-3 examples)
    │   └── No → Zero-shot with CoT
    ├── Does it require reasoning?
    │   ├── Yes → Chain-of-Thought
    │   │   └── Is accuracy critical? → Self-Consistency (5 runs)
    │   └── No → Few-shot or zero-shot
    ├── Is it multi-step?
    │   ├── Yes → Prompt chaining
    │   └── No → Single prompt with CoT
    └── Does it need tools/actions?
        └── Yes → ReAct or Plan-and-Execute

Token Optimization Tips

1. System messages are cached in many APIs — put stable content there

2. Few-shot examples cost tokens every call — consider fine-tuning if

you're running > 10K calls/day with the same examples

3. CoT increases output tokens — budget for 2-3× the raw answer length

4. Batch related tasks into one call when possible (classify 10 items

at once instead of 10 separate calls)

5. Use tiered models: GPT-4o-mini for classification, GPT-4o for reasoning


Measuring Prompt Quality

Track these metrics for every prompt in production:

MetricHow to MeasureTarget
Parse success rateDid the output match the expected format?> 98%
AccuracyHuman evaluation or automated checksTask-dependent
LatencyTime to first token + total generation time< 5s for interactive
Token efficiencyTokens used vs. useful output lengthMonitor trend
ConsistencySame input → same output (at temp=0)> 95%
Edge case handlingTest with adversarial inputsNo crashes
Chapter 2

Prompt Versioning Workflow

How to manage, version, test, and deploy prompt changes using the

registry system included in this kit.

Why Version Prompts?

Prompts are code. They have the same failure modes:

  • A "small tweak" breaks downstream parsing
  • You can't reproduce last week's results because the prompt changed
  • Two team members edit the same prompt and one overwrites the other
  • A production incident traces back to a prompt change but nobody

knows what changed or when

Prompt versioning solves all of these by giving every prompt change

a version number, timestamp, author, and diff history.


The Prompt Lifecycle

┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  Draft   │ →  │  Test    │ →  │  Stage   │ →  │  Prod    │
└──────────┘    └──────────┘    └──────────┘    └──────────┘
     │               │               │               │
  Write &        A/B test        Shadow run       Full traffic
  iterate        vs. current     alongside        (rollback-ready)

Stage 1: Draft

Create or modify a prompt template using the YAML format:

yaml
id: extraction.entity_extraction
name: "Named Entity Extraction"
version: "2.1"               # ← Semantic version you assign
category: extraction

system_message: |
  You are a precise entity-extraction engine...

user_template: |
  Extract all named entities from: {input_text}

Register it in the Python registry:

python
from src.registry import PromptRegistry

registry = PromptRegistry()

# Adding automatically increments the internal version counter.
# The YAML 'version' field is your human-readable semantic version.
record = registry.add(
    prompt_id="extraction.entity_extraction",
    name="Named Entity Extraction",
    category="extraction",
    content={
        "system_message": "You are a precise entity-extraction engine...",
        "user_template": "Extract all named entities from: {input_text}",
    },
    tags=["ner", "json-output"],
    metadata={"author": "your-name", "semantic_version": "2.1"},
)

print(f"Registered as internal version {record.version}")

Stage 2: Test

Run the prompt against a held-out evaluation set and compare metrics:

python
from src.ab_testing import ABTestHarness, ABTestConfig

harness = ABTestHarness()

config = ABTestConfig(
    test_name="entity-extraction-v2.1-vs-v2.0",
    variant_a_name="v2.0-current",
    variant_b_name="v2.1-candidate",
    metric_names=["precision", "recall", "parse_success_rate"],
    sample_size=100,
    confidence_level=0.95,
)

test_id = harness.create_test(config)

# Run your evaluation loop, recording results for each variant...
# (See the A/B testing module documentation for details)

report = harness.get_report(test_id)
print(report)

Stage 3: Stage (Shadow Mode)

Run the new prompt in production alongside the current one, but only

use the current prompt's output. Compare results offline:

python
# Pseudocode for shadow mode
current_prompt = registry.get("extraction.entity_extraction", version=5)
candidate_prompt = registry.get("extraction.entity_extraction", version=6)

current_result = llm.complete(current_prompt.render(input_text=text))
candidate_result = llm.complete(candidate_prompt.render(input_text=text))

# Log both, serve only current_result to the user
log_shadow_comparison(current_result, candidate_result, input_text=text)

Stage 4: Production Rollout

Once the candidate passes shadow testing, promote it:

python
# Tag the version as production-active
registry.tag("extraction.entity_extraction", version=6, tag="production")

Viewing History and Diffs

List All Versions

python
history = registry.history("extraction.entity_extraction")
for record in history:
    print(f"v{record.version} | {record.created_at} | {record.metadata}")

Diff Two Versions

python
from src.diff_tool import PromptDiff

differ = PromptDiff()

v5 = registry.get("extraction.entity_extraction", version=5)
v6 = registry.get("extraction.entity_extraction", version=6)

diff = differ.compare(v5.content, v6.content)
print(diff.summary())

# Output:
# system_message: 2 lines changed (added constraint about date formats)
# user_template: unchanged
# variables: 1 added (date_format)

Using the Registry Diff Shortcut

python
diff = registry.diff(
    "extraction.entity_extraction",
    version_a=5,
    version_b=6,
)
# Returns: {"added": [...], "removed": [...], "changed": [...]}

Export and Import

Export for Backup or Sharing

python
# Export the entire registry to a JSON file
registry.export_to_file(Path("prompts_backup_2025-06-17.json"))

# Export a single prompt's history
registry.export_prompt("extraction.entity_extraction", Path("entity_extraction_history.json"))

Import from File

python
new_registry = PromptRegistry()
new_registry.import_from_file(Path("prompts_backup_2025-06-17.json"))

Import from YAML Catalog

The kit includes 30 prompt YAML files in the prompts/ directory.

Load them all at once:

python
from src.template_engine import TemplateEngine

engine = TemplateEngine()
engine.load_directory(Path("prompts/"))

# All 30 templates are now available
template = engine.get("extraction.entity_extraction")
messages = template.build_messages(input_text="Acme Corp announced...")

Best Practices

1. One Change at a Time

Never change the system message AND user template AND examples in

the same version. Change one component, test it, then change the next.

This makes it possible to attribute quality changes to specific edits.

2. Write Change Notes

Add a change_notes field to metadata when registering:

python
registry.add(
    prompt_id="classification.sentiment",
    name="Sentiment Classifier",
    category="classification",
    content=new_content,
    metadata={
        "change_notes": "Added 'mixed' sentiment category for texts with both positive and negative aspects",
        "author": "your-name",
    },
)

3. Keep an Evaluation Set

For every prompt in production, maintain a set of 20-50 input/expected-output

pairs. Run this set against every new version before promoting.

python
eval_set = [
    {"input": "Great product!", "expected_sentiment": "positive"},
    {"input": "Terrible service.", "expected_sentiment": "negative"},
    {"input": "It's okay I guess.", "expected_sentiment": "neutral"},
    # ... 20+ more
]

accuracy = 0
for case in eval_set:
    result = run_prompt(new_version, case["input"])
    if result == case["expected_sentiment"]:
        accuracy += 1

accuracy_pct = accuracy / len(eval_set) * 100
print(f"Accuracy: {accuracy_pct:.1f}%")

if accuracy_pct < 90:
    print("FAIL: Accuracy below threshold. Do not promote.")

4. Rollback Plan

Always know which version is currently in production so you can

roll back instantly:

python
# Before deploying v6
previous_production = registry.get_tagged("extraction.entity_extraction", tag="production")
# Save previous_production.version for rollback

# If v6 has issues
registry.tag("extraction.entity_extraction", version=previous_production.version, tag="production")

5. Prompt Change Review

Treat prompt changes like code changes:

  • Require review from at least one other person
  • Test against the evaluation set
  • Document the reason for the change
  • Monitor metrics for 24 hours after deployment
LLM Prompt Engineering Kit v1.0.0 — Free Preview