Danh sách bài viết

Bài 26: Few-shot prompting — học từ ví dụ

Few-shot prompting là kỹ thuật đưa 2-5 ví dụ mẫu (demonstration) dạng input → output vào prompt để LLM "học" pattern và áp dụng cho input mới, dựa trên cơ chế in-context learning được mô tả lần đầu trong paper GPT-3 (Brown et al., arXiv:2005.14165, 2020). Khác với zero-shot ở Bài 25 — không có ví dụ — few-shot khoá format đầu ra, làm rõ định nghĩa nhãn niche, và xử lý edge case mà task description khó diễn tả bằng lời. Bài này phân biệt one-shot (1 ví dụ) / few-shot (2-10) / many-shot (100+ — Anthropic 2024), giải thích vì sao few-shot work mà không update weight (model chỉ "imitate" example trong context), khi nào nên dùng, cách chọn ví dụ tốt (đa dạng, đại diện, chất lượng cao, recency bias đặt ví dụ quan trọng cuối), số shot tối ưu (2-5 thường đủ; >10 cost cao và diminishing return), format consistency strict, áp dụng cho classification / extraction / translation / JSON output, kỹ thuật dynamic few-shot retrieve ví dụ theo embedding (foundation của RAG-style few-shot), so sánh với fine-tune, anti-pattern hay gặp, cost analysis, quy trình sweep n_shot để chọn n tối ưu, ghi chú về reasoning model 2024-2026, và code Python với OpenAI / Anthropic.

25/05/2026
13 phút đọc
0 lượt xem
1

Mục tiêu bài học

Sau bài học, bạn sẽ:

  • Định nghĩa được few-shot prompting và phân biệt với zero-shot (Bài 25), one-shot, many-shot.
  • Hiểu cơ chế in-context learning xuất phát từ GPT-3 paper (Brown et al., 2020) và biết few-shot KHÔNG update weight.
  • Biết khi nào nâng cấp từ zero-shot lên few-shot dựa trên tín hiệu cụ thể.
  • Áp dụng được 4 tiêu chí chọn ví dụ: đa dạng, đại diện, chất lượng cao, sắp xếp theo recency bias.
  • Viết được few-shot prompt cho classification, extraction, translation, JSON output với format consistency.
  • Cài được dynamic few-shot: encode query → retrieve top-K ví dụ tương tự → ghép prompt.
  • So sánh được few-shot và fine-tune để chọn đúng công cụ theo bối cảnh task.
  • Đo được accuracy theo n_shot (sweep 0, 1, 3, 5, 10) và chọn n tối ưu.
2

Few-shot là gì

Few-shot prompting là kỹ thuật đưa vào prompt một số ví dụ mẫu dưới dạng input → output, sau đó để input thật cuối cùng. LLM "đọc" pattern từ các ví dụ và áp dụng cho input mới.

Số "shot" = số ví dụ trong prompt. Theo cách dùng phổ biến từ paper GPT-3:

  • Zero-shot: 0 ví dụ (Bài 25).
  • One-shot: 1 ví dụ.
  • Few-shot: 2-10 ví dụ (typical 2-5).
  • Many-shot: 100+ ví dụ (mới khả thi khi context window đủ dài, xem mục 18).

Few-shot vẫn là inference-only: không có gradient update, không thay đổi trọng số model. Toàn bộ "học" xảy ra trong context, gọi là in-context learning (ICL).

3

Pattern tối giản

Khung sườn của một few-shot prompt:

[Task description ngắn]

Input: ABC
Output: XYZ

Input: DEF
Output: UVW

Input: GHI
Output:

Hai ví dụ đầu (ABC → XYZ, DEF → UVW) là demonstration. Dòng cuối Input: GHI + Output: bỏ trống là chỗ model điền. Model "đọc" hai ví dụ trên, suy ra ánh xạ và sinh output cho GHI theo cùng pattern.

