ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

高质量提示词工程实战:结构、参数、评测与避坑指南

高质量提示词工程实战:结构、参数、评测与避坑指南

“同一个模型,同一个问题,我把提示词改了三段,输出质量差出一个量级。”上个月帮朋友调一个合同摘要的小工具,他原来的提示只有一句“帮我总结一下这份合同的重点”,模型返回的东西排版漂亮但基本没用——该说的条款没说,不该下的结论乱下。我补了一段职责描述、两个少样本、一个固定的输出骨架,再加一条“原文没有的信息一律写‘未提及’”的兜底规则,同样的模型、同样的输入,摘要立刻能进业务流程。这种反差我经历过太多次,所以越来越确信:高质量提示词工程不是玄学,它是一门有明确输入、明确输出、明确评价标准,也有一张明确踩坑清单的手艺活。这篇内容写给三类人:刚接手大语言模型应用、还在靠“多试几次”碰运气的开发者;要把提示词交给团队协作、需要它稳定可复现的工程负责人;以及业务侧想自己动手调效果、不想每次都排期等研发的产品同学。全文不谈虚的,只讲结构怎么拆、参数怎么定、效果怎么验、坑怎么绕。

1. 先想清楚:提示词工程到底在解决什么问题

很多人对提示词工程的想象停留在“找一句咒语”,仿佛存在某个神秘句式,敲进去模型就变聪明。真做过几个落地项目就会明白,模型的能力边界是固定的,你能改变的只有三件事:给它什么信息、以什么结构给、用什么标准判断它答得好不好。这三件事合起来,就是提示词工程的全部战场。

1.1 从“会聊天”到“会指挥”的认知转变

聊天框里的交互是开放式的,你说一句它接一句,错了重来就行,成本几乎为零。但一旦把模型接进业务流,性质就变了:它变成流水线上的一个工位,上游给它原料,下游等它的半成品,这时候“大概齐”是不能接受的。我见过一个很典型的场景,某团队做发票信息提取,前两周在聊天框里测得好好的,一上量就崩——同样的发票版式,今天抽出金额,明天抽出的是税额,后天干脆把整段文字塞进一个字段里。问题不在模型,在于他们从来没写过“输出契约”,也就是没告诉模型结果必须以什么形状交付。

从聊天到指挥,核心转变是把隐含期待显式化。你脑子里知道“我要的是简洁的三行摘要”,模型不知道;你知道“金额必须是数字不带币种符号”,模型不知道;你知道“这份文档里没写生效日期就不要编”,模型更不知道。提示词工程做的,就是把这些只存在于你脑子里的约束,一条一条翻译成模型能读懂的指令。

1.2 四个真实痛点,决定了你必须认真写提示词

我把实际项目里遇到的麻烦归了归类,基本逃不出下面四类,每一类都直接对应一项提示词技巧,不是凭感觉对号入座:

痛点表现根因对应手段
输出格式天天变,下游解析老失败没有输出契约固定骨架 + 结构化约束 + 兜底值
同样的输入,两次结果差很多指令有歧义、缺少判定标准明确判定规则 + 少样本锚定
关键信息漏掉,或凭空捏造上下文组织混乱、无“未知”出口分段标注 + 显式拒答规则
换个人写就废,没法交接提示词没有版本和结构模板化 + 变量占位 + 版本记录

这四类问题有个共同点:它们都不是靠“换个更强的模型”能根治的。模型升级确实能抬高下限,但格式漂移、指令歧义、幻觉出口缺失这些属于“你没说清楚”,模型再强也只能猜。我在项目里反复验证过一件事:把一个中等能力模型上的提示词打磨到位,效果提升幅度往往大于直接换更强的模型,而且成本低得多。

1.3 一个必须提前接受的现实:提示词是有寿命的

这点很少有人提,但特别重要。你精心调好的提示词,在模型版本更新之后可能效果波动,甚至明显变差。原因不复杂——不同版本对指令的敏感度、对格式的偏好、对长上下文的处理方式都会有差异。所以从第一天起,我就建议把提示词当成代码资产来管:有版本号、有变更记录、有配套的评测集。改一版跑一遍评测,数字掉了就回滚,别靠记忆判断“好像变好了”。后面第 5 节会讲具体怎么搭这套东西。

2. 一条提示词的解剖:六个部件与它们的排列逻辑

写提示词最忌讳的是“想到哪写到哪”。我习惯用固定骨架,六个部件按顺序摆,写完自查一遍有没有漏。这套骨架不复杂,但能覆盖九成以上的常规任务。

