AI Computer Institute
Expert-curated CS & AI curriculum aligned to CBSE standards. A bharath.ai initiative. About Us

Few-Shot and In-Context Learning

📚 LLMs⏱️ 28 min read🎓 Grade 12
✍️ AI Computer Institute Editorial Team Updated: September 2026 CBSE-aligned · Peer-reviewed · 28 min read
Content curated by subject matter experts with IIT/NIT backgrounds. All chapters are fact-checked against official CBSE/NCERT syllabi.

A classifier with no training run

A food-delivery platform operating at Swiggy or Zomato scale receives tens of thousands of customer complaints a day and needs each one routed to the right queue: REFUND, DELIVERY, WRONG_ITEM, PAYMENT, or ESCALATE. The obvious engineering answer is to fine-tune a classifier on a few hundred thousand labeled complaints. The obvious answer is also expensive: someone has to label the data, someone has to own the GPU training run, and every time the company adds a new complaint category the model needs retraining. A team under deadline pressure instead reaches for a frozen, pretrained large language model behind an API and writes four or five labeled examples directly into the prompt, followed by the new complaint. No parameter in the model changes. No gradient is computed. The model simply reads the demonstrations as part of its input and produces a label for the new complaint by conditioning its next-token distribution on everything that came before — the demonstrations included. This is in-context learning (ICL): task-specific behavior that appears purely from what is placed in the context window of an already-trained, weight-frozen model.

The question of why a frozen transformer can do this at all — whether specific attention heads implement a copying-and-pattern-completion circuit, or whether the forward pass constructs something that behaves like an implicit task vector in activation space — is genuinely important mechanistic territory, and it is exactly what a companion chapter on this site works through in detail. This chapter takes that mechanism as given and asks the questions that come up the moment you actually have to ship one of these classifiers: the labeled examples you put in the prompt quietly bias the output in a specific, measurable, and correctable way; the examples themselves may be teaching the model far less about the correct label mapping than intuition suggests; and every token you spend on demonstrations has to be paid for, in dollars and in milliseconds, every single time the model runs.

Two biases hiding inside every few-shot prompt

Tony Z. Zhao, Eric Wallace, Shi Feng, Dan Klein, and Sameer Singh's "Calibrate Before Use: Improving Few-Shot Performance of Language Models" (ICML 2021) is the paper every engineer shipping a few-shot classifier should read before writing a single demonstration. Its central observation is that the raw output probabilities of a few-shot-prompted language model are systematically distorted by properties of the prompt that have nothing to do with the actual input being classified. Two of these distortions matter most in production:

Majority label bias. If a four-shot prompt happens to contain three REFUND-labeled examples and one DELIVERY-labeled example — a perfectly ordinary outcome of an engineer grabbing "a few representative tickets" from a support queue — the model's output distribution shifts toward REFUND even for inputs that provide no real evidence either way. The demonstrations are meant to teach a task; instead, their label frequencies leak into the model's prior the way class imbalance leaks into a badly sampled training set, except here there is no dataset to rebalance, only a prompt.

Common token bias. Independent of anything in the prompt, some label words are simply more frequent in the pretraining corpus than others. A label spelled "Yes" competes against a vast number of unrelated contexts in which the token "Yes" appeared during pretraining; a rarer label token starts from a lower baseline probability for reasons that have nothing to do with task semantics. Two labels that should be treated symmetrically by the classifier are not treated symmetrically by the model, purely because of token statistics baked in long before the few-shot prompt was written.

Zhao et al.'s fix is contextual calibration, and it costs one extra forward pass, not a retraining run. Feed the model the exact same prompt template and the exact same demonstrations, but replace the real input with a content-free — the string "N/A", or an empty string, or a few such placeholders averaged together. Because the carries no task-relevant signal, whatever label distribution the model produces for it is attributable entirely to the structure of the prompt: the label imbalance in the demonstrations and the token-frequency prior, exactly the two biases above. Call that distribution p_cf. The general form of the correction fits an affine map p̂(y|x) = softmax(W·p(y|x) + b); the version Zhao et al. show works well in practice sets b = 0 and W to the diagonal matrix diag(p_cf)⁻¹, which reduces to something a spreadsheet could compute: divide the raw probability of each label by that label's content-free probability, then renormalize so the corrected probabilities sum to one. The correction does not need labeled validation data. It needs only the same frozen model, called one extra time.

