Examples instead of endless instructions
Few-shot prompting uses a handful of concrete input and desired output pairs to teach Claude a format or style more reliably than any instruction, no matter how detailed. This article shows, through code style and commit message examples, how to pick representative examples, cover edge cases, and avoid common mistakes in prompt design.
Table of Contents
- 1. What few-shot prompting actually does
- 2. Zero-shot, one-shot, and few-shot compared
- 3. Why examples steer more reliably than instructions
- 4. Practical example: teaching consistent code style
- 5. Practical example: enforcing a commit message format
- 6. Choosing representative examples and covering edge cases
- 7. Using few-shot in Claude Code and the Anthropic API
- 8. Limits and risks of few-shot prompting
- 9. Few-shot prompting in direct comparison
- 10. Summary
- 11. FAQ
1. What few-shot prompting actually does
Few-shot prompting means giving a language model not just a task description, but also a small number of concrete examples of how a given input should be transformed into the desired output. The model picks up the pattern from the examples in context and applies it to new, similar inputs, an effect referred to in research as in-context learning. Unlike fine-tuning, this does not change a single model weight, the pattern only works within the current context window.
For developers this matters because many everyday tasks follow exactly this structure: raw text needs to be turned into a specific format, a function needs to be documented following a fixed schema, a diff needs to become a commit message with a fixed structure. Such tasks can technically also be described through pure instruction, but the description would have to spell out every format rule, every exception, and every stylistic nuance explicitly. Few-shot prompting shifts this work from writing a complete specification to curating a few, but highly informative, examples.
2. Zero-shot, one-shot, and few-shot compared
With zero-shot prompting, the model only receives the task description, no examples. This works well for tasks Claude already knows well from training, such as general summaries or standard translations. For project-specific formats, unusual conventions, or ambiguous style questions, zero-shot often produces usable but inconsistent results, because the model has to fill in the missing details itself, and that interpretation can vary slightly from request to request.
One-shot prompting with exactly one example already reduces this variance considerably, because a concrete pattern serves as an anchor. The risk here: the model can over-generalize properties of that single example, for instance treating a random variable naming convention as a binding rule. Few-shot prompting with typically three to eight examples strikes a balance, enough examples to separate the actual pattern from random detail, but few enough to avoid unnecessarily bloating the context and noticeably slowing down response time.
3. Why examples steer more reliably than instructions
Natural-language instructions such as write concise, idiomatic code are semantically underspecified. What counts as concise depends on the context, the language, and a team's conventions, and the model has to fill that gap with its own, often plausible but not always fitting, assumptions. A concrete example, by contrast, shows the desired result directly, without an abstract rule first having to be translated into concrete form. The model no longer has to interpret, it can interpolate, that is, produce a new result that sits structurally between the shown examples.
A second effect concerns consistency across multiple requests. Because language models do not respond deterministically to the same input, purely instruction-based results scatter more than example-based ones, especially on formatting questions such as indentation, parameter ordering, or docblock structure. Examples act like guardrails that deliberately narrow the model's solution space. This shows up clearly in practice: a team that only instructs Claude to write commits in Conventional Commits format tends to see more format deviations than a team that additionally supplies three real example commits from its own repository.
4. Practical example: teaching consistent code style
A typical scenario from Magento development: every new method should get a complete PHPDoc block with a description, an @param entry for every parameter, and an @return entry, as the project conventions require. A plain instruction to that effect usually works, but details such as the exact phrasing of the description, how optional parameters are handled, or the order of @param and @throws stay inconsistent unless explicitly specified.
Two to three example pairs from real project code pin this pattern down far more reliably. It is important that the examples do not only show the standard case, but also at least one method with an optional parameter and one with a void return type, so the model does not wrongly assume that every method has exactly one required parameter and a return value. The following JSON shows a few-shot set as it could live in a prompt template or a CLAUDE.md file.
{
"task": "Add a complete PHPDoc block above each public method",
"examples": [
{
"input": "public function getPriceForCustomer(int $productId, int $customerGroupId): float\n{\n return $this->priceResolver->resolve($productId, $customerGroupId);\n}",
"output": "/**\n * Resolves the effective price for a product within a customer group.\n *\n * @param int $productId Product entity id.\n * @param int $customerGroupId Customer group id used for tier pricing.\n * @return float Resolved price including applicable customer group rules.\n */\npublic function getPriceForCustomer(int $productId, int $customerGroupId): float\n{\n return $this->priceResolver->resolve($productId, $customerGroupId);\n}"
},
{
"input": "public function logDeprecationWarning(string $message, ?string $context = null): void\n{\n $this->logger->warning($message, ['context' => $context]);\n}",
"output": "/**\n * Logs a deprecation warning with optional context.\n *\n * @param string $message Human readable deprecation message.\n * @param string|null $context Optional context information, null if not applicable.\n * @return void\n */\npublic function logDeprecationWarning(string $message, ?string $context = null): void\n{\n $this->logger->warning($message, ['context' => $context]);\n}"
}
]
}
5. Practical example: enforcing a commit message format
A second, very common example is automatically formulating commit messages from a git diff. An instruction like use Conventional Commits with type and scope describes the format, but not how granular a team names its scopes, how long the summary line usually is, or whether a body paragraph is expected. These details differ from project to project and are hard to capture fully in text rules without making the prompt unwieldy.
It is more effective to supply three or four real, well-formed commits from the actual git history as examples, chosen so they cover different change types: a feature, a bugfix, and a pure refactor. The following script extracts such example commits automatically from the history and prepares them for a few-shot prompt.
#!/usr/bin/env bash
# collect-commit-examples.sh - extract well-formed commits as few-shot examples
set -euo pipefail
readonly REPO_DIR="${1:-.}"
readonly EXAMPLE_COUNT=4
cd "$REPO_DIR"
# Pick recent commits that already follow the conventional commit pattern
git log --pretty=format:"%H" -n 200 \
| while read -r hash; do
subject="$(git log -1 --pretty=%s "$hash")"
if [[ "$subject" =~ ^(feat|fix|refactor|docs|test)(\([a-z0-9_-]+\))?:\ .+ ]]; then
echo "$hash"
fi
done \
| head -n "$EXAMPLE_COUNT" \
| while read -r hash; do
echo "=== Example commit $hash ==="
git show --stat --format="%s%n%n%b" "$hash" | head -n 20
echo
done
These examples are then appended as a few-shot block in the prompt, followed by the current git diff --staged. In practice this noticeably reduces the amount of rework needed, because Claude no longer has to guess how long a summary line is allowed to be in this particular project, or whether scopes like checkout or catalog are in use, it derives that directly from the examples.
6. Choosing representative examples and covering edge cases
The quality of a few-shot prompt depends almost entirely on the selection of examples, not on their number. Three carefully chosen examples that show different aspects of a task outperform ten nearly identical examples that all cover the same case. A useful rule of thumb: at least one example for the standard case, at least one example for an edge case such as an empty input, an optional parameter, or an exception, and if possible one example that shows what the model should explicitly not do.
A common mistake is that all examples happen to come from the same part of the codebase and therefore share superficial similarities, for instance always the same variable names or always a return type of array. The model can wrongly interpret such coincidences as part of the actual pattern, an effect similar to overfitting in classical machine learning. The order of examples also matters, since models tend to weigh the most recently shown example slightly more heavily. Anyone who wants to emphasize a particular example should therefore place it deliberately at the end of the list, right before the actual request.
# build_fewshot_prompt.py - select diverse examples covering edge cases
from dataclasses import dataclass
@dataclass
class Example:
label: str
input_text: str
output_text: str
def select_representative_examples(pool: list[Example], max_examples: int = 5) -> list[Example]:
"""Pick a diverse subset: standard case, edge cases, and a negative example."""
required_labels = ["standard", "empty_input", "optional_param", "exception_path"]
selected: list[Example] = []
for label in required_labels:
match = next((ex for ex in pool if ex.label == label), None)
if match:
selected.append(match)
# Fill remaining slots with additional diverse examples, avoiding near-duplicates
for ex in pool:
if len(selected) >= max_examples:
break
if ex not in selected:
selected.append(ex)
return selected[:max_examples]
def render_prompt(task: str, examples: list[Example], new_input: str) -> str:
blocks = "\n\n".join(
f"Input:\n{ex.input_text}\n\nOutput:\n{ex.output_text}" for ex in examples
)
return f"Task: {task}\n\n{blocks}\n\nInput:\n{new_input}\n\nOutput:"
7. Using few-shot in Claude Code and the Anthropic API
In Claude Code, few-shot examples can be anchored permanently in two ways: directly in the project's CLAUDE.md file, with a short section containing two or three before-and-after examples for code style or commit format, or as a dedicated slash command template that pulls in the right examples on every invocation. The advantage over a plain text instruction in CLAUDE.md: the examples stay stable and reproducible across different sessions, while an abstract rule can be reinterpreted slightly differently in every new conversation. A section like this for commit messages could look like this in the CLAUDE.md file:
## Commit Message Format (Few-Shot Examples)
Example 1:
Input: git diff with a new payment method
Output: feat(checkout): add PayPal Express as payment method
Example 2:
Input: git diff with a bugfix to price calculation
Output: fix(catalog): correct tier price rounding for decimal quantities
Example 3:
Input: git diff with a refactor without behavior change
Output: refactor(customer): extract address validation into service class
When using the Anthropic API directly, few-shot examples are usually passed as alternating user and assistant messages in the messages array, followed by the actual new request as the final user entry. This structure uses the model more efficiently than examples bundled as plain text in a single message, because it matches the actual conversational format the model was trained on.
// build-fewshot-messages.js - construct a few-shot message array for the API
const client = require("@anthropic-ai/sdk");
function buildFewShotMessages(examples, newDiff) {
const messages = [];
for (const example of examples) {
messages.push({ role: "user", content: `Diff:\n${example.diff}\n\nWrite a commit message.` });
messages.push({ role: "assistant", content: example.commitMessage });
}
messages.push({ role: "user", content: `Diff:\n${newDiff}\n\nWrite a commit message.` });
return messages;
}
async function generateCommitMessage(anthropic, examples, newDiff) {
const response = await anthropic.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 200,
messages: buildFewShotMessages(examples, newDiff),
});
return response.content[0].text;
}
module.exports = { buildFewShotMessages, generateCommitMessage };
8. Limits and risks of few-shot prompting
Few-shot prompting is not a free mechanism. Every example consumes tokens in the context window, which shows up as measurable additional API cost and slightly increased latency for frequently repeated requests. With very long examples, such as entire files instead of short excerpts, the overhead can outweigh the benefit, especially when the prompt already carries a lot of project context. A sensible practice is to keep examples as short as possible but as complete as necessary.
A second risk concerns the quality of the source: if examples come from real but flawed or inconsistent existing code, the model learns those flaws along with the pattern. Examples should therefore be curated rather than pulled blindly from the repository. Third, examples drawn from sensitive code can accidentally carry internal details, customer names, or credentials into the prompt and potentially into logs or a provider's training data, which is why examples should be screened for sensitive content before use. And finally: few-shot improves consistency and format, but it does not replace code review, because a formally correct but logically wrong result often looks more convincing thanks to good examples, not less flawed.
9. Few-shot prompting in direct comparison
The following overview summarizes where plain instructions hit their limits and how a well-built few-shot pattern addresses each weakness directly.
| Task | Instruction only | Few-shot pattern | Benefit |
|---|---|---|---|
| Enforcing code style | Free text: "write clean code" | 2-3 before/after examples | Concrete pattern instead of interpretation |
| Commit messages | Instruction: "use Conventional Commits" | 3-4 real commits from history | Format is reliably adopted |
| Edge case coverage | Happy-path examples only | At least one edge case per variant | More robust generalization |
| Number of examples | One example for a complex task | 3 to 8 diverse examples | Reduces overfitting to one pattern |
| Format guidance | Examples without explanatory context | Examples plus a short rule summary | Combination beats either alone |
In practice, the two columns are rarely strictly separate: a short explanatory sentence before the examples helps the model understand the overall goal, while the examples pin down the concrete implementation. Combining both, rather than picking one side, typically produces the most reliable results at a reasonable token cost.
Mironsoft
Claude-powered development workflows for Magento and Hyvä projects
Consistent AI prompts for your dev team?
We help build few-shot prompts, CLAUDE.md conventions, and slash commands so Claude reliably and reproducibly delivers code style, commit messages, and review feedback in your project.
Prompt Audit
Review existing prompts and CLAUDE.md files for consistency and example quality
Few-Shot Libraries
Build representative example sets for code style, commits, and reviews
Claude Code Setup
Set up slash commands and project conventions for reproducible AI workflows
10. Summary
Few-shot prompting solves a fundamental problem of plain instruction prompts: natural language leaves too much room for interpretation on formatting questions, style decisions, and detail rules. Two to eight concrete input and desired-output pairs pin down this pattern far more precisely, because the model can interpolate instead of interpret. The effect is especially visible with code style requirements such as complete PHPDoc blocks and with commit message formats, because both tasks are strongly format-driven and hard to capture completely in text rules.
What matters for quality is not the number of examples but their diversity: at least one standard case, at least one edge case, and where useful a negative example. Anyone who makes this selection deliberately and stores the examples permanently in CLAUDE.md files or prompt templates gets noticeably more consistent results across many requests, but has to budget for extra tokens, maintenance effort, and the risk of overfitting to superficial patterns.
Few-shot prompting in practice, the essentials at a glance
Examples over rules
Concrete input-output pairs pin down format and style more precisely than abstract instructions.
3 to 8 examples
Enough to separate the pattern from randomness, few enough to keep context and cost low.
Diversity over volume
Combine a standard case, an edge case, and a negative example instead of collecting many similar ones.
No substitute for review
Few-shot improves consistency and format, but does not replace substantive review of the result.