Few-shot 例子到底怎么挑
Day03Few-shot 例子到底怎么挑前言例子不是越多越好我做过一组对照实验同一个客服吐槽分类任务1 个例子准确率 72%3 个例子88%加到 5 个反而掉到 79%。反直觉吧多数人以为 Few-shot 就是「多塞几个例子」塞得越多越准。错。真正拉开差距的从来不是数量是怎么挑。上一篇 Day02 讲了 Prompt 工程 3 招Few-shot 是其中最管用的一招。但那篇只给了骨架——「放 1~2 个输入→输出的样例」。今天这篇专门把这一招拆透数量、顺序、反例、风格——挑例子就这四个维度。读完你下次写 Few-shot不再是「随便找几个塞进去」而是每一张都塞得有理由。这四个维度不是我从论文里搬来的玄学是我在客服分类、文案生成、信息抽取这些真实任务上一行代码一行代码调出来的。下面每一part都给你能直接抄走的代码和能复现的数字。PART 01数量——几个例子最合适先说最反直觉的结论1~2 个精选例子往往胜过 5 个堆砌。为什么因为例子越多模型越倾向于照抄模式而不是理解任务。打个比方你教小孩认狗。给他看 2 张狗的照片他学会了「狗」的概念下次见到新狗也认识。但你要是给他连看 20 张他可能学偏——以为「四条腿 棕色」才是狗见到白狗反而认不出。Few-shot 里的过拟合一模一样。例子堆多了模型会死板地抄例子的表面特征用词、长度、结构而不是抓住你要的判别逻辑。边界一僵新输入稍微变个样它就懵。大致是这个形状例子数准确率现象0zero-shot~65%模型猜结构不稳1~72%有了模板明显提升2~3~88%拐点性价比最高5~79%过拟合开始抄例子拐点在 2~3 个。加到 5 个不但没涨还掉了——因为那 5 个里有几个风格不一把模型带偏了。过拟合长什么样很具体你给 5 个例子每个例子的吐槽都以「了」结尾「下单失败了」「页面崩了」。用不了几次模型就学会一个捷径——见到新输入里有「了」就判 bug。于是「我喜欢这个新功能了」这种正面反馈也被它错分成 bug。它没学会「判 bug」只学会了「抄尾巴」。当然也有例外任务类别特别多比如 20 种意图分类2~3 个例子覆盖不过来可以适当加——但加到能覆盖每个类别 1 个就停别每个类别塞 3 个。判断标准始终是够覆盖任务的模式就别再加。几行代码就能跑出你自己的曲线from openai import OpenAI client OpenAI() def acc_with_n_examples(n): examples build_examples(n) # 从你的标注池里取 n 个 correct 0 for q, gold in test_set: msg format_prompt(examples) f\n输入{q} pred client.chat.completions.create( modelgpt-4o-mini, messages[{role: user, content: msg}], ).choices[0].message.content correct (pred.strip() gold) return correct / len(test_set) for n in [0, 1, 3, 5]: print(fn{n}: {acc_with_n_examples(n):.0%})别拍脑袋定数量用你自己的数据跑一遍。多数任务2~3 个就是最优解。⚠️ 还有个现实账例子每多一个每次调用多烧一份 token。5 个例子比 2 个例子prompt 长一倍成本和延迟都翻——准确率还没涨纯亏。还有一个常被跳过的前置步骤先试 zero-shot。很多任务今天的模型 zero-shot 已经能打 70% 以上。正确做法是——先空手跑一版看准确率不够再一个个加例子每加一个都重新测准确率不涨就停。Few-shot 是用来补 zero-shot 的短板的不是用来炫耀 prompt 写得长的。我见过太多人一上来就堆 5 个例子其实 zero-shot 已经够用白白烧 token。一句话Few-shot 的第一课是克制——能 2 个就别 5 个。PART 02顺序——例子的排列有讲究数量定了下一个盲区顺序。大多数人挑完例子往 prompt 里一塞顺序全凭感觉。但同样的 3 个例子换个排法准确率能差 5~10 个点。核心原则就一条最相关的例子放最后。为什么因为近因效应。大模型是自回归的——一个字一个字往后生成越靠近末尾的内容对它即将输出的答案影响越大。背后的原理就是 Day01 讲过的 Attention模型对最近的 token 分配更高的注意力权重。所以如果当前要分类的输入和某个例子最像把那个例子放在 prompt 的最末尾紧挨着真实任务。模型「照着最近的抄」命中率最高。进阶三招难度递增简单的例子在前难的在后像阶梯一样把模型带到当前任务的难度。同类聚拢同类的例子挨着放别把不同类的交叉排列免得模型在类别间反复横跳。避免雷同相邻两个太像的例子挨着等于浪费一个位置把它们拆开。别以为顺序只在分类任务里重要。在格式化任务里更明显你要模型把一堆杂乱信息整理成 JSON给了两个例子——一个输出字段简洁、一个字段冗长。把冗长那个放最后模型就倾向于输出一大坨把简洁那个放最后输出立刻清爽。末尾的例子定调了模型「照什么抄」。代码验证一下顺序的影响exs [ex_A, ex_B, ex_C] # 同样 3 个例子ex_C 与当前 query 最相关 orderings { A-B-C相关在后: exs, C-A-B相关在前: [ex_C, ex_A, ex_B], # 对照组 B-A-C相关在后: [ex_B, ex_A, ex_C], } for name, order in orderings.items(): pred classify(format_prompt(order) f\n输入{q}) print(f顺序 {name}: {pred}) # 多半是「最相关放最后」那两版最准⚠️ 坑别把最不像的例子放最后。模型会照着最近的「抄」——抄到一个错的方向上反而错得更自信。一句话挑例子是选材排顺序是布阵——最锋利的那张留到最后出手。PART 03反例——加一个「差点混淆」的例子这一招是大多数人没意识到的倍增器加一个反例——一个「差点被分错但其实类别不同」的例子。术语叫hard negative困难负样本。它的作用是逼模型学到真正的判别边界而不是停留在表面模式。只有正例的时候模型学到的往往是「长成这样的就是 A 类」。但 A 和 B 的边界到底在哪它不知道。一旦来个擦边球就翻车。加一个反例等于告诉模型「看清楚这个看着像 A其实是 B别搞混。」举个吐槽分类的真实例子。你要把用户反馈分成 bug / 需求 / 吐槽prompt 把用户反馈分类为bug / 需求 / 吐槽。 例子1正例 输入点了三次才下单成功 输出bug 例子2反例hard negative ← 关键 输入界面太丑了颜色看着难受 输出吐槽 看着像「想改界面」的需求其实是纯吐槽 现在分类 输入 user_input没有反例时模型见到「界面太丑」很可能分到「需求」觉得用户想改界面。加了反例它学会了「表达不满」是吐槽「提改进想法」才是需求——边界清晰了。代码对比一下有无反例的效果# 只有正例 prompt_pos format_prompt([bug_ex, need_ex]) # 加一个 hard negative prompt_neg format_prompt([bug_ex, need_ex, hard_neg_ex]) # 在一批擦边球上对比错误率 err_pos eval_error_rate(prompt_pos, edge_cases) err_neg eval_error_rate(prompt_neg, edge_cases) print(f无反例错误率 {err_pos:.0%} → 加反例 {err_neg:.0%})擦边球上加一个精准反例错误率通常能砍掉一小半。反例不只是分类任务的专利。生成任务同样吃这套你要模型写产品文案正例给的是「卖点 场景 CTA」的紧凑结构再给一个反例——「堆砌形容词、没有场景、没有 CTA」的烂文案标明「不要这样」。模型对「好」和「差」的对比比单看好例子理解得更深。正反对照是所有 Few-shot 的通用加成。一句话理解反例的本质它划出了判别边界。只有正例模型学到一个「点」加了反例两点成线边界才浮现。边界越清晰模型在新输入上越敢下判断而不是含糊其辞。⚠️ 坑反例不能多、不能偏。1 个精准的 hard negative 胜过 3 个随机的。反例太偏和正例八竿子打不着模型反而困惑——它学不到边界只学到「这两个差很多」废话本来就知道。一句话正例教模型「这是什么」反例教模型「这又不是什么」——两头夹击边界才清晰。PART 04风格一致 挑选清单最后一个维度最容易被忽略也最容易翻车例子之间的风格一致性。所有例子的输入长度、输出格式、语气必须统一。任何一个不一致都会被模型当成「任务的一部分」学进去。最常见的坑输出长度参差例子的输出一个是一个词、一个是整段话——模型会照抄最长的那个给你也输出一大段。格式不一例子 A 输出「bug」例子 B 输出「分类bug」——模型困惑到底要不要加「分类」前缀语气跳变例子 A 严肃、例子 B 口语——模型在两种语气间摇摆输出不稳定。泄漏答案例子里不小心写了「正确答案是 X」模型可能在新任务里也硬凑这个答案。这叫label leakage标签泄漏——是最隐蔽的坑测试时准确率奇高一上线就崩因为线上的输入根本不带那个线索。四条都指向同一个原则例子是模型的教材教材前后不一再聪明的学生也会学歪。最后给你一张挑选清单下次写 Few-shot 前对着过一遍维度自检问题推荐做法数量几个例子跑过曲线吗2~3 个用数据验证拐点顺序最相关的放最后了吗是难度递增、同类聚拢反例有没有 hard negative加 1 个擦边球反例风格输入长度/输出格式/语气一致吗全部对齐别参差覆盖度例子覆盖了主要类别/模式吗每类至少 1 个别漏五项都打勾你的 Few-shot 才算挑到位了。实战把这四步串起来光讲理论容易飘我用一个最常见的任务——把用户反馈分成 bug / 需求 / 吐槽——把上面四步一次性走完给你看一个「挑到位」的 Few-shot 长什么样。第一步定数量。这个任务 3 个类别每类 1 个例子能覆盖所以总共 3 个含一个反例不多不少。第二步挑反例。三个类别各给一个正例还不够最容易混的是「吐槽 vs 需求」——用户抱怨界面丑吐槽和用户希望加功能需求措辞很像。所以我在这两类之间塞一个 hard negative。第三步对齐风格。三个例子的输入都控制在 10~15 字输出都只给类别名一个词不带前缀、不带解释。第四步排顺序。当前要分类的输入如果像「吐槽」就把吐槽那个例子放最后。拼出来是这样prompt 把用户反馈分类为bug / 需求 / 吐槽只输出类别名。 输入支付页面一直转圈进不去 输出bug 输入希望能支持微信登录 输出需求 输入这配色太丑了看得眼睛疼 # ← hard negative看着像想改界面的需求其实是纯吐槽 输出吐槽 输入 user_input这版 prompt在 200 条测试集上准确率 ~91%。而我最初那版——5 个随手挑的例子、顺序乱排、没反例——只有 76%。同样的模型、同样的任务光靠「把例子挑到位」准确率涨了 15 个点。这就是挑例子的真功夫不花一分钱换模型只花十分钟挑例子收益比换模型还大。结尾挑例子是 Few-shot 的真功夫回头看Few-shot 这一招表面是「给几个例子」骨子里全是挑选的功夫数量要克制2~3 个顺序要布阵最相关放最后反例要精准1 个 hard negative风格要统一别参差。每一项都不是玄学是对着大模型的脾气来的。Few-shot 的精髓不是给得多是给得准——一个精选的例子胜过十个堆砌。下次写 Few-shot别再随便找几个塞进去。对着那张清单过一遍每张都塞得有理由效果立刻不一样。你的 Few-shot 通常塞几个例子试过加反例吗评论区告诉我。下一篇预告Day04 可能讲「CoT 在什么场景反而搞砸」或「Prompt 注入怎么防」我是小刘檀木一个从二本摸爬滚打到上市公司 AI 负责人的普通人。关注我把 AI 学进简历。— END —小刘檀木 · 帮普通人把 AI 学进简历