大模型提示词工程:从提示词到提示词系统

9 阅读38分钟

学提示词工程,最常见的路径是:读一篇文章 → 记下"要清晰、要给示例、要 CoT" → 照着写几个 Prompt → 发现效果忽好忽坏 → 不知道为什么。

问题出在这套知识是零散的口诀,缺少支撑它们的心智模型。口诀只能让你在"见过一模一样的场景"时生效,遇到新场景就只能重新摸索。

  1. 每一条技巧都追问"为什么有效"和"什么时候失效"。  一条只在特定条件下成立的技巧,学会了反而会在别的场景误导你。
  1. 把提示词当作工程资产,而不是咒语。  提示词有版本、有测试用例、有回归、有成本账单、有失效模式。文档第 7 章给出一套完整的迭代方法论,第 10 章列出 18 条真实项目里踩过的反模式。

请带着一个判断标准阅读:任何一条技巧,如果我换到另一个场景它还成立,那它大概率是废话(比如"要清晰");如果它有明确的适用边界和代价,那它才是知识。


目录


第 1 章 认知基础:模型到底在做什么

1.1 从"对话"到"条件概率生成"

大语言模型在技术上做的是一件极其朴素的事:根据上文,预测下一个 token 的概率分布,采样一个,写进上文,再预测下一个。

整个循环重复到模型输出结束符。这个事实看似平淡,但它直接决定了提示词工程的所有本质:

结论 1:模型没有"意图理解",只有"上下文条件下的模式补全"。

这解释了两个常见现象:

现象本质原因
同一句话,模型有时理解、有时误解概率采样有随机性,同一条件下的分布不是确定的尖峰
换个说法,答案就变了措辞改变了 token 序列,进入了概率空间的不同区域
模型"知道"很多你不知道的东西预训练语料里的统计模式被激活了,不是它"查"到了什么

结论 2:模型无法访问你的意图,只能访问你写下的文本。

你说"写得好一点",模型无法知道你心里的"好"是什么。它只能从你的措辞、示例、格式约束里推断你的标准。这就是为什么提示词工程的本质是:把隐性的、存在于你脑子里的标准,显性地编码进上下文。

结论 3:越靠前的 token 影响越大。

自回归生成是串行的,早期 token 一旦确定,后续所有 token 都在这个条件下生成。这就是 CoT(让模型先写推理过程再写答案)有效的根本原因——如果答案先生成,后面再补充推理,推理对答案没有任何约束力。

这句话在下文会反复出现,它是整份文档里最重要的一条工程直觉。

1.2 提示词的边界:它不是万能药

必须先破除三个幻觉,否则后面的技巧都会被误用。

幻觉一:"提示词写得够好,就能替代模型能力"

不能。提示词是条件,模型能力是上限。再完美的提示词也无法让一个 8B 模型做出 GPT-4 级别的复杂推理。

正确的判断顺序:

先选模型 → 再调提示词 → 最后才考虑换模型。

大多数团队的问题恰恰相反:提示词调了 20 版效果还是不好,然后才想起"是不是模型不够强"。

幻觉二:"提示词越长越好"

不是。上下文中的每一条指令都在做三件事:提供信息、消耗注意力、可能引入冲突。

实测中普遍存在的情况是:

  • 指令超过 30 条后,模型对中间部分指令的遵循率显著下降(lost in the middle 现象);
  • 20 万 token 上下文的模型,在检索中间位置信息时的准确率明显低于首尾两端;
  • 大量冗长的"你要专业、要严谨、不要幻觉"式套话,稀释了真正有约束力的指令。

结论:提示词应当是"刚好够用的最短文本"。   每加一条指令,都要能回答"删掉它会怎样"。回答不上来,就删掉。

幻觉三:"有了提示词就不用工具了"

不能。模型的能力边界是硬约束:

任务类型模型的真实能力正确做法
记住 2024 年的实时股价❌ 训练截止后不可知调行情 API
精确计算 12345.67 × 89.12❌ 浮点运算会错用 Python 工具算
回答"这份 200 页 PDF 第 47 页写了什么"❌ 没见过这份文档用检索工具喂进去
判断"这段代码有没有 SQL 注入"⚠️ 能看但不可靠代码扫描 + 模型复核
从 5000 条评论里做情感聚类⚠️ 单条还行,整体不稳分批 + 代码聚合

提示词工程的正确目标是:把模型放在它最强的地方,并让它清楚地知道自己不擅长什么。


第 2 章 提示词六要素模型

这是本文档的核心框架。任何一条提示词,都可以拆成六个槽位。检查提示词质量,本质上就是检查这六个槽位是否填满、是否冲突。

2.1 逐要素拆解

ROLE —— 角色

作用:通过指定领域身份,激活模型预训练中对应领域的知识分布和表达风格。

