
简介这份PDF是Google出品的提示工程白皮书面向具备编程基础、希望系统提升大语言模型交互效果的开发者、数据科学家与机器学习工程师。内容从LLM输出配置讲起明确Temperature、Top-K与Top-P等参数如何影响生成结果随后梳理零样本、少样本、系统提示、角色提示、思维链、思维树及ReAct等常用提示技巧并专章介绍代码生成、解释、调试与审查的提示写法以及自动提示工程APE和多模态提示。资源共1个PDF文件压缩包约1018KB篇幅完整但轻量适合通读或按需查阅。文档中穿插大量实例与代码片段给出保持简洁、明确输出要求、优先使用指令而非限制条件等最佳实践可帮助读者将提示调优落地到文本生成、代码编写、数据解析等具体任务中。目前已有394人学习下载是一份兼顾概念与实操的提示工程速查参考。1. 一份Google风格的提示工程PDF为什么大多数人都把提示词写成了玄学同样是让大模型写一段能跑的代码有人回车三次就拿到结果有人来回对话十几轮还在抱怨“模型不听话”。差别不在模型多半在提示词。我拿到这份《google提示工程.pdf》后最大的感受是它把提示工程从“靠灵感碰运气”变成了一条可复现的路径怎么分层写指令、怎么设计少样本、怎么让模型先思考再回答、怎么自动搜索更好的提示词每个环节都有模板和参数说明。它不是学术论文是给做 LLM 应用、写代码生成工具、天天调 Prompt 的工程师准备的操作手册。接下来我按自己的实操顺序拆解这份 PDF先讲模型输入端的基本前提再说代码生成和思维链的具体写法然后列出最容易翻车的五个坑最后给一套能证明“提示词改得值不值”的评测方法。2. 动手前先补基础三个事实决定提示词该怎么写读这份 PDF 最大的收获其实是它先纠正了一个心态提示工程不是靠灵感碰运气而是建立在模型工作原理上的可控过程。我不建议直接跳到后面的模板先把这三个基础事实过一遍后面所有模板你都能自己改出理由而不是照着抄。2.1 事实一模型输出是概率采样提示词就是可控偏置大语言模型在处理你的提示时做的并不是“查答案”而是把提示拆成 token 序列然后逐步预测下一个 token 的概率分布。温度temperature和 top_p 控制的就是这个分布的采样行为温度越高分布越平输出越“发散”温度越低越倾向于高概率 token输出越保守。提示词的本质是在生成之前就改变这个条件分布——你写进 prompt 的每一个字符都在让某些答案的路径更容易被选中。我一直把模型当成一个“根据前缀续写概率的黑匣子”提示词就是我能伸进黑匣子的唯一旋钮。# 大多数模型 API 都暴露了 temperature 和 top_p 参数 response client.chat.completions.create( modelgpt-4o-mini, # 换成你实际使用的模型即可 temperature0.2, # 结构化任务压低代码生成建议 0~0.4 top_p0.9, # 与 temperature 二选一微调不必两个都动 max_tokens2048, # 给足代码输出空间但别超过上下文限制 messages[ {role: system, content: 你是 Python 代码生成助手只输出可运行代码。}, {role: user, content: 写一个读写 CSV 的函数要求处理文件不存在的情况。} ] )这块的逻辑系统消息先定义了模型的行为底盘用户消息再给出具体任务。temperature 参数直接影响概率分布的“随机性权重”做代码生成时我一般固定在 0 到 0.4 之间top_p 做的是另一种截断采样控制累积概率阈值。不要同时大幅度动两个参数否则输出方差会被放得很大后续排查分不清是谁的锅。这份 PDF 里有一张参数对照表核心结论就一句话先固定参数再调提示词否则你所有改动都混在随机噪声里根本看不出效果。2.2 事实二结构化指令影响注意力分配顺序不是玄学同样的一句话放在系统提示里和夹在长篇上下文中效果完全不同。模型的注意力机制对位置和格式敏感放在最前面的指令会成为它解释后续内容的基础被淹没在中间的要求很容易被跳过。所以我的提示词固定分四层角色、任务、约束条件、输入数据。这个分层方法其实就是从这份 PDF 里抄来的我的实际体感是按这个顺序写出来的 prompt比想到哪写到哪的版本稳定很多。prompt f 你是资深后端工程师精通 {language}代码要可维护、可测试。 任务{task_description} 约束 - 只输出代码和必要注释 - 不要修改公共接口签名 - 兼容 Python {python_version} - 输入为空时返回合理默认值 输入示例 {input_example} 每一层承担的功能不一样角色层决定了模型调用哪部分知识体系任务层给出明确目标约束层限制方案的边界输入层提供具体数据。PDF 里把中间三层的顺序做了对比实验结论是“任务在约束之前、约束在输入之前”比反序更稳。我自己的经验也差不多——约束太靠后容易被长输入抢占注意力导致模型光顾着分析输入忘了遵守接口限制。2.3 事实三输出格式必须写进提示否则会收获自由发挥自由文本输出对于人读可能还行但对程序处理是个灾难。做 LLM 应用第一步就是要让输出结构的 schema 稳定。如果你不告诉模型“给我 JSON”它会很自然地把答案写成一封礼貌的信。代码生成同理不指定“只输出代码块”它就会在代码前后加解释下游脚本做拼接时就抓狂。prompt f 分析下面单据提取关键信息并输出 JSON {{ company_name: 客户公司名, total_amount: 总金额数字, currency: 币种, risk_level: high | medium | low } 不要输出 JSON 以外的任何文字。 单据内容 {document_text} # 下游解析先抽 JSON 再反序列化 import json, re def parse_llm_json(raw: str) - dict: match re.search(r\{.*\}, raw, re.S) # 等一等这里要配合提示词里的 JSON 标记 if not match: raise ValueError(no json found) return json.loads(match.group(0))这个代码引出一个关键做法提示词里给出 JSON 模板解析时就按模板字段取下游只认键名不认格式。我在实际工程里还会在提示词里加一对标记类似BEGIN_JSON和END_JSON这样正则抽取的成功率能从八成提升到接近满格。格式稳定之后你才敢把模型输出接进后续流程否则每次返回结构都不一样接口根本没法写。3. 代码生成实战把需求翻译成准确代码的三种提示写法代码生成是提示工程里最实用也最容易出成果的场景。你可能已经发现直接甩一句“帮我写个爬虫”给模型它给你一个能跑但漏洞百出的版本。这不是模型蠢而是你给的目标函数太模糊。把提示词写成下面三种形态代码生成的可用率会明显提升。3.1 先做需求澄清别让模型一上来就猜实现需求描述不清是代码生成翻车的最常见原因。产品说“写个分页查询”这里既没有说清排序字段也没有说明参数名。我现在的做法是在正式生成代码前先让模型给出一组澄清问题用户回答之后再带着边界条件去生成代码。def build_clarifier_prompt(raw_requirement: str) - str: return f 你负责把需求转写成可执行的开发任务。下面这条需求描述不完整 请按清单提问 - 输入输出边界 - 排序与去重规则 - 错误处理方式 - 依赖与版本约束 需求{raw_requirement} 只输出问题清单不要输出代码。 这一步的逻辑是把“模糊需求”转化为“精确需求”让模型自己参与对话式的需求收敛。第二次调用时把用户澄清过的约束拼进完整 promptfinal_prompt f 需求{raw_requirement} 边界条件 {answers_from_user} 请输出 1. 完整实现代码 2. 三条核心边界用例的测试断言 参数上第一次调用 temperature 可以设到 0.5因为我们需要模型发散提问第二次生成代码时降到 0.2保证实现稳定。max_tokens 给足到 2048 以上否则代码写一半被截断回来又是一轮排错。这一步最容易被忽略但很多“模型乱写”的现场追根溯源都是需求没对齐。3.2 少样本示范法正误对照比只给正确代码更稳纯零样本让模型写代码它容易走典型套路给一个正确示例它会模仿结构给一组“正确 错误”的对照它会开始理解边界。这份 PDF 里强调了少样本的关键不是数量而是覆盖度。我用下来最有效的组合是“一个正确样本 一个常见错误样本 一句错误原因”。few_shot_prompt 翻译需求为 Python 函数实现。 示例 1正确 需求给定商品价格列表 prices返回按价格从小到大排序且去重的列表。 实现 def sort_and_dedupe(prices): return sorted(set(prices)) 示例 2常见错误 需求同上。 错误实现 def sort_and_dedupe(prices): return list(set(prices)) # 漏了排序测试会失败 新需求给定用户订单列表按订单金额降序取前 N 条金额相同按时间升序。 实现 这里的逻辑是给模型一个“正确路径”和一个“错误路径”模型在续写时会更刻意避开错误路径。注意错误示例的注释不能太长两三句说明白就行否则模型会把注意力放在错误分析上反而写不出代码。少样本代码生成时我把 temperature 设为 0.1目的就是最大程度复用示例里的结构而不是让模型自由发挥。3.3 把测试用例写进提示让代码自己过一遍校验提示工程里最能提升代码可用率的其实是把验收标准提前。与其让模型猜“什么算写完”不如直接把断言塞进提示让它对着测试生成实现。这个做法来自工程里的 TDD 思路移到提示词里同样成立。prompt f 请实现 merge_intervals 函数输入是形如 [(1,3),(2,6),(8,10)] 的区间列表 返回合并后不重叠的区间列表。 要求代码必须通过以下断言 assert merge_intervals([(1,3),(2,6),(8,10)]) [(1,6),(8,10)] assert merge_intervals([(1,4),(4,5)]) [(1,5)] assert merge_intervals([]) [] assert merge_intervals([(1,2),(3,4)]) [(1,2),(3,4)] 只输出实现代码不要解释。 用下来效果最好的流程是生成代码后先本地跑一遍断言如果失败把失败信息原样追加到对话上下文再让模型修一次。这样模型能看到它输出的真实后果而不是凭空猜哪里错了。这个“生成—运行—报错反馈—再生成”的闭环本质上就是提示工程版的调试循环。4. 思维链让模型“先想后答”的工程化写法思维链Chain of Thought可能是提示工程里被讨论最多、也最容易被误用的技巧。很多人以为只要在 prompt 里写“请一步一步思考”准确率就一定涨。实际不是这样它只对需要多步推理的任务有明显帮助对短问答反而可能画蛇添足。4.1 原理中间推理结构给了模型更多计算步骤模型是逐 token 续写的复杂任务需要的中间计算结果如果不在生成序列里出现模型就只能靠内部“一次成型”很容易漏掉步骤。思维链的本质是让模型把中间结果写到输出序列里这样每一步都能基于前面已经算出的 token 继续推。我写过一组对比测试让模型直接算“一件商品原价 980 元打八折再减 45最后售价多少”准确率在六成左右加上“先计算打折价再减去 45”的推理引导后准确率直接到了九成以上。prompt f 输入一件商品原价 980 元先打八折又降价 45 元最后售价是多少 请先写出计算步骤再给出最终答案。 这个提示词看起来简单但核心在于“请先写出计算步骤”这句话。它把模型的输出路径从“直接给答案”扭转成“先列中间量”而中间量的存在价值就是给后续每一步提供了一个确定的参照点。不过要注意这条技巧只对多步计算、逻辑推理、复杂生成这类任务有效像“这句话有没有语法错误”这种单步判断加了思维链反而会引入不必要的横生枝节。4.2 少样本思维链的构造示例里要有完整的推理层零样本思维链效果不稳定少样本思维链才能把“怎么想”的格式固定下来。关键在于示例里不能只有问题和答案必须把中间的推理步骤也写出来模型才能学到那种思考模式。完整的示例结构是“输入—推理—答案”三段式。few_shot_cot f 示例 1 输入一支笔 2 元买 5 支再买一本 15 元的本子总共多少钱 推理5 支笔的总价是 2 * 5 10 元加上本子 15 元总共 10 15 25 元。 答案25 元 示例 2 输入甲乙两地相距 240 公里车速 80 公里/小时中途休息 20 分钟问全程耗时多少分钟 推理行驶时间 240 / 80 3 小时 180 分钟加上休息 20 分钟总共 200 分钟。 答案200 分钟 新输入一个梯形上底 6 厘米下底 10 厘米高 4 厘米面积是多少 推理步骤不用写得很学术重点是它展现了“先算局部再汇总”的顺序。少样本数量控制在 2 到 3 个就够太多会拉长 prompt反而挤压模型输出的空间。这类任务 temperature 设 0因为思维链示例本身已经在定义路径随机扰动只会增加噪声。4.3 输出拆解与长度控制既要推理又要答案格式稳定思维链最大的副作用是输出变长、格式变散。模型可能在推理过程中顺带把答案写进某个句子里导致下游解析无从下手。解决办法是在提示词里强制划分“推理区”和“答案区”用显式标签把两部分隔开。prompt f 请按以下格式输出 reasoning 在这里写推理过程简洁一点。 /reasoning answer 在这里写最终答案必须是独立完整的数字或句子。 /answer 输入{problem} 对应解析端可以用一个很简单的正则把 answer 取出来import re def extract_answer(raw_output: str) - str: match re.search(ranswer(.*?)/answer, raw_output, re.S) return match.group(1).strip() if match else 这里的逻辑是先把“思考”和“交付物”解耦推理区写给模型自己持续计算用答案区写给下游解析用。max_tokens 也要相应调高给推理区留出余量但可以限制整个输出长度防止模型在推理区没完没了地写。我一般把 max_tokens 设为推理预期长度的 1.5 倍够用但不失控。5. 避坑与常见问题五条踩坑记录与对应的提示修正这部分是血泪经验汇总。提示工程看着灵活其实每一条改动背后都有代价。下面五个坑是我和团队在实际项目里都真踩过的每条按“现象—原因—解决”梳理方便你对照排查。5.1 提示词越长越“全”效果反而越差现象一开始我以为把需求、背景、格式、示例全塞进去更保险于是写了一条 600 多字的 prompt模型返回的代码反而漏掉了最关键的异常处理。原因太长之后关键约束在 token 序列里被稀释注意力被大量“背景资料”带走核心指令失去权重。解决把 prompt 压缩成“角色 任务 约束 输入”四段背景资料放进单独的上下文区并且最多保留两段。处理这种情况要用“先摘要后执行”的思路让模型先对上下文做三句话摘要再执行主任务输出更稳定。5.2 礼貌用语越足输出越“滑”现象我在英文和中文场景都试过“请帮我”“谢谢”“麻烦了”部分模型会回撤成更客套、空泛的文本尤其在代码生成里。原因客套词也是 token会软化指令的约束性质模型倾向于“像一句礼貌回应一样”地接续而不是“像一条指令一样”地执行。解决常规生成任务里把提示词写成中性命令式代码生成不需要礼貌用语只有伦理边界类任务才需要额外措辞。5.3 少样本全是“标准答案”泛化能力就崩现象我做过一组测试给模型两条完美示例它能把所有输入都往那两个模板上靠给一个正确示例加一个常见错误示例反而学会了判断边界。原因少样本的真正作用是定义“分布”只给正例等于把分布压到太窄。解决对每个典型难度档保留一个“正确示例 错误对照”错误对照只要一行注释说明为什么错就够不要写成大段分析。5.4 思维链输出解析失败答案乱到没法用现象让模型“请逐步思考”它确实逐步了但最终答案埋在一堆叙述里正则能抓到一堆无关数字。原因思维链天然鼓励叙述如果不单独约定答案格式最终答案就随叙述漂移。解决在提示里规定“推理写在reasoning里最终答案写在answer里”并用解析脚本把 answer 块提出来。原则永远是先约定格式再开思维链顺序反了就是给自己挖坑。5.5 参数照搬默认值提示词怎么调都像在抽卡现象默认温度 0.7 跑代码生成同一段需求每次返回的变量名都不一样测试用例跟着失效我又试了 temperature 0结果模型总是返回同一个方案完全丢失了合理多样性。原因不同任务对随机性的容忍度完全不同代码生成偏确定性创意写作才需要更高温度。解决按任务固定参数并在每次评测里记录用的是什么温度temperature 和 top_p 两个参数只动一个避免它们叠加作用让输出方差失控。6. 进阶落地搭一套最小评测集验证提示改动到底值不值前面几章都在讲怎么把提示词写得更准但这里有个更重要的工程问题你怎么知道一条改动是真变好了还是刚好碰上这次运气好如果不解决这个问题提示工程就永远停留在“感觉论”阶段。我的建议是从这份 PDF 里学到的第一件事就应用到实践——搭一套最小评测集让提示词改动有数据可复盘。6.1 构建 10~20 条固定用例的评测集不用一上来就搞几百条10 到 20 条覆盖典型难度的用例就够用了。关键是每条用例都要有明确的“输入—期望行为—通过标准”。我习惯用表格维护像下面这样用例输入期望行为通过标准基本调用calculator(add, 3, 5)返回 8断言相等边界输入calculator(divide, 10, 0)返回错误提示不崩溃断言异常类型空列表calc_mean([])返回None或约定默认值断言返回值格式稳定性任意问题输出可被parse_json解析断言解析成功评测集建立之后不要频繁动它一旦改动提示词就固定跑这一套结果才能横向比较。6.2 指标计算与回归记录每次改动都要有可比数据评测不是看一眼输出好不好就行要换算成数字指标。最常用的三个指标通过率、格式命中率、平均输出 token 数。通过率表示功能正确程度格式命中率表示下游可解析程度token 数是衡量成本三个指标一起看才完整。def evaluate_prompt(prompt_fn, cases): passed 0 for case in cases: code prompt_fn(case[requirement]) result run_with_asserts(code, case[test_code]) if result[pass]: passed 1 return passed / len(cases)这个函数的逻辑是把“提示词生成代码”和“代码过测试”两件事绑定起来。参数上每个用例的 test_code 必须固定不能跑过了再改断言评价时模型的 temperature 也固定在同一个值否则随机性会把真正的影响盖住。我自己的操作方式是每次改动只动一个变量——要么只改提示词要么只改参数绝不同时改两处。6.3 自动提示工程在评测中的落地用法有了评测集自动提示工程APE才真正有用武之地。它把提示词本身当成搜索对象让算法在有限的候选区间里做小步变异调整指令顺序、替换示例、增加约束每轮用评测集的得分做筛选。评分函数就是 6.2 里的通过率指标。# 伪代码展示自动提示搜索的核心循环 candidate seed_prompt for epoch in range(20): variants mutate(candidate) best_score 0 for v in variants: score evaluate_prompt(make_prompt_fn(v), eval_set) if score best_score: best_score score candidate v这里的 mutate 可以是“加一条约束”“换一个示例”“改一种措辞”但每次只变异一个维度否则分不清哪个动作带来了提升。自动搜索的价值不是取代人工设计而是让人从“逐条试错”里解放出来把精力放在定义评测集和通过标准上。评测集质量决定了自动搜索的上限——如果通过标准定义错了搜索出来的提示词再准也只是在错误方向上跑得很远。从那以后我每次调整提示词都会先回到评测集跑一遍旧提示和新提示记录温度、通过率、输出 token 数、失败用例再决定要不要替换。前一百次改提示靠感觉后续全是靠数据。这份 PDF 里最值钱的就是那套可以直接抄走的模板但模板背后这一整套“先有基线、再改动、最后对比”的方法你自己动手写一遍才算真正接住了。希望帮到你。本文还有配套的精品资源点击获取