Delimiter (Input: / Output:) có thể đổi sang Q: / A:, Câu: / Nhãn:, hoặc XML tag <example> — quan trọng là nhất quán giữa các ví dụ và input cuối.

4

One-shot vs Few-shot vs Many-shot

  • One-shot: chỉ 1 ví dụ. Đủ cho task mà format quan trọng hơn nội dung (vd "trả về JSON đúng schema này"). Bound vì 1 ví dụ không cover đa dạng.
  • Few-shot: 2-10 ví dụ. Cover được vài biến thể input, đủ để model bám pattern. Sweet spot 3-5 ví dụ cho phần lớn task production.
  • Many-shot: 100-1000 ví dụ (Anthropic, "Many-Shot In-Context Learning", arXiv:2404.11018, 2024). Tận dụng context window dài (200K+), tiệm cận chất lượng fine-tune trên một số task. Cost token cao nhưng không cần training pipeline.

Phân ranh giới không tuyệt đối — có paper gọi 8-32 ví dụ là few-shot, có paper gọi 64+ là many-shot. Quan trọng là tư duy: 0 / 1 / vài / rất nhiều, mỗi mức có đánh đổi riêng.

5

Vì sao few-shot work — in-context learning

Hiện tượng được đặt tên trong paper GPT-3 — Brown et al., "Language Models are Few-Shot Learners" (arXiv:2005.14165, 2020). Cốt lõi:

  • Model chỉ làm next-token prediction trên toàn bộ context (prompt + ví dụ + input).
  • Với ví dụ ABC → XYZ, DEF → UVW, model rút ra "khi thấy chuỗi kiểu X, sinh chuỗi kiểu Y" — đây là pattern matching cấp cao trong attention layer.
  • Khi gặp GHI → ?, hidden state đã được "điều kiện" bởi mấy ví dụ trước → output bám theo cùng phân phối.
  • Không có gradient, không có weight update — toàn bộ thông tin học được nằm trong activation tạm thời.

Nhiều paper sau đó cố giải thích cơ chế: Garg et al. (arXiv:2208.01066, 2022) cho thấy Transformer có thể implicit-learn các thuật toán đơn giản (linear regression, decision tree) chỉ từ ví dụ trong context. Olsson et al. (Anthropic, "In-context Learning and Induction Heads", 2022) chỉ ra induction head — một loại attention head — chịu trách nhiệm chính cho ICL. Chi tiết không quan trọng cho practitioner; điểm cần nhớ: ICL là khả năng emergent, mạnh dần theo scale model.

6

Khi nào dùng few-shot

Few-shot phù hợp khi xuất hiện một trong các tín hiệu:

  • Zero-shot accuracy chưa đủ trên test set (vd cần ≥90% nhưng chỉ đạt 75%).
  • Task niche — taxonomy nội bộ, label tiếng Việt đặc thù, quy ước domain.
  • Output format đặc thù mà mô tả bằng lời khó (vd "kèm chú thích trong ngoặc đơn theo cùng phong cách").
  • Nhiều edge case: sarcasm, mixed language, code-switching, lỗi chính tả phổ biến.
  • Cần consistency cao về phong cách / tone (vd reply email).

Nếu task phổ thông + format đơn giản + zero-shot đã đạt mục tiêu, không cần nhảy lên few-shot — chỉ tốn token và latency.

7

Chọn ví dụ tốt

Bốn tiêu chí khi chọn ví dụ vào prompt:

  • Đa dạng: cover các lớp / loại / độ dài / kiểu input khác nhau. Ba ví dụ đều positive sentiment làm model nghĩ "luôn trả positive".
  • Đại diện: input dạng typical, không phải edge case kỳ quặc. Ví dụ edge case dạy model pattern sai.
  • Chất lượng cao: label đúng, format consistent. Ví dụ sai dạy model trả sai theo.
  • Recency-aware: model có recency bias — ví dụ đặt cuối có ảnh hưởng lớn hơn. Đặt ví dụ quan trọng / khó / gần với input thật ở cuối danh sách.