Worked example: calibrating a complaint router

An engineering team builds a four-shot prompt for the REFUND vs. DELIVERY split of their router: three demonstrations happen to be labeled REFUND and one is labeled DELIVERY, because that was the order the tickets appeared in the team's shared drive. A new complaint arrives: "the item that showed up was the wrong size, and I want my money back." Run through the model, the raw output is p(REFUND|x) = 0.80, p(DELIVERY|x) = 0.20. Taken at face value, that clears a typical auto-routing threshold of 0.75 confidence, and the ticket gets routed straight to the refunds team without a human in the loop.

Before trusting that number, run the calibration probe: same prompt, same four demonstrations, input replaced by "N/A". The model returns p_cf(REFUND) = 0.70, p_cf(DELIVERY) = 0.30 — a distribution that should have been exactly 0.5/0.5 if the demonstrations carried no bias, but instead reflects the 3:1 label imbalance sitting in the prompt. Divide and renormalize:

p_raw = {'REFUND': 0.80, 'DELIVERY': 0.20}
p_cf  = {'REFUND': 0.70, 'DELIVERY': 0.30}

unnorm = {label: p_raw[label] / p_cf[label] for label in p_raw}
z = sum(unnorm.values())
p_cal = {label: v / z for label, v in unnorm.items()}

for label in p_raw:
    print(f'{label:<10} raw={p_raw[label]:.3f}  cf={p_cf[label]:.3f}  calibrated={p_cal[label]:.4f}')

Tracing it by hand: unnorm[REFUND] = 0.80 / 0.70 = 1.14286, unnorm[DELIVERY] = 0.20 / 0.30 = 0.66667, and their sum is z = 1.80952. Dividing each unnormalized value by z gives p_cal[REFUND] = 0.6316 and p_cal[DELIVERY] = 0.3684. The script prints exactly:

REFUND     raw=0.800  cf=0.700  calibrated=0.6316
DELIVERY   raw=0.200  cf=0.300  calibrated=0.3684

The calibrated confidence for REFUND, 0.632, falls below the 0.75 auto-routing threshold. The raw score said "route automatically, no human needed." The calibrated score says "this is genuinely ambiguous, send it to a human." Nothing about the actual complaint changed between those two numbers — only the removal of a bias contributed entirely by which four tickets happened to get pasted into the prompt. A team that skips calibration is not just leaving accuracy on the table; it is silently auto-routing tickets on the strength of a threshold check that the label-imbalance artifact, not the model's read of the complaint, is the thing actually clearing.

Visualizing the calibration pipeline

Contextual Calibration for a Few-Shot Complaint Classifier Zhao et al. (2021) — correcting label bias with zero gradient updates Content-free probe: same 4 demos + input replaced by the null string "N/A" Frozen-weight forward pass, no training step p_cf(REFUND)=0.70 p_cf(DELIVERY)=0.30 Real query: same 4 demos + actual input: "wrong size, want refund" Frozen-weight forward pass, no training step p(REFUND|x)=0.80 p(DELIVERY|x)=0.20 Calibration step — no retraining, no new data: p'(y) = p(y|x) / p_cf(y) then rescale so p'(REFUND) + p'(DELIVERY) = 1 0 .25 .5 .75 1.0 Content-free probe (p_cf) 0.70 0.30 Raw query, uncalibrated 0.80 0.20 Calibrated query (p') 0.632 0.368 REFUND DELIVERY Only the bottom (calibrated) row removes the 3:1 REFUND:DELIVERY ratio baked into the four demonstrations — that row is the distribution safe to threshold for auto-routing.