2.1 六个必备部件清单

  1. 角色与职责:不是“你是一位资深律师”,而是“你负责从合同中提取与付款相关的条款,不做法律意见判断”。
  2. 任务定义:一句话说清输入是什么、要产出什么,动词要具体,“提取”“归类”“改写”比“分析”“处理”明确得多。
  3. 上下文材料:待处理的原文、参考资料、历史对话,用清晰的分隔标记包起来。
  4. 约束条件:字数、语气、禁止项、边界情况怎么处理。
  5. 示例:一到三条高质量输入输出对,用于锚定风格和粒度。
  6. 输出契约:字段名、类型、顺序、缺失值怎么写、允不允许额外解释。

我的经验是,第六项被忽略得最狠,但收益最高。哪怕你只是加一句“只输出 JSON,不要任何前后说明文字”,下游解析失败率都能降一大截。

2.2 顺序为什么这么排,而不是随便放

部件顺序不是审美问题,它直接影响模型的注意力分配。我的排法遵循三条经验规则:

第一,任务定义要靠近材料。模型在读到大段原文时,容易“沉浸”进去而忘了要干什么,所以任务说明放在材料前一句、材料后再复述一遍关键要求,效果比只在开头说一次好。

第二,输出契约放在最后。多数模型的注意力对结尾位置更敏感,把格式要求压在末尾,比埋在中间更不容易被冲淡。这一点在长提示里尤其明显。

第三,示例放在约束之后、契约之前。示例的作用是“示范粒度”,它要能同时参照前面的约束和后面的格式,位置夹在中间最合适。如果你的示例很长,考虑压缩到最关键的一两条,长示例会挤占真正指令的注意力。

提示:不要试图用空行和符号把提示词排得花里胡哨。清晰的分隔(比如用 XML 风格标签或三级标题)有用,但一堆星号、波浪线、箭头只会让结构更难读,对模型也没帮助。

2.3 系统提示与用户提示,别混着写

如果你用的是带系统提示(system)和用户提示(user)分离的接口,一定要利用好这个分层。我的划分原则很简单:

  • 系统提示放“不变的东西”:角色、职责边界、全局禁止项、输出契约的骨架。
  • 用户提示放“每次都变的东西”:这一次的原文、这一次的具体任务、这一次的额外要求。

这么分的好处很实际。系统提示稳定,可以配合缓存机制降低成本、提高响应速度;用户提示短小,调试时只改一小段,不会牵一发动全身。我见过不少项目把所有内容堆在用户提示里,结果每次调用都要重传几百字规则,调试时改一个标点都得整体回归,非常低效。

顺带说一个容易踩的坑:系统提示里的规则和用户提示里的规则冲突时,模型不一定按你期望的优先级执行。所以两条原则:一,不要写互相矛盾的规则;二,如果业务上确实需要“用户可覆盖”的默认值,就在系统提示里明确写出覆盖规则,比如“若用户另行指定长度,以用户指定为准”。

3. 六个高频技巧:正确用法、常见误用与替代方案

技巧本身不难找,难的是知道什么时候该用、什么时候用了反而添乱。下面这六条是我用得最多、也见过最多误用的。

3.1 角色设定:写职责,不写头衔

“你是一位拥有二十年经验的资深专家”这类写法,坦白说收益很有限。它唯一的作用是给模型一个大概的语域方向,但“资深专家”到底怎么说话、关注什么、不关注什么,全是空的。

真正有效的角色设定写的是职责边界,包含三样东西:负责什么、不负责什么、遇到越界情况怎么办。举个例子对比一下:

弱:你是一位专业的财务分析师。 强:你负责从财报原文中提取营收、毛利率、经营现金流三项数据。 你不做投资建议,不评价公司好坏。 原文没有明确披露的项,填“未披露”,不要用推算值填充。

第二种写法带来的差别是可观测的:越界回答明显减少,“未披露”这类兜底值让下游能准确判断数据完整性。角色设定本质上是给模型划定行为空间,而不是给它戴一顶帽子。

3.2 少样本示例:数量、排序和“坏例子”

示例(few-shot)是最有效的技巧之一,但也是最容易被用坏的。三个实操要点:

数量上,两到三条通常足够。一条太少,模型抓不到规律;四五条以上边际收益迅速递减,还会挤占上下文预算。如果任务确实复杂,宁可拆成两个子任务分两次调用,也别硬塞十条示例。