Quy trình thực dụng: với dataset có label sẵn, lấy 20-30 case → chọn 5 ví dụ cover các nhãn / độ dài → giữ phần còn lại làm test set để đo.

8

Số ví dụ tối ưu

  • 2-5 ví dụ: vùng tối ưu cho phần lớn task. Đủ để khoá format, đa dạng vừa phải, cost còn rẻ.
  • 5-10 ví dụ: dùng khi task có nhiều nhãn (vd phân loại 10+ topic) hoặc edge case quan trọng cần cover.
  • >10 ví dụ: thường rơi vào diminishing return — cost tăng tuyến tính, accuracy tăng chậm dần và đôi khi đi xuống vì model "ngợp" context.
  • Many-shot (100+): chỉ chọn khi đã đo và thấy lợi rõ; cần context window đủ rộng và pipeline đủ rẻ.

Không có con số "đúng" sẵn — phải sweep n_shot trên test set của chính bạn (mục 22).

9

Format consistency

Model bám format strict theo ví dụ. Mọi inconsistency nhỏ đều có thể bị "học" thành pattern sai. Cần đồng bộ:

  • Cùng delimiter: Input: / Output: xuyên suốt, không trộn với Q: / A:.
  • Cùng capitalization: nhãn viết thường hết, hoặc viết hoa chữ đầu — không lẫn lộn.
  • Cùng dấu câu: ví dụ 1 có dấu chấm cuối, ví dụ 2 không → model phân vân.
  • Cùng khoảng trắng: Output: positive vs Output:positive là hai chuỗi khác trong tokenizer.
  • Cùng quote style với input: nếu ví dụ bọc input trong "...", input cuối cũng phải bọc.

Khi viết prompt, dán cả block ví dụ ra editor cố định-width và soi từng dòng — sai lệch dễ thấy bằng mắt.

10

Few-shot cho classification

Phân loại sentiment:

"Sản phẩm rất tốt." → positive
"Tệ, không recommend." → negative
"Bình thường." → neutral

"Dùng cũng ổn, không có gì đặc biệt." →

Ba ví dụ phủ ba lớp. Delimiter đơn giản, dễ nhất quán. Khi parse output, lấy token đầu tiên là đủ.

Mở rộng: nếu thêm lớp mixed cho review có cả khen lẫn chê, cần ít nhất một ví dụ mixed trong prompt — nếu không model gần như không bao giờ trả nhãn đó.

11

Few-shot cho extraction

Extract names (chỉ tên người, dạng JSON list):

"John works at Google." → ["John"]
"Alice and Bob play tennis." → ["Alice", "Bob"]
"Công ty FPT là một tập đoàn lớn." → []

"Cô ấy gặp Mai và Linh ở quán." →

Ba ví dụ đại diện: một tên, nhiều tên, không có tên (case rỗng). Ví dụ thứ ba quan trọng — không có nó, model có xu hướng "cố nặn" ra một tên dù input không chứa người.

12

Few-shot cho translation

Dịch sang English, giữ tone formal:

"Xin chào, rất vui được gặp anh." → "Hello, it's a pleasure to meet you."
"Cảm ơn vì đã giúp đỡ." → "Thank you for your assistance."

"Hẹn gặp lại tuần sau." →

Translation là chỗ few-shot ăn điểm so với zero-shot — ví dụ giúp model nhận biết tone (formal / casual / business), cách xử lý kính ngữ tiếng Việt và xưng hô. Đổi 2 ví dụ formal thành 2 ví dụ casual → toàn bộ output sẽ shift sang casual.

13

Few-shot cho JSON output

Extract info → JSON:

Input: "John, 30, NYC"
Output: {"name": "John", "age": 30, "city": "NYC"}

Input: "Alice, 25, LA"
Output: {"name": "Alice", "age": 25, "city": "LA"}

Input: "Bob, 28, SF"
Output:

