主题
02.3 示例工程 Few-shot
给示例比写规则更有效,但只在你懂得怎么给的时候。
读完你能做什么:设计出一组能真正约束输出的示例,并识别出正在污染结果的坏示例。
一、为什么示例比规则强
回到第一性原理:模型在做条件概率预测。
- 规则:「输出要简洁」→ 模型需要把这个抽象概念映射到具体的输出分布,映射过程有巨大的不确定性。
- 示例:给三个实际的简洁输出 → 模型直接在这些样本附近采样,不确定性大幅降低。
一条经验:当你发现自己在用形容词描述期望输出(「专业的」「简洁的」「友好的」),停下来,改成给一个示例。
二、示例的数量曲线
| 示例数 | 效果 | 说明 |
|---|---|---|
| 0 | 基线 | 完全依赖指令 |
| 1 | 明显提升 | 建立基本格式认知 |
| 3 | 通常是甜点 | 足以让模型归纳出模式 |
| 5-7 | 边际收益递减 | 复杂任务可能需要 |
| 10+ | 可能变差 | 占用大量上下文;示例间的细微不一致会被放大 |
2.1 为什么 30 个示例反而更差
三个原因:
- 上下文成本 —— 30 个示例可能占掉几千 token,挤压了真正的任务空间。
- 不一致性放大 —— 你很难保证 30 个示例风格完全统一。模型会捕捉到你没意识到的模式差异,产生不可预测的行为。
- 过拟合到表层特征 —— 如果你的 30 个示例碰巧都以「首先」开头,模型会认为这是必须的。
结论:宁可给 3 个精心打磨的示例,不要给 20 个随手凑的。
三、示例的黄金结构
3.1 基本格式
text
<examples>
<example>
<input>
用户报告:点击提交按钮后页面一直转圈
</input>
<output>
**类型**:前端交互异常
**优先级**:P2
**需补充信息**:浏览器版本、网络面板中该请求的状态码、是否所有用户都能复现
**初步方向**:请求未返回 / 返回了但前端未处理 / 前端状态机卡死
</output>
</example>
<example>
<input>
用户报告:导出的 Excel 里金额少了两位小数
</input>
<output>
**类型**:数据精度问题
**优先级**:P1
**需补充信息**:具体订单号、数据库中该字段的原始值、导出模板的格式定义
**初步方向**:导出层做了错误的类型转换 / 数据库存储时已丢精度
</output>
</example>
<example>
<input>
用户报告:这个功能太难用了
</input>
<output>
**类型**:无法立即处理(描述不具备可操作性)
**优先级**:待定
**需补充信息**:具体是哪一步遇到困难、期望的行为是什么、当前行为是什么
**初步方向**:需要先与用户确认具体场景
</output>
</example>
</examples>注意第三个示例 —— 它演示的是"遇到无效输入时该怎么办"。这是最容易被遗漏、但价值最高的一类示例。
3.2 示例设计的三个维度
一组好的示例应该覆盖:
| 维度 | 作用 | 示例数 |
|---|---|---|
| 典型情况 | 建立主要模式 | 1-2 |
| 边界情况 | 划定处理范围 | 1 |
| 拒绝情况 | 演示什么时候不该硬答 | 1 |
上面那组示例正好是 典型 + 典型 + 拒绝 的结构。
四、负例(Negative Examples)
有时候展示"什么是错的"比展示"什么是对的"更有效。
4.1 对比式负例
text
<examples>
<example>
<input>解释什么是数据库索引</input>
<bad_output>
数据库索引是一种数据结构,它可以提高数据检索的速度。就像书的目录一样,
通过索引可以快速定位到需要的数据,而不用扫描整个表。索引有很多种类型,
包括 B-tree 索引、哈希索引等等。合理使用索引可以大幅提升查询性能。
</bad_output>
<why_bad>
全是通用百科内容,没有任何可操作信息。读者读完不知道该做什么。
</why_bad>
<good_output>
索引 = 用额外的写入成本和存储空间,换取查询时避免全表扫描。
**什么时候该建**:
- WHERE / JOIN / ORDER BY 中高频出现的列
- 该列的选择性高(distinct 值多)
**什么时候不该建**:
- 表很小(几千行以内,全表扫描更快)
- 该列写入极频繁(每次写都要维护索引)
- 选择性低(如性别字段,索引几乎无用)
**怎么验证**:
```sql
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 123;
-- 看是 Index Scan 还是 Seq Scan,以及实际耗时
```
</good_output>
</example>
</examples><why_bad> 这一栏是关键 —— 它把负例从"这个不行"升级成"这个不行的原因是 X",模型能把这个原因泛化到新场景。
五、示例污染:最隐蔽的失败模式
5.1 症状
你给了示例,但输出总是带上一些你没要求的特征。
5.2 三种常见污染源
污染源 1:无意的格式一致性
text
❌ 你的三个示例碰巧都是 3 条要点
→ 模型认为"必须是 3 条",遇到只有 2 个要点的场景会硬编一个修复:让示例的长度和条数故意不一致。示例 1 给 2 条,示例 2 给 5 条,示例 3 给 1 条。
污染源 2:主题泄漏
text
❌ 你在演示"如何写 commit message",三个示例都是关于支付模块的
→ 模型可能认为输出应该和支付有关修复:示例的主题要分散,与实际任务的主题保持距离。
污染源 3:难度偏斜
text
❌ 三个示例全是简单场景
→ 遇到复杂输入时,模型仍会给出简单场景的输出粒度修复:示例难度要有梯度,至少包含一个复杂案例。
5.3 检测污染的方法
给一个故意不同的输入,看输出是否被示例带偏:
text
{你的完整提示词 + 示例}
现在处理这个输入:{一个与所有示例都不相似的输入}如果输出仍然保留了示例的表层特征(相同的条数、相同的开头、相同的主题倾向),说明存在污染。
六、动态示例:从你自己的历史中提取
这是最被低估的技巧。
做法:当你和 Claude 的某一轮对话产生了满意的输出,把「你的输入 + 它的输出」保存下来,作为未来同类任务的示例。
在 Claude Code 里可以自动化:
markdown
---
name: bug-triage
description: 把用户报障描述转换成结构化的工单。当用户粘贴一段模糊的问题描述并需要分类定级时使用。
---
# Bug 分诊
按 `examples.md` 中的格式处理输入。
@examples.mdexamples.md 就是你逐步积累的示例库。随着使用,它会越来越贴合你团队的实际标准。
七、示例 vs 规则:怎么组合
最强的写法是两者都要:
text
<constraints>
- 每条建议必须包含可执行的验证命令
- 不确定时明说,不要用模糊措辞
- 长度控制在 200 字以内
</constraints>
<examples>
{2-3 个示例,演示上述约束在实际输出中长什么样}
</examples>分工:
- 规则负责覆盖示例没穷举到的情况(泛化能力)
- 示例负责把抽象规则锚定到具体输出(准确性)
只有规则 → 输出符合规则但形态不可预测。 只有示例 → 遇到示例外的情况时行为不确定。
八、Checklist
设计示例时逐项确认:
- [ ] 示例数量在 2-5 之间
- [ ] 至少有一个边界/异常情况的示例
- [ ] 示例的长度、条数、结构故意不完全一致(避免格式污染)
- [ ] 示例的主题与实际任务主题不同(避免主题泄漏)
- [ ] 示例中包含至少一个"信息不足,需要澄清"的案例
- [ ] 示例用
<example>/<input>/<output>标签明确分隔 - [ ] 已用一个与所有示例都不相似的输入做过污染检测