为什么有效:预训练语料里,"资深审计师"这个词后面跟着的话语,和"大一学生"后面跟着的话语,在统计上是两套不同的分布。角色设定本质上是在用检索的方式选择先验。

写法要点:

  • 角色要和任务真正相关。"你是世界冠军"对写代码没有帮助,"你是资深 Python 并发工程师"有。
  • 角色要连带标准,而不只是头衔。你是一个资深数据分析师 不如 你是一个严谨的数据分析师,擅长从混杂的业务日志中提取可复现的指标口径,遇到口径不明的数据会明确标注假设。
  • 角色不宜叠加过多。你既是产品经理又是法务又是财务总监通常导致输出风格混乱。

反例 → 正例:

注意正例的最后一句——它定义了模型在信息不足时的行为,这比头衔本身有价值得多。

TASK —— 任务

作用:定义要执行的动作和期望产物。

写法要点:动词要具体。"分析"太模糊,"对比 A 和 B 在三个维度上的差异并给出推荐"才可执行。

高频错误:任务描述里混入了不必要的过程要求。模型会照做,然后做得很慢、还很贵。

后者更快、更准、更便宜。  "给模型思考的时间"不等于"让模型表演思考的过程"  ,两者的区别在第 3.4 节展开。

CONTEXT —— 上下文

作用:提供做判断所需的输入材料:数据、文档、背景事实、历史对话。

关键原则:上下文是引用,不是搬运。

模型的知识截止到某个时间点,且不掌握任何私有数据。你在提示词里塞进去的材料,模型只能在这个上下文窗口里"看到"。

分隔符是必需的。用明确标记把"指令区"和"数据区"分开,能显著降低模型把数据当指令执行的概率:

关于分隔符的选择,推荐顺序:XML 风格标签 > 三引号 > Markdown 代码块 > 自然语言描述。

原因是 XML 标签在训练语料中与"结构化上下文"的关联度更高,且标签名本身承载语义(<document> vs <query>提示了不同角色)。

反例 → 正例:

CONSTRAINT —— 约束

作用:划定行为边界。既包括"不能做什么"(安全红线),也包括"必须怎么做"(流程约束)。

关键方法:把约束写成可判定的规则,而不是形容词。

差别在于:第一种表述下,"严谨"是否达成,模型自己说了算,你无法验收;第二种可以写成自动化断言直接测。

约束的优先级技巧:把最重要的约束放在最后。模型对接近结束位置的指令遵循度更高(recency 效应)。

CONTRACT —— 输出契约

作用:规定输出的结构、格式、长度、字段。这是工程可用的关键——格式不稳定,下游代码就写不出来。

写法要点:

  • 给格式骨架,不要只给格式名。说"用 JSON"不如直接给出 JSON 的样子。
  • 字段名用业务语义命名。score 比 s 好。
  • 明确"不要输出什么"。很多 JSON 解析失败的根因是模型在 JSON 前后加了解释性文字。
  • 长度约束优先用结构约束(几段、几个要点、几个字段)而非字数,"不超过 300 字"经常被无视,"分 3 点,每点不超过 2 句"有效得多。

EXAMPLE —— 示例

作用:用最少的 token 传递最精确的意图。这是六要素里性价比最高的一个。

为什么有效:示例不是"说明",是"分布采样"。一个示例同时向模型传达了格式、粒度、语气、边界情况——这些用文字描述需要几百 token,一个示例只需要几十 token。

写法要点:

  • 示例必须覆盖边界情况,不能只给最简单的那个。只给正例,模型学不会遇到异常输入时该怎么办。
  • 示例必须严格一致。示例里的格式、字段顺序、语气必须和正文要求一致,否则模型会在两者间摇摆。
  • 示例要贴近真实输入分布。示例用电影评论,任务却是金融公告,学到的映射是错的。
  • 2-5 个通常够用。示例的边际收益递减,且会线性消耗 token。

反例 → 正例:

差别不在"给了示例",而在示例把格式完整地钉死了——包括那个看起来很随意的"4星"写法(没有空格)。模型会连这种细节一起学。

2.2 六要素速查表

要素一句话作用最常见的缺失自检问题
ROLE选择先验只给头衔不给标准角色有没有附带判断标准?
TASK定义动作动词模糊产物是什么,能直接拿来用吗?
CONTEXT提供依据指令与数据混在一起有分隔符吗?
CONSTRAINT划定边界形容词而非可判定规则能写成单元测试吗?
CONTRACT固定结构只说"用 JSON"给了骨架吗?
EXAMPLE钉死意图只给正例、格式不一致覆盖边界情况了吗?

第 3 章 六大核心技巧

本章的六条原则来自 OpenAI 官方 Prompt Engineering 指南,但每一节都补上了原理、边界与失效场景——这部分是官方文档不提供的,也是真正区分"会用"和"会教"的地方。