排序上,把最接近真实分布的放最后。模型对靠近结尾的示例更敏感,最后一条示例的“示范权重”最高。所以别把最极端的边界案例放最后,除非你就是要它重点学会处理边界。

最关键的一点:示例的格式必须和输出契约完全一致。我见过太多反例——契约里写“输出 JSON”,示例却是一段自然语言描述,模型当然会优先模仿示例。示例就是模型的模板,格式不一致等于自己拆自己的台。

关于“坏例子”,我的看法是谨慎使用。有些场景确实需要示范“什么是不该输出的”,比如“不要输出这种笼统的表述:本文主要介绍了……”。但负面示例有副作用,模型可能被带偏去做类似风格的输出。如果一定要用,把它放在明确的“反例”标签下,并在后面紧跟一条正例,形成对照。

3.3 输出契约:从“请用表格”到可执行的格式约束

“请用表格输出”这种要求,在聊天框里够用,在工程里不够。因为“表格”有无数种形态:几列、列名叫什么、空值怎么表示、单元格里能不能换行。工程上需要的是一份契约,我通常包含这几项:

  • 字段名与顺序(固定,不允许增删)
  • 字段类型(字符串、数字、布尔、数组)
  • 缺失值约定(统一写null或"未提及",二选一,全篇一致)
  • 长度上限(比如摘要不超过 120 字)
  • 附加说明的处理方式(统一放在某个指定字段里,或干脆禁止)

如果接口支持结构化输出或 JSON 模式,优先用它,能从机制层面减少格式漂移。如果不支持,那就把契约写得足够死,并配一条“只输出内容本身,不要任何解释、不要代码块标记”的硬性要求——这条看似多余,实际能省掉大量清洗工作。

3.4 让模型“先想后答”的正确姿势

让模型先推理再给结论,对多步计算、逻辑判断题确实有帮助。但很多人的用法有个问题:把推理过程也当成了交付物,结果输出里一半是思考、一半是答案,下游还得自己切。

正确做法是分离推理和结果。要么在契约里明确要求“先输出分析过程,用<分析>标签包裹,再输出<结果>标签包裹的最终答案”,要么更干脆——分两次调用,第一次让它列要点,第二次基于要点出结果。后一种方式在工程上更容易控制,因为每一步的输出都能单独校验。

还有个反直觉的经验:简单任务不要强行让它推理。抽取字段、改写句子这类任务,加了推理步骤反而容易引入噪音,甚至让模型把推理里的中间猜测写进结果。判断标准很简单——如果你的任务不需要多步推导,就别加。

3.5 负面指令为什么老是失效

“不要编造”“不要说废话”“不要用专业术语”——这类否定句,实际效果往往很差。原因在于,模型处理否定信息的方式和人类不同,它对“编造”“废话”这些词的激活强度,可能高于对“不要”的抑制。你越强调不要什么,越容易把注意力引到那上面。

替代方案是把否定转成肯定,并给出可执行的替代动作:

失效写法改写后
不要编造信息每个结论后标注来源句编号;无来源句支撑则输出“无依据”
不要写得太啰嗦每个要点不超过 30 字,全篇不超过 5 个要点
不要用口语使用书面语,避免“啊”“呢”“其实”等词
不要漏掉关键条款按“付款、违约、期限、争议”四类逐项检查,缺项写“无”

改写后的共同点是:给了模型一个可执行的动作,而不只是一个禁令。这是我这些年最有价值的一条经验,几乎适用于所有“模型不听话”的场景。

3.6 分步拆解:把一个大任务切成能验收的小任务

一个提示词干三件事,几乎注定失败。信息抽取 + 逻辑判断 + 文风改写,这三件事对上下文的要求、对温度的要求都不一样,混在一起必然互相拖累。

我的做法是拆成流水线,每步一个提示词,每步的输出都能单独验收。举个文档处理的实际拆法:第一步清洗和分段,第二步逐段抽取结构化字段,第三步汇总去重,第四步生成成稿。每一步的提示词都很短,出问题能立刻定位到是哪一环。代价是调用次数变多、成本上升,所以拆到什么粒度要看业务容忍度——高价值场景值得多花几次调用,批量低价值场景就合并成两步。

4. 实操:从零搭一个可复用的提示词模板

光讲原则不够,我把一次完整的搭建过程摊开写,你可以直接照着改。

4.1 第一步:把需求拆成信息清单