Hai ví dụ là đủ để model bám đúng key, kiểu dữ liệu (string vs number) và thứ tự field. Khi kết hợp với JSON mode / response format của OpenAI hoặc tool use của Anthropic (Bài 24), tỉ lệ parse fail xuống gần 0.

Nếu có field optional (vd email có thể vắng), thêm 1 ví dụ với input thiếu field đó để model học cách bỏ key hoặc dùng null — bạn quyết định và demonstrate trong ví dụ.

14

Order matters — recency bias

Thứ tự ví dụ ảnh hưởng output. Lu et al. (arXiv:2104.08786, 2021) cho thấy chỉ permute thứ tự ví dụ có thể làm accuracy dao động hàng chục phần trăm trên một số task. Hai hệ quả thực dụng:

  • Recency bias: model nhớ ví dụ gần input cuối hơn. Đặt ví dụ "khó" / "quan trọng" / gần input thật ở cuối danh sách.
  • Tránh cluster theo nhãn: ba ví dụ positive xếp liền nhau, rồi đến input cuối → model có xu hướng trả positive vì context bị "nhuộm". Trộn nhãn ngẫu nhiên hoặc đan xen.

Khi prompt quan trọng, chạy permutation test: thử 3-5 thứ tự khác nhau, so accuracy, chọn order ổn nhất.

15

Few-shot CoT (preview Bài 27)

Few-shot Chain-of-Thought kết hợp few-shot với reasoning step. Mỗi ví dụ không chỉ có input → output mà còn có chuỗi suy luận trung gian:

Q: Roger có 5 quả bóng. Anh ấy mua thêm 2 hộp, mỗi hộp 3 quả.
   Hiện anh ấy có bao nhiêu quả?
A: Roger bắt đầu có 5 quả. 2 hộp × 3 quả/hộp = 6 quả mới.
   5 + 6 = 11. Đáp án: 11.

Q: Cửa hàng có 23 quả táo, dùng 20 quả nấu ăn,
   sau đó mua thêm 6 quả. Còn lại bao nhiêu?
A:

Đây là setup gốc của Wei et al., "Chain-of-Thought Prompting" (arXiv:2201.11903, 2022) — paper khai sinh CoT. Bài 27 sẽ deep-dive: zero-shot CoT vs few-shot CoT, khi nào dùng, cách viết bước suy luận, và tại sao trên reasoning model 2024-2026 (o1, R1, Claude thinking) thường không cần kỹ thuật này nữa.

16

Dynamic few-shot

Static few-shot: cùng K ví dụ cố định trong mọi prompt. Dynamic few-shot: chọn ví dụ theo từng query, lấy những ví dụ giống input nhất từ một kho ví dụ có label.

Pipeline cơ bản:

  • Có kho ví dụ {(input_i, output_i)} đã gắn nhãn (vài chục đến vài nghìn case).
  • Pre-compute embedding của input_i bằng model embedding (vd OpenAI text-embedding-3-small, BGE, E5) — lưu vào vector store.
  • Khi có query mới: encode query → similarity search → lấy top-K (vd K=5) ví dụ gần nhất.
  • Ghép K ví dụ đó vào prompt → gọi LLM.

Ưu điểm: ví dụ luôn relevant với query → accuracy cao hơn static cùng K. Đây là foundation của RAG-style few-shot — bản chất là retrieval phục vụ prompt, sẽ được mở rộng sâu trong module RAG (Bài 36-46). Nhược điểm: cần hạ tầng vector store, latency thêm 50-200ms cho retrieval.

Frameworks hỗ trợ sẵn: LangChain SemanticSimilarityExampleSelector, LlamaIndex FewShotPromptTemplate với retriever.

17

Few-shot trong API

Hai cách ghép ví dụ vào API call:

Cách 1 — ví dụ trong một message duy nhất: tất cả ví dụ và input cuối nằm trong một string ở vai trò user. Đơn giản, dễ test.

Cách 2 — multi-turn message: mỗi ví dụ là một cặp user + assistant, input thật là user cuối. Cách này thường cho kết quả ổn hơn với model chat (được tuning trên dạng dialogue):