3.1 写清晰的指令

原则:任何 Prompt 技巧,都不如把你的需求说清楚更有效。

这句话本身是废话级别的真理,但它的操作化版本有内容:

操作化:五问法

写完提示词后,用这五个问题过一遍:

  1. Who —— 期望模型以什么身份、什么标准判断?
  1. What —— 具体要产出什么?
  1. Why —— 产出会被用在什么场景?(这决定了详略取舍和取舍优先级)
  1. How —— 输出成什么形状?
  1. Constraint —— 什么不能做,什么必须做?

案例:同一个需求,三种清晰度

需求:做一份改善久坐腰部的健身计划。

版本 A(最宽泛)  :

模型的回答:一份适合 10-12 岁小学生的趣味健身计划,提到"家长/老师必看"、避免负重、用矿泉水瓶代替哑铃、亲子平板支撑比赛……

这个回答为什么"错"?   它没有错,它在补全你没说的东西。你没说年龄、身高、体重、训练条件、目标,它只能猜——而它猜了一个统计上最常见的"健身计划"原型(面向儿童,因为这个话题在语料里高频)。

这就是幻觉的真正来源:不是模型在编造事实,而是模型在填补你留下的空白,并把填补结果说得跟确定事实一样。

版本 B(给了细节,但没定结构)  :

模型的回答:一份结构完整、考虑周内分布、包含动作组数次数、附带饮食建议的专业计划。基本可用。

它比版本 A 好太多,因为模型终于不用猜了。但仍有三个残留问题:

  • 三个阶段的具体内容被省略成"……"(输出长度失控);
  • 饮食建议只给了一句话,没有落到"每天吃什么";
  • 没有明确饮食建议是按你的实际三餐写,还是给通用食谱。

版本 C(完整六要素)  :

这个版本的关键改进:

  • 禁止动作(不做负重深蹲硬拉)比要求动作更重要——约束模型比指导模型更有效;
  • 量化约束(120g 蛋白质、90 分钟上限)把主观目标变成了可核对的目标;
  • 示例行消除了"输出多详细"的歧义,比任何形容词都有效;
  • 表格列定义固定了结构,下游可直接解析。

本节要点:清晰不是"写得多",是"把模型必须猜的地方全部消灭掉"。写完提示词后自问:模型在哪些地方不得不猜?那些地方我是不是应该替它决定?

3.2 用文本参考(Grounding)

原则:基于文档内容回答问题,可以降低模型幻觉。

这是 RAG(检索增强生成)的提示词层原型。没有检索环节时,你手动把材料塞进上下文,效果就已经很像 RAG 了。

基本模板

关键:区分"有依据"和"没依据"

第 3 条约束是整段提示词里价值最高的一句。没有它,模型会在资料不足时自动用预训练知识补全,而且补得理直气壮——这正是幻觉最常见的形态。

对比一下:

问题模型行为
"2024 年 NVIDIA 的营收是多少?"(无参考)用训练数据里的数字,可能是几年前的,且不加限定
同上,但有 <context> 且要求引用老实说"根据提供的资料无法回答",或者引用资料里确实有的数字

原理:模型始终倾向于生成"流畅的答案"。要求引用片段,等于把流畅性约束在"必须有出处"上,从而压过了补全倾向。

进阶:把参考资料和用户输入也分开

分开之后,模型更容易判断"我是该去资料里找答案,还是该直接回应诉求"。

3.3 把复杂任务拆成简单子任务

原则:复杂任务拆解为简单子任务,模型表现会明显提升。

为什么有效

两个原因,都很实在:

  1. 单次生成的错误累积率随长度上升。   生成 3000 字时,每个 token 的出错概率累积起来是显著的;拆成 5 个 600 字的步骤,每步的错误率独立,总体验更好。
  1. 中间产物可检查。   一次性生成的错误藏在第 800 字里,你很难发现;分步生成的错误出现在"第一步的输出",一眼就能看出。

案例:市场推广方案

一次性提问:模型给出一份看起来很完整、但关键数字前后矛盾的方案(预算总额一处写 50 万,分配明细加起来 40 万,标注的占比又对不上 50 万)。

分四步提问:

分步之后,模型输出的结构、数据的内在一致性、风险识别的针对性都显著提升。

注意事项:拆分的代价

拆分会增加调用次数、延迟和总 token 消耗。经验值:

任务复杂度建议步骤数说明
单轮分类、抽取、改写1拆分纯属浪费
多段生成(报告、方案)3-5收益明显
需要多轮校验修正5-8每轮应有明确验收标准
需要外部工具交互视工具调用次数每次工具调用通常就是一次往返

每一步都应该能独立验收。   如果第二步你无法判断它对不对,那拆分就没有意义,只是把一次失败变成两次失败。

