提示词工程实战:5大核心要素与代码示例
聊大模型应用我见过太多次这种情况同一个模型有人用起来像经验丰富的助理交代一句就能给出结构清晰的产出有人用起来像只会复读关键词的机器人输出空洞、跑题、格式稀烂。差别往往不在模型本身而在你输入的那段文字——提示词。提示词工程说白了就是一门“如何把需求写成大模型能读懂、能稳定执行的指令”的技术。这门技术解决的核心问题很实际大模型生成结果有一定随机性同样一个问题换个问法结果可能天差地别。提示词工程就是把这种“看运气”的交互变成可预测、可复用、可评测的工程方案。无论你是在做聊天机器人、内容生成工具还是把大模型接进内部业务系统都需要这套方法。它不是什么玄学而是一套可以拆解、可以测试、可以不断迭代的实践。这篇文章我会从底层逻辑讲起拆解5个决定提示词质量的核心要素然后给出一份完整的实战代码示例最后分享我踩过的一些坑和排查经验。适合刚接触大模型开发的工程师也适合被“模型输出不稳定”折磨的产品和运营同学。1. 提示词工程的价值与适用范围1.1 提示词为什么突然变成一门“手艺”过去写代码输入输出都是严格定义好的函数接口参数类型错了直接报错。大模型不一样它没有硬性的API约束唯一的“接口协议”就是你写给它的自然语言。模型能力基本固定之后提示词就成了整个系统里唯一可以主动调控的变量。我习惯把提示词比作面试问题设计。同样是考察一个候选人你问他“介绍一下你自己”得到的回答大概率是简历复述你换成“请用3分钟介绍你做过的其中一个项目重点讲你遇到的技术难点和解决思路”得到的有效信息密度完全不一样。大模型也是一样问题设计得越清晰它的答案就越靠近你想要的。在真实业务里提示词的质量会直接决定下游系统的表现。比如做一个客服工单分类功能提示词里只写“帮我把工单分类”模型可能输出“这个工单是关于网络问题的建议联系网络部门”这种混合了分类和解释的文字但如果你在提示词里明确“只输出JSON字段为category和confidence”下游代码就能直接解析。能不能落到工程里差距就在这一步。1.2 什么样的提示词才算“有效”很多人对“有效”的理解就是“模型听懂了”但站在工程角度这个标准太低。一个可以上线使用的提示词至少要满足五个维度维度含义不达标的典型表现稳定同一输入多次运行结果差异小同一句话这次给结论下次给列表准确输出内容命中任务目标让判断情绪结果写了一堆建议可解析输出格式能被程序直接处理要求JSON结果带了前后说明文字可控可以通过参数或指令控制风格、长度、敏感度说“简短”输出还是洋洋洒洒几百字可复用换一批输入数据模板仍然好用换个产品名称输出就跑题这五个维度里“可解析”是我在实际项目里最看重的一个。原因很简单纯给人看的提示词偶尔跑偏还能接受但一旦接了代码格式不稳定就意味着解析报错、字段缺失整个流程直接断掉。1.3 提示词工程的三层通用框架我把提示词工程拆成三层方便定位问题出在哪里。底层是模型能力边界。你得清楚模型的上下文窗口多大、在什么任务上容易幻觉、什么指令它天生执行不好。这不是提示词能完全补救的不改底层能力光靠措辞优化是治标不治本。中间层是结构化指令。也就是接下来要讲的“5大核心要素”。这一层决定模型能不能正确理解你的意图并给出符合预期的输出。上层是工程配套。包括温度参数的设置、失败重试策略、输出结果的解析与校验、以及提示词版本的评测管理。很多人只写提示词不搭配套工程一旦线上出问题连是提示词的问题还是后处理的问题都分不清。这三层缺一不可。本文重点讲中间层但后两章的代码和评测方法会把三层串起来。2. 核心要素逐项拆解5个决定提示词质量的关键变量2.1 单一化任务目标让模型只干一件事一个提示词只做一件事这是我写提示词的第一原则。很多新手喜欢把多个需求塞进一句话比如“帮我看一下这段文字的情感倾向顺便总结一下重点再给几个修改建议”。结果模型常常哪个都做得不够好。原因不难理解模型要在有限的输出长度内分配注意力任务越杂每个目标分到的“带宽”就越少。下游要做情感判断就专门做情感判断要总结就专门给总结。任务描述建议用这个公式写清楚动作 对象 质量标准 输出形式举例。差的写法是“帮我写个活动通知。”——对象不明确质量标准和输出形式全无。好的写法是“为内部读书会写一条200字的活动通知内容包括时间、地点、报名方式语气正式但亲切最后请附上报名二维码占位符。”显式化还有一个小技巧让模型先复述任务再回答。尤其是在Agent类场景里模型先用自己的话描述一遍它要做什么能显著降低理解偏差。虽然会多消耗一些输出token但换来的是更高的任务完成率这个买卖值得。2.2 角色与语气锚定模型的回答视角角色设定的本质是利用模型训练数据里的“风格分布”来锁定回答视角。同样是解释一个Bug让模型以“资深开发工程师”的角色回答它会倾向于先给结论、再给排查路径最后给代码让它以“教程作者”的角色回答它会倾向于从概念讲起加上类比和步骤。角色描述一定要具体不能只写“你是专家”。我试过只写“你是一名数据分析师”模型输出的东西仍然很泛。改成“你是一名有5年经验的数据分析师回答时要先说明分析思路再给出结论遇到数据不足的情况要直接说明”效果立刻不一样。角色里带上行为约束比单独写规则更有效。语气也是角色的一部分。给B端客户做工具输出应该精炼、结论前置给C端用户做助手输出应该亲切、解释充分。同样的功能只要在角色描述里加一句“用平实易懂的语言解释避免专业术语堆砌”用户感受会差很多。这里要提醒一点角色不是万能的。模型能力不足时角色设定只能改变“说法”弥补不了“知识”。如果模型本身对某个领域不了解你把它包装成顶级专家它也只是“用专家的口吻编造答案”这恰恰是最危险的情况。2.3 上下文与背景信息补全先给背景再问问题大模型不是搜索引擎它不知道你的项目背景、业务规则和用户画像。很多人提问翻车不是模型笨是模型缺少必要的上下文。我总结的上下文投喂原则是只给与当前任务直接相关的信息多余的一律去掉。模型上下文窗口是有限的塞进去越多不相关内容注意力被稀释得越厉害而且token费用也更高。上下文可以分层组织全局背景、业务规则、本次输入。以客服工单回复助手为例正确的提示词结构应该是全局背景你服务于某产品的客服团队用户在工单里反馈的问题涉及付费、退款或技术故障。业务规则退款类问题优先引导自助退款技术故障类问题提供排查文档涉及辱骂内容一律不回应。本次输入这是用户提交的原始工单内容。这比你直接把工单丢给模型然后问“怎么回复”要可靠得多。模型知道了前两层规则输出才会在规则框架内少了规则层它可能自由发挥出完全不合规的回复。关于token成本可以简单算一笔账设提示词里的固定部分长度为A token每次调用输出长度为B token单价为P元/千token单次调用成本就是(AB)×P/1000。如果你每天调用10万次每次提示词多塞500个token日成本就会多出5000×P元这个数字不小。上下文要做减法不只是为了效果也是为了成本。2.4 输出格式约束把自由发挥改成定制交付人看内容喜欢自然语言程序解析内容喜欢结构化数据。提示词工程里格式约束是让大模型从“聊天工具”变成“功能组件”的关键一步。格式约束有两种写法建议同时使用。第一种是描述性说明明确告诉模型“以JSON格式输出包含字段A、B、C”。第二种是结构示范直接给一个符合要求的伪代码或示例JSON让模型照着填。描述定逻辑示例定细节两者配合效果最稳。实际项目中JSON输出最常见的翻车点是模型在JSON前后加了一堆解释性文字比如“以下是您需要的JSON格式结果”。解决方法是提示词里写清楚“只输出JSON对象本身不要任何解释、前后缀和Markdown标记”同时在代码层做兜底处理从返回文本中用正则提取JSON块再解析。输出格式的选择也要根据用途来。给人看的内容用Markdown或表格渲染出来清晰给机器解析的内容用JSON需要人工快速浏览的列表用编号形式。格式本身不复杂麻烦的是格式与内容描述冲突。比如你要求输出JSON又希望“语言亲切自然”模型就很容易在JSON里塞口语化的value导致解析后无法直接使用。格式要求一定要和内容要求对齐JSON就保持字段精炼自然语言才考虑语气。2.5 边界规则与少量示例堵住乱编和跑题大模型天然的倾向是“把话说完”信息不够时它会脑补。边界规则的核心作用就是明确定义“不要做什么”和“做不到怎么办”。比如让模型写产品文案我通常会加一条规则“如果要求提供的数据或事实在你的知识范围内不确定直接说明‘该信息需要核实’不要编造。”再比如做内容分类时加规则“如果输入内容不属于任何已知类别输出unknownconfidence置为0。”这些规则不是可有可无的装饰它们是拦截幻觉的最后一道闸门。示例few-shot是另一种强约束。给模型两个输入输出对它会快速模仿你的格式和语气。我常用的模板是先给任务描述再给两个示例然后才是真实的输入。示例的数量级经验是简单分类任务给3到5个即可复杂结构化任务给5到10个。给太多示例反而会挤占上下文窗口增加成本和延迟效果还不一定更好。把5个要素串起来一个高质量的提示词模板大致长这样角色 单一任务 上下文/规则 边界约束 示例 输出格式后面我会用代码把这套结构固化下来避免每次写提示词都从零开始。3. 实战代码示例做一个能自动跑的周报摘要提示词3.1 场景设定与需求拆解假设一个具体场景每周让你收集团队成员的周报文本需要自动生成一份摘要并把待办事项和风险点提取成结构化数据。这个任务如果手动做每次要读十几份周报、人工提炼要点费时费力如果让模型做关键就是提示词要设计到“输出能直接入库”的程度。先做需求拆解明确三件事输入多名成员的周报原始文本内容长短不一有口语有书面语。输出一个JSON对象包含overview全局概况两句话以内、todos待办事项字符串数组、risks风险与阻塞字符串数组。运行约束模型只做提取和总结不新增内容信息不足时字段返回空数组而不是编造。拆完之后提示词的每个部分都有了明确目标角色负责控制文风任务描述控制工作内容格式约束保证输出可解析边界规则防止幻觉。3.2 提示词模板的工程化拼装我习惯把提示词写成一个可复用的Python模板函数通过参数拼接不同部分。这样做的好处是改需求时只改对应区块不用重写整段提示词。下面是一个示例模板代码def build_weekly_report_prompt(team_name: str, weekly_reports: list[str]) - str: examples 示例输入 - A同学本周完成了登录模块的重构解决了超时问题。下周二计划联调支付接口。 - B同学等待设计稿前端进度受阻预计延迟2天。 示例输出 {overview: 本周主要推进登录模块重构支付接口下周进入联调前端进度因设计稿未交付有所延迟。, todos: [联调支付接口], risks: [A同学负责的前端依赖设计稿存在2天延迟风险]} reports_text \n.join(f- {text} for text in weekly_reports) prompt f 你是某项目的研发负责人助手。请阅读以下团队成员周报完成两项任务 1. 写一段不超过两句话的全局概要。 2. 提取所有待办事项和潜在风险。 规则 - 只根据输入内容总结不要新增任何输入中没有的信息。 - 待办事项只保留有明确动作的描述。 - 如果某一类别没有内容对应字段返回空数组。 - 输出必须是合法的JSON对象不要包含任何解释、前后缀或Markdown标记。 参考示例 {examples} 本次周报输入 {reports_text} 请直接输出JSON return prompt这里有几个工程细节值得注意。一是示例放在任务描述后面让模型先理解规则再看到模仿对象。二是把规则和示例分开规则负责“不能做什么”示例负责“长什么样”两者职责清晰后续好维护。三是在真实周报文本前加了“- ”前缀统一每条的格式模型更容易对齐输入结构。3.3 调用大模型API的完整Python代码模板拼好之后剩下就是调用大模型接口。下面这段代码用requests实现了一个最简可用的调用封装接口地址和模型名换成你自己的配置就行。import json import re import requests API_URL https://api.example.com/v1/chat/completions API_KEY your-api-key def call_llm(prompt: str, temperature: float 0.2, max_tokens: int 800): headers { Content-Type: application/json, Authorization: fBearer {API_KEY} } payload { model: your-model-name, messages: [ {role: system, content: 你是一个严格遵循指令的助手。}, {role: user, content: prompt} ], temperature: temperature, max_tokens: max_tokens } resp requests.post(API_URL, headersheaders, jsonpayload, timeout30) resp.raise_for_status() return resp.json()[choices][0][message][content] def safe_parse_json(text: str): # 优先直接解析失败时尝试提取代码块内的JSON try: return json.loads(text) except json.JSONDecodeError: match re.search(r(?:json)?\s*(\{.*?\})\s*, text, re.DOTALL) if match: return json.loads(match.group(1)) raise ValueError(f无法从模型输出中解析JSON: {text}) weekly_reports [ A同学本周完成了登录模块的重构解决了超时问题。下周二计划联调支付接口。, B同学等待设计稿前端进度受阻预计延迟2天。, C同学完成了数据迁移脚本本地验证通过待上线审核。 ] prompt build_weekly_report_prompt(某项目, weekly_reports) raw_output call_llm(prompt, temperature0.2) result safe_parse_json(raw_output) print(json.dumps(result, ensure_asciiFalse, indent2))关于参数我在这里特别说明一下temperature的含义。这个参数控制随机性取值越低输出越稳定。做信息提取、分类、格式转换这类任务我通常调成0到0.3做创意写作、头脑风暴才会调到0.7以上。周报摘要属于信息压缩任务稳定性优先所以设0.2。safe_parse_json这个后处理函数也很有必要。模型并不是100%遵守“只输出JSON”的规则尤其是在系统消息和用户消息共同作用的情况下偶尔会在结果外加注释。先直接解析失败就提取Markdown代码块两层兜底之后解析失败率能降到很低。3.4 案例效果与结果验看跑完上面代码得到的输出大概是这样的{ overview: 本周主要推进登录模块重构和支付接口联调准备前端进度因设计稿未交付有所延迟。, todos: [联调支付接口, 数据迁移脚本待上线审核], risks: [前端依赖设计稿存在2天延迟风险] }验证结果是否合格我一般对照三件事。第一overview是否覆盖了所有成员的周报信息有没有把某一天的内容漏掉第二todos字段是否只包含有具体动作的事项像“等待设计稿”这种状态描述不应该被提取为待办第三risks是否准确反映了阻塞和风险而不是把普通工作内容也塞进去。如果某次输出把“完成了登录模块重构”也放进了todos说明提示词的规则“待办事项只保留有明确动作的描述”还不够严格。我的处理办法是在规则后面追加一句“已完成事项不要放入todos”再补一个反例效果通常能立刻改善。4. 从能用变好用提示词的评测与迭代方法4.1 建一个二十条的评测集取代“感觉还行”我在实际工作中吃过“感觉这个提示词挺好”的亏。试了3条输入觉得不错放到线上跑一天各种边界情况全出来了。后来我养成了一个习惯固定一个20条左右的评测集覆盖正常输入、边界输入、异常输入三类每次改提示词都跑一遍。评测集的样式可以参考这样类别样例描述期望表现正常周报包含常规进度、待办、风险各1条三类字段都能正确提取边界周报只有两句话无明确待办todos返回空数组异常周报内容为空或全是表情符号不报错overview写“无有效内容”隐患周报中出现“可能延期”但没有明确时间risks中体现风险不编造日期评测的标准也不难定核心是三个格式通过率、字段提取准确率、幻觉比例。我通常写一个几十行的评测脚本跑完自动输出得分。改提示词之前记住基线分数改完之后重新跑高于基线才保留新版本。这个流程虽然不复杂但能省掉大量线上返工的麻烦。4.2 一次只改一个变量防止劣化迭代提示词最常见的误区是“一次改三处”。改完效果变差了你都不知道是角色设置的问题还是新增规则的问题还是示例写法的问题。我的迭代顺序是固定的先改任务描述确定目标没有跑偏再改输出格式保证结构化然后改边界规则减少幻觉最后调角色语气优化表达风格。示例放在最后动因为它对格式的影响最直接容易掩盖其他问题。举个例子。用户反馈周报摘要太长我先检查overview部分的字数要求是不是明确把“不超过两句话”改成“不超过30个字”只改这一处跑评测集看是否影响字段提取。如果发现字数变短后risks字段更容易丢那说明问题出在规则之间的冲突而不是字数规则本身。这种排查方法慢但每一步都可控适合所有线上场景。4.3 成本与延时的平衡提示词也占资源提示词不是一次性的它会在每次调用里反复发送。提示词越长单次延迟越高成本也越高。我见过有人为了追求效果把提示词写到两三千token效果确实稳了但成本翻了数倍接口响应时间也明显变长。对成本敏感的批量场景有几个实用优化手段。一是把固定部分的提示词做成缓存避免每次请求重复传输二是把不常用的长示例从主提示词移到“按需拼装”的备用模块里只有遇到失败样本时才动态追加三是使用更长的输入模型和短输入模型做分级调用简单请求走快模型复杂请求再上完整提示词。我一般会在评测集里加一个“耗时指标”记录每次调用的平均延迟。提示词优化不能只看效果如果加了500个token只换来0.5%的准确率提升这个改动就要重新评估。5. 常见问题与避坑心得5.1 常见问题速查表现象可能原因解决方向输出规格时好时坏格式描述太模糊或示例与格式要求冲突增加结构示范删掉与格式矛盾的描述模型编造不存在的细节缺少“不知道就说明”的规则temperature偏高增加边界规则把temperature降到0.3以下角色不生效角色描述太抽象没有具体行为约束在角色后追加“你要先…再…遇到…要…”这类句式内容过长或过短字数要求没有量化max_tokens与期望不匹配明确“不超过X字”同时调整max_tokens回答语言混杂没有指定回答语言在规则里显式写“请始终使用中文回答”换一批输入就失效提示词里写死了具体示例中的事物名称把示例抽象成泛化模板实际输入用占位符注入5.2 六个容易踩坑的细节细节一否定式指令不如肯定式指令可靠。“不要提到价格”这类表述模型经常忽略“不要”两个字结果照旧提价。更好的做法是“如果内容涉及价格请跳过该部分并输出提示语‘含价格信息’”用明确的替代动作堵住漏洞。细节二示例里的数据不要用真实敏感业务数据。我见过有人直接把真实用户名和手机号贴在示例里传给了模型这既不安全也容易被意外外泄。示例一律用明显虚构的数据格式不变就行模型照样能学到结构。细节三提示词也需要版本管理。在公司场景里我把提示词模板放在配置中心或代码仓库里每个版本记录改了哪一项、评测分数是多少。没有版本追踪的提示词改坏了根本回不去。细节四不要忽略temperature之外的采样参数。一些平台还有top_p、frequency_penalty、presence_penalty它们都会影响输出。在评测集上如果输出异常先检查这一组参数而不是一味改提示词。细节五上下文窗口不是塞得越满越好。模型处理长输入时对早期内容的记忆保持度会下降。如果必须投喂长文档建议先让模型做分段摘要再基于摘要执行主任务效果比一次性灌入全文更好。细节六安全不能只靠提示词约束。提示词里的规则再严密也只是“软约束”。涉及用户数据脱敏、敏感回复拦截、恶意输入检测仍然要在代码层做独立过滤不要把安全问题寄托在模型的自觉性上。5.3 最后的个人经验小结做了这么多提示词工程的实际项目我的体会是提示词工程最难的并不是“写出一句精彩的话”而是把提示词当成一套需要持续维护的系统来对待。先明确任务边界再固化格式约束然后用评测集做迭代回归最后把经验沉淀成模板库。这套流程跑通之后换新场景、换新模型都能快速上手。如果一定要分享一个最实用的建议那就是“先跑通最简版本再逐步加规则”。不要试图第一次就把提示词写到完美。先用3到5条典型输入跑起来看输出在哪里不达标然后针对性地补规则、补示例。大多数复杂提示词都不是设计出来的而是迭代出来的。