messages = [
    {"role": "user", "content": "Input: ABC"},
    {"role": "assistant", "content": "Output: XYZ"},
    {"role": "user", "content": "Input: DEF"},
    {"role": "assistant", "content": "Output: UVW"},
    {"role": "user", "content": "Input: GHI"},
]

Anthropic hỗ trợ cả hai cách. OpenAI cũng vậy. Cách 2 đặc biệt hữu ích khi muốn dùng system prompt cho task description và để ví dụ "kể chuyện" qua nhiều turn.

18

Many-shot in-context learning

Paper Anthropic "Many-Shot In-Context Learning" (Agarwal et al., arXiv:2404.11018, 2024) cho thấy khi tăng số ví dụ lên 100-1000 (tận dụng context window 200K-1M):

  • Accuracy tăng tiếp tục sau ngưỡng 10-32 ví dụ, vốn được coi là plateau của few-shot.
  • Trên một số task (translation low-resource, math, planning), many-shot tiệm cận hoặc vượt fine-tune-cùng-data.
  • Hiệu quả lớn ở task khó / niche / có label format đặc thù.

Điều kiện cần: model context window đủ lớn (Claude 3+, Gemini 1.5+, GPT-4 Turbo 128K trở lên) và pipeline chịu được cost token đầu vào lớn. Khi đã có vài trăm case có nhãn nhưng chưa muốn fine-tune, many-shot là baseline đáng thử trước.

19

Few-shot vs Fine-tune

  • Few-shot: không train, đổi ví dụ là đổi behavior, prompt dài → cost per call cao, latency cao hơn. Phù hợp khi task còn thay đổi, data label ít (10-100), lưu lượng thấp-trung bình.
  • Fine-tune: train một lần trên dataset (thường ≥500-5000 case), prompt ngắn → cost per call thấp, latency thấp. Phù hợp khi task ổn định lâu dài, data label nhiều, lưu lượng cao.

Khi nào chọn cái nào — heuristic thực dụng:

  • Có <50 case label: zero-shot hoặc few-shot tĩnh.
  • 50-500 case: dynamic few-shot / many-shot.
  • >500 case + task ổn định + chạy nhiều: cân nhắc fine-tune (LoRA cho open weight, OpenAI / Anthropic fine-tune API cho closed).
  • Đặc biệt nếu tổng token few-shot × số call/tháng > cost fine-tune training → fine-tune sẽ rẻ hơn về dài hạn.

Module fine-tuning trong cùng series (Bài 47-52) sẽ cover chi tiết.

20

Cost analysis

  • Một ví dụ ngắn thường ~50-200 token (input + output).
  • 5 ví dụ × 100 token = 500 token overhead mỗi call.
  • Với mô hình rẻ (GPT-4o-mini, Claude Haiku 4.5, Gemini Flash): chi phí 500 token input ≈ vài chục VND/call → nhỏ.
  • Với mô hình đắt (GPT-4o, Claude Opus 4, o1): 500 token input có thể vài trăm VND/call. Nhân lưu lượng triệu call/tháng → cộng dồn đáng kể.
  • Prompt caching (Anthropic, OpenAI 2024+) cho phép cache phần đầu prompt (task description + ví dụ tĩnh) → giảm cost vài lần khi cùng prefix dùng lặp lại.

Khi static few-shot stable, bật prompt caching gần như bắt buộc cho pipeline lưu lượng cao.

21

Anti-pattern

  • Format không nhất quán: một ví dụ trả positive, ví dụ khác trả Positive. — model phân vân.
  • Quá nhiều ví dụ: 30+ ví dụ chèn ngẫu nhiên → cost cao, đôi khi accuracy giảm.
  • Ví dụ bias: chỉ chọn positive case → model hiếm khi trả negative dù input rõ ràng tiêu cực.
  • Label sai trong ví dụ: một ví dụ mislabel có thể kéo accuracy xuống vài %.
  • Ví dụ rò rỉ test set: trùng input giữa ví dụ và test → đánh giá tăng giả tạo.
  • Ví dụ quá dài: cho cả đoạn 500 token vào ví dụ trong khi input thật chỉ 50 token → model bám nhịp dài, output dài thừa.
  • Mâu thuẫn task description và ví dụ: description bảo "trả 1 từ", ví dụ trả nguyên câu → model nghe theo ví dụ.
