逐日AI
第 1 周 · D2约 3 小时

few-shot、思维链、分步与自检;什么时候这些都不管用

四个最常用的提示词技巧各解决什么问题、各有什么代价,以及在什么情况下它们一个都救不了你。

今日目标 0/3

登录后可以勾选并保存进度。

今日目标

  1. 能为一个任务判断该不该给示例,给几个,示例里最容易埋什么坑
  2. 能说清思维链、分步与自检三者的区别,并各写出一段可用的提示词
  3. 能识别提示词技巧失效的三种典型情形,并说出应该换什么手段

昨天我们把一句模糊的需求写成了一张四要素齐全的便签。今天在这张便签上加四种技巧,但重点不在技巧本身——网上讲技巧的文章太多了——而在每种技巧解决什么、花什么代价、什么时候不该用。读完正文、做完实验之后,回到页面顶部把三条目标勾掉。

小白版讲解

少样本示例:给模型看几份做好的活

回到那位只能通过便签沟通的新同事。你想让他按团队规范写周报,有两种办法:一种是写三百字描述规范(「先写本周完成,再写下周计划,每条不超过一行,用动词开头……」),另一种是直接把上周两份写得好的周报钉在便签后面,说「照这个写」。几乎所有人都会选第二种,因为看两份样本比读三百字规范更不容易理解错

少样本示例(few-shot)就是这个办法:在提示词里放几组「输入 → 输出」的例子,再给真正的输入让模型接着写。它有效的原因跟昨天讲的心智模型直接相关——模型在补全文本,示例就是在直接展示「下文该长什么样」,比用文字描述格式和边界规则精确得多。特别是那些用文字说起来很拗口的规则,比如「一条反馈里既有 bug 又有需求时按用户先提到的算」,一个示例就能说清。

代码形态上,示例可以直接写进用户消息,也可以拼成交替的 user / assistant 消息对,让模型以为「之前已经这么答过几次了」:

few-shot.ts
import Anthropic from '@anthropic-ai/sdk'
 
const client = new Anthropic()
 
// 每个示例覆盖一种不同的情况,最后一个是边界样本(混合反馈 → 以先提到的为准)
const examples: Array<[string, string]> = [
  ['登录之后点头像没反应', 'bug'],
  ['能不能加个夜间模式', '需求'],
  ['你们支持导出 PDF 吗', '咨询'],
  ['列表加载很慢,另外希望能按标签筛选', 'bug'],
]
 
// 拼成交替的 user / assistant 消息,模型会把它们当成「之前的对话」
const shots = examples.flatMap(([input, label]) => [
  { role: 'user' as const, content: `反馈:${input}` },
  { role: 'assistant' as const, content: label },
])
 
const res = await client.messages.create({
  model: 'claude-sonnet-5',
  max_tokens: 10,
  system: '把用户反馈分类成「bug」「需求」「咨询」之一,只输出类别名。一条反馈含多类内容时以最先提到的为准。',
  messages: [...shots, { role: 'user', content: '反馈:导出 Excel 标题带逗号会错位,能不能顺便支持 CSV?' }],
})
console.log(res.content[0].type === 'text' ? res.content[0].text : '')

注意第四个示例。前三个只教了「三个类别各长什么样」,第四个才教「混合时怎么办」——它是专门放进去的边界样本。如果你的模型一直在某种边界情况上出错,多半不是示例太少,而是示例里没有那种情况。

示例里的坑:顺序、数量、过拟合与偏见

示例太好用,以至于很多人的第一反应是「多放几个」。但每个示例都有代价,而且不只是费用。

数量。每个示例都占上下文窗口、都要计费,五个示例可能比你的任务描述本身还长。更重要的是,示例的作用是覆盖不同类型的情况,不是堆数量:两个都是「必填字段缺失」的示例,模型学到的是「校验只有这一种」;四个覆盖四类坏输入的示例,才教会它校验有四类。数量由「要覆盖几种情况」决定,通常两到五个。

过拟合。示例给多了,模型会开始模仿示例的表面特征——长度、措辞、甚至标点习惯——而不是它们背后的规则。你给的三个示例输出都恰好是两句话,模型就会倾向于输出两句话,哪怕这个输入需要四句。