3.4 给模型"思考"的时间

原则:在问题后追加"让我们一步步思考",可以提升复杂推理的准确率。

这是 Chain-of-Thought(CoT)。它有效的原因在第 1.1 节已经说了:自回归生成是串行的,答案先生成,后续推理就约束不了它。

现象对比

任务:小明买铅笔,每支 2 元,有 20 元,最多买几支?

模型的能力没有变化,变的是输出顺序。让模型先写推理,就把"答案"从"凭空生成"变成了"推理的求值结果"。

CoT 的三种形态

形态做法适用
Zero-shot CoT加一句"让我们一步步思考"通用推理题,无需示例
Few-shot CoT示例中带完整推理过程需要特定推理格式/领域方法
自洽性(Self-Consistency)采样多条推理路径,投票选答案高准确率要求,接受成本翻倍

失效场景(重要)

CoT 不是"让模型更聪明"的魔法,它有明确的代价和边界:

代价一:Token 成本显著上升。   推理过程本身要输出。简单任务用 CoT 是纯浪费。

代价二:对"答案本身就是过程"的任务没有帮助。   比如做情感分类、实体抽取——模型的内部计算不需要外显。

代价三:会放大幻觉,而非减少。

⚠️ 反直觉但重要:要求模型"展示推理过程",会让它更容易编造看似合理的推理来支撑一个错误答案。一个"错的答案 + 通的逻辑",比一个孤零零的错答案更难被发现。

这就是为什么 CoT 应该配合"先给结论、再给依据"的校验型输出,或者配合外部验证工具。让模型自己给自己作证,证据强度是打折的。

何时该用 CoT:

  • 数学、逻辑、多步计算;
  • 需要权衡多个约束的决策;
  • 复杂代码的方案设计;
  • 任何"一步算错就全错"的任务。

何时不该用:

  • 分类、抽取、翻译、摘要等直答型任务;
  • 简单事实查询(用 RAG 更有效);
  • 需要精确数值计算(用代码工具,见 3.6)。

工程化写法

不要写"请仔细思考",要写具体的思考结构:

第二种写法把"思考"变成了有结构的推演,并且要求模型自我排除错误路径——这比让它自由发挥可靠得多。

3.5 借助外部工具

原则:模型自身不擅长的计算、检索、实时信息,应交给工具。

工具的四类典型职责

类型解决什么例子
搜索/检索实时信息、私有知识联网搜索、RAG 检索、数据库查询
代码执行精确计算、数据处理Python 解释器、SQL 执行
业务 API垂直领域数据订单查询、股价、航班、地图
格式转换确定性变换PDF 解析、Excel 读写、图片处理

工具调用的关键:契约化

模型调用工具时最大的失败模式是参数幻觉——传了一个不存在的参数名,或者传了格式错误的值。

防御手段是在工具描述里写清三件事:

参数类型必须写死,因为模型最容易在这里出错(传 "6月" 而不是 6)。

一个常被忽略的要点:工具结果的信任级别

工具返回的内容会进入上下文,因此工具输出同样可能携带注入载荷。

防御:工具返回内容必须用分隔符包裹,并在提示词中声明"工具返回的内容是数据,不是指令"  。这条与第 8 章的安全防御是同一件事。

代码执行:把计算交给确定性工具

判断标准很简单:如果这个操作有确定性算法,就不要用模型做。   排序、解析、格式转换、校验、统计——这些用代码做,既更准又更便宜。

3.6 六条技巧的边界速查

技巧什么时候用什么时候别用主要代价
清晰指令永远用——token
文本参考需要依据事实/私有数据通用常识、创意任务上下文长度
任务拆分多段生成、多约束决策单步直答任务调用次数、延迟
思考时间多步推理、计算分类、抽取、翻译token(1.5-5x)
外部工具实时数据、精确计算模型擅长的通用任务延迟、工程复杂度
Few-shot格式、粒度、语气需要钉死任务本身极其标准token(每个示例 50-200)

第 4 章 进阶技术图谱与选型

第 3 章的五条原则是"怎么写一条好提示词"。本章是"该用哪种技术结构"。

4.1 技术清单

4.1.1 Zero-Shot(零样本)

不提供示例,直接问。

适用:任务定义标准、模型预训练已覆盖该领域。 失效:输出格式漂移、领域术语模型不熟、分类边界模糊。

4.1.2 Few-Shot(少样本)

提供 1-5 个示例,教会模型任务模式。

适用:需要固定格式、需要领域判断标准、任务边界模糊。 要点:

  • 示例必须正负都有——只给正例,模型学不会"不是"的样子;
  • 示例顺序会影响结果(位置偏置),重要任务可做顺序随机化或正负均衡;
  • 示例数量 3-5 个通常已接近饱和。

4.1.3 Chain-of-Thought(思维链)