What the demonstrations are actually teaching

Calibration fixes the confidence a few-shot classifier reports, but it leaves open a stranger question: what exactly are the four demonstrations doing to produce that confidence in the first place? The intuitive answer — the model reads each labeled example and learns the input-to-label mapping, the way a from-scratch classifier learns from a training set — turns out to be only partially right, and the gap matters for how carefully an engineer needs to curate demonstration labels.

Sewon Min, Xinxi Lyu, Ari Holtzman, Mikel Artetxe, Mike Lewis, Hannaneh Hajishirzi, and Luke Zettlemoyer's "Rethinking the Role of Demonstrations: What Makes In-Context Learning Work?" (EMNLP 2022) ran a striking ablation: take a standard few-shot classification prompt and replace every demonstration's gold label with a label drawn uniformly at random from the same label set, so the mapping between each example's text and its shown label becomes pure noise. On many classification benchmarks, accuracy barely moved. What did matter, when the researchers ablated it separately, were the label space (which label words are valid answers at all), the distribution of the input text (in-domain examples versus out-of-domain gibberish), and the overall format of the prompt (the fact that it is structured as input, then label, repeated). Correctness of the specific input-label pairing was, for the models and tasks they tested, the least load-bearing ingredient of the four.

That finding does not mean input-label correctness is irrelevant everywhere, and a second paper complicates it usefully. Jerry Wei, Jason Wei, Yi Tay, and colleagues, in "Larger Language Models Do In-Context Learning Differently" (2023), showed that the picture is scale- and training-dependent: as models get larger and are instruction-tuned, they become increasingly able to override the semantic prior a label word carries and actually follow flipped or randomized label mappings shown in the prompt, in a way small base models cannot. In other words, the "format is what matters, not correctness" result from Min et al. describes models that are largely falling back on pretrained priors when demonstrations don't clearly override them; frontier instruction-tuned models are more capable of actually using the input-label evidence when it is present, which also means they are more capable of being misled by demonstrations that are wrong. The safe production takeaway is not "label quality doesn't matter" but "label quality matters differently depending on which model is doing the classifying, and that dependency should be tested per model, not assumed."

Common misconception

The misconception this section exists to correct: a student encountering few-shot prompting for the first time typically models it as a miniature, symmetric version of ordinary supervised training — four labeled examples going in should function like four labeled training points, so getting the labels exactly right should matter roughly as much as getting labels right in a training set matters, and adding more correctly labeled examples should reliably improve the model's grip on the task the same way more training data reliably helps a from-scratch classifier. Min et al.'s finding directly breaks that analogy: for many tasks, replacing correct labels with random ones from the same label space costs little accuracy, because the demonstrations are doing most of their work by fixing the label vocabulary, the topic, and the input/output format rather than by teaching a mapping through repeated correct examples the way gradient descent would. The correct mental model is closer to a strong structural prior and a topic filter than to a labeled training set: the demonstrations tell the frozen model "here is the set of valid answers, here is the kind of input you'll see, and here is the shape your answer should take," and the model's pretrained knowledge supplies most of the actual reasoning about which label fits. This also explains why calibration is necessary in the first place — if the demonstrations were truly functioning as a small training set, an imbalanced label count would be a data problem to fix by rebalancing, not a bias to correct after the fact with a content-free probe; because they are functioning more as a structural prior, the imbalance leaks into the prior itself and needs a mechanism like Zhao et al.'s to be removed.

Choosing demonstrations at query time

Every example so far has used a fixed set of demonstrations, chosen once by an engineer and reused for every incoming complaint. Jiachang Liu, Dinghan Shen, Yizhe Zhang, William B. Dolan, Lawrence Carin, and Weizhu Chen's "What Makes Good In-Context Examples for GPT-3?" (2021) asks whether that is even the right design: instead of one static demonstration set, embed a large pool of candidate examples with a sentence encoder, embed the incoming query the same way, and at inference time retrieve the k nearest neighbors by cosine similarity to serve as that specific query's demonstrations. They call this KATE (kNN-Augmented in-conText Example selection), and it consistently beat randomly chosen demonstrations across the tasks they tested, because it guarantees every query sees demonstrations that are actually topically and structurally close to it, rather than demonstrations chosen once for the "average" query and reused regardless of fit.

