Skip to content
Codeloom
Prompt Engineering

Few-Shot Prompting: Learning from Examples

Master few-shot prompting to teach LLMs new tasks through carefully selected examples, formatting patterns, and example ordering strategies.

·8 min read · By Codeloom
Beginner 12 min read

What you'll learn

  • How few-shot learning works and why examples matter
  • How to select and order examples for best results
  • Formatting patterns that improve consistency
  • The difference between few-shot and zero-shot prompting
  • When to use few-shot vs fine-tuning

Prerequisites

  • Basic familiarity with LLM APIs

What Is Few-Shot Prompting

Few-shot prompting means including a handful of input-output examples in your prompt before the actual task. The model learns the pattern from these examples and applies it to the new input. No training, no fine-tuning, no gradient updates. Just examples in the prompt.

Extract the product name and price from the text.

Text: "The new AirPods Pro 2 are available for $249"
Product: AirPods Pro 2
Price: $249

Text: "Get the Samsung Galaxy S24 Ultra starting at $1,299.99"
Product: Samsung Galaxy S24 Ultra
Price: $1,299.99

Text: "Apple's M4 MacBook Air costs $1,099 for the base model"
Product:
Price:

The model sees two completed examples and understands exactly what to extract and how to format it. Without examples, it might return a full sentence, use different labels, or miss edge cases like the “$1,299.99” format.

Zero-Shot vs Few-Shot

Zero-shot:    Instruction ──────────────────> New Input ──> Output
            (model interprets what you want)

Few-shot:     Instruction ──> Example 1 ──> Example 2 ──> New Input ──> Output
            (model sees exactly what you want)
Zero-shot vs few-shot prompting

Zero-shot prompting gives instructions but no examples. It works well for tasks the model already understands clearly: “Translate this to French,” “Summarize this article,” “Is this email spam?”

Few-shot prompting is better when:

  • The output format is specific or unusual
  • The task is ambiguous and examples remove ambiguity
  • You need consistent formatting across many calls
  • The model tends to deviate from your instructions

How Many Examples

Research consistently shows diminishing returns after 3-5 examples for most tasks. Here is a practical guide:

ExamplesWhen to use
0 (zero-shot)Simple, well-known tasks
1-2Format demonstration
3-5Complex extraction, classification with nuance
5-10Highly specific output format, edge cases
10+Rarely worth it; consider fine-tuning instead

More examples mean more tokens, higher cost, and more latency. Each example should earn its place by teaching something new.

Selecting Good Examples

The quality of your examples matters far more than the quantity. Here are the principles.

Cover the variety of inputs. If your task handles different formats, include examples of each.

SENTIMENT_EXAMPLES = """Classify the sentiment as positive, negative, or neutral.

"This product changed my life! Best purchase ever!" -> positive
"Arrived broken. Returning immediately." -> negative
"It's a phone. It makes calls." -> neutral
"The camera is great but the battery is terrible." -> mixed-negative
"Just received it, haven't opened yet." -> neutral

"{new_text}" ->"""

Notice the examples cover enthusiastic positive, angry negative, flat neutral, mixed sentiment, and a non-opinion. Each example teaches the model something different about where the boundaries are.

Include edge cases. The model will encounter ambiguous inputs. Show it how to handle them.

DATE_EXTRACTION = """Extract the date from the text. If no specific date is mentioned, output "NONE".

"Meeting scheduled for March 15, 2025" -> 2025-03-15
"Let's meet next Tuesday" -> NONE
"The report from 12/31/2024 needs review" -> 2024-12-31
"We launched sometime in Q3 last year" -> NONE
"Due by Jan 1" -> NONE

"{text}" ->"""

The “next Tuesday” and “Q3 last year” examples explicitly teach the model that relative dates should be NONE, not guessed. Without these, the model would try to resolve them.

Match the difficulty of your actual inputs. If your production inputs are messy (typos, abbreviations, mixed languages), your examples should be messy too. Clean examples teach the model to expect clean input.

Example Ordering

The order of examples affects model output. Two rules of thumb:

  1. Put the most similar example last. Models pay more attention to examples closer to the actual input (recency bias).
  2. Vary the classes. If you are doing classification, do not put all positives first and all negatives last. Interleave them.
# Bad ordering: model may default to "negative"
examples = [
    ("Great product!", "positive"),
    ("Love it!", "positive"),
    ("Amazing quality", "positive"),
    ("Terrible service", "negative"),
    ("Broken on arrival", "negative"),
    ("Worst purchase ever", "negative"),  # Last examples are all negative
]

