课程0基础Agent开发课 / Prompt工程 / Zero-shot与Few-shot选择指南-实际项目中如何决策
— 11 min read

Zero-shot与Few-shot选择指南-实际项目中如何决策

> **本文适合谁**

Zero-shot 与 Few-shot 选择指南:实际项目中如何决策

本文适合谁

在实际项目中不确定该用 Zero-shot 还是 Few-shot 的开发者。本文给出可操作的决策框架,不是理论讨论,而是根据任务特征的具体判断标准。


两种提问方式

Zero-shot vs Few-shot决策树
Zero-shot vs Few-shot 决策树——根据任务特点、数据量和成本约束做出最优选择

Zero-shot(零样本提示):直接告诉模型做什么,不给任何例子。就像面试时问候选人"请自我介绍",没有示范,考察的是候选人本来的能力。

code
请判断以下评论的情绪倾向,输出"正面"、"负面"或"中性"。
评论:这款手机拍照效果真的很惊艳,电池也很耐用。

Few-shot(少样本提示,即给模型几个示例示范):在提问之前先给几个示范例子,让模型学习"应该怎么做"的模式,再处理实际任务。就像面试前给候选人看几个参考答案,期望他按照类似格式回答。

code
请判断以下评论的情绪倾向。

示例1:
评论:发货速度很快,包装也很用心。
情绪:正面

示例2:
评论:质量一般,不值这个价格。
情绪:负面

示例3:
评论:东西收到了。
情绪:中性

现在请判断:
评论:这款手机拍照效果真的很惊艳,电池也很耐用。
情绪:

为什么这个选择很重要

很多人的直觉是"给例子总是更好,所以每次都用 Few-shot"。这个直觉是错误的。

Few-shot 的代价是真实存在的:

首先是 Token 成本。每个示例都消耗 Token,而 API 按 Token 计费。如果每次请求都携带 5 个示例,每个示例 200 Token,就是额外的 1000 Token/次。100 万次调用就是 10 亿 Token 的额外成本。对于高频接口,这个数字不可忽视。

其次是延迟增加。Prompt 越长,生成速度越慢。用户等待时间变长。

更关键的是,Few-shot 并不总是比 Zero-shot 效果更好。当任务本身很简单,模型已经充分理解,强行加入示例反而可能引入偏差——模型会过度学习示例的特定表述,而不是抽象出任务的本质。

因此,选择 Zero-shot 还是 Few-shot,应该是一个有意识的工程决策,而不是习惯性地选一种。

系统化决策框架

任务类型

不同任务类型对 Few-shot 的依赖程度差异很大:

任务类型 说明 Zero-shot 通常够用? 推荐策略
情绪分类 正面/负面/中性 Zero-shot 优先
标准摘要 对文章做总结 Zero-shot 优先
特定格式提取 从文本中提取字段 取决于格式复杂度 格式复杂则 Few-shot
自定义分类体系 公司内部的类别定义 Few-shot 必要
风格化写作 模仿特定文风 Few-shot 必要
复杂推理 多步骤逻辑推理 通常否 Few-shot + CoT
代码生成 通用代码 Zero-shot 优先
领域特定代码 内部框架/API 使用 Few-shot 必要

模型对任务的熟悉程度

可以这样判断:这个任务是否在模型的训练数据里大量出现过?

  • 通用任务(写邮件、翻译、摘要、常见分类):模型训练数据覆盖充分,Zero-shot 通常效果很好
  • 垂直领域任务(法律条款分类、医疗实体识别、金融风险评级):模型对领域知识掌握程度参差不齐,Few-shot 能显著补足
  • 公司内部规范(内部工单分类、自定义标签体系):模型完全不知道你的分类逻辑,Few-shot 是必须的

输出格式要求

这是最直接的判断维度:

  • 标准格式(JSON、Markdown、纯文本段落):Zero-shot 通常能产生符合要求的格式
  • 特殊结构(公司定制的报告格式、特定 XML 结构、带嵌套逻辑的 JSON):Few-shot 示例能大幅降低格式错误率
  • 精确的字段命名(字段名必须完全匹配,不能有歧义):Few-shot 示例是最直接的规范手段

Few-shot 示例设计原则

决定使用 Few-shot 之后,示例的设计质量至关重要。坏的示例比没有示例更糟糕——它会把模型引向错误方向。

原则一:数量 2 到 8 个通常足够

大量实验表明,Few-shot 的效果在 2 到 8 个示例之间基本达到饱和,继续增加示例的边际收益很小,但 Token 成本持续增加。特别情况:

  • 任务极简单:2-3 个足够
  • 分类类别多(比如 20 个类别):每个类别至少 1 个,示例数量需要更多
  • 格式非常特殊:3-5 个能覆盖各种变体即可

原则二:覆盖边界情况

示例不应该只展示"典型"情况,更要覆盖容易出错的边界情况。

比如情绪分类,不要只给明显正面和明显负面的例子,应该包含:

  • 讽刺性表达("质量好得让我哭了"——实际是负面)
  • 混合情绪("功能强大但价格贵"——中性或混合)
  • 简短模糊的表达("还行"——中性)

原则三:示例质量决定输出质量

Few-shot 的核心机制是模式学习:模型会提取示例中的隐含规律,并应用到新输入上。如果示例本身有错误、不一致或存在歧义,模型就会学习这些错误。

建立示例库时,建议:

  • 每个示例都由领域专家验证
  • 同一类别的标签必须完全一致(不能有时写"正面"有时写"积极")
  • 定期审查示例是否仍然符合当前业务规范