偏见。这是最隐蔽的一个。四个分类示例里三个标了 bug,模型就会更倾向判 bug,跟输入内容关系不大。示例的类别分布要大致均衡,或者至少你要知道自己引入了什么倾向。

顺序。多数模型对靠后的示例更敏感,尤其是最后一个。所以把最像目标输入的示例放最后,把边界样本放最后,都是有依据的做法。反过来,如果你发现模型的输出总是「长得像最后一个示例」,那就是顺序在起作用。

还有一条与格式有关的坑,是昨天格式栏的延伸:示例是最强的格式信号,比说明强。你在格式栏写「不要客套话」,示例的输出里却以「好的,下面是我的分析」开头,模型学到的就是要先客套一句。示例的输出部分必须与格式栏逐字一致——段数、代码块数、语言标记——写完先对一遍。

思维链:让它先想再答

新同事算一笔账,你说「直接告诉我结果」,他心算,错了你也看不出来;你说「把每一步算式写在便签背面」,他每写一步都要看着上一步,出错的概率低得多,而且错在哪一眼就能看到。思维链(chain of thought)就是让模型「把算式写在背面」:在提示词里要求它先逐步列出推理过程,最后再给答案。

它为什么有效,跟「补全」这个心智模型又对上了:模型是逐字生成的,写出来的中间结果会成为后面文字的上下文,等于每一步都在给下一步提供校验材料。直接给结论时这些中间结果只在「脑子里」一闪而过,没有机会被检查。

所以它在哪类任务上提升明显,就很清楚了:多步算术、需要排除干扰项的判断、要在几个条件之间权衡的决策。反过来,在单步任务上它几乎没有增益——分类、抽取、格式转换这类「看一眼就知道答案」的活,让模型先写三段分析再给结论,只会更慢、更贵、输出更长,而最后那一步面对的还是同一个判断。

代价要算清楚:输出从一个数字变成七八行,延迟与费用都按输出长度涨。对「错了很难发现」的任务这笔钱值得花,对「错了一眼就看出来」的任务不值得。还有一条容易被忽视的边界:思维链写出来的是「看起来合理的过程」,不是模型真实的内部计算。它可以帮你发现错误,但不能当作「模型确实是这么算的」的证据。

用法上有一个细节:要求它把最终答案放在固定位置、用固定格式,比如「最后单独一行,格式为『答案:X 元』」。否则你的程序要在一大段推理文字里找答案,比解析自由文本更痛苦。近一两年的推理类模型内置了思考过程,多数情况下不用再写「一步步想」,但答案的格式与位置仍然要指定。

分步与自检:拆成几张便签,再让它自己复查

你给新同事一张便签,上面写「审查这段代码、修复所有问题、补上测试、再写份 README」。他会怎么做?前面审查得很仔细,修复也还行,测试开始敷衍,README 三行了事——不是他偷懒,是一张便签的篇幅有限,四件事平分下来每件都不够。模型一模一样:一次回答的长度有上限,塞进去的任务越多,每个任务分到的输出预算越少,结果就是「前面细后面糙」。

分步的解法是拆成四张便签、四次调用:第一次只审查、只输出问题列表;第二次拿着列表只修复严重的;第三次为修改过的每处写测试;第四次写文档。每一步有独立的输出预算、独立的格式要求,而且后一步可以拿前一步的输出当输入——这在一次调用里做不到。它和思维链的区别就在这里:思维链是一次调用内让模型想得更细,输出预算还是同一份;分步是多次调用,预算翻倍,还能传递中间结果。判断口径是「任务是想得不够细,还是一次装不下」。

steps.ts
import Anthropic from '@anthropic-ai/sdk'
 
const client = new Anthropic()
 
async function ask(system: string, user: string): Promise<string> {
  const res = await client.messages.create({
    model: 'claude-sonnet-5',
    max_tokens: 4096,
    system,
    messages: [{ role: 'user', content: user }],
  })
  return res.content[0].type === 'text' ? res.content[0].text : ''
}
 