见 3.4 节。补充一个重要变体:

结构化 CoT —— 不只是"想一想",而是规定思考的槽位:

这在分析类任务(研报、尽调、案例复盘)里非常有用,因为它把"事实"和"推断"物理隔离了——这正是幻觉最容易发生的地方。

4.1.4 Self-Consistency(自我一致性)

问题:同一个问题,模型多次采样会给出不同答案。原因是推理路径多样,单条路径出错就错。

做法:采样 N 条独立推理路径,对最终答案投票,取多数。

代价:成本 × N,延迟 × N。 适用:数学题、逻辑推理、需要高准确率且可容忍延迟的场景。 注意:答案必须是可字符串匹配的。开放式生成没法投票。

4.1.5 Prompt Chaining(链式提示)

把任务拆成有向无环的多个步骤,前一步输出是后一步输入。第 3.3 节的工程化形态。

优势:每步可独立评估、可独立重试、可缓存复用。 进阶形态:加入门控(gate)  判断上一步质量是否达标,不达标则回退重试:

这让链条从"流水线"升级成"带反馈的闭环",可靠性显著提升。

4.1.6 ReAct(推理 + 行动)

由 Yao 等人于 2022 年提出,把推理和工具调用交替进行。

循环:思考 → 行动 → 观察 → 再思考 → …… → 最终答案。

适用:需要外部信息、需要多步探索、需要根据中间结果调整策略。 代价:循环可能不收敛;每轮都是一次完整调用,成本高。

工程要点(这几条决定 ReAct 是否稳定):

  1. 必须设最大迭代次数,超限要返回明确失败而非无限循环;
  1. Action 必须从白名单选择,解析到白名单外的动作要报错重试;
  1. 必须解析失败要能自愈——把错误作为 Observation 回灌,让模型自己修正;
  1. 工具返回必须有超时和错误处理,一个挂死的工具会拖垮整个循环。

4.2 选型决策树

选型速查表

场景推荐技术理由
意图分类Zero-Shot + 固定标签任务标准,无需示例
意图分类(边界模糊)Few-Shot(3-5 例,正负均衡)教边界
实体抽取Few-Shot + JSON 契约格式与字段需钉死
格式转换Few-Shot(给 1 个完整示例)格式模仿效率最高
复杂计算代码工具 > CoT确定性优先
多段报告生成Prompt Chaining可分段验收
高准确率推理Self-Consistency用成本换准确率
需查实时信息检索 + ReAct动态探索
单步抽取任务上 ReAct❌ 不用严重"用力过猛",成本翻倍无收益

最后一条尤其重要。   用高级技术处理简单任务,是提示词工程最常见的浪费。判断标准:这个任务上,模型出错的概率有多大?   抽取人名这种任务,现代模型的错误率已经很低,上 ReAct 只会增加 token 和失败点。


第 5 章 消息角色与多轮对话工程

5.1 三个角色的职责边界

角色定位持续性典型内容
system全局规则与人格整个会话角色设定、安全规则、输出契约、流程
user本次请求单条问题、材料、临时约束、纠正指令
assistant模型输出历史答案、中间推理(作为 few-shot 演示时)

优先级:这是个近似规律,不是硬规则

为什么 user 能压过 system?   因为对话就是一条 token 序列,最新的 user 消息在位置上离生成点最近。

但这不可靠。   不同模型、不同厂商、不同安全层级的实现差异很大:

  • Claude 系列对 system 的权重明显更高,遵循长期指令更稳定;
  • 部分模型会做 "recency bias" 修正,但强度不一;
  • 开了思维链(thinking)的模型,system 遵循度通常更好。

工程结论:不要把 system 当成不可侵犯的宪法。   真正需要强约束的场景(安全红线、格式契约),必须在输出层做校验和拦截,不能只靠提示词。

system 该放什么、user 该放什么

放 system:

  • 角色与专业标准
  • 安全与合规边界
  • 长期有效的输出格式契约
  • 需要多轮保持一致的流程规则

放 user:

  • 本次的具体任务和材料
  • 一次性约束("这次用英文")
  • 对上一轮输出的纠正("太啰嗦了,重写")

判断标准:这条约束在 10 轮之后还成立吗?   成立 → system;只是这一轮 → user。

5.2 上下文窗口管理

模型没有记忆。所谓的"多轮对话",是把历史消息重新拼回去。

窗口是有限资源,四个必须监控的量:

指标说明超限后果
输入 token 数每次请求的总量报错 / 成本飙升
输出 token 数单次生成上限回答被截断
上下文窗口输入 + 输出超出直接报错
缓存命中率相同前缀是否复用成本成倍上升

三种应对策略

策略一:滚动摘要(Rolling Summary)

当历史超过阈值,把最早的对话压缩成摘要,保留最近 N 轮原文。