22

Test quality — sweep n_shot

Quy trình chuẩn để chọn n_shot tối ưu cho một task:

  • Build test set 30-100 case (ground truth gắn tay), không trùng với pool ví dụ.
  • Cố định task description, format requirement.
  • Chạy với n_shot ∈ {0, 1, 3, 5, 10} (thêm 20 / 50 nếu nghi ngờ many-shot có lợi).
  • Đo accuracy / F1 mỗi mức.
  • Plot accuracy theo n_shot. Tìm điểm bão hoà — n_shot mà thêm ví dụ không cải thiện đáng kể.
  • Chọn n = điểm bão hoà (cân nhắc cost).

Nếu plot không bão hoà ở 10, thử 20 / 50 / 100 → có thể task hưởng lợi từ many-shot. Nếu đường cong phẳng từ đầu (0 = 5 = 10) → task này zero-shot đã đủ, không cần few-shot.

23

Ghi chú reasoning model

  • Reasoning model 2024-2026 (o1, o3, DeepSeek-R1, Claude 3.7 / 4 thinking, Gemini 2.5 thinking) thường zero-shot rất tốt cho task suy luận → few-shot ít cần thiết hơn so với model thường.
  • OpenAI khuyến nghị với o1 / o3: tránh few-shot kèm reasoning chains trong ví dụ vì có thể nhiễu chuỗi suy luận nội bộ của model.
  • Few-shot vẫn rất hữu ích cho format-strict task trên reasoning model: nhãn cụ thể, JSON đúng schema, phong cách reply email.
  • Với task vừa đơn giản vừa cần format chặt, model non-reasoning + few-shot có thể vừa rẻ vừa ổn định hơn reasoning model zero-shot.
24

Code Python

Bốn ví dụ ngắn: so sánh zero-shot vs few-shot, sweep n_shot, few-shot multi-turn với Anthropic, dynamic few-shot tối giản.

# 1) Zero-shot vs few-shot trên cùng task sentiment
from openai import OpenAI

client = OpenAI()
MODEL = "gpt-4o-mini"

TASK = "Phân loại sentiment thành: positive, negative, neutral. Chỉ trả 1 từ."

FEW_SHOT = """
"Sản phẩm rất tốt." → positive
"Tệ, không recommend." → negative
"Bình thường." → neutral
""".strip()

def classify(text: str, mode: str) -> str:
    if mode == "zero":
        prompt = f"{TASK}\n\nCâu: \"{text}\"\nSentiment:"
    else:
        prompt = f"{TASK}\n\n{FEW_SHOT}\n\n\"{text}\" →"
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
        max_tokens=5,
    )
    return resp.choices[0].message.content.strip().lower()

sample = "Dùng cũng ổn, không có gì đặc biệt."
print("zero:", classify(sample, "zero"))
print("few :", classify(sample, "few"))
# 2) Sweep n_shot trên một test set nhỏ
EXAMPLES = [
    ("Sản phẩm rất tốt.", "positive"),
    ("Tệ, không recommend.", "negative"),
    ("Bình thường.", "neutral"),
    ("Giao hàng nhanh, đóng gói cẩn thận.", "positive"),
    ("Sản phẩm hỏng, mất 2 ngày mới đến.", "negative"),
    ("Hàng đúng mô tả, không có gì nổi bật.", "neutral"),
    ("Chất lượng vượt mong đợi.", "positive"),
    ("Lừa đảo, không bao giờ mua lại.", "negative"),
    ("Dùng tạm, chưa rõ độ bền.", "neutral"),
    ("Tuyệt vời, recommend mạnh.", "positive"),
]