Applied to the complaint router, the intuition is direct: a "late delivery" complaint should be shown late-delivery demonstrations, not a demonstration about a duplicate charge, even if the duplicate-charge example happened to be one of the four an engineer pasted into the static prompt months ago. The following code, using small illustrative 3-dimensional vectors standing in for real sentence-embedding output, retrieves the two most relevant demonstrations from a four-example pool for an incoming query about a late order:

import math

def cosine_similarity(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    norm_a = math.sqrt(sum(x * x for x in a))
    norm_b = math.sqrt(sum(x * x for x in b))
    return dot / (norm_a * norm_b)

# Toy 3-D stand-ins for real sentence-embedding vectors -- illustrative,
# not the actual output of any specific embedding model.
demo_pool = [
    {'text': 'Order arrived 2 hours late, food was cold',
     'label': 'DELIVERY', 'emb': [0.90, 0.10, 0.00]},
    {'text': "Received someone else's order entirely",
     'label': 'WRONG_ITEM', 'emb': [0.20, 0.90, 0.10]},
    {'text': 'Charged twice for the same order',
     'label': 'REFUND', 'emb': [0.10, 0.20, 0.90]},
    {'text': 'Rider took 90 minutes, live tracking froze',
     'label': 'DELIVERY', 'emb': [0.85, 0.15, 0.05]},
]

query_emb = [0.80, 0.20, 0.00]  # "Food showed up 90 min after the promised slot"

scored = [(cosine_similarity(query_emb, d['emb']), d) for d in demo_pool]
scored.sort(key=lambda pair: pair[0], reverse=True)

k = 2
selected = scored[:k]
for score, d in scored:
    print(f"{d['label']:<10} {score:.4f}")

Tracing the arithmetic for the first candidate: query_emb · [0.90, 0.10, 0.00] = 0.72 + 0.02 + 0 = 0.74; |query_emb| = √0.68 ≈ 0.8246; |[0.90,0.10,0.00]| = √0.82 ≈ 0.9055; cosine similarity = 0.74 / (0.8246 × 0.9055) ≈ 0.9910. Repeating for all four candidates and sorting by similarity, the script prints exactly:

DELIVERY   0.9959
DELIVERY   0.9910
WRONG_ITEM 0.4446
REFUND     0.1569

With k = 2, selected holds the "rider took 90 minutes" and "arrived 2 hours late" demonstrations — both DELIVERY, both genuinely close to the incoming complaint — while the REFUND and WRONG_ITEM examples, irrelevant to this particular query, are correctly left out. A static four-shot prompt built once and reused for every query would have shown this same late-delivery complaint the REFUND and WRONG_ITEM examples regardless of relevance, diluting the demonstration set with noise the retrieval-based approach avoids entirely.

The serving-side price of demonstrations

Retrieval-augmented demonstration selection buys accuracy, but it is not free, and the cost shows up specifically at inference time rather than anywhere in training. Production LLM serving engines exploit the fact that a transformer's attention computation over a prefix of tokens can be cached: once the key and value vectors for a given sequence of tokens have been computed in one forward pass, a later request that begins with the identical sequence of tokens can reuse those cached key/value pairs and only run the forward pass on the new tokens that follow. Anthropic's and OpenAI's prompt-caching APIs and vLLM's automatic prefix caching all exploit exactly this mechanism. A static few-shot prompt is the ideal case for it: the demonstration block is identical on every request, so it sits at the front of the prompt as a fixed, reusable prefix, and only the customer's actual complaint at the end changes from request to request.

The saving is roughly proportional to token counts. Suppose the four-shot demonstration block runs to about 2,000 tokens and each incoming complaint adds roughly 50 tokens on top of it. Without caching, every request pays the prefill cost of the full 2,050-token sequence. With prefix caching, only the 50 new tokens need a fresh forward pass through the model; the 2,000-token prefix's attention keys and values are read from cache. That is roughly a 2050 / 50 ≈ 41× reduction in the token-count-proportional part of prefill compute for the part of the request that dominates time-to-first-token in a typical serving setup — a first-order, token-count estimate, not an exact FLOP count, since actual savings depend on the attention implementation and hardware, but the direction and rough scale are real and are the entire reason prefix caching exists as a product feature.

Per-query kNN retrieval, by construction, breaks this. If the demonstration set is assembled fresh for every query based on which examples are nearest to that specific complaint, then no two consecutive requests are guaranteed to share the same prefix, and the caching engine sees a cache miss on the demonstration block almost every time. The 41× saving on the shared portion of the prompt reverts to close to 1×: every request effectively re-prefills its full prompt length. The embedding and cosine-similarity search that pick the demonstrations are themselves cheap — a handful of dot products against a small pool, not an LLM forward pass — but the accuracy gain from KATE-style retrieval has to be weighed against the loss of prefix-cache reuse on the demonstration block, which for a high-traffic endpoint can dominate the compute bill. A team choosing between a static prompt and per-query retrieval is choosing between cheaper-but-less-accurate and more-accurate-but-costlier-to-serve, and the right choice depends on traffic volume, latency budget, and how much accuracy retrieval actually buys on their specific task — not on which technique is more sophisticated.

Active recall

Attempt each question before reading its answer.

  1. Why does probing with a content-free input like "N/A" isolate exactly the bias that contextual calibration is meant to remove, without needing a labeled validation set?
  2. A balanced two-shot prompt (2 REFUND, 2 DELIVERY) still shows some bias from label-token frequency. For a new query, the raw model outputs p(REFUND|x) = 0.68, p(DELIVERY|x) = 0.32, and the content-free probe returns p_cf(REFUND) = 0.52, p_cf(DELIVERY) = 0.48. Compute the calibrated probabilities.
  3. Starting from the main worked example (3 REFUND : 1 DELIVERY demonstrations, raw p(REFUND|x) = 0.80, calibrated p'(REFUND) = 0.632), suppose engineers add a fifth demonstration, a second DELIVERY example, so the prompt becomes 3 REFUND : 2 DELIVERY, with everything else about the query and the model held fixed. List every downstream quantity in this chapter's pipeline that this change plausibly touches, and which stays the same.
  4. A junior engineer argues: "Min et al. (2022) showed random demonstration labels work almost as well as correct ones, so I don't need to double-check my few-shot labels before shipping." What is wrong with this reasoning?
  5. A team switches the complaint router from a static four-shot prompt to per-query KATE-style retrieval to improve accuracy on rare complaint types. What specific serving-side cost does this introduce, and how would you estimate its rough size?

Answers.

1. The biases Zhao et al. target — majority label bias and common token bias — are properties of the prompt's structure (which labels appear how often, which label tokens are inherently more frequent) and are entirely independent of the real input's content. Replacing the real input with a content-free removes the one piece of the prompt that should legitimately influence the answer, so whatever label distribution the model still produces for that can only be coming from the structural bias. No labeled validation set is needed because the probe is not testing accuracy against ground truth; it is measuring the model's default lean when given no real evidence, which is precisely the quantity to divide out.

2. unnorm[REFUND] = 0.68 / 0.52 = 1.30769, unnorm[DELIVERY] = 0.32 / 0.48 = 0.66667, sum z = 1.97436. Calibrated: p'(REFUND) = 1.30769 / 1.97436 = 0.6623, p'(DELIVERY) = 0.66667 / 1.97436 = 0.3377. Note the raw margin (0.68 vs. 0.32, a 0.36 gap) barely narrows after calibration (0.6623 vs. 0.3377, a 0.325 gap) — a much smaller correction than in the main 3:1 example, because a genuinely balanced demonstration set has less label-count bias to remove; what remains is only the smaller common-token-frequency effect reflected in p_cf not being exactly 0.5/0.5.

3. Ripple effects, traced fully: (a) the prompt's token count grows by roughly one demonstration's worth of tokens, lengthening the shared prefix. (b) The content-free probe p_cf shifts: with the label ratio now 3:2 instead of 3:1, the majority-label bias toward REFUND weakens, so p_cf(REFUND) should move down from 0.70 toward something closer to (but still above) 0.5. (c) The raw p(REFUND|x) for the same real query plausibly shifts down too, in the same direction, since the same demonstration-count imbalance that biases the content-free probe also biases the real-query output. (d) Because both the numerator (p(y|x)) and the denominator (p_cf(y)) of the calibration ratio move in the same direction for the same underlying reason, the calibrated output p'(y) should be comparatively stable relative to how much either raw number moved on its own — this robustness to exactly how the demonstrations happen to be balanced is the practical value of calibrating rather than just manually rebalancing label counts. (e) On the serving side, if this prompt is static and prefix-cached, the change from a 4-demo to a 5-demo prefix invalidates the previously cached prefix entirely; the first request after the change pays a full, uncached prefill, and every subsequent request caches and reuses the new 5-demo prefix normally. (f) The retrieval-based (KATE) section of this chapter is unaffected by this scenario, since it describes a different, per-query demonstration-selection design; this ripple applies only to the static-prompt setting. (g) Per Min et al., adding a demonstration with the correct label and an in-distribution, correctly formatted input changes only the label balance, not the label space or the prompt format, so this particular change is one Min et al.'s results suggest should have a smaller effect on raw task accuracy than, say, introducing an entirely new label or malformed example would.

4. The reasoning over-generalizes a result that is neither universal nor complete. First, Wei et al. (2023) found that larger, instruction-tuned models are increasingly able to use (and be misled by) the actual input-label correspondence in demonstrations rather than falling back on format alone, so "labels barely matter" is least true for exactly the frontier models most production systems deploy. Second, even in settings where Min et al.'s result holds, they found label space and prompt format still matter a great deal; a genuinely wrong label (as opposed to a randomly reassigned one from the correct label set) could corrupt the label space itself, which is a different and consequential failure mode. Third, label-count imbalance in the demonstrations still produces the majority-label bias covered earlier regardless of whether the mapping is "understood" by the model, so unchecked demonstration labels still corrupt the calibration baseline even if they don't corrupt raw task accuracy.

5. Per-query retrieval means the demonstration block is no longer identical across requests, so the shared, cacheable prefix that a static prompt provides disappears; nearly every request becomes a full prefill instead of a cheap continuation of a cached prefix. Using the earlier estimate, if a static prompt lets the engine skip prefill on roughly 2,000 of 2,050 tokens per request (about a 41× reduction in the token-proportional part of prefill compute), switching to per-query retrieval forfeits essentially all of that saving, since each request's demonstration set differs and the cache misses. The embedding lookup itself (a similarity search over a small pool) is cheap by comparison; the real cost is the lost prefix-cache reuse on the LLM forward pass, and it should be weighed against whatever accuracy gain retrieval delivers on the specific task before deciding to switch.

Think About It

Think about this: How would you explain few-shot and in-context learning to a friend who has never seen a computer? What real-world analogy would you use? Imagine you had to build a system using these concepts — what would be your first step? Try this: before moving on, write down three things you learned and one question you still have.

Key Takeaways — Summary and Recap

Let us recap what we covered: the core ideas behind few-shot and in-context learning, how they connect to real-world applications, and why they matter for your journey in computer science. Remember these key points as you move forward. For competitive exam preparation (CBSE, JEE, BITSAT), focus on understanding the WHY behind each concept, not just the WHAT.

← Chain-of-Thought Prompting: Unlocking Reasoning AbilityParameter-Efficient Fine-tuning: Adapters and LoRA →

Found this useful? Share it!

📱 WhatsApp 🐦 Twitter 💼 LinkedIn