提示工程:技巧与范式 本节摘要:大多数人写提示词就像在给朋友发短信,然后纳闷为什么一个两千亿参数的模型给出的答案平庸。提示工程(Prompt Engineering)不是花招,而是理解一个事实——你发送的每一个 token 都是一条指令,而模型会字面意义上地执行指令。写出更好的指令,就能得到更好的输出。就这么简单,也这么难。本节将带你吃透提示工程的核心:一次 API 调用的三段式结构(系统消息/用户消息/助手预填充)、为什么「你是一个专家 X」能起作用(它是激活函数,不是咒语)、指令清晰度的五条规则、十种可跨模型复用的提示范式,以及跨模型提示设计的实战心法。读完本节,你能把模糊请求改写成精确指令,并用一个测试框架在多个模型间对比提示效果。
本节摘要:大多数人写提示词就像在给朋友发短信,然后纳闷为什么一个两千亿参数的模型给出的答案平庸。提示工程(Prompt Engineering)不是花招,而是理解一个事实——你发送的每一个 token 都是一条指令,而模型会字面意义上地执行指令。写出更好的指令,就能得到更好的输出。就这么简单,也这么难。本节将带你吃透提示工程的核心:一次 API 调用的三段式结构(系统消息/用户消息/助手预填充)、为什么「你是一个专家 X」能起作用(它是激活函数,不是咒语)、指令清晰度的五条规则、十种可跨模型复用的提示范式,以及跨模型提示设计的实战心法。读完本节,你能把模糊请求改写成精确指令,并用一个测试框架在多个模型间对比提示效果。
对应原课程:Phase 11 · Lesson 01 ·
prompt-engineering(原英文phases/11-llm-engineering/01-prompt-engineering/docs/en.md)。本节为中文改编样章,演示后续批量汉化的标准写法。
阅读完本节,你应当能够:
你打开 ChatGPT,输入:「给我写一封营销邮件」。你得到的是泛泛的、臃肿的、不能用的东西。你再加细节,好一点,但还是不对。你花 20 分钟反复改写同一个请求。
这不是模型的问题,是指令的问题。同一个任务,两种写法:
模糊提示:
给我们的新产品写一封营销邮件。
工程化提示:
你是一家 B2B SaaS 公司的资深文案。为 DevFlow(一款 CI/CD 流水线调试工具)写一封产品发布邮件。 目标读者:B 轮初创公司的工程经理。 语气:自信、技术向、不推销。 长度:150 字。 包含一个具体数据(流水线调试速度提升 3.2 倍)。 以单个 CTA(链接到演示页)结尾。 只输出邮件正文,不要主题行建议。
第一个提示激活的是模型训练数据里「营销邮件」的通用分布;第二个激活的是一个狭窄、高质量的切片。同一个模型、同样的参数,输出天差地别。
「你问的」和「你得到的」之间的这道鸿沟,就是整个提示工程学科。它是人类意图与机器能力之间的主接口,也是更大的「上下文工程(Context Engineering)」(本系列第 05 节)的一个子集——后者管的是进入上下文窗口的所有东西,不只是提示本身。
💡 提示工程没有死。说它已死的人,和 2015 年说 CSS 已死的是同一批人。变化在于它成了入场券——每个认真的 AI 工程师都需要它,问题不是「要不要学」,而是「学到多深」。
每次 LLM API 调用都有三个组件,理解各自的作用会改变你写提示的方式:
system_instruction 当作独立的生成配置字段,而非一条消息。{"role":"assistant","content":"```json\n{"},模型就会接着往下写,直接产出 JSON 而无前言。Anthropic 原生支持,OpenAI 不支持(改用结构化输出)。「你是一个资深 Python 开发者」不是魔法咒语,它是激活函数。
LLM 在数十亿文档上训练,这些文档里有业余者和专家的文字、有 0 赞的 Stack Overflow 回答也有 5000 赞的。当你说「你是一个专家」时,你在把模型的采样分布偏向训练数据中「专家」那一端。
具体的角色优于泛泛的角色:
| 角色提示 | 激活的是什么 |
|---|---|
| 「你是一个有帮助的助手」 | 通用、中等质量的响应 |
| 「你是一个软件工程师」 | 更好的代码,但仍宽泛 |
| 「你是一个 Stripe 专攻支付系统的资深后端工程师」 | 窄、高质量、领域特定 |
| 「你是一个在 LLVM 上工作了 10 年的编译器工程师」 | 激活某主题的深度技术知识 |
角色越具体,分布越窄,质量越高——但有上限。如果角色具体到很少有训练样本匹配,模型就会幻觉。「你是量子引力弦拓扑学世界第一专家」会产出自信的胡说八道,因为这个交叉点几乎没有高质量文本。
提示工程的第一大错误,就是该具体时却模糊。提示里每一处含糊,都是模型去猜的分支点——有时猜对,有时猜错。
改写前(模糊):
总结这篇文章。
改写后(具体):
用恰好 3 个要点总结这篇文章。每个要点一句话,最多 20 字。 聚焦定量发现,而非观点。面向技术读者。
模糊版可能产出 50 字段落、500 字长文或 10 个要点;具体版约束了输出空间——有效输出越少,得到你想要的那个的概率越高。
指令清晰的五条规则:
约束是护栏。没有它们,模型会做它「以为有用」的事,而那往往不是你需要的。
温度控制随机性,是提示之外影响最大的单一参数。
| 设置 | 温度 | Top-p | 用例 |
|---|---|---|---|
| 确定性 | 0.0 | 1.0 | 数据抽取、分类、代码生成 |
| 保守 | 0.3 | 0.9 | 总结、分析、技术写作 |
| 平衡 | 0.7 | 0.95 | 通用问答、解释 |
| 创意 | 1.0 | 1.0 | 头脑风暴、创意写作 |
| 混乱 | 1.5+ | 1.0 | 生产环境绝不要用 |
Top-p(核采样)是另一个旋钮,把采样限制在累计概率超过 p 的最小 token 集合里。用温度或 Top-p,不要同时用——两者交互不可预测。
⚠️ 上下文窗口的大小不如用法重要。一个 1 万 token、90% 是有效信号的提示,胜过一个 10 万 token、只有 10% 有效信号的提示——更多上下文意味着注意力机制要过滤更多噪声。这正是上下文工程(第 05 节)是更大学科的原因。
下面十种范式跨模型通用。它们不是复制粘贴的模板,而是要因地制宜的结构模式。
1. 角色范式(Persona) —— 用具体角色激活专家分布。
2. 模板范式(Template) —— 让模型按命名槽位填充结构。
3. 元提示范式(Meta-Prompt) —— 让 LLM 为另一个任务写提示。
4. 思维链范式(CoT) —— 强制先推理再作答,提升 1040% 准确率。
5. 少样本范式(Few-Shot) —— 给 210 个输入输出示例锚定格式。
6. 护栏范式(Guardrail) —— 用规则限定模型行为边界。
7. 分解范式(Decomposition) —— 把复杂问题拆成子问题再合并。
8. 批判范式(Critique) —— 先生成,再自评,再改进。
9. 受众适配范式(Audience Adaptation) —— 为不同读者调复杂度。
10. 边界范式(Boundary) —— 硬性限定回答范围,越界即拒答。
💡 反范式警示:① 提示注入(用户输入覆盖系统提示,无 100% 有效的缓解);② 过度约束(规则太多,模型把算力花在守规矩而非做事上,系统提示尽量控制在 500 token 内);③ 矛盾指令(「要简洁」又「要覆盖每个边界情况」,模型无法两全,会随机选一个);④ 假设模型特有行为(在 ChatGPT 有效不等于在 Claude/Gemini 有效,要跨模型测试)。
最好的提示是模型无关的——在 GPT、Claude、Gemini 和开源模型(Llama、Qwen、DeepSeek)上几乎不用调就能用。心法:
我们把上述概念落到一个可运行的 Python 测试框架:一个范式库 + 一个提示构造器 + 一个多模型测试器 + 一个评分器。完整代码见原课程 code/prompt_engineering.py,这里给出关键骨架。
把十种范式定义为带元信息的字典,每个范式有名字、模板、变量、推荐温度:
PROMPT_PATTERNS = { "persona": { "name": "角色范式", "template": "你是{role},具备{experience}。\n" "你的沟通风格是{style}。\n" "你优先{priority}。\n\n{task}", "variables": ["role","experience","style","priority","task"], "temperature": 0.7, }, "few_shot": { "name": "少样本范式", "template": "这是期望的输入/输出格式示例:\n\n{examples}\n\n现在处理这个输入:\n{input}", "variables": ["examples","input"], "temperature": 0.0, # 抽取类任务用 0 温度保证稳定 }, "chain_of_thought": { "name": "思维链范式", "template": "请逐步思考。\n\n问题:{problem}\n\n步骤:\n" "1. 识别关键组件\n2. 分析每个组件\n" "3. 综合发现\n4. 给出结论\n\n给出最终答案前先展示推理。", "variables": ["problem"], "temperature": 0.3, }, # ... 其余七种范式同理:template_fill / critique / guardrail / # meta_prompt / decomposition / audience_adapt / boundary }
设计要点:把提示当作数据而非散落的字符串,是工程化的第一步。这样版本管理、A/B 测试、变量校验都能复用通用工具。
按范式名填充变量,组装成完整的消息结构(系统 + 用户 + 可选预填充):
def build_prompt(pattern_name, variables, system_override=None): pattern = PROMPT_PATTERNS[pattern_name] missing = [v for v in pattern["variables"] if v not in variables] if missing: raise ValueError(f"缺少变量: {missing}") rendered = pattern["template"].format(**variables) system = system_override or f"你是一个使用{pattern['name']}的 AI 助手。" return {"system": system, "user": rendered, "temperature": pattern["temperature"]}
按字数、关键词覆盖、禁用短语、格式合规打分,并算出综合分:
def score_response(text, criteria): s = {} if "max_words" in criteria: n = len(text.split()) s["length_compliant"] = n <= criteria["max_words"] if "required_keywords" in criteria: found = [k for k in criteria["required_keywords"] if k.lower() in text.lower()] s["keyword_coverage"] = len(found) / len(criteria["required_keywords"]) if "expected_format" in criteria and criteria["expected_format"] == "json": try: json.loads(text); s["format_valid"] = True except: s["format_valid"] = False # 综合分 = 所有 bool/float 字段的均值 vals = [v for v in s.values() if isinstance(v,(bool,float))] s["composite_score"] = round(sum(1.0 if v is True else v for v in vals)/len(vals), 3) return s
把同一个提示发给多个模型(用 provider 抽象屏蔽 API 差异),收集响应、token、延迟,再按 criteria 排名。原代码用 simulate_llm_call 模拟响应,实际使用时替换成真实的 OpenAI/Anthropic/Google HTTP 调用即可,框架其余部分无需改动。
💡 这套框架的真正价值不在「跑通」,而在可复现——temperature=0 下,同一个提示对同一模型给出同样的输出,你才能客观比较「改了这条规则后,输出到底变好还是变坏」。
# client.chat.completions.create( # model="gpt-5", temperature=0.0, # messages=[{"role":"system","content":"你是资深 Python 开发者,只输出代码不解释。"}, # {"role":"user","content":"写一个找最长回文子串的函数。"}])
OpenAI 的系统消息最先处理、获高注意力权重;temperature=0 使输出确定性——对测试与复现至关重要。
# client.messages.create( # model="claude-opus-4-7", temperature=0.0, # system="你是数据抽取引擎,只输出合法 JSON。", # messages=[{"role":"user","content":"抽取:张三,34 岁,2019 起在谷歌任资深工程师。"}, # {"role":"assistant","content":"{"}]) # ← 预填充 # result = "{" + response.content[0].text
助手预填充("{")强制 Claude 接着产出 JSON 而无前言——这是 Anthropic 独有特性,比基于提示的 JSON 请求更可靠。
# model = genai.GenerativeModel("gemini-2.5-pro", # system_instruction="你是技术分析师,要精确并引用来源。", # generation_config=genai.GenerationConfig(temperature=0.3, max_output_tokens=2048))
Gemini 把系统指令作为模型配置而非消息处理;200 万 token 上下文意味着你能塞进 GPT/Claude 装不下的海量少样本示例。
# prompt = ChatPromptTemplate.from_messages([ # ("system","你是{role},用{format}回答。"), # ("user","{question}")]) # chain_openai = prompt | ChatOpenAI(model="gpt-5", temperature=0) # chain_claude = prompt | ChatAnthropic(model="claude-opus-4-7", temperature=0)
写一份提示模板,跨厂商运行——这是「跨模型提示设计」的工程落地。
本节产出两个可复用文件(位于原课程 outputs/):
prompt-prompt-optimizer.md:一个元提示,接收任何草稿提示,用本节十种范式重写。喂给它模糊提示,得到工程化提示。skill-prompt-patterns.md:一个决策框架,根据任务类型、所需可靠度、目标模型选择合适的提示范式。Python 代码(code/prompt_engineering.py)是独立测试框架,把 simulate_llm_call 换成真实 API 调用即可投入生产,范式库、构造器、评分器、对比逻辑均无需修改。
补全测试套件:给 TEST_SUITE 再加 5 个用例覆盖剩余范式(元提示、分解、批判、受众适配、边界),跑全套,找出哪个范式跨模型得分最一致。
接真实 API:把 simulate_llm_call 换成至少两家厂商(OpenAI + Anthropic 免费额度)的真实调用,对同一提示测量响应长度、格式合规、关键词覆盖、延迟,记录哪家更听话。
提示注入测试:写 10 条对抗性输入(如「忽略之前的指令……」)测试护栏范式,统计成功率,提出缓解方案。
提示优化器:给定提示与评分标准,用 temperature=0.7 跑 5 次、评分、找最弱项、改写提示,迭代 3 轮,观察分数是否提升。
提示 diff 工具:给定两个版本的提示,识别改动(加约束/删示例/改角色/改格式),预测质量升降,再用真实输出验证预测。
下一节,我们将进入「少样本、思维链、思维树」——把本节的静态范式升级为引导模型多步推理的动态模式。