// 第一步只审查:独立的输出预算,独立的格式
const issues = await ask(
  '你是代码审查员。只输出问题列表,每条「位置:问题:严重程度」,按严重程度降序。不改代码。',
  `审查这段 TODO API:\n${code}`
)
 
// 第二步拿第一步的输出当输入:这是分步与思维链最本质的差别
const fixed = await ask(
  '你是后端工程师。只修复列表中严重程度为高的问题,输出修改后的完整代码,一个代码块,不加解释。',
  `问题列表:\n${issues}\n\n原代码:\n${code}`
)
console.log(fixed)

分步的代价是多次往返的延迟,以及你要在代码里传递上下文。这恰好是 Agent 类工具在自动化的事——把「拆步、传递、决定下一步」交给一个循环去做。今天先手动拆,体会一下每一步的边界在哪。

自检解决的是另一类问题:模型写代码时「顺手编了一个合理的函数名」,写完不会回头看。自检就是把「回头看」写进任务:「写完之后逐个检查测试里引用的每个函数名、变量名、导入路径,确认在给定代码里真实存在;不存在的改掉或删掉并说明」。关键有两点。一是指定检查什么,「检查一下有没有问题」没用,「逐个核对引用是否存在」才有用;二是要求它输出检查结果,比如一个「引用核对」列表,把自检从口头保证变成可验证的产出。自检本身也可能出错,所以真正的兜底还是把测试跑一遍,自检只是把错误率压下来。

什么时候这些都不管用

现在到了这一天最重要、也是几乎没有教程会讲的部分:有些任务,提示词写得再好也做不对。识别它们比学任何技巧都值钱,因为你会省下大量在提示词上反复折腾的时间。失效情形有三种。

缺知识。你问模型「项目里用的校验库这个版本有没有已知漏洞」,它的知识有截止日期,之后披露的漏洞它一个都不知道;你的私有数据、公司内部规范,它也不知道。更糟的是它可能编出一个格式完全正确的漏洞编号——格式越严格,编出来的东西越像真的。判据是一句话:如果这个信息是昨天才出现的,模型有可能知道吗?不可能,就别指望提示词。解法在模型外面:把资料贴进上下文,或者接一个检索系统让它按需查——这是本平台 RAG 专题课的内容。

缺工具。任务需要对外部世界做动作或查询:跑一条命令、查一次数据库、发一个请求、读一个文件。模型只能生成文字,一个「只能打字的人」做不了的事它也做不了。判据就是这句:一个只能打字、不能动手的人能完成这件事吗?不能,就要给模型接工具——让它输出「我要调用哪个工具、参数是什么」,由代码去执行,再把结果还给它。这就是工具调用(tool use),本平台 MCP 专题课专讲这个。

任务本身写错了。需求自相矛盾(「不要改接口、但把响应改成分页」),或者你要的其实是另一件事(说「优化性能」其实想要的是「别超时」)。判据:两个人读这条需求会不会做出相反的事?会,就回去改需求,改提示词没用。

三种情形有一个共同点:解法都不在提示词层面。这也是为什么昨天说提示词工程是「系统性补齐上下文」——当缺的不是上下文而是知识、工具或需求本身时,它就到边界了。评估的时候有个便宜的做法:测试集里故意放几条模型不可能知道的样本,看它是老实说「不知道」还是编一个像样的答案。D4 建测试集时你会用到。

把示例任务的提示词升级一版

回到贯穿全课的任务:给 TODO API 补输入校验和单元测试。昨天的便签已经有四要素,今天用上面的选择顺序过一遍。缺不缺示例?缺——「三段式输出」用文字说清楚了,但模型偶尔还是会在段间加过渡语,两个严格按格式栏写的示例能把这个问题压下去;两个示例要覆盖不同的坏输入类型(比如必填缺失和日期非法),输出部分与格式栏逐字一致。需不需要思维链?不需要——写校验和测试不是多步推理,加了只会让输出变长。一次装不装得下?「补校验 + 写测试」两件事,四类校验加五个测试,一次输出可能贴着上限,但还装得下;如果你发现测试部分开始敷衍,就拆成两步。有没有反复出现的事实性错误?有——测试里偶尔引用不存在的辅助函数,加一条指定检查项的自检,并要求输出引用核对列表。

