为什么”多写两句提示词”远远不够
很多团队第一次把大模型接入业务系统时,经历都差不多:先写一段自然语言指令,跑几个 case 觉得效果还行,然后正式上线后输出质量开始忽高忽低。你让运营写一份商品描述,模型有时候给你返回 JSON,有时候给你返回一段散文;你让它做合同条款分类,简单类型分得挺准,但一旦遇到”部分违约且涉及第三方担保”这种边界情况,模型就开始”编故事”。
问题的根源不在于模型不够强,而在于提示工程(Prompt Engineering)本身是一种工程能力。你给模型的每一个约束、每一个示例、每一句推理引导,都是在用自然语言写一段”程序”。区别在于,这段程序没有编译器帮你检查语法,没有类型系统帮你约束边界,所有错误都只在运行时暴露。
所以真正要解决的,不是”怎么写出一句好 Prompt”,而是怎么让提示策略从零散的经验变成一套可复用、可测试、可迭代的工程方法。这篇文章会从 Few-shot 和 Chain-of-Thought 两个核心技巧切入,讲清楚它们各自能解决什么问题、在什么场景下会失效,以及实际项目中该怎么组合使用。
从 Zero-shot 到 Few-shot:示例不是越多越好
Zero-shot 的天花板在哪里
Zero-shot 提示是最直接的用法:你给模型一个任务描述,不给任何示例,直接让它输出。对于分类任务、格式化任务、简单摘要这类”输入到输出映射比较明确”的场景,现代大模型在 Zero-shot 模式下通常已经能做到不错的基线效果。
但 Zero-shot 有一个致命弱点:它对输出格式和推理深度的控制力很弱。你告诉模型”请把用户反馈分类为正面、负面或中性”,它可能给你三个选项加一段分析;你告诉它”只输出 JSON”,它可能给你一个 JSON 外面裹着 markdown 代码块。没有示例做锚定,模型的输出分布是不确定的,尤其在输入模式多样化的情况下。
Few-shot 的真正价值:不是教模型”知识”,而是约束”行为”
很多人对 Few-shot 有个误解:以为多给几个示例是在教模型新知识。实际上,大模型在预训练阶段已经见过海量数据,你给的几个示例几乎不可能教会它新的事实。Few-shot 的核心作用是对齐输入输出的映射关系和格式约束——你展示的不是一个知识点,而是一种行为模式。
举个例子,假设你在做一个客服意图分类系统。Zero-shot 你可能这么写:
请对以下用户消息进行意图分类,类别包括:退款咨询、物流查询、产品咨询、投诉、其他。
用户消息:{input}
意图分类:
模型可能在大部分情况下能正确分类,但在边界情况下输出不稳定。而 Few-shot 版本则是这样:
请对以下用户消息进行意图分类,类别包括:退款咨询、物流查询、产品咨询、投诉、其他。
示例:
消息:我昨天买的手机壳还没收到,物流信息也不更新
意图:物流查询
消息:这个充电器用了三天就坏了,你们质量也太差了吧
意图:投诉
消息:想问下你们这款耳机支不支持降噪
意图:产品咨询
消息:麻烦帮我退一下上周的订单,东西收到后发现不合适
意图:退款咨询
用户消息:{input}
意图分类:
这里的关键不是示例本身的内容,而是示例展示了一种输入到输出的映射方式:只输出意图类别,不做额外解释。这种格式锚定效果,是 Zero-shot 很难稳定做到的。
设计 Few-shot 示例的三条原则
在实际项目中,示例的设计比数量重要得多。以下几条原则是从踩坑中总结出来的:
- 示例要覆盖困难 case,而不是只放简单 case。如果你只放明显能分对的示例,模型学不到边界判断。真正有价值的是那些”看起来像 A 实际上是 B”的样本——比如”这个充电器用了三天就坏了”表面是产品咨询,实际应该归为投诉。
- 示例之间要保持格式一致。输入的长度、输出的长度、字段顺序,都要尽量统一。如果第一个示例输出是单词,第二个示例输出是带解释的句子,模型会困惑到底该跟哪个模式。
- 控制示例数量在 3-8 个之间。超过 8 个示例,边际收益急剧下降,同时 Token 消耗和推理延迟线性上升。如果你的任务复杂到需要 20 个示例才能稳定,那说明这个任务可能不适合纯 Prompt 驱动,应该考虑微调。
有一个在团队中反复出现的场景很能说明问题:做舆情分析时,标注团队花了很大精力准备了 15 个 Few-shot 示例,结果在测试集上的准确率跟 5 个示例几乎一样,反而因为上下文太长,模型开始出现”前部示例干扰后部判断”的现象——后面的分类结果被前面的示例内容带偏了。后来精简到 6 个高质量示例,效果反而更稳定。
Chain-of-Thought:让模型”展算过程”而不是”猜答案”
直接输出结果的致命问题
当你让模型处理一个需要多步推理的任务时——比如一道数学应用题、一个条件复杂的风控判断、一个需要查多张表的 SQL 组合查询——直接让它给出最终答案,模型的错误率会显著上升。这不是因为模型”不会算”,而是因为 Transformer 的自回归生成机制决定了:模型生成下一个 Token 时,它”看到的”只有前面已经生成的 Token。如果直接跳到答案,中间的推理步骤就完全不存在于模型的”工作记忆”里。
Chain-of-Thought(CoT)的核心思想很简单:强制模型先输出推理过程,再输出最终结论。这相当于给模型提供了一个”草稿纸”——它可以一边写推理过程,一边利用自己生成的内容作为后续推理的上下文。
最早验证 CoT 效果的论文用的是 Few-shot CoT:在示例中展示完整的推理链,让模型学会”先推理再结论”的模式。比如:
问题:小明有 12 个苹果,给了小红 4 个,又从妈妈那里得到 7 个,现在小明有几个苹果?
推理:小明一开始有 12 个苹果。给了小红 4 个后,剩下 12 - 4 = 8 个。又从妈妈那里得到 7 个,所以现在有 8 + 7 = 15 个。
答案:15
模型看到这个示例后,会在处理新问题时也遵循”先推理再结论”的模式。这种引导的效果在多步推理任务上非常明显——GSM8K 数学推理基准上,Few-shot CoT 相比直接 Few-shot 的准确率提升通常在 10-20 个百分点以上。
Zero-shot CoT:一句话带来的巨大提升
后来研究者发现一个更简单的做法:你甚至不需要给推理示例,只需要在指令末尾加一句 “Let’s think step by step”(中文可以写”请一步一步地思考”),就能在不少任务上触发模型的推理链能力。这就是 Zero-shot CoT。
这个发现的意义不在于”一句话能提升效果”——而在于它揭示了一个事实:大模型本身具备多步推理能力,很多时候只是没有被正确激活。模型知道怎么推理,但默认的生成策略倾向于直接给出答案。CoT 提示做的,是把这条”推理路径”从模型的隐含能力变成显式输出。
不过 Zero-shot CoT 也有明显的局限。在任务定义模糊或者推理路径有多种可能的情况下,模型自己选的推理方向未必正确。Few-shot CoT 通过示例对推理路径做了示范,稳定性通常更高,但代价是 Token 消耗更大、提示词维护更复杂。
| 策略 | 适用任务类型 | 效果稳定性 | Token 成本 | 维护复杂度 |
|---|---|---|---|---|
| Zero-shot | 简单分类、格式化 | 中 | 低 | 低 |
| Few-shot | 格式约束、模式匹配 | 高 | 中 | 中 |
| Zero-shot CoT | 中等推理复杂度 | 中 | 低-中 | 低 |
| Few-shot CoT | 多步推理、复杂判断 | 高 | 高 | 高 |
| Self-Consistency | 高精度推理需求 | 很高 | 很高 | 高 |
Self-Consistency:用”多路投票”对抗推理路径的不确定性
CoT 的一个隐藏问题是:模型每次生成的推理链不一定相同,有些推理路径是对的,有些在中间步骤就走偏了。Self-Consistency 策略的核心思路是:让模型对同一个问题生成多条不同的推理链(通过设置较高的 temperature),然后对最终答案做多数投票,取出现频次最高的结果。
这听起来粗暴,但在数学推理、逻辑判断等”最终答案有唯一性”的任务上效果出奇地好。一个典型场景:在做保险条款适用性判断时,单条 CoT 推理的准确率大约 78%,而用 Self-Consistency 生成 5 条推理链后投票,准确率能提升到 88% 左右。代价是推理成本翻了 5 倍——所以这个策略更适合离线批量处理或者对准确率要求极高的场景,不适合实时对话。
这里有一个容易被忽视的实践细节:Self-Consistency 要求你对”答案”有清晰的定义。如果任务输出的是一段自由文本,你很难做投票。它最适合的是最终答案可以枚举的任务——选择题、数值计算、分类标签。如果你的任务输出是一段长文,可以考虑将推理过程和最终结论分离,只对结论部分做投票。
实际项目中最容易踩的坑
坑一:CoT 用在不该用的地方
不是所有任务都能从 CoT 中受益。对于简单分类、短文本摘要、关键词提取这类”直觉式”任务,强制模型输出推理过程反而可能引入噪声。一个常见的错误是:在情感分类任务里加”请一步一步思考”,结果模型开始对一些明显是正面的文本做过度分析,反而把情感判断搞复杂了。
判断一个任务是否需要 CoT,有一个简单的经验法则:如果这个任务人类专家也需要几秒钟的中间思考才能回答,那大概率需要 CoT;如果人类专家一眼就能判断,那 CoT 可能是多余甚至有害的。
坑二:Few-shot 示例和测试集分布不一致
这是工程实践中最隐蔽的问题。你在开发阶段用了一批示例,测试集也来自类似分布,效果很好。但线上真实数据的分布跟你的示例不一致——比如你给的示例都是短文本输入,线上来了一条 500 字的长文本,模型的行为就会偏离预期。
解决这个问题的方法不是”多放示例覆盖所有情况”,而是要定期监控线上输入分布的变化,并且维护一批从真实流量中采样的示例(脱敏后)作为 Few-shot 候选库。当发现某类输入效果下降时,针对性地补充这类型的示例。
坑三:忽略了推理链的 Token 成本
CoT 会显著增加输出 Token 数量。一个直接给出答案可能只需要 10 Token 的任务,加上推理链后可能输出 200-500 Token。如果你用的是按 Token 计费的 API,而且任务量大,这个成本差异非常可观。
更隐蔽的问题是延迟:输出 Token 多了,首 Token 延迟和总延迟都会增加。对于实时性要求高的交互场景(比如客服对话),过长的推理链会让用户等太久。一个实用的折中方案是:在提示词中要求模型”用简洁的推理过程”,控制推理链的长度,在效果和延迟之间找平衡。
落地建议:从需求出发选择策略
聊了这么多技巧,回到一个实际的问题:如果你团队现在要上线一个 LLM 驱动的功能,该怎么选择提示策略?我的建议是按任务的”推理深度”和”输出确定性”两个维度来判断。
- 简单分类 / 格式化任务:Zero-shot 起步,用结构化输出约束(JSON Schema 或 Function Calling)。如果格式不稳定,加 3-5 个 Few-shot 示例做锚定。不需要 CoT。
- 中等复杂度的判断任务(如意图识别中需要结合上下文推断):Few-shot + Zero-shot CoT。”请一步步分析”这句引导足够,不需要给完整推理链示例。
- 多步推理任务(如数据分析、合同条款匹配、数学计算):Few-shot CoT。示例中要展示完整的推理过程,推理链的粒度和深度直接影响效果。
- 高精度要求的关键决策(如风控审批、医疗辅助判断):Few-shot CoT + Self-Consistency。接受更高的推理成本,换取更可靠的决策。同时要配合人工审核兜底。
还有一个实践中很重要的认知:提示工程不是一次性的工作,而是一个持续优化的过程。好的做法是建立一套评估集(20-50 条覆盖典型 case 的输入输出对),每次修改提示词都跑一遍,量化评估效果变化。没有评估集的提示词优化,本质上是在碰运气——你改了一句提示词,在某个 case 上变好了,同时在另一个 case 上变差了,但你根本不知道。
最后说一句:Few-shot 和 CoT 都不是银弹。当你的任务复杂到需要超过 10 个示例才能稳定,或者 CoT 推理链长到模型开始”跑题”,那大概率意味着这个任务应该走微调路线,而不是继续在 Prompt 层面做文章。提示工程的适用边界是明确的——它在任务理解、格式约束和推理引导上很有价值,但它替代不了领域知识的深度注入和模型行为的系统性校准。理解这一点,才能避免在 Prompt 层面做无效的过度投入。
原创文章,作者:,如若转载,请注明出处:https://fudengji.cn/article/293/