简介:《AI引擎:Prompt指令设计绿皮书》是一份面向ChatGPT、Claude、Bard等主流AI工具的Prompt设计指南,适合内容运营、职场办公及个人学习等场景使用。书中先讲解指令写作的七个技巧公式,包括明确定义需求、提供足够上下文、使用简单直白的语言、详细说明输出要求、举例示范、添加限制条件以及多次迭代优化;再按应用场景整理出新媒体运营、简历写作、求职面试、个人发展四大模块,并给出小红书笔记万能指令、短视频开头写作指令等可直接套用的现成模板,方便举一反三。整份资源以PDF形式提供,共1个文件,体积3.64MB,附带完整目录和更新日志,便于按章节快速查阅。目前已有6677人浏览学习,适合内容创作者、职场人士以及对AI工具感兴趣的入门和进阶用户作为Prompt设计参考手册,帮助摆脱低质量回复、提升AI输出的一致性与可用性。
1. AI引擎的油门在用户手里:Prompt指令设计到底是什么
长期做AI应用落地的人,慢慢会对一种现象脱敏:同样的模型、同样的算力、同样的数据管道,有的团队交付出来的对话体验像丝滑的助理,有的却像喋喋不休的复读机。差别往往不在模型,而在往AI引擎里喂的那段指令。Prompt指令设计就是研究“怎么把需求翻译成模型能严格执行的语言”的那套方法。它不是让模型更聪明,而是让用户手里那个油门更能发挥引擎本身的动力。适合正在搭RAG、做自动化、写客服机器人和做内容生成工具的人。这篇笔记我把实际项目里验证过的模板、参数、翻车记录一次讲透。
2. 指令设计的地基:角色、任务、格式三要素
Prompt工程师从零开始设计指令,第一件事不是堆砌技巧,而是把指令拆成三个可管理的问题:模型以什么身份回答、它到底要完成什么动作、输出长成什么样子。这三块决定了模型生成时的落点。把这三件事写清楚,后面再加few-shot、思维链,才是在同一个地基上盖楼。
2.1 角色设定:让模型知道自己是谁
角色不是装饰。给模型一个角色说明,等于给它划定一个知识调用范围和语言风格范围。比如“你是一名资深运维工程师”和“你是一个友好的客服”背后的用词密度、专业缩写比例和语气收敛程度完全不同。常见的一个坑是角色写得过于宽泛,例如“你是一个数据库专家”,这样的设定对模型约束力很弱。我一般会把角色说明写成一段两行内的句子,带上岗位、服务对象和不做什么。
一个我常用的写法是:
你是一名有十年经验的数据库运维工程师,负责回答开发者的数据库性能问题。 你的回答要直接给结论,然后解释原因;不输出任何与问题无关的寒暄。这里的逻辑是:第一个句号前定义了身份,第一个句号后定义了交流风格。模型在生成时会把“工程师”和“直接给结论”作为顶层约束,而不是等到内容生成完再过滤。如果你只写了岗位没写交流风格,模型往往会按训练数据里的平均对话习惯输出,语气飘忽不定。
角色设定的另一个作用是压缩上下文。好的角色说明本身就在告诉模型“哪些知识不用反复引用”,比如设定成“资深运维”,模型就不需要再解释什么是索引、什么是锁等待。这个压缩在长会话里尤其值钱,因为token预算会直接影响成本。反过来,角色设定别堆太多形容词。“你是最厉害的、无人能及的文案大师”这类措辞,模型不会更努力,只会把输出淹没在浮夸词里。
从实测表现看,角色这一栏在Prompt里占的token权重不高,影响却很直接。同一个任务,切换成“严谨的审计师”和“开朗的培训讲师”,输出里出现数字精确度和语气词量的差异非常明显。这意味着角色设定是一个典型的低成本高杠杆旋钮,值得在每条业务Prompt里单独留一个位置。
2.2 任务描述:把模糊需求压成明确动词
任务描述是最容易被写废的部分。很多人把任务写成一个名词短语,比如“生成一段产品介绍”“写一个关于云计算的说明”,这等于把选材和侧重点全权交给模型。模型在预测下一个词时,没有动词就没有强制的行为区间。
我在实际项目中总结出一个任务描述公式:任务 = 动作 + 对象 + 约束条件。动作尽量用“列出、对比、解释、重写、翻译、总结”这类有明确输出的动词;对象写具体的材料或数据;约束条件写长度、风格、立场、输出的边界。这里有一个容易被忽略的细节:约束条件是给模型的行为限制,不是给模型的目标。比如“不要超过80字”是行为限制,“写得有吸引力”是目标,两者要分开写,否则模型容易在追求吸引力时牺牲长度约束。
一个示例:
请对比“MySQL 8.0”和“PostgreSQL 15”在以下维度上的表现: 1. 事务隔离级别 2. 分区表维护成本 3. 高可用方案成熟度 输出成一个三列的对比表格,每行一个维度,每列不超过 80 字。注意这里的动作是“对比”,对象是两个具体数据库,维度列表直接给出。对比这个动作如果没有维度,模型通常会自己发明四个维度,其中至少一个不是用户关心的。这种“动作+对象+约束”的结构还有一个好处:后续调参时你能一眼看出是哪一处约束没生效。
当任务本身比较复杂时,我还会在动作描述里加上“先…再…最后…”这种顺序连接词。这相当于给模型一个临时的程序计数器,防止它在一次生成本里突然跳到结论。比如先抽取关键词,再分类,最后生成摘要,这种流程化描述比一句“给我做个完整分析”稳定得多。顺序词不要超过三个,超过之后模型没法在生成本中维护太长的状态机,效果反而下降。
任务描述里还有一个容易踩的坑:把context和task混在一起。比如“根据用户买的商品生成感谢信,该商品是跑步机,用户姓王”,这里的“跑步机”是背景,“写感谢信”是任务。如果混成一句,模型偶尔会把“跑步机”当作主题来发挥,反而忘了写信。正确做法是背景放在前面一句,任务动词另起一句。
2.3 输出格式:用结构约束取代口头要求
输出格式是Prompt设计里性价比最高的部分。同样一个任务,口头说“请以列表形式输出”,模型给出的格式可能千奇百怪;直接给一个JSON结构,模型就会严格按结构来。原因是模型对标记语言和代码块的结构敏感度远高于自然语言描述。
一个我在生产环境验证过的格式约束:
{ "summary": "一段不超过50字的概括", "points": ["观点1", "观点2", "观点3"], "risk_level": "low|medium|high" }配合的指令是:“严格按照上述JSON结构输出,不要输出其他文字。如果无法判断,risk_level字段输出unknown。”模型见到这样一个明确的schema,生成时的词汇候选空间会被压到很小。相比自然语言里的“请输出JSON”,这个方案把JSON样例放到了指令里,模型更容易对齐。
格式约束最容易出的问题是不给兜底。如果我让模型判断风险等级,却没定义“无法判断时怎么办”,模型会硬选一个等级,这比给不出答案更麻烦。所以我在格式模板里永远留一个“unknown”或“无”的合法值。另外,输出格式要在整个指令里只定义一次,不要前面定义了JSON,后面又加一句“也可以输出表格”,这种模棱两可会让模型失去对齐依据。
关于格式载体,我目前的排序是:结构化数据类任务优先JSON,阅读类任务优先Markdown,交互类任务优先纯文本。JSON适合被程序解析,Markdown适合带层级的长文,纯文本适合聊天场景。这个选择也决定了后续下游程序解析的复杂度。如果你在做一个RAG系统,输出格式选错,后面的解析脚本就要跟着返工,这是Prompt设计里不多见的可以提前止损的决策点。
3. 从零跑通一个可用Prompt:最小模板与两种主流程
前面讲清楚了三个地基支点,这一章直接给能抄作业的东西。工作里最常见的诉求不是设计一条完美Prompt,而是用最小的改动让一条指令从“能用”变成“稳定”。我把它拆成一个最小模板和两种主流程。
3.1 五段式最小模板:一条提示词覆盖大部分场景
我日常项目的起点基本是一个五段式结构:角色、背景、任务、格式、边界。这五段在Prompt里按顺序排列,每段用一行分隔。
prompt = f"""角色:你是{role},负责{service}。 背景:当前环境是{context},用户的问题是:{user_query}。 任务:请完成以下{action},必须包括{required_items}。 格式:用Markdown输出,使用列表和加粗。 边界:不要输出与问题无关的内容,不要推测数据来源。"""这段代码里,{role}和{context}这些占位符在程序里会被业务数据动态填充。五段式的核心在于把不同信息类型放在不同段落里,模型在解析时会把“背景”里的信息当作约束,而不是当作任务本身。如果你把背景和任务混在一起写,模型偶尔会把背景内容当作要执行的动作,就会跑偏。
参数说明上,role、service、context、action、required_items是五个必填位。role和action前面说过了;context是给模型的参考材料,比如用户日志、商品信息、工单内容;required_items是最低限度的需求清单,宁可少列不要多列,列得太多模型会在次要项上浪费表达空间。service这个字段我单独拿出来,是因为很多人会把服务和背景搞混。服务描述的是“你在这个任务里提供什么价值”,比如“负责给开发者的数据库问题给出诊断结论”,背景是“当前环境是什么”,两者承担的约束作用不同。
关于边界这一栏,最好的写法是“不要做什么”而不是“要做什么”。模型对否定指令的敏感度其实不低,但前提是它要放在Prompt的后半段。如果放在开头,模型读完就忘了;放在格式之后,作为收尾强调,遵守率会明显上升。如果你发现模型经常输出了一堆废话,就检查一下边界里有没有明确列出禁止项。
3.2 单轮直给流程:适合一次性生成场景
单轮直给适用于每次请求都是独立任务、不需要记住前文的场景。比如批量生成商品描述、给每条工单写回复草稿、把一段会议记录转成待办事项。这种场景下,Prompt应该做成一个纯函数,即输入进去的材料和约束决定输出,不依赖任何历史状态。
def generate_product_desc(product_info: dict) -> str: prompt = f""" 角色:你是电商文案编辑,擅长提炼产品卖点。 背景:产品信息如下:{product_info} 任务:写一段面向年轻消费者的商品描述,突出实用性和性价比。 格式:三段式,每段不超过60字,第三段以“适合”开头。 边界:不要编造产品参数。 """ response = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=300 ) return response.choices[0].message.content逻辑说明:这个函数把业务数据通过product_info注入Prompt,temperature设成0.3是为了让输出在“稳定”和“自然”之间取平衡。如果设成0,描述会偏干瘪;设成0.7以上,卖点会飘。max_tokens设300,和“三段式每段不超过60字”是对应的,留出约30%的余量以防格式换行挤占token。
单轮直给场景里有一个常见翻车点:在Prompt里写“记住你是电商文案编辑”这句话没任何意义,因为模型不保留上一次请求的状态。每次调用都是重新开始,所以角色、背景、任务、格式、边界五段必须在一个Prompt里写全。这也是为什么我坚持把单轮Prompt写成纯函数。
批量调用单轮Prompt时,有一个隐藏性能点:不要每次调用都重复组装Prompt字符串。把静态部分比如角色和格式定义放在外层常量,只拼接动态部分,能省下不少token。虽然单次省的量不起眼,但一天跑几十万次调用时,这个优化直接体现在账单上。我见过有团队在prompt上反复做字符串拼接,每次多出几百个重复token,月底账单多了一截,还以为是模型调贵了。
3.3 多轮迭代流程:适合复杂任务
复杂任务比如“先分析文本,再生成摘要,最后把摘要翻译成英文并在翻译中保留术语一致性”这种,单轮Prompt也可以写,但一旦用户中途追加需求,完全重写Prompt比继续追加历史消息要昂贵得多。多轮迭代流程更适合这类需要逐步逼近的场景。
messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": "第一轮:请找出下面这篇文本里的所有产品名和型号:" + text}, {"role": "assistant", "content": assistant_result_1}, {"role": "user", "content": "第二轮:基于上面识别出的实体,生成一个摘要,不能引入外部知识。"}, {"role": "assistant", "content": assistant_result_2}, {"role": "user", "content": "第三轮:将摘要翻译成英文,保持术语一致,输出成表格。"}, ]逻辑说明:三轮对话把一个大任务拆成了“识别->生成->翻译”三个阶段,每一轮拿到的上下文比单轮里一次性塞入任务描述要短,模型在每一阶段的注意力更集中。这里有一个很重要的坑:多轮迭代中,assistant的历史输出会被当作下一次推理的上下文,所以中间轮次的Prompt一定要写“只输出结果,不要解释过程”,否则历史里的废话会被写进下一次请求,污染上下文。
多轮流程相对单轮的代价是token消耗高。如果任务可以一次并行处理,没必要硬上多轮。我一般根据两个信号判断要不要用多轮:一是任务是否能拆成顺序依赖的步骤;二是用户的反馈是否有“保留上一轮结果再改局部”的需求。两者任一满足,多轮更划算。
多轮里还要注意system prompt的处理。系统指令在每一轮都会生效,而不是只在第一轮生效,所以不要把一次性的信息塞进system prompt。比如“本次对话要分析的文件是xxx”应该放在第一轮user消息里,而“你是翻译助手,输出必须是英文表格”这种长期约束才放system。放反了的话,后续追加的轮次里模型会迷失方向。
4. 参数与指令的协作:temperature、top_p、max_tokens怎么调
提示词不是唯一的控制变量。同样的Prompt,换一组采样参数,输出质量会有肉眼可见的波动。这一章把工程师最常揪住的三个旋钮讲透,并且说明它们和Prompt之间的协作关系。很多人调参失败,是因为只碰参数不回头改Prompt,这个习惯要先纠正。
4.1 temperature:随机性的刻度盘
temperature控制的是采样时对低概率词的偏好程度。数值越低,模型越倾向于选择概率最高的词,输出越确定;数值越高,低概率词被选中的机会越大,输出越发散。默认值通常落在0.7到1.0之间,但业务场景里我很少直接用默认值。
分类、抽取、格式转换这类任务,我会把temperature压到0.1到0.3之间。文案创作、头脑风暴、广告语生成这类任务,我会放到0.7到0.9。这里有个反直觉的现象:temperature设成0并不完全等同于确定性,因为模型后端可能还有top_k和重复惩罚等其他采样逻辑参与。
temperature和Prompt的关系,我习惯这样理解:Prompt负责框定“输出空间”,temperature负责在这个空间里做探索。如果模型在较低温度下的输出仍然不对,说明Prompt的约束没写到位,这时候加温度是雪上加霜。我在项目里常用的调参顺序是先固定temperature在0.3,把Prompt调到稳定,再按任务特点上下浮动温度。
| 任务类型 | temperature 建议 | top_p 建议 | 适用场景说明 |
|---|---|---|---|
| 抽取、分类、格式化 | 0.1 - 0.3 | 0.7 - 0.9 | 事实要准确,格式要稳定 |
| 摘要、翻译、改写 | 0.3 - 0.5 | 0.9 | 需要一定自然度,但不能天马行空 |
| 营销文案、创意写作 | 0.7 - 0.9 | 0.9 | 冒险多一点,允许低频词出现 |
这张表不是绝对标准,更像是我做项目时的参考基线。具体的数值会因模型而变,同样的temperature在不同代际的模型上,输出发散程度可能不同。所以表格里给了范围,没给死值。
4.2 top_p:核采样的截断策略
top_p是另一个采样旋钮,控制模型在生成时只考虑累积概率达到p的候选词集合。比如top_p=0.9,意味着模型只在概率排名前90%的候选词里采样。它和temperature一样作用于输出的随机性,但机制不同。temperature改变的是概率分布的“形状”,top_p改变的是候选集合的“范围”。
实操中,这两个参数可以配合,也可以各管一个。主流服务商一般不建议同时大改两个参数,典型做法是改一个。我个人的习惯是:用temperature做主要随机性控制,top_p固定为0.9作为安全网。如果模型在temperature较低时输出内容还是太杂,我会把top_p下调到0.8,缩小候选词集合。
top_p和Prompt协同的关键点在于约束密度。当Prompt里已经有明确格式约束时,top_p高一点也不会太危险,因为模型被JSON结构框死了;可当Prompt比较宽松时,top_p就是最后的刹车。反过来,如果输出过于呆板,不是只调top_p就能救回来的,回到Prompt里增加“用口语化表达”这一条约束往往更直接。
4.3 max_tokens:给输出留够空间
max_tokens是模型生成的最大token数。这个参数表面看只是长度限制,实际上它和输出完整性强相关。如果设得太小,模型在生成过程中被硬截断,经常出现半句话、半张表、没闭合的JSON括号。如果设得太大,浪费算力和等待时间,成本也要翻。
一个经验值是:按预期输出字符数的1.5到2倍来估计token上限。中文场景里,一个token大约相当于0.6到0.8个汉字,英文大约0.75个单词。比如你希望输出300字的商品描述,max_tokens设300到400比较稳。注意这个估算只覆盖正文,如果输出里还有Markdown符号、JSON键名、换行符,都会占token。
max_tokens还有一个容易被忽略的副作用:它影响模型对“完整回答”的决策。如果剩余token额度明显不足,模型会倾向提前收尾。所以在设计Prompt时,别在任务描述里要求“输出长篇大论”,同时把max_tokens调小,这等于给模型一个自相矛盾的目标。token额度要给足,但也不能给到完全无限制,因为在长输出里模型更容易累积重复。
4.4 一套可复制的参数调优封装流程
把三个旋钮组合起来,常规做法是写一个小函数,固定一个Prompt,快速跑几组参数看差异。我一般会这样封装:
def run_with_params(prompt, temp=0.3, top_p=0.9, max_tokens=500, times=5): outputs = [] for i in range(times): resp = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": prompt}], temperature=temp, top_p=top_p, max_tokens=max_tokens ) outputs.append(resp.choices[0].message.content) return outputs这个函数做的事情很简单:同一段Prompt,用同一组参数跑5次,返回一个输出列表。拿到列表后,我会人工或脚本检查三件事:格式是否都合法、内容长度是否稳定、关键信息是否出现。如果5次输出格式一致性低于80%,优先改Prompt;如果格式稳定但内容分散,再调温度。
调试顺序建议是:先固定temperature=0.3、top_p=0.9、max_tokens按预估给,跑出一组基线;然后单独拉高temperature到0.7跑一组,观察发散方向;再单独降低top_p到0.7跑一组,观察候选收窄效果;最后组合出一个最稳的参数组。这个过程每次改动只动一个变量,问题定位才不会嫁错对象。
还有个实际项目里常见的坑:不少人习惯把temperature和top_p联动调低,结果输出过度保守,改写任务的用词变得干瘪。这时候不是参数错了,而是Prompt里缺了“保持表达自然”的风格约束。参数调优和Prompt改写要交替进行,不是一条道走到黑。
5. 避坑指南:Prompt设计最常见的五个翻车现场
这一章记录我做提示词工程时翻过车、也看团队翻过车的地方。每一条都按现象、原因、解决三段来写,可以直接当排查手册用。这里的案例都来自真实调优场景,不是理论推演,参数和写法都能直接拿去对照。
5.1 现象:模型答非所问,回了一堆解释文字
现象:我让模型“输出三个具体建议”,它却先讲了一堆“建议的重要性”和“建议的维度分类”,到最后都没有给具体建议。原因:Prompt里没有明确“只输出建议本身”这一约束,而且任务动词是“谈谈建议”而不是“列出建议”。“谈谈”是一个开放动作,模型会把相关的背景知识一并输出。解决:把动作从“谈谈”改为“列出”,并在边界里加一句“不要输出建议的前置说明或总结”。
修复后的Prompt:
prompt = """任务:针对下述问题,列出三条可执行建议。 问题:{issue} 格式:每行一条,每条不超过30字。 边界:不要输出引言、解释或总结,直接给建议。"""这段修复的要点在于“直接给建议”这个边界放到了Prompt末尾,模型在读到边界时已经完成了前半段内容的编码,末尾指令会压住生成阶段的倾向。如果只改前面的动词不改边界,效果会差一截。
5.2 现象:输出格式不稳定,有时是JSON有时是正文
现象:同样带有“输出JSON”的Prompt,有时候返回的是代码块包裹的JSON,有时候是纯JSON,偶尔还混着解释文字。原因:模型训练数据里“JSON”这个词和代码块有强关联,光说“输出JSON”它可能默认带代码块。而“不要输出其他文字”没有放在格式约束同一行,导致优先级不够。解决:在格式定义后面直接加“输出裸JSON,不要使用Markdown代码块,不要输出任何解释”。
// 推荐写法 { "result": "严格输出上述JSON结构,不要Markdown代码块,不要任何其他文字" }注意这里我用注释来解释,实际Prompt里这个注释不要写进去,只是给阅读者看的。模型看到一个内嵌JSON样例时,会直接模仿样例的结构。配合的调试手段是:用程序检查输出是否由一对花括号完整包裹,如果不是,就触发重试一次。这种做法能掩盖大部分小概率的不稳定输出,但根本解法还是在格式约束里把“不要代码块”写死。
5.3 现象:模型一本正经地编造事实
现象:让模型总结一篇文档里提到的数据,文档里根本没有某个数值,模型却给出了一个合理但不存在的数字。原因:模型在生成时倾向于让回答“完整”,缺数据会触发补全机制。如果没有在Prompt里声明“缺失就写无”这个兜底,它就会编一个。解决:给所有需要事实的字段都增加“如果原文未提供,则输出null或unknown”的兜底说明。
prompt = """总结以下文档中提到的项目周期、预算和负责人。 文档:{document} 格式:JSON { "project_duration": "填写文档中的周期,原文未提及则写null", "budget": "填写文档中的预算,原文未提及则写null", "owner": "填写文档中的负责人,原文未提及则写null" } """这里的关键是每个字段都单独写了兜底,而不是在文档末尾统一写一句“没有的信息不要编”。单个字段写兜底,模型在生成每个字段时都要做一次“这个信息是否存在”的判断,兜底会更可靠。习惯了统一写兜底的团队,通常只会在第一层防住幻觉,字段级别的兜底才真正把幻觉概率压低。
5.4 现象:多轮对话越到后面越跑偏
现象:前几轮回答很精准,第8轮开始回答变得冗长且重复。原因:多轮对话里历史消息逐渐变长,模型的注意力被旧消息分散;加上中间轮次的assistant输出没做“只输出结果”约束,冗余内容被当成上下文重用。解决:定期压缩历史消息,把关键信息抽成一个固定格式的state,替代原始历史消息;同时要求中间轮次assistant只输出结果。
def compress_history(history: list, max_rounds: int = 6) -> list: if len(history) <= max_rounds * 2: return history latest = history[-max_rounds * 2:] summary_prompt = f"请压缩以下对话历史为一段摘要,保留用户需求和已确认结论:{history[:-max_rounds]}" summary = call_model(summary_prompt) return [{"role": "system", "content": f"对话历史摘要:{summary}"}] + latest这段代码的逻辑是在历史超过6轮之后,用一次模型调用把旧历史压成摘要,再替换掉旧消息。压缩后的摘要保留了用户的核心需求和已确认的结论,丢弃中间寒暄和冗余推理。每次压完摘要,token占用会大幅回落,模型的指令遵循能力也跟着回稳。
5.5 现象:指令里写了“不要”,模型反而照着做了
现象:明确写了“不要提到预算”,生成的文本里却出现了预算相关词汇。原因:有些模型对否定词的处理不稳定,它可能只关注了关键词“预算”而没有处理“不要”的语义。这个在较小的开源模型上更容易出现。解决:把否定表达改成肯定表达。“不要提到预算”改成“只讨论工期和范围”,让模型有明确的正面行为。
这是一条血泪经验。早期我写Prompt老是喜欢堆叠否定词,后来发现模型不是逻辑处理器,它是在玩概率补全,否定词在长文本里会被淡化。现在只要发现“不要”类约束失效,我会第一时间去检查能不能用一个肯定动作来替代。
判断否定词是否生效有一个简单方法:跑四五轮,看输入与输出的语义方向。只要连续出现输出往反方向跑的情况,就不必强行修补参数或指令结构,直接改成肯定句即可。这里的成本和收益不成比例,所以我的经验是永远把“不要”当作最后手段。
6. 把Prompt变成可复用资产:版本管理与评测方法
这一章收在工程方法上:Prompt不能当一次性字符串用完就扔。团队协作里,Prompt的迭代速度远高于模型版本,如果没管理好,一次回归失误就要耗费大量返工时间。
6.1 用版本表记录每次改动的实际影响
我给Prompt做版本管理的起点是一张表格,记录了版本号、改动位置、改动内容、影响指标。不要只记录“改成什么样了”,还要记录“为什么改”。有一次我为了提升输出格式稳定性把JSON样例改得更细,结果温度高了之后输出更长,导致max_tokens被截断。如果没有记录改动位置,这个根因会找不到。
| 版本 | 改动位置 | 改动内容 | 影响观测 |
|---|---|---|---|
| v1.0 | 初始版 | 角色+任务+格式 | 格式稳定率 78% |
| v1.1 | 边界 | 增加“不要代码块” | 格式稳定率 89% |
| v1.2 | 参数 | temperature 0.7→0.3 | 内容准确率 +6%,多样性下降 |
这张表的用途有两个:一是回滚,当新版本效果变差,能精确回到上一个版本而不是从头再调;二是沉淀,团队成员接手时能知道每个改动的背景。Prompt改动的评估周期我一般设为一周,因为有些问题要在足够多的真实流量里才能暴露。
6.2 建一个回归测试集,用固定用例守护质量底线
Prompt是代码,就该有测试。只有一条Prompt时靠感觉没问题,一旦同时维护5条以上的业务Prompt,回归测试就是必需品。我一般维护一个20到30条用例的回归集,覆盖不同类型的输入形态。
test_cases = [ {"case": "短输入", "input": "库存不足", "expect": "包含解决方案"}, {"case": "长输入", "input": "产品介绍全文1024字...", "expect": "输出包含核心参数"}, {"case": "特殊字符", "input": "A&B: 特价100%", "expect": "不出现Markdown解析错误"}, ] def run_regression(prompt_func, test_cases, n=5): for tc in test_cases: outputs = [prompt_func(tc["input"]) for _ in range(n)] pass_rate = sum(1 for o in outputs if tc["expect"] in o) / n print(f"{tc['case']}: pass_rate={pass_rate:.2f}")这段测试代码的逻辑是每个用例跑5次,统计通过率。通过的标准可以是包含某个关键词、JSON能被解析、或者长度不超限。注意“expect”字段不要写得过于严格,否则测试会在合理波动下误报,反而让人不再信任测试结果。通过率低于0.8,就说明Prompt在某个输入形态下不稳定,需要回到设计流程里去调。
6.3 我的最后一条习惯
我的习惯是每次上线一条新Prompt,强制自己写三个问题:如果用户只给五个词,它能输出什么;如果用户给一万字的文档,它会不会被淹没;如果用户没说任何格式要求,它会不会自己创造格式。这三个问题帮我挡住了大多数生产事故。提示词设计做到后面,比的不是谁掌握了更炫的技巧,而是谁愿意把指令当作正儿八经的产品资产来维护。希望帮到你。
本文还有配套的精品资源,点击获取