# Good ordering: balanced, interleaved
examples = [
    ("Great product!", "positive"),
    ("Terrible service", "negative"),
    ("It works fine", "neutral"),
    ("Love the design!", "positive"),
    ("Broke after a week", "negative"),
    ("Average quality, fair price", "neutral"),
]

Formatting Patterns

How you format examples matters. The model replicates the exact format it sees.

Key-value format (good for extraction):

Input: "John Smith, age 34, lives in Boston"
Name: John Smith
Age: 34
City: Boston

Arrow format (good for classification):

"Great product!" -> positive
"Terrible quality" -> negative

JSON format (good for structured output):

Input: "The 2024 Tesla Model 3 starts at $38,990"
Output: {"product": "Tesla Model 3", "year": 2024, "price": 38990}

Markdown table (good for multi-field extraction):

| Text | Category | Priority |
|------|----------|----------|
| "Server is down" | incident | high |
| "Add dark mode" | feature | low |

Pick one format and use it consistently across all examples. Mixing formats confuses the model.

Few-Shot in Code

Here is a reusable pattern for few-shot prompting with the OpenAI API.

import openai

client = openai.OpenAI()

def few_shot_classify(
    text: str,
    examples: list[tuple[str, str]],
    categories: list[str],
    model: str = "gpt-4o-mini"
) -> str:
    """Classify text using few-shot examples."""

    # Build the examples section
    example_text = "\n".join(
        f'"{inp}" -> {out}' for inp, out in examples
    )

    prompt = f"""Classify the text into one of these categories: {', '.join(categories)}
Respond with only the category name.

{example_text}

"{text}" ->"""

    response = client.chat.completions.create(
        model=model,
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
        max_tokens=20
    )
    return response.choices[0].message.content.strip()

# Usage
result = few_shot_classify(
    text="The checkout page keeps crashing on mobile",
    examples=[
        ("My payment was charged twice", "billing"),
        ("App crashes when I open settings", "bug"),
        ("Can you add Apple Pay support?", "feature_request"),
        ("Login page shows a 500 error", "bug"),
        ("I was charged the wrong amount", "billing"),
    ],
    categories=["billing", "bug", "feature_request", "general"]
)
# result: "bug"

Dynamic Example Selection

In production, you often have a large pool of examples and want to select the most relevant ones for each input. This is called dynamic few-shot or retrieval-augmented few-shot.

from sentence_transformers import SentenceTransformer
import numpy as np

model = SentenceTransformer('all-MiniLM-L6-v2')

# Your example bank
example_bank = [
    {"input": "Server returns 503 errors", "output": "infrastructure"},
    {"input": "Button color should be blue", "output": "design"},
    {"input": "Add export to PDF feature", "output": "feature_request"},
    {"input": "Database connection timeout", "output": "infrastructure"},
    {"input": "Fonts are too small on mobile", "output": "design"},
    # ... hundreds more
]

# Pre-compute embeddings
bank_texts = [e["input"] for e in example_bank]
bank_embeddings = model.encode(bank_texts)

def select_examples(query: str, k: int = 3) -> list[dict]:
    """Select the k most similar examples to the query."""
    query_embedding = model.encode([query])
    similarities = np.dot(bank_embeddings, query_embedding.T).flatten()
    top_k = np.argsort(similarities)[-k:][::-1]
    return [example_bank[i] for i in top_k]

# For a new input, select relevant examples dynamically
new_input = "The API rate limiter is blocking valid requests"
relevant_examples = select_examples(new_input, k=3)
# Returns infrastructure-related examples, not design ones

This approach scales better than cramming all examples into every prompt and gives the model more relevant context.

Few-Shot vs Fine-Tuning

AspectFew-shotFine-tuning
Setup timeMinutesHours to days
Cost per callHigher (more tokens)Lower (no examples in prompt)
FlexibilityChange examples anytimeRequires retraining
Data needed3-10 examples50-1,000+ examples
Best forPrototyping, varied tasksHigh-volume, single task

Start with few-shot. If you are making thousands of identical calls per day and the few-shot prompt is expensive, switch to fine-tuning. Few-shot is your prototyping tool; fine-tuning is your optimization tool.

Key Takeaways

Few-shot prompting is the most reliable way to teach an LLM a new task without training. Select examples that cover the variety of your inputs, include edge cases, and match the messiness of real data. Order matters: interleave classes and put the most relevant example last. Use a consistent format. And when your example bank grows large, use embedding-based retrieval to select the best examples dynamically for each input.