假设任务是从用户反馈里提取问题类型和紧急程度,输出成结构化记录给客服系统。先别急着写提示词,先列清单:

  • 输入是什么:一条用户反馈原文,长度几十到几百字,可能带错别字和情绪表达。
  • 输出要什么:问题类型(限定枚举值)、紧急程度(三档)、关键信息摘要(不超过 40 字)、是否能自动回复(布尔)。
  • 边界情况有哪些:反馈内容为空、反馈是纯情绪无实质内容、一条反馈包含多个问题、语言混杂。
  • 判定标准是什么:紧急程度靠什么区分,这是最容易含糊的地方,必须写死。

这一步花的时间最值。清单列完,提示词基本就成型了一半,剩下的只是措辞。

4.2 第二步:搭骨架与变量占位

我习惯用一个固定的模板文件,变量用双花括号占位,方便程序替换和人工审阅:

# 角色 你负责把用户反馈整理成工单记录。你不回复用户,不评价产品,只做信息归类。 # 任务 读取下方【反馈原文】,按输出契约产出记录。若原文包含多个独立问题,只提取最主要的一个,其余在备注中列出数量。 # 判定规则 问题类型只能取:功能异常 / 使用咨询 / 体验建议 / 费用疑问 / 其他。 紧急程度判定: - 高:涉及无法使用、资金损失、数据错误 - 中:影响部分功能但可绕过 - 低:咨询、建议、表达不满但无具体故障 # 约束 - 摘要在 40 字以内,只陈述事实,不带情绪词 - 原文未提及的信息一律填“未提及”,禁止推测 - 只输出 JSON,不要任何解释文字,不要代码块标记 # 示例 输入:付了两次钱,第一次显示失败我又点了一次,现在扣了两笔 输出:{"type":"费用疑问","urgency":"高","summary":"用户重复支付两笔,首次显示失败","autoReply":false,"note":"未提及"} # 输出契约 {"type": string, "urgency": string, "summary": string, "autoReply": boolean, "note": string} # 反馈原文 {{feedback_text}}

这份模板有几个值得注意的设计。示例放在契约前、原文后,让模型在读完材料后再看一遍“标准答案长什么样”。原文放在最末尾,紧贴生成位置,减少中间内容对注意力的稀释。兜底值“未提及”和“禁止推测”成对出现,一个给出口,一个堵入口,比单说“不要编造”有效得多。

4.3 第三步:参数怎么定,别凭感觉

提示词之外的调用参数,对稳定性影响同样大。下面是我常用的起步配置,不是绝对标准,但作为初始值很少需要大改:

参数抽取/归类类任务创作/改写类任务说明
温度(temperature)0 ~ 0.20.6 ~ 0.8越低越确定,抽取任务几乎不需要随机性
top_p0.1 ~ 0.30.9与温度配合,一般不两头都调
最大输出长度按契约上限 +20%按需留余量但别无限,长输出容易跑偏
停止词可按需设置一般不用结构化输出时可用于截断多余内容

一个实操心得:调试阶段先把温度压到 0。这样同一个输入跑十次结果基本一致,你才能判断“改动提示词带来的差异”和“随机性带来的差异”哪个在起作用。等提示词稳定了,再根据业务需要把温度往上调。

4.4 第四步:跑通并记录第一版结果

拿二十条真实反馈跑一遍,我记录的内容包括:通过条数、失败类型分布、典型失败样本。第一版通常能过十五到十七条,剩下的是宝贵的调试素材。这里有个必须提醒的点——别用你调试时反复看的那几条样本当评测集。人一旦对某条样本熟悉,就会不自觉地围绕它优化,最后提示词只在那几条上好使。评测集要从一开始就留出一部分“不看”的样本。

5. 怎么判断提示词真的变好了

没有评测的提示词迭代,本质上是盲改。这套东西搭起来不复杂,一个下午够了,但收益是长期的。

5.1 二三十条样本就够起步

不需要几百条,二十到三十条覆盖主要场景和边界情况即可。关键是分层抽样:正常情况占大头,边界情况(空输入、超长输入、多问题混合、语言混杂)各留几条。每条样本要有人工标注的“正确答案”或“合格标准”,哪怕是粗略的也行。

样本集要冻结。改提示词的时候不动它,否则你永远不知道是提示词变好了还是题目变简单了。需要扩充就新增一份,旧的那份留着做回归对比。

5.2 打分维度拆开看,别只打总分

我一般拆成四个维度,各打通过/不通过,比打总分更有诊断价值:

维度看什么常见不通过原因
格式合规能否被程序直接解析多了说明文字、字段拼写错、类型不对
内容准确关键信息与原文一致数值抄错、漏掉核心问题、把备注当成主问题
边界处理异常输入是否按约定兜底空输入时自己编内容、多问题时强行合并
表达质量摘要是否简洁无赘述带情绪词、超字数、把原话整段复制

四列分开看,问题定位会快很多。比如格式维度全过但内容维度掉了一半,说明是抽取逻辑的问题,不用去动格式部分。

5.3 迭代记录:写下来,别靠记忆

我用一张很朴素的表管版本,字段就这几个:

版本改动点通过率失败主因是否采纳
v1初版75%摘要超字数-
v2摘要限制改为例示写法85%边界输入仍会编造采纳
v3加“未提及”兜底92%无采纳

这张表的价值在模型升级时体现得最明显。新版本一上线,先跑一遍评测集,通过率掉到 80% 就知道要复查了;对照记录能快速定位是哪类改动失效了。没有这张表,你只会感觉“好像变差了”,然后陷入无休止的试错。

6. 常见问题排查实录

下面这些是我被问得最多、自己也踩过最多次的坑,按现象归类,附排查顺序。

6.1 输出忽好忽坏,同样输入两次结果不同

先查参数,再查提示词。温度高于 0.5 的抽取类任务天然不稳定,压到 0 复测一轮;如果压到 0 还波动,那就是指令有歧义。最常见的歧义源是判定标准写得含糊,比如“重要的问题标为高优先级”——什么叫重要?模型只能猜。把判定标准改成分条可判定的条件,波动基本会消失。

还有一种情况容易被忽略:输入里含有相互矛盾的信息。比如反馈里用户先说“能用”,后说“打不开”,模型在两次采样中可能各偏向一边。这时候别指望模型自己权衡,直接在提示词里规定冲突时的取舍规则。

6.2 长文档里指令被“淹没”

处理长文档时,把指令全放开头,模型读到后面就忘了要干什么,这是很普遍的现象。我的处理顺序是:

  1. 把关键指令在文档前和文档后各放一次,后一次紧贴输出位置,措辞可以更短。
  2. 用清晰的分隔标签把文档包起来,比如<document>...</document>,让模型知道哪里是材料、哪里是指令。
  3. 如果文档超长,先做分段预处理,每段单独抽取,再合并结果,而不是指望一次读完。
  4. 材料内部如果有小标题或编号,保留它们,结构信息对模型理解内容帮助很大。

6.3 结构化输出解析失败

按这个顺序排查,基本能覆盖九成情况:

  • 有没有多输出内容:最常见的是模型在 JSON 前后加了解释或代码块标记。加一条硬性禁止,必要时用停止词截断。
  • 字段名是否拼错:契约里写autoReply,模型可能输出auto_reply。契约里把字段名用引号原样列出,能显著降低出错率。
  • 类型是否漂移:布尔值被写成字符串"false",数字被写成带单位的文本。在契约里明确类型,并给一个正确示例。
  • 特殊字符是否破坏结构:摘要里带引号或换行会把 JSON 弄坏。要求摘要内不带引号、不换行,或让程序侧做转义兜底。

6.4 排查速查表

现象优先怀疑快速验证方法
格式漂移输出契约不完整 / 示例格式不一致对照契约与示例,看是否完全同构
内容编造缺少“未知”出口加“原文未提及则填 X”后复测
指令被忽略位置太靠前 / 上下文过长把关键指令复制到末尾再测一次
输出过长无长度约束加字数上限与“超出即视为失败”的说明
语气不对角色描述空泛改成职责描述 + 一条风格示例
多问题混淆未规定冲突处理明确“只取主要问题,其余记入备注”

最后分享两个我自己常用的小技巧。一是反向测试:故意喂一条完全无关的输入,看模型会不会硬编一个答案出来,能兜底住才算合格。二是朗读测试:把提示词当成写给一个新同事的交接文档读一遍,如果读起来你会反问“这里到底啥意思”,那模型八成也会反问——只不过它不会问,它会猜。

这套方法我用了两年多,最大的感受是:提示词的收益不在某一次灵感爆发,而在每次改动都能被验证。我早期也靠感觉调,改十版有八版是原地打转;后来把评测集和版本记录补上,迭代速度反而快了一倍,因为知道哪条路走不通,就不会反复去走。至于模型本身的能力,交给厂商去卷就好,我们把手头这几百字写到没有歧义,已经能吃掉大部分红利了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进