升级之后的便签比昨天长了一倍,但每一段都对应一个你真的观察到的问题。这是技巧的正确用法:先观察输出错在哪,再选对应的技巧,而不是先把技巧列一遍再往上套。明天我们把便签的格式栏推到极致——让输出变成程序能直接读的结构化数据。

源码导读

动手实验

🧪 D2 实验:五个改写前后对照

代码位置:labs/prompt-engineering-5days/day-02-before-after-rewrites

验收标准:

  1. 五个案例的「改写后」全部填完,每个只用一种主技巧,且「技巧」一栏与改写内容一致。
  2. 每个案例的「为什么选这个技巧」都能回答「换成别的为什么不行」。
  3. 案例五的「失效情形」写的是三种情形之一,并给出了提示词之外的解法。
  4. 两个少样本示例的输出部分与 D1 的格式栏一致,且覆盖不同的坏输入类型。
  5. 随便挑两个案例改写前后各跑一次,改写后至少在一个可核对的点上更好。

今天仍然是文档型实验。打开 labs/prompt-engineering-5days/day-02-before-after-rewrites先不要看 solution

  1. starter/rewrites.md 里五个「改写前」,每个先判断它缺的是示例、推理空间、拆分还是复查,把判断填进「技巧」一栏。
  2. 为每个案例写「改写后」,只用一种主技巧,再写一到两句「换成别的为什么不行」。
  3. 案例五改完后把改写前后都跑一遍,确认它仍然做不对,然后写出它属于哪种失效情形与提示词之外的解法。
  4. 填第二部分:为示例任务补两个少样本示例,写完对着 D1 的格式栏核一遍段数、代码块数与语言标记。
  5. 全部填完再打开 solution/rewrites.md 对照,技巧选得不同不一定错,看理由能不能站住。

面试题

今天 3 道题在下方题库区,分别对应少样本示例的代价、思维链与分步的区别、提示词失效的边界。每道题的「分析过程」都给了一条可复用的判断句,先照着推一遍再看要点。

检查清单与明日预告

  • 能为一个任务判断该不该给示例,给几个,示例里最容易埋什么坑
  • 能说清思维链、分步与自检三者的区别,并各写出一段可用的提示词
  • 能识别提示词技巧失效的三种典型情形,并说出应该换什么手段
  • 五个改写对照的 5 条验收标准全部通过
  • 3 道面试题不看要点也能答出至少 2 道

明天(D3)我们把便签的「格式」栏推到极致:不再让模型输出一段人读的文字,而是输出程序能直接读的结构化数据。你会看到为什么「请输出 JSON」这句话不够用、schema 到底约束了什么、两家 API 的结构化输出开关各有什么限制,以及解析失败时该怎么兜底。D3 也是本课第一个可以跑的实验——一个把需求描述抽成固定字段的脚本,支持离线模拟,没有 API key 也能做。