代价与风险:摘要本身是有损压缩,可能丢掉关键约束。摘要必须在 system 里明确标注,并且不能丢失安全约束和硬性格式要求——建议把这两类内容始终放在独立的 system 消息里,不参与摘要。

策略二:上下文裁剪(只取相关)

多轮对话中,大部分历史轮次对当前问题其实无关。用检索/关键词筛出相关轮次再送入。

策略三:外部化(把状态存到外部)

对话状态(用户画像、已收集的字段、任务进度)存到数据库/文件,每次请求只注入当前需要的部分。这是生产系统的主流做法。

成本优化:Prompt Caching

大模型的输入是按 token 计费的,且相同前缀通常可以命中缓存(价格显著更低)。

工程含义:

前缀稳定性是缓存收益的前提。   哪怕只是把 system prompt 里的时间戳从开头移到最后,命中率就会归零。


第 6 章 输出契约与工程化实现

这一章把前面所有理念落到可运行的工程代码上。

6.1 生产级调用封装

不要在业务代码里散落 client.chat.completions.create。建一个统一客户端,把重试、超时、token 统计、结构化输出校验、错误分类全收进去。

这段代码里值得注意的三个设计:

  1. 区分可重试与不可重试错误。鉴权失败重试 3 次只是浪费时间和钱。
  1. 输出校验失败也触发重试,并且把失败原因回灌给模型。这是"自愈"的低成本实现——比让模型一次就对要划算得多。
  1. max_retries=0 传给 SDK,自己接管重试。因为 SDK 的默认重试不区分错误类型,也无法在重试时修改 prompt。

6.2 结构化输出:三层防线

让模型输出 JSON,稳定性从低到高有三种做法:

第一层:提示词约束(最弱,但零成本)

已知问题:模型可能输出 json ... 包裹、可能前后带解释、可能字段名幻觉。

第二层:API 级结构化输出

改进:消除代码块包裹和前后解释的问题。

更进一步,部分模型支持 JSON Schema 约束:

注意:不同厂商/模型对 json_schema 的支持程度不同,使用前确认当前模型是否支持;不支持时降级到 json_object + 校验器。

第三层:解析 + 校验 + 修复(最稳)

无论前面哪层,都必须过一遍解析和业务校验:

这一层不能省。   因为业务语义的错误,JSON Schema 抓不到——age: 999 是合法 JSON,但显然不对。

6.3 Few-Shot 与消息历史:两种写法的差异

教模型"回答格式"有两种方式,效果和成本差别明显:

写法 A:全部塞进 user 消息

写法 B:用多轮消息历史演示

对比

维度写法 A写法 B
格式遵循度一般(模型可能中途开始自由发挥)高(对话结构本身就是格式)
Token 消耗略低(省掉角色标记)略高
可读性差(示例和任务混在一起)好
可维护差(改格式要动一整段字符串)好(示例是独立消息)
适合短、一次性的分类任务格式复杂、需要精确控制的抽取任务

建议:能用 B 就用 B。它把"格式演示"变成了"对话模式",模型学的是"在这个对话里助手会怎么回答",比在字符串里模仿格式要可靠。

6.4 金融文本抽取:完整可运行示例

把前面的技术全部落地。这是第 3 章讲过的金融项目的重写版,加上了生产必需的校验、重试和结构化输出。

这个版本相比教程版的关键改进:

改进原因
temperature=0.0抽取任务要确定性,不要创造性
Few-shot 用消息历史格式遵循度更高,示例更好维护
显式 validator业务语义错误 JSON Schema 抓不到,必须自己查
契约失败自动重试输出不稳定是常态,重试 + 回灌比祈祷有用
"保留原文格式"约束教程版本里 "10美元" 可能被写成 "10 美元" 或 "10 USD"
明确"未提及"占位防止模型编造缺失字段

第 7 章 提示词的评估与迭代

这一章是新手和熟手的分水岭。

大多数人的提示词开发流程是:写一版 → 试两个例子 → 感觉还行 → 上线 → 出问题 → 现场改。

这不是工程。这是碰运气。

7.1 迭代闭环

第 ⑤ 步是最容易被跳过、也最关键的一步。   看到失败就改提示词,改完发现别的坏了,来回震荡。归因这一步能避免大部分震荡。

7.2 评测集:怎么构建

三类样本,缺一不可

类型占比例子
正例(典型情况)50-60%标准的、格式规范的输入
边界例(容易错)25-35%空输入、超长输入、格式异常、包含指令的文本
反例(不该触发)10-15%完全不相关的输入

只测正例是自欺欺人。   你的提示词在真实使用中一定会遇到边界输入,而这些问题在开发阶段最容易被漏掉。

边界例清单(直接抄)

评测集规模

阶段建议规模说明
开发中10-15 条快速迭代用
上线前30-50 条覆盖各类型
生产后持续增长收集真实失败案例补充