TEST_SET = [
    ("Hài lòng với dịch vụ.", "positive"),
    ("Không đáng tiền.", "negative"),
    ("Cũng được, không có gì để chê.", "neutral"),
    # ... thêm 27 case
]

def build_prompt(n: int, query: str) -> str:
    shots = "\n".join(f'"{x}" → {y}' for x, y in EXAMPLES[:n])
    if n == 0:
        return f"{TASK}\n\n\"{query}\" →"
    return f"{TASK}\n\n{shots}\n\n\"{query}\" →"

def accuracy(n: int) -> float:
    correct = 0
    for text, gold in TEST_SET:
        prompt = build_prompt(n, text)
        resp = client.chat.completions.create(
            model=MODEL,
            messages=[{"role": "user", "content": prompt}],
            temperature=0,
            max_tokens=5,
        )
        pred = resp.choices[0].message.content.strip().lower()
        correct += int(pred == gold)
    return correct / len(TEST_SET)

for n in [0, 1, 3, 5, 10]:
    print(f"n_shot={n}: acc={accuracy(n):.2%}")
# 3) Few-shot multi-turn với Anthropic Claude
from anthropic import Anthropic

anth = Anthropic()

messages = [
    {"role": "user",      "content": "Câu: \"Sản phẩm rất tốt.\""},
    {"role": "assistant", "content": "positive"},
    {"role": "user",      "content": "Câu: \"Tệ, không recommend.\""},
    {"role": "assistant", "content": "negative"},
    {"role": "user",      "content": "Câu: \"Bình thường.\""},
    {"role": "assistant", "content": "neutral"},
    {"role": "user",      "content": "Câu: \"Dùng cũng ổn, không có gì đặc biệt.\""},
]

msg = anth.messages.create(
    model="claude-haiku-4-5",
    max_tokens=5,
    system="Phân loại sentiment thành: positive, negative, neutral. Chỉ trả 1 từ.",
    messages=messages,
)
print(msg.content[0].text.strip().lower())
# 4) Dynamic few-shot tối giản với embedding
import numpy as np

POOL = EXAMPLES  # kho ví dụ có label

def embed(texts: list[str]) -> np.ndarray:
    resp = client.embeddings.create(
        model="text-embedding-3-small",
        input=texts,
    )
    return np.array([d.embedding for d in resp.data])

POOL_EMB = embed([x for x, _ in POOL])  # pre-compute 1 lần

def top_k(query: str, k: int = 3) -> list[tuple[str, str]]:
    q = embed([query])[0]
    sims = POOL_EMB @ q / (
        np.linalg.norm(POOL_EMB, axis=1) * np.linalg.norm(q) + 1e-9
    )
    idx = sims.argsort()[-k:][::-1]
    return [POOL[i] for i in idx]

def classify_dynamic(text: str, k: int = 3) -> str:
    shots = top_k(text, k)
    body = "\n".join(f'"{x}" → {y}' for x, y in shots)
    prompt = f"{TASK}\n\n{body}\n\n\"{text}\" →"
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
        temperature=0,
        max_tokens=5,
    )
    return resp.choices[0].message.content.strip().lower()

print(classify_dynamic("Hàng đến trễ 3 ngày, đóng gói rách."))

Đoạn 4 là dynamic few-shot tối giản: cosine similarity trên numpy, không cần vector database. Khi pool ví dụ >1000, chuyển sang FAISS / Chroma / Qdrant — module RAG (Bài 36+) sẽ cover.

25

Bài tập

Bài 1 — Ba few-shot prompt. Viết few-shot prompt (3-5 ví dụ) cho 3 task: sentiment 3 lớp, NER tên người tiếng Việt, dịch tiếng Việt → tiếng Anh giữ tone formal. Format ví dụ phải nhất quán delimiter và punctuation.