原则四:最相关的示例放最后

研究发现,模型对上下文的处理存在近因效应——最靠近问题的内容影响力更大。因此:

  • 如果示例有长有短:把与当前输入最相似的示例放在最后
  • 如果示例有难有易:把最接近当前输入难度的示例放在最后
  • 固定示例库时:可以根据当前输入动态选择最相关的 K 个示例,按相关度从低到高排列

对同一任务的 Zero-shot 与 Few-shot 实现对比

非程序员可跳过代码,重点看文字说明。

以下是一个"客户工单分类"任务的对比实现,同时演示如何快速测试效果差异:

python
from openai import OpenAI
import json

client = OpenAI()

# ---- Zero-shot 实现 ----
def classify_zero_shot(ticket: str) -> str:
    prompt = """请将以下客户工单分类到以下类别之一:
- 账单问题
- 技术故障
- 退款申请
- 账户安全
- 其他

只输出类别名称,不要其他内容。

工单内容:{ticket}""".format(ticket=ticket)

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


# ---- Few-shot 实现 ----
def classify_few_shot(ticket: str) -> str:
    # 精心设计的示例,覆盖各类别和边界情况
    examples = [
        {
            "input": "我的账单上有一笔我没有消费的扣款,要求退回",
            "output": "账单问题"
        },
        {
            "input": "APP 一直崩溃,打开就闪退,已经重装了三次",
            "output": "技术故障"
        },
        {
            "input": "我已经申请退款两周了,还没有收到,要投诉",
            "output": "退款申请"
        },
        {
            "input": "我收到短信说账户在异地登录,我没有操作过",
            "output": "账户安全"
        },
        {
            "input": "想知道你们下午几点关门",  # 边界情况:非标准问题
            "output": "其他"
        },
    ]

    # 构建 Few-shot Prompt
    examples_text = "\n\n".join([
        f"工单:{ex['input']}\n类别:{ex['output']}"
        for ex in examples
    ])

    prompt = f"""请将以下客户工单分类到以下类别之一:
- 账单问题
- 技术故障
- 退款申请
- 账户安全
- 其他

只输出类别名称,不要其他内容。

以下是一些示例:

{examples_text}

现在请分类:
工单:{ticket}
类别:"""

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


# ---- 快速对比测试 ----
test_cases = [
    # 清晰案例
    "我的信用卡被重复扣款了",
    # 模糊案例(可能是账单问题也可能是退款)
    "我购买了会员但无法使用,要退钱",
    # 边界案例
    "你们的客服态度很差",
    # 组合问题
    "登录不上去,而且上个月多收了我钱",
]

print(f"{'工单内容':<25} {'Zero-shot':<12} {'Few-shot':<12}")
print("-" * 55)
for ticket in test_cases:
    zero_result = classify_zero_shot(ticket)
    few_result = classify_few_shot(ticket)
    match = "✓" if zero_result == few_result else "✗ 不一致"
    print(f"{ticket[:22]:<25} {zero_result:<12} {few_result:<12} {match}")

特殊情况:One-shot 的适用场景

One-shot(单样本提示) 只给 1 个示例,是 Few-shot 的最小化版本。它特别适合以下场景:

  • 格式规范:你只需要告诉模型输出格式长什么样,内容多样性不重要。比如"输出一个包含 name 和 score 字段的 JSON",一个例子就够了。
  • 防止零样本的格式偏差:有时候 Zero-shot 对格式的理解存在歧义(比如"简洁"对你意味着 100 字,对模型意味着 500 字),一个 One-shot 示例能校正理解偏差,代价比 Few-shot 小得多。
  • Token 极度敏感的场景:响应速度要求极高或成本极度敏感时,One-shot 是比 Few-shot 更经济的折中方案。

决策流程图

是,通用任务

否,领域/公司专属

格式标准

格式特殊/严格

低,简单分类/翻译/摘要

高,多步推理/复杂判断

格式不稳定

分类错误率高

理解有歧义

需要设计 Prompt

模型对这类任务是否充分熟悉?

输出格式是否特殊或严格?

需要 Few-shot

任务难度是否高?

需要 Few-shot

Zero-shot 优先试试

Few-shot + CoT

Zero-shot 效果够用吗?

✓ 使用 Zero-shot 上线

哪里不够好?

加 1 个 One-shot 示例

优化 Zero-shot 措辞

设计 Few-shot 示例集

示例是否覆盖边界情况?

补充边界示例

测试 2/4/8 个示例

选择效果最好且成本可接受的数量

✓ 使用 Few-shot 上线

实验方法:快速测试效果差异

不要凭直觉决定,用数据说话。标准的测试流程:

  1. 准备 20-50 个测试用例,覆盖典型情况和边界情况,每个用例都有人工标注的正确答案
  2. 分别测试 Zero-shot、One-shot、Few-shot(2/4/6 个示例)各版本
  3. 记录两个指标:准确率(与正确答案的符合程度)和 Token 消耗(每次请求的平均 Token 数)
  4. 计算性价比:(准确率提升) / (Token 增加量),找到边际收益最大的那个点

通常会发现:从 Zero-shot 到 2-shot,准确率提升最大;从 4-shot 到 8-shot,收益明显下降。这个"拐点"就是你的最优示例数量。

对 Java 工程师来说,这个过程完全可以类比为 JVM 调优:先用基准测试摸清当前性能,再逐步调整参数,观察收益,找到最优的配置点,而不是凭经验拍一个数字。

本页目录