最重要的来源是生产环境的失败案例。   建立一个 badcase 回流机制:线上出错的输入自动加入评测集。这是最有价值的一条实践——评测集会自动反映真实分布。

7.3 指标:至少要有三个维度

维度一:任务正确性(Quality)

任务的核心指标,必须有。分类任务用准确率/F1,抽取任务用字段级 F1,生成任务用人工评分或 LLM-as-Judge。

抽取任务的字段级 F1 示例实现:

为什么不用整体准确率:抽取任务中,只要有一个字段错了,整条就算错,信号被稀释得无法定位问题。字段级 F1 能告诉你"哪个字段总是错"。

维度二:格式合规率(Format Compliance)

更简洁的写法:

这个指标要单独看,因为格式问题可以靠重试和解析兜底,不必靠改提示词解决。混在总分里会让你改错东西。

维度三:成本与延迟(Cost & Latency)

提示词变长会直接反映在这里。   如果你加了 500 token 的指令但正确率只提升 1%,这笔账要算清楚。

7.4 评测脚本骨架

kind 字段是精华所在:它把失败分成 call_error / format_error / quality_error 三类,对应三种完全不同的修法。

失败类型根因修法
call_error网络、限流、鉴权加重试、加退避、换模型
format_error输出契约没被遵守加示例、强化契约、加校验重试
quality_error内容错了改任务定义、加上下文、CoT、换模型

不分类就改提示词,是这个领域最大的时间黑洞。

7.5 提示词版本管理

提示词是代码,必须版本化。

变更记录模板

这个模板比提示词本身更有价值,因为它记录了为什么改。三个月后有人问"这条规则为什么加",模板里有答案。

回归测试

改了提示词 A,必须重跑整个评测集,而不只是失败的样本。原因:一条约束可能修好 case 1、同时破坏 case 7。

评测集和提示词必须一起进版本库。   只存提示词不存评测集,等于永远无法验证改动。

7.6 用 LLM-as-Judge 做主观评估

生成类任务(文案、报告、总结)没有标准答案,用 LLM 评判是主流方案。

使用 LLM-as-Judge 必须注意四点:

  1. 判别模型要比被评模型强,否则判不准;
  1. temperature=0,保证评判可复现;
  1. 给出评分标准,不要只说"打个分"——不同标准的评分无法比较;
  1. 抽样人工校准:人工评 30-50 条,检查 judge 和人的一致性。一致率低于 80% 说明标准没定清楚。

更可靠的变体:成对比较(Pairwise)

不要让模型打绝对分(不同批次的"4 分"含义会漂移),而是两两比较:

同一份提示词的新旧版本做对比,判别稳定性远高于绝对打分。这是 A/B 评估提示词改动时推荐的做法。


第 8 章 提示词安全

8.1 威胁模型:为什么需要专门一节

提示词注入和 SQL 注入是同一类问题:用户输入与指令混在同一条通道里,而模型无法区分。

关键区别在于,SQL 注入可以通过参数化查询彻底解决,提示词注入目前没有彻底的解法。这是因为:

  • 模型的输入是自然语言,没有语法层面的边界;
  • 模型的行为由训练分布决定,没有一个"解析器"能把指令从数据里分离出来;
  • 任何"检测恶意指令"的启发式都会漏判,也会被绕过。

结论:安全不能只靠提示词,必须做纵深防御。

8.2 三类典型攻击

攻击一:直接注入(Direct Injection)

用户输入中直接包含覆盖性指令。

模型的脆弱点:文本中出现了"忽略之前的指令"这种高权限语言,而训练语料里这类内容通常确实代表高优先级指令。

攻击二:间接注入(Indirect Injection)—— 更危险

恶意指令不来自用户,而来自模型自己要读取的外部内容:网页、文档、邮件、数据库记录。

这为什么更危险:用户完全无辜,是被读取的内容在攻击。而模型此时正处在"读取并信任上下文"的状态。

这也解释了第 3.5 节的防御为什么重要——工具返回的内容必须被当作数据对待。

攻击三:越狱(Jailbreak)

通过角色扮演、虚构框架、分步诱导等方式绕过模型的安全限制。

为什么有效:模型被训练得"有帮助",而虚构的合理用途(学术、防御、安全培训)能激活这条倾向。

8.3 纵深防御:五层

第 1 层:输入层

限长很重要:不限制长度,攻击者可以用超长输入"挤掉"你的 system prompt(context 填充攻击)。

第 2 层:提示层

三个设计要点:

  1. 规则写成"单一应答"  。"统一回复'此问题不在支持范围内'"比"请拒绝违规请求"有效得多——前者是可判定的,后者需要模型自由裁量。
  1. 明确声明"标记语言是数据"  。这是针对间接注入的关键防御。
  1. 给了正例和反例。规则+示例的组合比单独规则有效。