Bài 2 — Zero-shot vs 3-shot. Lấy 20 review tiếng Việt có label tay (positive / negative / neutral). Chạy zero-shot và 3-shot bằng gpt-4o-mini. So sánh accuracy. Ghi nhận case nào few-shot fix được, case nào không.

Bài 3 — Permutation test. Lấy 3 ví dụ ở Bài 2. Tạo cả 6 hoán vị thứ tự. Chạy mỗi hoán vị trên cùng test set 20 case. So sánh accuracy giữa các hoán vị — bạn có thấy gap không?

Bài 4 — Dynamic few-shot. Build pool 20 ví dụ sentiment. Cài đoạn code 4 ở mục 24 hoặc dùng LangChain SemanticSimilarityExampleSelector. So sánh accuracy giữa static 3-shot (3 ví dụ cố định) và dynamic 3-shot (3 ví dụ gần query nhất) trên 20 test case.

Bài 5 — Sweep n_shot (optional). Mở rộng đoạn code 2 với test set 50 case. Plot accuracy theo n_shot ∈ {0, 1, 3, 5, 10, 20}. Xác định điểm bão hoà và quyết định n tối ưu cho task của bạn.

26

Tóm tắt

  • Few-shot prompting = task description + 2-5 ví dụ input → output + input thật. Model học pattern qua in-context learning, không update weight.
  • Phân biệt: zero-shot (0) / one-shot (1) / few-shot (2-10) / many-shot (100+, Anthropic 2024).
  • Cơ chế: induction head trong attention layer, emergent từ GPT-3 (Brown et al., 2020); paper sau phân tích sâu (Garg 2022, Olsson 2022).
  • Tín hiệu chuyển từ zero-shot lên few-shot: accuracy chưa đủ, task niche, format đặc thù, edge case nhiều, cần consistency cao.
  • Chọn ví dụ: đa dạng, đại diện, chất lượng cao, sắp xếp recency-aware (ví dụ quan trọng đặt cuối).
  • Số shot: 2-5 thường đủ; 5-10 cho task nhiều nhãn; >10 thường diminishing return trừ khi many-shot.
  • Format consistency strict: delimiter, capitalization, dấu câu, khoảng trắng đồng bộ giữa ví dụ và input thật.
  • Order matters: permute thứ tự có thể đổi accuracy đáng kể (Lu et al., 2021); test permutation khi prompt quan trọng.
  • Áp dụng: classification (cover cả nhãn), extraction (có case rỗng), translation (khoá tone), JSON (khoá schema).
  • Few-shot CoT — kèm reasoning step trong ví dụ (Wei et al., 2022) — sẽ tách riêng ở Bài 27.
  • Dynamic few-shot: encode query → retrieve top-K ví dụ tương tự → ghép prompt. Foundation của RAG-style few-shot.
  • API: single message hoặc multi-turn user/assistant. Multi-turn thường tốt hơn cho chat model.
  • Many-shot ICL (100-1000 ví dụ) tiệm cận fine-tune trên task khó nếu context window đủ rộng (Agarwal et al., 2024).
  • Few-shot vs fine-tune: heuristic theo số case label — <50 zero/few-shot, 50-500 dynamic / many-shot, >500 ổn định lâu dài → cân nhắc fine-tune.
  • Cost: ~50-200 token mỗi ví dụ; bật prompt caching cho prefix tĩnh khi lưu lượng cao.
  • Anti-pattern: format lệch, quá nhiều ví dụ, ví dụ bias, label sai, mâu thuẫn description-ví dụ, ví dụ trùng test set.
  • Quy trình chọn n: sweep n_shot ∈ {0, 1, 3, 5, 10, ...} trên test 30-100 case → plot → chọn điểm bão hoà.
  • Reasoning model 2024-2026 thường không cần few-shot cho reasoning, nhưng vẫn nên dùng cho format-strict task.
  • Bài 27 sẽ deep-dive Chain-of-Thought — kỹ thuật bổ trợ trực giao với few-shot.