面试题库

  • few-shot 为什么有效?示例给多了会出什么问题?你怎么决定给几个?Why does few-shot prompting work, what goes wrong when you give too many examples, and how do you decide how many to include?
    国内高频海外高频基础#few-shot#prompt-techniques

    分析过程 · 先想清楚再作答

    1. 这题在筛「有没有把示例当成格式与边界的信号,而不是当成让模型变聪明的魔法」。答成「示例越多模型越懂」会暴露没在生产里调过提示词。
    2. 拆法:先答原理——模型在补全,示例直接展示了「下文该长什么样」,比文字描述格式和边界规则更不容易被误读;示例是最强的格式信号。
    3. 再答代价:每个示例都占上下文与费用;示例过多会让模型过拟合示例的表面特征(长度、措辞、顺序),还会把示例里无意带进去的偏见放大,比如四个示例里三个是 bug,它就更倾向判 bug。
    4. 结论:数量由「要覆盖几种类型」决定而不是越多越好,通常两到五个,每个覆盖一种不同的情况,并且至少一个是边界样本。
    5. 可预期的追问:示例的顺序有影响吗?有,多数模型对最后一个示例更敏感,所以把最像目标输入的放最后;另一个追问是示例和说明冲突时模型听谁的,答案是多半听示例,所以示例必须与格式栏逐字一致。

    How to reason about it · think before answering

    1. The screen is whether you treat examples as signals for format and boundaries rather than as magic that makes the model smarter. 'More examples, better model' reads as untested.
    2. Mechanism first: the model completes text, and examples show the continuation directly, which is harder to misread than prose describing a format or an edge rule. Examples are the strongest format signal.
    3. Then the cost: each example consumes context and money; too many cause overfitting to surface features such as length, wording and order, and amplify accidental bias — three bug examples out of four nudges everything toward bug.
    4. Conclusion: the count follows the number of distinct cases you need to cover, typically two to five, each a different case, with at least one boundary sample.
    5. Follow-ups: does order matter? Yes, models weight the last example more, so place the one closest to the target input last. And if examples contradict the instructions, the model usually follows the examples, so they must match the format spec exactly.

    答题要点

    • 示例直接展示下文该长什么样,比文字描述格式和边界规则更不容易被误读
    • 示例过多的代价:占上下文与费用、过拟合表面特征、放大示例里的类别偏见
    • 数量按「要覆盖几种不同情况」定,通常两到五个,至少一个边界样本
    • 顺序有影响,最像目标输入的放最后;示例与说明冲突时模型多半听示例

    Key points

    • Examples show the continuation directly, which beats prose for conveying format and edge rules
    • Too many examples cost context and money, overfit surface features, and amplify class bias
    • Pick the count by how many distinct cases need coverage, typically two to five with one boundary case
    • Order matters — put the closest match last; when examples and instructions conflict the model follows the examples
  • 思维链在什么任务上提升明显,在什么任务上是浪费?它和「分步」有什么区别?Where does chain-of-thought prompting help most, where is it a waste, and how does it differ from splitting a task into steps?
    国内高频海外高频进阶#chain-of-thought#prompt-techniques

    分析过程 · 先想清楚再作答

    1. 题眼在「浪费」和「区别」。只会说「让模型先思考再回答效果更好」的候选人没有算过账,面试官想听的是你什么时候会主动不用它。
    2. 拆法:思维链的价值来自「中间结果可以校验下一步」,所以它在多步推理、算术、需要排除干扰项的判断上提升明显;在单步判断(分类、抽取、格式转换)上几乎没有增益,只有更慢更贵更长的输出。
    3. 区别:思维链是一次调用内让模型写出中间过程,输出预算还是同一份;分步是拆成多次调用,每步有独立的预算、独立的格式、并且后一步可以拿前一步的输出做输入。任务是「想得不够细」用思维链,任务是「一次装不下」用分步。
    4. 结论:先问任务是否需要多步推理,不需要就不用;需要的话再问一次输出装不装得下,装得下用思维链,装不下拆步。
    5. 追问:推理类模型内置了思考过程,还要写思维链吗?多数情况不用再写「一步步想」,但仍要指定最终答案的格式与位置,否则解析会很痛苦;另一个追问是思维链的内容能不能信,答案是它是「看起来合理的过程」而非真实的内部计算,只能当辅助校验不能当证据。

    How to reason about it · think before answering

    1. The discriminators are 'waste' and 'difference'. Anyone can say thinking first helps; the interviewer wants to hear when you deliberately skip it.
    2. Its value comes from intermediate results checking the next step, so it shines on multi-step reasoning, arithmetic and judgments with distractors; on single-step tasks such as classification, extraction or format conversion it adds latency, cost and length with little gain.
    3. Difference: chain-of-thought keeps everything in one call and one output budget; splitting uses several calls, each with its own budget and format, and later steps can consume earlier outputs. Use CoT when the model thinks too shallowly, split when one answer cannot hold the work.
    4. Conclusion: ask whether the task needs multi-step reasoning at all; if yes, ask whether one output can hold it — CoT if so, split if not.
    5. Follow-ups: with reasoning models that think internally, do you still write 'think step by step'? Usually no, but you still pin the answer format and position. And can you trust the written reasoning? It is a plausible narrative, not the actual computation — use it as a check, not as proof.

    答题要点

    • 思维链的价值是中间结果校验下一步,多步推理与算术上提升明显,单步判断上是浪费
    • 代价是更长的输出、更高的延迟与费用,所以不需要推理的任务要主动不用
    • 与分步的区别:思维链是一次调用内写过程,输出预算不变;分步是多次调用,每步独立预算且可传递输出
    • 推理模型内置思考后一般不必再写「一步步想」,但仍要指定答案格式与位置

    Key points

    • CoT helps because intermediate results check the next step; strong on multi-step reasoning and arithmetic, wasted on single-step judgments
    • Cost is longer output, higher latency and spend, so skip it when no reasoning is needed
    • Versus splitting: CoT stays in one call with one budget; splitting uses multiple calls with independent budgets that can chain outputs
    • With reasoning models you rarely need 'think step by step' but still pin the answer format and location
  • 提示词写得再好也做不对的任务有哪些特征?遇到这类任务你会怎么办?What are the signs of a task that no amount of prompt engineering will fix, and what do you do when you hit one?
    国内高频海外高频进阶#prompt-limits#failure-modes

    分析过程 · 先想清楚再作答

    1. 这题考的是「知道提示词的边界在哪」。一直往提示词上堆技巧的候选人会被判为缺乏判断力;能说出「这题不该用提示词解」才是成熟的信号。
    2. 拆法:把失效分三类。缺知识——信息在模型训练截止之后或本来就在你的私有数据里,模型不可能知道,还可能编出格式正确的假答案;缺工具——任务需要对外部世界做动作或查询(跑命令、查库、发请求),文字生成做不到;任务写错——需求本身自相矛盾或者你要的其实是另一件事。
    3. 每类给一个判据:缺知识问「这信息是昨天才出现的,模型有可能知道吗」;缺工具问「一个只能打字的人能完成这件事吗」;任务写错问「两个人读这个需求会不会得出相反的做法」。
    4. 结论:缺知识就把资料贴进上下文或接检索;缺工具就接工具调用或在代码里做完再让模型解读;任务写错回去改需求。三种都不是提示词层面的解法。
    5. 追问几乎必然是「格式越严格假答案越像真的怎么办」——答案是对事实类输出要求带出处或可验证的标识,并在代码里校验;以及「怎么在评估里提前发现这类任务」,答案是测试集里放几条模型不可能知道的样本,看它是否老实说不知道。

    How to reason about it · think before answering

    1. This tests whether you know where prompting ends. Piling techniques onto a hopeless task signals poor judgment; saying 'this is not a prompting problem' signals maturity.
    2. Three failure classes. Missing knowledge: the fact postdates training or lives in your private data, and the model may fabricate a well-formatted answer. Missing tools: the task needs an action or query against the world. Wrong task: the requirement is contradictory or you actually want something else.
    3. One test each: could the model plausibly know something that appeared yesterday? Could a person who can only type complete this? Would two readers of the requirement do opposite things?
    4. Conclusion: paste the material or add retrieval for missing knowledge; add tool use or compute in code for missing tools; fix the requirement for a wrong task. None of these is a prompt change.
    5. Follow-ups: stricter formats make fabrications look more credible — require sources or verifiable identifiers and validate in code. And to catch these early, seed the test set with a few unknowable items and check that the model admits it does not know.

    答题要点

    • 三类失效:缺知识(截止日期之后或私有数据)、缺工具(需要对外部世界做动作)、任务写错(需求自相矛盾)
    • 缺知识的危险在于模型会编出格式正确的假答案,格式越严越像真的
    • 解法都在提示词之外:贴资料或接检索、接工具调用或代码先算、回去改需求
    • 测试集里放几条模型不可能知道的样本,检查它会不会老实说不知道

    Key points

    • Three failure classes: missing knowledge, missing tools, and a wrongly specified task
    • Missing knowledge is dangerous because the model fabricates well-formatted answers, and stricter formats make them more convincing
    • Fixes live outside the prompt: paste material or add retrieval, add tool use or compute in code, or fix the requirement
    • Seed the test set with unknowable items to check the model admits ignorance

评论

登录后即可参与讨论

还没有评论,来说第一句。