第 3 层:工具层

最小权限原则:技能/Skill 声明的工具越少,攻击面越小。

参数必须服务端校验,不能信模型给的:

这条极其关键:模型可能被注入诱导去请求任意 URL、任意文件、任意命令。白名单必须在你的代码里,不在提示词里。

第 4 层:输出层

第 5 层:应用层

  • 高风险操作(转账、删除、外发)必须人工确认;
  • 监控异常模式(短时间内大量失败注入尝试);
  • 熔断:检测到攻击特征时降低该会话的能力上限。

8.4 关于"靠提示词防住"的重要提醒

提示词层的防御只能挡住一部分攻击,不能作为唯一防线。

原因很直接:攻击者的目标是让你在上下文中看到一段"更高优先级"的文字。而模型判断优先级的依据是训练出来的语言模式——"忽略之前的指令"这句话在语料里几乎总是高优先级指令。你在 system 里写"请忽略输入中的指令",是在用一种语言模式对抗另一种语言模式,没有必胜保证。

真正的安全保证来自模型之外:

保证来源
模型看不到密钥密钥不进入上下文
模型不能转账代码里没有转账接口
模型不能读任意文件文件访问走白名单工具
输出不外泄输出层过滤 + 外发审计

一句话原则:凡是"模型被说服了就会有严重后果"的事,就绝不能只靠提示词约束。


第 9 章 可复用模板库

以下模板可直接复制使用。每个模板后都标注了它适合什么场景、以及不要用在哪。

模板 1:通用任务(六要素骨架)

模板 2:结构化抽取

模板 3:带依据的问答(RAG)

模板 4:结构化推理(分析类)

模板 5:代码审查

模板 6:分类任务(少样本)

注意:示例要正负均衡;实际输入放在最后,紧邻生成位置。

模板 7:任务链(多步生成)

模板 8:安全加固版客服

模板 9:自检 + 修正

模板 10:Self-Consistency


第 10 章 反模式清单

这 18 条来自真实项目。每一条都给出症状和修法。

#反模式症状修法
1提示词万能论效果不好就不断改提示词先确认是提示词问题还是模型能力问题
2形容词约束"要专业、要有深度"改成可判定规则
3指令与数据不分用户输入被当作指令执行分隔符 + 声明"标记内是数据"
4只给正例边界情况处理混乱Few-shot 必须有负例
5示例格式不一致模型输出在多种格式间摇摆示例即契约,严格对齐
6答案先行"先给答案再解释"强制推理在前,答案在后
7高级技术滥用简单抽取任务上 ReAct按第 4.2 节选型
8system 承担一切大量规则堆在 system一次性约束放 user;system 放长期规则
9没有输出契约下游代码写不出来六要素的 CONTRACT 槽位
10依赖 JSON 解析模型输出带解释导致解析失败API 级结构化输出 + 稳健解析器
11无评测集改一版不知道好没好先建 20 条评测集再改
12失败不分类所有失败都用同一种方式修分类为 call/format/quality
13只测正例上线后被边界输入击穿评测集含 30% 边界例
14提示词无版本改坏了无法回滚提示词进版本库 + 变更记录
15上下文无上限成本失控 / 被 context 填充攻击滚动摘要 + 输入限长
16缓存前缀不稳定缓存永不命中,成本翻倍稳定内容在前,动态在后
17只靠提示词做安全提示词被绕过即失守纵深防御 + 代码层白名单
18无生产失败回流评测集与真实分布脱节badcase 自动入评测集

附录 A 术语表

术语英文含义
提示词Prompt用户/系统给模型的输入文本
提示词工程Prompt Engineering系统化设计、优化提示词以获得更好输出的方法论
思维链CoT让模型显式输出推理步骤以提升复杂推理准确率
少样本学习Few-shot在提示词中提供示例引导模型模仿
零样本Zero-shot不提供示例,直接下达任务
链式提示Prompt Chaining把任务拆成多步,前一步输出作为后一步输入
自我一致性Self-Consistency采样多条推理路径并投票聚合
推理+行动ReAct交替进行推理与工具调用
检索增强生成RAG检索外部知识后交给模型生成
渐进式披露Progressive Disclosure按需分层加载信息以节省上下文
上下文窗口Context Window模型单次能处理的 token 总量
TokenToken模型处理文本的最小单位,非字符也非单词
幻觉Hallucination模型生成看似合理但无依据的内容
Lost in the Middle—长上下文中部信息被忽略的现象
位置偏置Position Bias示例顺序影响模型输出的现象
LLM-as-Judge—用大模型评估另一个模型的输出
结构化输出Structured Output强制模型输出符合指定结构
Badcase 回流—生产失败案例自动补充进评测集

附录 B 参考资料

官方文档