第 2 章 示例与结构化
学习目标
- 说明示例会同时传递预期规则和偶然模式,并找出、消除偶然模式。
- 按相关性、多样性和格式一致性组织 few-shot 示例,将示例与评估数据分开。
- 用 XML 标签划分指令、上下文、示例和输入的边界。
- 根据接收方(人、系统、语音)选择输出格式,确定数据字典和缺失值的表示方法。
- 针对机器读取的输出,在指令、示例和结构化输出中选择合适的方法,分别检查格式合规性与内容准确性。
- 把依赖预填充的提示词迁移为适用于最新模型的方法。
引言
一家邮购公司编写了一个提示词,把商品咨询分成“配送、换货、付款、其他”四类。负责人加入了四个示例,巧合的是,它们都是以“您好”开头的礼貌语句。投入使用后,没有问候、措辞简短的咨询大量被归入“其他”,几十条写明紧急情况的咨询被搁置了一天多。负责“其他”类别的同事抱怨工作量增加,过了一周,负责人才查明原因。模型不但学到了负责人想教的分类标准,还学到了没人想教的规则:“只有礼貌语句才算正式咨询。”造成偏差的是负责人挑选的示例,而不是他写的指令。示例是最有力、也最难控制的指令。
本章先介绍好示例的条件、多样性设计、边界案例、减少偏差的步骤,以及示例与评估数据的分离。接着讨论划分指令与资料边界的标签、适合接收方的格式、数据字典与缺失值表达、结构化输出保证的范围与局限、预填充的替代方法,以及依据字段的设计。深入阅读则讨论如何向具备思考功能的模型展示方法,以及显示环境带来的格式问题。
核心概念
示例就是交给裁缝的样衣
对裁缝说“一件利落的衬衫”,远不如递给他几件样衣来得准确。但如果样衣全是白色短袖,裁缝可能会误以为顾客只要白色短袖。few-shot 示例也是如此,它是展示几组“输入与期望输出”的方法。Anthropic 指南将示例列为调整输出格式、语气、结构最可靠的手段之一。但模型也会连同示例中隐藏的、并非有意为之的模式一起学去。
加入示例前,把“这组示例教了什么”分成两栏填写,就能看出风险。
| 想教的内容 | 可能无意教会的内容 |
|---|---|
| 分类标准(哪些咨询属于换货) | 句子长度、有无问候语、是否使用敬语 |
| 输出格式(一个标签词) | 特定标签的频率(四个中三个是配送) |
| 语气(平实的说明) | 示例反复使用的表达、专有名词、数值大小 |
如果右栏内容在各示例中没有均匀混合,模型可能会将其视为规则。
好示例的条件
| 条件 | 含义 | 依据 |
|---|---|---|
| 相关性 | 示例与实际输入相似 | Anthropic 指南 |
| 多样性 | 包含边界案例,彼此差异足以避免模型学到非预期模式 | Anthropic 指南 |
| 结构 | 用 <example> 包裹,多个示例用 <examples> 汇总,与指令区分 |
Anthropic 指南 |
| 格式一致性 | 所有示例结构相同,连分隔符、标签和换行都一致 | Gemini 指南 |
对于数量,各供应商的侧重点不同。Anthropic 建议 3~5 个,并补充指出,可以让模型评估示例的相关性与多样性,或生成更多示例。Gemini 指南建议始终加入示例,同时也警告示例过多可能让回复过度贴合示例,造成过拟合。OpenAI 的推理模型最佳实践则建议先尝试不提供示例(zero-shot)。另一方面,Google 文档也介绍,在长上下文中加入数百个示例(many-shot),在某些任务上取得了接近微调模型的表现。归纳起来就是:“内容要多样,格式要统一,数量靠实验确定。”逐步增加示例,用相同评估集测量;当分数不再上升,或输出开始模仿示例语句时,就停止增加。
用表格设计多样性
“多样一些”也是第 1 章介绍的不可判定表述。选择示例时,应将多样性拆成不同维度填写表格。
| 维度 | 检查问题 |
|---|---|
| 标签 | 是否每个标签至少出现一次?是否与实际比例相差过大? |
| 长度 | 是否混合了短输入和长输入? |
| 文风 | 是否混合了措辞客气的语句、简短便条、带有错别字的文本? |
| 边界 | 是否包含跨在两个标签之间的输入? |
| 例外 | 是否包含缺信息或无关的输入? |
| 顺序 | 同一标签是否连续出现?最后一个示例是否固定为特定标签? |
表中的空缺,就是下一步需要寻找的示例。从真实日志中寻找能补上空缺的输入,但须先去除个人信息再加入。
边界案例与对比样本对
简单示例,模型本来就能答对。能教会判定标准的是容易混淆的示例。“箱子压坏了,但还没打开产品”属于配送问题,还是换货请求?为这种边界案例标上正确答案,模型就能学到两个类别的分界线在哪里。
想让边界更清楚,可以用对比样本对:两个几乎相同的输入,仅因一个细微差别而得到不同标签。
<examples>
<example>
<input>收到的鞋有一只鞋跟掉了。请换成同样尺码的。</input>
<label>换货</label>
</example>
<example>
<input>收到的鞋有一只鞋跟掉了。我想直接退款。</input>
<label>退款</label>
</example>
</examples>
展示错误输出作为示例时要谨慎。长篇展示错误格式,会让该格式在上下文中留下强烈印象,反而可能被照搬。如果确实需要错误示例,应保持简短,标明“不要这样做”并说明理由,紧接着给出正确示例。默认做法是展示想要的结果。
减少示例偏差的步骤
示例偏差,是指示例组合的倾向影响模型判断的现象。常见类型有三种:某个标签过多,导致输出偏向该标签;示例顺序或最后一个示例牵引结果;直接照抄示例措辞。可按以下步骤诊断并减少偏差。
- 用数字确认表现。 比较各标签准确率、输出标签分布与实际分布。如果某个标签出现得比实际更多,就存在偏向。
- 将示例对照多样性表。 查看偏向的标签在示例中是否也过多,文风或长度是否集中于一类。
- 每次只改一项。 在平衡标签分布、打乱呈现顺序、混合文风中任选一项进行调整,用同一评估集重新测量。
- 检查照抄。 生成任务应统计输出与示例语句的重合程度。如有重合,让示例表达彼此不同,并说明“示例用于展示结构和语气,不得照搬句子”,同时附上理由。
- 不要用规则堆补。 按 Anthropic 上下文工程文章的建议,先选好一组代表性示例,而非罗列冗长的例外。
不混用示例与评估数据
挑选示例的来源,与制作评估集的来源,常常是同一批日志。这时,如果已经用作示例的输入仍然留在评估集中,就相当于让模型再做一遍已经看过正确答案的题目,得到的分数就会高于实际水平。正确的工作顺序如下:先把用于评估的输入单独划出来,锁定不再用于挑选示例,然后才从剩余输入中选择能填满多样性表的示例。每次修改示例时,都要确认它们没有与评估输入重叠。第 5 章会以“分离改进集与确认集”为题,再次讨论这一原则。
用 XML 标签划清边界
提示词中如果混杂着指令、参考资料、示例和用户输入,模型可能会把参考资料里的句子误当成指令。Anthropic 指南解释,用 <instructions>、<context>、<input> 等标签包裹不同内容,可以减少误解。标签的作用就像文件夹里的彩色索引页。
<instructions>
阅读询价邮件,提取所需商品和期望交期。
</instructions>
<price_policy>
报价有效期为出具之日起 30 天。
</price_policy>
<email>
{{CUSTOMER_EMAIL}}
</email>
使用标签的原则很简单。
- 标签名没有固定要求。选择能说明内容的名称,一旦确定,就始终保持一致。
- 有层级的内容使用嵌套。多份文档可在
<documents>中放入<document index="1">,也可以像 OpenAI 指南那样,用 XML 属性附加元数据,供指令引用。 - 标签只负责标明边界。输出格式需要另行确定,标签也不是安全屏障。如果外部资料可能混入
</email>等字符串破坏边界,则按第 3 章的方法用 JSON 包装会更安全。 - OpenAI 和 Anthropic 都提到,Markdown 标题也能划分区域。同一提示词内应统一使用一种方式。
根据接收方选择格式
确定格式时,首先要问的是:“谁来接收这个输出?”
| 接收方 | 合适格式 | 注意事项 |
|---|---|---|
| 人在屏幕上阅读 | 段落,只在必要时使用表格与列表 | 确认显示环境能否渲染 Markdown |
| 人阅读印刷品 | 带标题的段落、表格 | 用出处名称代替链接 |
| 语音朗读 | 简短陈述句 | 明确说明禁用符号、括号、缩写、表格的理由 |
| 系统解析 | JSON 等具有明确 schema 的格式 | 用结构化输出强制约束,与面向人的说明分开 |
| 粘贴至电子表格 | CSV 或制表符分隔格式 | 规定如何处理值中的逗号、换行、引号 |
如果需要同时获得面向人的说明和面向系统的数据,可以将说明放在指定标签中、数据放在单独字段中,或拆成不同调用。说明句插入数据之间会使解析器失败。
数据字典与缺失值表达
只确定字段名却不确定含义,同一个字段就会因人、因请求而填入不同内容。编写 schema 前,先建立数据字典。
| 字段 | 业务含义 | 类型·单位 | 允许值 | 缺失时 |
|---|---|---|---|---|
requested_items |
客户希望报价的商品 | 字符串数组 | 商品代码表中的代码 | 空数组 [] |
due_date |
客户期望的交期 | 日期(YYYY-MM-DD) | 今天之后 | null |
urgency |
邮件体现的紧急程度 | 字符串 | high、normal |
无法判断时为 unknown |
尤其要避免把所有“没有”混为一谈。原文中没有信息、该项目不适用、依据不足无法判断,在后续业务中的含义各不相同。应为三者定义不同的值,同时写入指令和 schema 描述。若只设置必填字符串字段,模型即使没有信息,也会尝试填入看似合理的值。对于可能没有值的字段,schema 必须允许 null。
结构化输出:强制格式的功能
固定输出格式有三个层次。
| 方法 | 保证程度 | 适用场景 |
|---|---|---|
| 通过指令请求格式 | 通常遵守,但不保证 | 人阅读的输出 |
| 通过示例展示格式 | 一致性提高 | 文风与结构也需要一致时 |
| 结构化输出(JSON schema) | 强制遵循 schema | 系统直接读取并保存的输出 |
OpenAI 文档区分 JSON 模式和结构化输出。二者都生成有效的 JSON,但只有结构化输出保证遵守 schema,因此建议在条件允许时使用结构化输出。各供应商的要求略有不同。
| 供应商 | 设置 | 需要了解的内容 |
|---|---|---|
| OpenAI | 在 Responses API 的 text.format 中设置 json_schema 和 strict: true,或使用函数调用的 strict 模式 |
所有字段均需放入 required,可选字段用与 null 的联合类型表示,每个对象都需要 additionalProperties: false。输出遵循 schema 的键顺序 |
| Anthropic | output_config.format(JSON 输出)与工具定义中的 strict: true |
通过受约束解码遵循 schema。不支持 minimum、maximum、minLength、maxLength 等部分约束,直接发给 API 会返回 400 错误;多数 SDK 辅助工具会将其转移到描述中发送,具备响应验证功能的辅助工具会再按原约束检查。必需属性在前,可选属性在后 |
| 将响应指定为 JSON 并提供 schema | 只支持 JSON schema 的一部分。官方要求即使输出语法正确,应用也始终要验证值 |
分类任务应使用 enum 定义允许的标签。Anthropic 文档建议分类时使用含 enum 字段的工具或结构化输出,同时说明 enum 值的大小写不保证一致,应忽略大小写进行比较,不要定义仅大小写不同的值。
格式合规与内容准确是两回事
结构化输出保证的是形状,而非内容正确。OpenAI 文档明确指出,结构化输出也可能包含错误,并建议完善指令、提供示例,或将任务拆成简单子任务。因此,面向机器的输出应分四层检查。
- 语法: 能否作为 JSON 解析。
- Schema: 字段、类型、enum 是否正确。对于不支持、未能强制执行的约束(最大值、长度),在这里通过代码检查。
- 业务规则: 交期是否在今天之后,商品代码是否在代码表中。
- 原文核对: 值是否确实存在于原文。抽样由人工确认,或通过搜索原文字符串检查。
注意
结构化输出也有例外。如果模型出于安全原因拒绝请求,或因达到输出上限而被截断,结果可能不符合 schema。此时 Anthropic 的 stop_reason 为 refusal 或 max_tokens,OpenAI 则通过 refusal 字段或 incomplete 状态告知。解析之前,先检查停止原因。
预填充的原理与替代方法
预填充(prefill)是预先填入 assistant 消息的开头,让模型接着写的技巧。例如,最后一条 assistant 消息填入 {,模型就接着写 JSON 的其余部分。它利用模型通过预测下一个字符来生成文字的特性,固定输出的开端。
根据 Anthropic 文档,从 Claude 4.6 模型开始(以及 Claude Mythos Preview),不再支持最后一个 assistant 轮次的预填充,这类请求会返回 400 错误。旧模型仍支持预填充,在对话中间加入 assistant 消息也不受影响。文档解释,模型遵循指令的能力已经提高,多数用途不再需要预填充,并按用途给出迁移路径。
| 预填充的用途 | 替代方法 |
|---|---|
| 固定 JSON、分类格式 | 结构化输出、带 enum 字段的工具。也可以先要求遵守格式,并配合重试 |
| 去掉开场白 | 在系统指令中要求“不要开场白,直接回答”、在标签内输出、结构化输出或工具调用。偶尔残留的开场白可通过后处理移除 |
| 避免不必要的拒绝 | 在用户消息中给出清楚的指令即可 |
| 续写被中断的回复 | 在用户消息中放入上一条回复的末尾,要求接着写,或重新发送请求 |
| 长对话中提醒背景 | 将需要提醒的内容放入用户轮次,或在工具、上下文压缩阶段加入 |
更换模型时,首先要检查预填充。出错的位置明确,因此容易找到;但它原本承担的工作应该由什么代替,仍需按上表根据用途分别决定。
依据字段应要求简短说明
很多时候,我们希望在判断结果之外也得到依据。这里要设计两点。第一是字段顺序。模型从前往后生成内容,让它先写依据、后写判断,有助于使判断建立在依据之上。OpenAI 的结构化输出遵循 schema 键顺序,Anthropic 则先输出必需属性,因此要保持顺序,需将所有属性设为必需,或在解析时考虑重排。
第二是依据字段要求什么。在具备思考功能的最新 Claude 模型中,要求在 reasoning、thinking、trace 等字段中写出逐步思考过程,可能收到 reasoning_extraction 类别的拒绝。官方文档建议,改为要求简短解释或支持结果的证据。字段名也应明确表达所需内容,例如 evidence、explanation。第 4 章将再次讨论这一主题。
深入阅读
向具备思考功能的模型展示方法
示例对具备思考(thinking)功能的模型同样有效。Anthropic 文档解释,解题示例会影响模型在思考块中处理类似问题的方式,并建议每个示例都呈现“问题、适用方法、期望答案”。只展示输入和答案的示例,只能教会答案的形式;展示方法的示例,则能教会公司特有计算规则这类模型无法从常识中获知的流程。
| 示例形式 | 教会的内容 | 风险 |
|---|---|---|
| 输入 → 答案 | 答案的格式与数值规模 | 偏向生成与示例答案相近的数字 |
| 输入 → 方法 → 答案 | 要应用的规则与顺序 | 示例变长,token 增加 |
即使展示了方法,也应要求最终答案只能从指定字段或标签中提取,避免说明与答案混合导致解析失败。
显示环境决定格式
模型的默认格式若不适合显示环境,用户就会直接看到符号。典型情况是无法渲染 Markdown 的界面上显示出星号和井号。Anthropic 文档说明,最新模型默认使用 LaTeX 表示数学内容,并提供示例指令:需要纯文本时,不使用 LaTeX 或 MathJax,而只用 /、*、^ 等符号表达公式。
修正格式问题时,第 1 章的原则同样适用。
- 说明想要的格式,而非只写禁止。用“流畅衔接的段落”代替“禁止 Markdown”。
- 附上理由。“此界面无法渲染格式,星号会直接显示为文字。”
- 让提示词格式接近期望输出。需要纯文本时,也移除提示词中的标题和项目符号。
- 将后处理留作最后手段。用正则表达式删除符号,可能连本来需要的符号(例如公式中的乘号)也一并删掉。
工作场景
日出诊所:把挂号备注填入病历栏
社区医院“日出诊所”希望从护士在挂号窗口写下的备注中提取症状、发病时间和正在服用的药物,预先填入电子病历的输入栏。最初的提示词是“从下面的备注中把信息提取为 JSON”,外加两个示例。实际运行后发现,onset 字段名有时会变成 start_date,没有服药时整个字段会直接缺失。如果备注只写“几天前开始”,还会编造一个具体日期。
信息组的徐专员把原因分成三方面。第一,两个示例都是有服药记录且发病时间明确的备注,没有展示“没有”或“模糊”时的格式。第二,仅靠指令和示例,无法保证字段名和字段是否存在。第三,onset 是必填日期字段,模型没有办法将其留空。
徐专员先建立数据字典。onset 表示“患者说的症状开始时间”:备注里有日期就填日期;只有“三天前”等相对表达时,将原文表达放入 onset_text,onset 设为 null。服药信息区分“明确说没有”(空数组)和“备注未提及”(null),因为护士下次问诊需要追问的是后者。
接着,按多样性表将示例增至四个:明确说没有服药的备注、未提及药物的备注、使用相对时间表达的备注,以及包含多种症状的备注。四个示例使用相同标签和字段顺序。备注原文用 <memo> 包裹,与指令分开。病历输入由系统直接读取,因此用结构化输出强制遵循 schema,并将 onset 改为允许日期或 null。
一名团队成员建议,提取不到日期就填挂号日期,徐专员没有采纳。挂号日期不是症状开始日期,填入看似合理的值,医生可能不经核实就略过。最后,先检查停止原因,只有正常结束才填入病历,每天抽十条让护士与原文核对。此后,字段名改变或缺失的情况消失了,抽样中也未再发现编造日期。关键在于分工:示例负责判断边界,schema 负责格式,数据字典负责含义。
转角办公:纠正设施投诉分类的偏向
共享办公运营商“转角办公”将入驻企业通过应用提交的设施投诉分为“设备故障、清洁、噪声、出入·安保、其他”五类,并自动分配给对应团队。试运行两周,各团队负责人积累了不少意见:设备组收到大量不相关投诉,噪声投诉则频频被归为“其他”。
运营策划负责人车经理将人工重新分类的 400 条投诉与模型分类比较。模型选择“设备故障”的频率远高于实际。将示例对照多样性表后,原因显现了:五个示例中三个是设备故障,五个全是长篇礼貌语句,最后一个也属于设备故障。而实际投诉中,“3 楼会议室旁边太吵”等短句超过一半。
修改前,车经理先从 400 条中划出 150 条作评估并锁定,再从剩余 250 条中选择示例补齐多样性表。每个标签至少一个,混合长短文本,并加入两个边界案例。其中一个是“空调声太大,没法打电话”,看似噪声,但源头是设备,所以归设备故障;另一个“有人一直在走廊大声打电话”则归噪声。两个示例除标签外,还附上“源头是设备则归设备故障”这一简短理由。示例顺序也打乱,避免同一标签连续出现。
输出由分配系统直接读取,因此通过结构化输出将 label 限定为 enum,并让模型在 evidence 字段中简短摘录作为判断依据的投诉原话,供团队负责人查看。他没有设置填写思考过程的字段。
审查会上有人提议“给每个标签增加例外规则”,但车经理决定先评估只改示例组合的版本,因为规则和示例同时改变,就无法知道哪项有效。用锁定的 150 条比较后,噪声投诉准确率明显提高,设备故障的偏向减轻。剩余错误大多是“其他”与别的标签之间的边界问题,车经理只将这些类型记录为下一步修改对象。
易错点
- 示例越多越好。 增加同一类型的示例只会加重偏向,过多还会导致过拟合。数量应通过实验确定。
- 示例好,评估就可信。 用作示例的输入混进评估集,会使分数虚高。应先划出评估输入。
- 输入用了标签,输出也会结构化。 输出格式需要另外指定,机器读取的输出要用 schema 强制约束。
- 用了 JSON 模式,字段也会被遵守。 JSON 模式只保证语法,字段和类型要靠结构化输出来保证。
- 遵守 schema,值就一定正确。 结构化输出只保证形状,不保证内容。业务规则和原文核对仍须另行检查。
- 设为必填字段就不会遗漏。 没有信息却要求必填,会诱使模型编出合理值。可能不存在的值应允许
null。 - 预填充在哪里都管用。 最新 Claude 模型会返回 400 错误,应按用途迁移至替代方案。
要点速览
| 主题 | 需要记住的事 |
|---|---|
| 示例的力量与风险 | 最可靠地传递格式、语气和边界,但也会传递偶然模式 |
| 好示例 | 相关性、多样性、结构,格式全部一致,数量靠实验确定 |
| 减少偏差 | 用数字确认 → 多样性表 → 逐项修改 → 检查照抄 |
| 数据分离 | 先划出评估输入,再从剩余输入中选示例 |
| 标签 | 名称一致且有描述性,层级使用嵌套;只标边界,不是安全屏障 |
| 数据字典 | 含义、类型、允许值、缺失规则;区分没有、不适用、无法判断 |
| 结构化输出 | 强制遵循 schema;各供应商约束不同,拒绝和截断属于例外 |
| 四层检查 | 语法 → schema → 业务规则 → 原文核对 |
| 预填充 | Claude 4.6 起返回 400 错误,改用结构化输出、直接指令、标签 |
查阅官方文档
- Anthropic — Prompting best practices:阅读 “Use examples effectively”“Structure prompts with XML tags”“LaTeX output”“Migrating away from prefilled responses” 几节。
- Google — Prompt design strategies:阅读关于 few-shot 示例数量和格式一致性的说明。
- OpenAI — Structured model outputs:确认与 JSON 模式的区别、必填字段和
additionalProperties规则,以及如何处理拒绝。 - Anthropic — Structured outputs:查看
output_config.format、strict 工具、不支持的 schema 功能,以及属性顺序。 - Anthropic — Refusals and fallback:阅读
reasoning_extraction拒绝及正确请求依据的方法。
自测
2-1. 分别举出两个示例“想教的内容”和“可能无意教会的内容”。
2-2. 挑选示例和制作评估集的唯一来源是同一批日志。应怎样安排工作顺序?如果顺序颠倒,会出现什么问题?
2-3. 用标签改写“为下面的活动咨询写回复草稿。下雨时活动移至室内体育馆。咨询:……”,使指令、处理策略和输入彼此分离。
2-4. 同一份销售业绩数据,要输出到(甲)高管汇报界面、(乙)门店广播、(丙)库存系统。分别写出合适格式和一个注意事项。
2-5. 差旅费报销单有一个提取“同行者姓名列表”(字符串数组)的字段。对明确写无同行者、完全未提及是否同行、字迹模糊无法辨认三种情况,分别确定用什么值表示,并说明理由。
2-6. 写出启用结构化输出后,回复仍可能不符合 schema 的两种情况,以及解析前需要检查什么。
2-7. 有三个提示词预先填入了最后一条 assistant 消息,用途分别是(甲)只输出一个标签、(乙)去掉回复开头的问候、(丙)续写被截断的长文。迁移到最新 Claude 模型时,各用什么替代?
实操练习
练习
示例组合对比实验(45 分钟)
- 编写一个把咨询或意见分为三类的提示词。
- 先单独编写 20 个测试输入(含 6 个边界案例)。这 20 个不得用作示例。
- 版本 A 不带示例;版本 B 带 3 个只涵盖一种类型的示例;版本 C 带 4~5 个混合三种类型、边界案例、不同文风和长度的示例。
- 将 20 个测试输入分别用于三个版本,列表记录各版本总答对数、边界案例答对数及输出标签分布。
完成标准: 能从表中确认版本 B 的标签偏向,以及版本 C 的边界案例答对数;如果结果与预期不同,用一行写明原因,即为完成。
练习
设计数据字典与 schema(40 分钟)
- 从收据、申请表、电子邮件中选一种,确定五个待提取字段。
- 用数据字典表写出每个字段的业务含义、类型·单位、允许值、缺失时的值。至少区分没有、不适用、无法判断中的两种。
- 将数据字典转换为 JSON schema。分类字段用
enum,可能没有值的字段允许null。 - 用五个输入获取结果,其中三个缺少部分信息,亲自进行四层检查(语法、schema、业务规则、原文核对)。
完成标准: 五份结果的四层检查都有表格记录,且三个缺信息输入均未出现编造值,即为完成。