同一个大模型,为什么在不同人手里效果差别巨大?有人把它当成“高级搜索框”,一问一答就结束;有人却能用它产出结构化数据、稳定代码,甚至搭起一个业务原型。真正拉开差距的,往往不是模型本身,而是提示词工程这项基本功。
如果你已经写过几条 prompt,也看过一些“提示词模板大全”,却依然觉得输出不稳定、格式不可控、规则一多就失灵、换个场景就失效,那么这篇文章就是为你准备的。接下来会按一个两小时的学习节奏,把提示词工程从概念、原理、实操到排错完整过一遍,重点不是列模板,而是让你具备自己设计、调试和迭代提示词的能力。
先给一个明确判断:提示词工程不是“怎么跟 AI 聊天”的话术,而是人与大模型之间的接口设计。它和软件工程里的 API 设计、协议设计一样,需要关注输入结构、输出约束、错误处理、版本演进,最终会变成团队级工程能力,而不是某个人手里的感觉。
两小时怎么分配:前 45 分钟搞清楚核心概念与运行机制,中间 60 分钟跑通一组完整示例代码,最后 15 分钟对照常见问题做排查。建议你准备一个能调用大模型 API 的环境,边看边试,效果远比只读文章好。
1. 为什么提示词工程突然成了必修课
很多开发者在第一次接触大模型时,会觉得提示词很简单:“模型都这么聪明了,我自然说话就行,何必刻意设计?”但一旦进入真实业务,问题就来了。
举个例子:你想让模型从一段招聘 JD 中抽取薪资范围、技能要求和学历门槛。第一次写提示词,模型可能老老实实输出一段散文,你可以看懂,但程序没法解析。你在后面加一句“请输出 JSON”,模型可能会照做,也可能偶尔在前缀补一句“好的,这是您需要的 JSON:”。运行一个晚上,程序崩溃三次,排查后发现是 JSON 前后多了说明文字。
再复杂一点:你希望模型先当“客服意图分类器”,再当“数据清洗工具”,最后还能写代码。如果只用一句万能提示词切换角色,模型很容易被用户的措辞“带节奏”,说好的规则被两句反问就绕开。此时你已经不是“不会聊天”,而是缺少一套系统设计提示词的方法。
提示词工程之所以在这两年迅速变成必修课,原因有三:
第一,模型能力再强,也需要显式的任务边界。模型本身是概率生成,它不知道你的业务希望它输出什么格式、多大长度、是否可以发挥。你不说,它就按训练数据中最常见的形态作答。第二,同样一个模型,提示词设计的差距可以造成 20% 到 50% 的效果差异。这在自动化场景里是可用与不可用的差别。第三,越来越多项目开始把大模型嵌入生产流程,提示词不再是一次性对话,而是需要被评测、维护、回归的工程资产。
从更宏观的角度看,”提示词工程“正在和”上下文工程“、”Agent Skill 体系“一起构成大模型应用开发的知识地图。只看提示词本身是不够的,还要理解模型输入侧还有哪些可以控制的东西。
2. 提示词、上下文、Agent 与 Skill:概念先分清
很多初学者把”提示词工程“理解成一个很宽泛的词,好像只要是大模型相关的输入优化都属于它。真正的技术社区里,这几个概念已经分化得很清楚了。
2.1 什么是提示词和提示词工程
提示词(Prompt),指的是你传给大模型的一整段输入,通常包括系统消息、用户消息、历史消息,也可能包含示例。提示词工程,则是设计、调试、优化这段输入的方法论,目标是让模型在可控成本下稳定产出符合预期的结果。
注意,提示词不是“一句话”,而是一个结构化的东西。尤其是在 Chat 类模型中,messages 数组里的角色和顺序,本身就是提示词的结构。
2.2 从提示词工程到上下文工程
上下文工程关注的是“模型在这一轮请求里到底能看见什么”。大模型有上下文窗口,窗口不是无限大,也不是塞得越多越好。上下文工程做的事情包括:
- 从知识库中检索最相关的片段,再拼进提示词;
- 对长对话做摘要、压缩,放不下的历史先归纳成要点;
- 对上下文内容排序,把重要指令放在更容易生效的位置;
- 控制 token 消耗,防止长文本把预算烧光。
提示词工程更关注“怎么问”,上下文工程更关注“喂什么”。“喂什么”其实是比“怎么问”更前置的问题。如果你的知识库内容不相关、指令被埋在一堆噪音里,措辞再漂亮也没用。
2.3 系统提示词和 Skill 有什么区别
系统提示词(System Prompt)是 messages 数组里 role 为 system 的那条消息,通常用来设定模型的身份、任务边界和输出规则。你可以把它理解成“初始化配置文件”。
Skill 是从 Agent 框架里发展出来的概念。一个 Skill 往往不只是提示词,它可能包含:
- 一组可以复用的提示词模板;
- 工具或函数的描述信息;
- 触发该 Skill 的条件判断逻辑;
- 处理结果的后置校验逻辑。
也就是说,系统提示词是“一段设置”,而 Skill 是“一个能力包”。同样是做代码评审,系统提示词只能说明“你是评审专家”;Sk ill 则会把评审标准、需要调用的静态检查工具、输出模板、异常处理逻辑全部打包。进入 Agent 开发阶段后,你会更频繁地听到“系统提示词工程与 Skill Agent 的区别”,其实区别就在粒度:一个是输入侧的编排,一个是完整的行为封装。
3. 提示词的底层运行机制:模型到底看到了什么
想写好提示词,不能只在表面打磨措辞,还要理解模型工作的基本规律。
大模型本质上是根据给定 token 序列,逐个预测下一个最可能的 token。模型本身没有“理解”和“执行”的严格区分,它只是在一个概率空间里生成后续内容。这带来几个工程结论:
第一,模型的输出不是确定性的。即使完全相同的提示词,也可能因为 temperature 参数、随机种子采样等原因产生不同结果。在自动化场景中,这不是 bug,而是模型特性,需要用工程手段兜底。
第二,指令并不会天然“凌驾”于其他内容。模型并没有一个专门的“指令执行区”,它在整个输入序列上进行注意力计算。传统软件开发中,配置文件一定比普通数据优先级更高,但大模型里,系统提示词和用户输入之间是互相影响的。这也是为什么“指令覆盖”类问题那么多:模型很容易被用户消息里的极端措辞带偏。
第三,角色设定是一种强先验,但不等于绝对约束。比如你告诉模型“你是数据库专家”,模型输出会偏向专业、严谨,但这个偏向不是加密权限,它不会阻止模型在其他任务上自由发挥。只要任务描述足够具体,角色设定的效果才会放大。
第四,输出格式约束需要“双保险”。模型可以学会“输出 JSON”,但学会并不等于每次遵守。更稳妥的做法是三层:提示词里写清楚格式要求,参数里设置低 temperature,代码里做格式校验和重试,必要时甚至用 JSON Schema 约束。提示词是设计的一部分,但不能是唯一依赖。
理解了这些,再回看提示词工程,它就有了明确的目标:把模型的概率行为推向业务确定性的边界。
4. 环境准备:一套最简的大模型调用环境
提示词工程不能只靠想象,必须跑起来验证。这里准备一套最简环境,不依赖复杂框架,也能覆盖绝大多数学习场景。
4.1 基础依赖
建议使用 Python 3.9 以上版本,并安装 OpenAI 兼容的 Python SDK。多数大模型服务平台都提供 OpenAI 兼容接口,这意味着用同一套代码可以切换到不同模型服务,对学习和迁移都方便。
python --version pip install openai如果你的网络环境需要配置代理,请先保证代理稳定;不需要代理的环境则直接配置接口地址即可。注意,本文只讨论常规的大模型 API 调用,不涉及任何其他网络工具。
4.2 准备 API 地址和密钥
通常你会拿到一个服务地址和 API Key,例如:
from openai import OpenAI client = OpenAI( base_url="https://your-llm-endpoint.example.com/v1", api_key="your-api-key", )这里的 base_url 和 api_key 需要替换成你实际使用的服务商提供的值。建议把敏感信息放到环境变量,不要写死在代码里。
4.3 本地模型方案
如果你不想使用云服务,也可以使用本地推理工具,例如 Ollama 或 vLLM 提供 OpenAI 兼容接口。启动本地模型后,把 base_url 指向本机地址即可。不同模型对提示词的敏感度不一样,建议在开始学习时固定一个模型,避免频繁切换带来的变量干扰。
环境准备好之后,就可以开始设计第一组提示词。下一步我们先把完整流程拆开。
5. 核心流程拆解:从需求到稳定提示词的五个步骤
提示词工程不是“想到一句话就丢给模型”,它有一套可以被复制到任何项目的流程。
5.1 第一步:定义任务输入与输出
写提示词之前,先在纸上把任务说清楚。
- 输入是什么:是一段文本、一组已知字段,还是要让模型主动提问?
- 输出是什么:是一段短文、一个 JSON 对象、一个分类标签,还是一个代码片段?
- 输出的约束是什么:长度范围、枚举值、格式要求、字段是否必需。
这一步最容易犯的错误是:输出定义得太模糊。模型不知道你希望 JSON 里是字符串还是数字,是每个字段都返回还是缺失字段可以跳过。你越早把输出 schema 定下来,后面调试越轻松。
5.2 第二步:设计角色与指令边界
根据任务选择角色。角色不是装饰,而是帮助模型调取对应语料分布的手段。比如做代码生成时,“你是资深后端工程师”就比“你是 AI 助手”更容易产出工程化代码。
同时要交代边界:哪些事情归属于你,哪些不能做。例如“只回答与技术相关的问题,其他问题回复无法回答”,这就是边界。
5.3 第三步:选择示例与推理策略
当指令描述很难讲清楚时,优先使用示例。示例数量不必太多,三到五个高质量样本通常就能建立模式。需要模型做多步计算或因果判断时,可以要求它“先列出已知条件,再分步计算”,也就是思维链。
5.4 第四步:搭建评测集
提示词的每一次改动都可能引入回归。建议为任务准备一个 10 到 20 条输入的小评测集,标注期望输出。每次修改提示词后,批量跑一遍,对比通过率。没有评测集,所谓“优化”只能是感觉。
5.5 第五步:记录、迭代、回归
每次调试都记录:提示词版本、模型参数、输入样例、输出结果、通过与否。不同模型对相同提示词的响应差异很大,记录版本能让你快速定位是“提示词变了”还是“模型侧变了”。
这个流程看起来简单,但大多数团队做不到,原因是没有把提示词当代码管理。后面会在最佳实践里专门展开。
6. 完整示例与代码实现
下面用四个代码示例串起整个提示词工程核心场景。代码均基于 OpenAI 兼容接口,可直接替换为自己的模型服务。
6.1 基础调用:跑通第一段提示词
# 文件路径:prompt_demo/basic_call.py from openai import OpenAI client = OpenAI( base_url="https://your-llm-endpoint.example.com/v1", api_key="your-api-key", ) response = client.chat.completions.create( model="your-model-name", messages=[ {"role": "system", "content": "你是资深后端工程师,回答要求简洁、准确,不写多余解释。"}, {"role": "user", "content": "请解释什么是接口幂等性,并给出一个 HTTP PUT 接口的简单写法。"}, ], temperature=0.3, ) print(response.choices[0].message.content)运行这个脚本后,你会看到模型按系统提示词的角色要求输出结果。这里有两个值得注意的工程点:
- system 消息负责“定义身份和回答风格”;
- temperature 设置为 0.3,让输出更稳定,适合技术问答。
如果你把 temperature 调到 0.9,同样的问题可能给出更发散、更像口语化的回答。基础调用的目的不是测试模型能力,而是确认你的环境、参数和 messages 结构都正确。
python prompt_demo/basic_call.py只要能看到一段解释幂等性的文字,说明调用链路已经通了。
6.2 系统提示词与结构化输出:让模型返回 JSON
生产中经常需要模型输出结构化数据,下面以从招聘 JD 中抽取关键字段为例。
# 文件路径:prompt_demo/structured_output.py from openai import OpenAI import json client = OpenAI( base_url="https://your-llm-endpoint.example.com/v1", api_key="your-api-key", ) system_prompt = """ 你是数据抽取引擎。用户会输入一段招聘JD文本。 你需要抽取以下字段,并严格输出JSON对象,不要输出任何解释、前后缀或代码块标记: { "job_title": "职位名称", "skills": ["技能1", "技能2"], "years_experience_min": 数字, "education": "学历要求" } 如果字段信息无法确定,对应值填 null。 """ user_input = """职位:高级Java开发工程师,要求计算机相关专业本科以上学历, 3年以上Java开发经验,熟悉Spring Boot、MySQL、Redis、消息队列, 有高并发系统经验者优先。""" response = client.chat.completions.create( model="your-model-name", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_input}, ], temperature=0, ) content = response.choices[0].message.content print(content) data = json.loads(content) print(data["job_title"]) print(data["skills"])运行结果类似:
{ "job_title": "高级Java开发工程师", "skills": ["Java", "Spring Boot", "MySQL", "Redis", "消息队列"], "years_experience_min": 3, "education": "本科" }这段代码的核心价值在于:先用系统提示词定义 schema,再把 temperature 设为 0,然后在代码里用json.loads做校验。提示词并不是万能的,模型偶尔还是会输出解释文字,这时json.loads会抛出异常。更稳妥的做法是捕获解析失败后做一次重试,或者把这段输出交给一个 JSON 修复工具处理。
6.3 Few-shot 示例:用例子代替规则
有些任务的分类边界靠语言描述很难讲清,比如“电商客服意图分类”。与其写一大段“尺码咨询包括……退货流程包括……”,不如直接给它几个真实例子。
# 文件路径:prompt_demo/few_shot_classify.py from openai import OpenAI client = OpenAI( base_url="https://your-llm-endpoint.example.com/v1", api_key="your-api-key", ) messages = [ {"role": "system", "content": "你是电商客服意图分类器。用户会输入一个问题,你只输出以下分类之一:尺码咨询、退款退货、物流查询、价格优惠、其他。"}, {"role": "user", "content": "这件衣服有L码吗?"}, {"role": "assistant", "content": "尺码咨询"}, {"role": "user", "content": "怎么申请退货?"}, {"role": "assistant", "content": "退款退货"}, {"role": "user", "content": "包邮吗?"}, {"role": "assistant", "content": "价格优惠"}, {"role": "user", "content": "你们发货用哪家快递?"}, ] response = client.chat.completions.create( model="your-model-name", messages=messages, temperature=0, ) print(response.choices[0].message.content)这里的结构是:系统消息负责任务设定,用户与助手消息交替提供示例,最后的用户消息才是真实待分类输入。模型会从示例中归纳映射规律,而不是死记硬背某个词。
Few-shot 的有效性依赖于示例与真实场景的相似度。如果你的真实输入包含大量口语化表达,示例里就必须有口语化句子,否则分类效果会下降。示例数量并非越多越好,3 到 5 个典型样本通常就能起到很好的约束作用。
6.4 思维链(CoT):让模型分步推理
很多任务需要多步计算,比如判断一条开发方案是否合理。直接让模型出结论,它容易跳过中间步骤、在数字上犯低级错误。此时可以让它先列出已知条件和计算过程。
# 文件路径:prompt_demo/cot_judge.py from openai import OpenAI client = OpenAI( base_url="https://your-llm-endpoint.example.com/v1", api_key="your-api-key", ) prompt = """ 请判断下面这段开发方案是否合理,并分步解释: “一个系统每天产生300万条日志,每条日志平均2KB。 我们估算每天需要600MB存储,一个月约18GB, 所以准备20GB磁盘来存一个月的日志。” 要求: 1. 先列出已知条件; 2. 写出每天的日志总量计算过程; 3. 列出一个月需要的存储量; 4. 最后给出是否够用的结论。 """ response = client.chat.completions.create( model="your-model-name", messages=[{"role": "user", "content": prompt}], temperature=0.3, max_tokens=800, ) print(response.choices[0].message.content)这个例子的关键不是结果,而是过程。300 万条日志乘以 2KB 得到约 6GB/天,一个月约 180GB,原文方案说每天 600MB、月 18GB,明显低估,准备 20GB 不够。思维链的价值就在于让模型把隐含计算显性化,出错时你也能立刻定位是哪里算错了,而不是得到一句“方案合理”的盲猜。
在需要精确数字的生产场景中,更推荐把计算交给 Python 代码,而不是让模型做算术。模型擅长结构化推理和文本理解,数学计算应该走确定的工具调用路径。
7. 运行结果与效果验证:怎么判断提示词真的变好了
很多开发者在优化提示词时没有量化标准,只凭“感觉输出变好了”。正确做法是建立一套简单的评估流程。
7.1 准备评估样例
从真实业务中挑选 10 到 20 条输入作为评测集,每条给出期望输出。评测集要覆盖正常场景、边界场景和容易翻车的场景。比如做意图分类时,评测集里至少要有一条“用户问得很啰嗦但意图简单”的输入。
7.2 定义评估指标
- 格式通过率:输出能否被 JSON 解析、是否符合字段类型。
- 内容准确率:输出结果与期望结果是否一致,可以用人工,也可以让另一个模型打分。
- 稳定性:同一输入多次调用获取结果的一致程度。
7.3 对比实验
修改提示词前,先在同样参数下跑一遍旧版本并记录结果;修改后,再跑新版本。只有对比,才知道改动是正向还是负向。很多团队用脚本批量跑评测集,输出一个通过率百分比,这是提示词工程走向正规化的第一步。
例如,你从上面的结构化输出示例开始,尝试把temperature从 0 调高到 0.5,然后跑 10 条 JD 数据,你会发现格式通过率明显下降。这个结果说明:对于此任务,低 temperature 是必要约束。类似的实验也适用于检测角色设定是否有效。
8. 常见问题与排查方法
下面这份表格基于真实开发中高频出现的提示词问题整理。遇到问题时,先按因果链排查,而不是干拍脑袋。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 模型不按格式输出 JSON | 提示词对格式约束不严格,或模型受上下文干扰 | 查看输出内容中是否在 JSON 前后有解释文字 | 在系统提示词中写明“只输出 JSON,不要代码块标记”;代码层增加重试与后处理 |
| 同样提示词,结果忽好忽坏 | temperature 过高或模型采样随机性大 | 检查请求参数和采样次数 | 将 temperature 降到 0.2 以下;生产环境可设置固定 seed |
| 用户几句反问就能“带跑”模型 | 系统提示词边界定义不清晰,或用户消息优先级被模型放大 | 检查 messages 中系统消息与用户消息的内容强度 | 强化系统提示词中的边界规则,必要时增加“遇到无关反问时统一回复固定文案” |
| Few-shot 示例不生效 | 示例与真实输入分布差异大,或示例数太少 | 对比示例和真实输入的语言风格 | 收集真实输入补充进示例,保证 3 到 5 个高质量样本 |
| 长对话后模型“忘记”之前的要求 | 关键指令被长上下文淹没 | 检查指令在上下文中的位置 | 将关键指令放在 system 消息或最新一次 user 消息的开头;必要时做历史摘要 |
| 模型总是多解释、不直接给结果 | 没有显式要求回复形式 | 检查系统提示词里的输出约束 | 增加“不要解释,直接输出结果”等明确约束,或设置 stop 参数 |
| 输出结果正确但 token 消耗很高 | 提示词过长或 max_tokens 设置过大 | 查看请求日志中 token 用量 | 精简提示词,压缩重复指令,合理设置 max_tokens |
一个容易被忽略的问题是:提示词的改动看起来是“小改动”,但在不同模型版本上可能产生完全不同的结果。排查时要记录模型名称和版本,避免把模型升级导致的变化误判成提示词问题。
9. 最佳实践与工程建议
提示词工程到了一定程度,瓶颈不再是“会不会写一句好话”,而是“能不能稳定维护一套提示词系统”。以下建议是从工程化角度给出的。
9.1 把提示词当成代码管理
建议把提示词放在独立的配置文件中,而不是散落在业务代码里。可以用 JSON 或 YAML 管理系统提示词、用户模板和示例。
# 文件路径:prompts/extract_job.yaml task: extract_job_fields model: your-model-name temperature: 0 system_prompt: | 你是数据抽取引擎。 严格输出 JSON,不要输出任何解释。 字段规则见 schema 定义。 user_template: | 职位:{job_description} schema: job_title: string skills: array years_experience_min: integer education: string在代码里读取配置后,再组装成 messages。这样每次修改提示词都有 diff 可看,能回溯,也能评审。
9.2 为提示词配置版本与评测记录
建议为每个提示词任务建立一个“档案”,记录:
- 任务名称和目的;
- 当前提示词版本;
- 评测集文件;
- 最近一次评测通过率;
- 已知失败案例。
团队协作时,这个档案能让所有人快速知道当前系统靠谱到什么程度。
9.3 敏感信息不要进提示词
提示词可能被记录在日志中,也可能被模型服务端留存。API Key、用户手机号、身份证号等敏感信息,一律不能出现在系统提示词或测试数据中。生产场景中涉及用户隐私时,先脱敏再进入模型。
9.4 控制成本与延迟
大模型调用成本主要看 token 消耗,而提示词每增加一段历史记录都可能让单次请求变贵。建议:
- 缓存高频请求,例如相似意图分类结果;
- 对长历史做摘要或只保留最近几轮;
- 设置合理的 max_tokens;
- 监控每次请求的 token 用量,在仪表盘上跟踪异常增长。
9.5 安全边界与兜底设计
提示词工程能做到的优化是有上限的。即使提示词写得很完善,也可能遇到模型输出错误格式、给出危险建议或概率性失败。生产系统必须设计兜底:
- 格式解析失败时走重试或降级逻辑;
- 涉及代码生成时做安全审查,不直接执行;
- 涉及权限操作前必须人工确认;
- 将模型定位为“建议者”而不是“决策者”。
10. 总结与后续学习方向
提示词工程入门不难,真正难的是建立工程思维。你需要在提示词里显式定义任务边界和输出格式,需要用评测集来验证每次改动,还需要理解大模型的概率生成特性,不能把一次成功当成稳定可靠。
学完提示词基础后,下一步有三个方向值得深入:
第一,上下文工程。当你的知识库、对话历史、工具调用结果越来越多时,如何选择、压缩、排序上下文是关键瓶颈。第二,提示词评测与自动调优。用一套评测脚本在多个提示词候选中自动选优,比人工凭感觉调参高效得多。第三,Agent 与 Skill 体系。当需要模型调用工具、自主规划任务时,你会把提示词封装成 Skill,配合工具描述和校验逻辑使用。
这份内容建议收藏备用。下次再遇到“模型就是不按我说的做”的时候,别急着换模型,先拿这份清单逐条排查提示词本身的问题。