RAG 的 Prompt 应该怎么写?不要让模型自由发挥
前面几篇文章里,我们已经讨论了 RAG 的基础流程、文档切分、Embedding、向量数据库、Hybrid Search 和 Rerank。
这些内容主要解决的是一个问题:
如何把正确的资料找出来,并且把更有用的内容排到前面。
到这里,一个相对完整的检索链路已经形成了:
用户问题 ↓ Query 处理 ↓ 向量检索 / 关键词检索 ↓ Metadata Filter ↓ 候选合并与去重 ↓ Rerank ↓ 选择最终上下文但 RAG 系统并不会停在检索阶段。
最终还需要大模型基于这些资料生成答案。
也就是说,检索和排序只是把证据准备好,真正展示给用户的是模型生成出来的回答。
这时候 Prompt 就变得非常关键。
很多 RAG 系统明明检索到了正确资料,最后答案仍然不稳定,原因不一定在向量数据库,也不一定在 Rerank,而是 Prompt 没有约束好模型。
模型可能会自由发挥,可能会把资料里没有的信息补出来,也可能会忽略引用来源,还可能在资料不足时硬给答案。
这篇文章就讨论一个工程上非常重要的问题:
RAG 的 Prompt 应该怎么写,为什么不能让模型自由发挥。
普通 Prompt 和 RAG Prompt 不一样
很多人刚开始做 RAG 时,会直接写一个很简单的 Prompt:
请根据以下资料回答用户问题。 资料: {context} 问题: {question}这个写法能跑。
但它太松了。
它只是告诉模型“可以参考资料”,却没有告诉模型:
- 如果资料里没有答案怎么办。
- 能不能使用模型自己的知识。
- 答案需要多详细。
- 是否必须引用来源。
- 是否可以推测。
- 输出格式应该是什么。
- 多个资料冲突时怎么处理。
普通聊天 Prompt 的目标是让模型回答得自然、完整、有帮助。
但 RAG Prompt 的目标不只是“回答得像样”。
RAG Prompt 更重要的目标是:
让模型基于检索资料回答,并且在资料不足时不要编。
这是两种完全不同的约束。
普通问答里,模型可以依赖预训练知识。
比如用户问:
Python 的 list 和 tuple 有什么区别?模型直接回答通常没有问题。
但在企业知识库问答里,用户问:
我们公司试用期员工能不能休年假?这时模型不能凭常识回答。
因为每家公司制度不一样。
即使模型知道一般劳动法或常见公司制度,也不能替代当前知识库里的正式资料。
如果 Prompt 没有明确约束,模型可能会给出一个看起来合理、但不符合内部制度的答案。
这就是 RAG Prompt 和普通 Prompt 的核心区别。
普通 Prompt 追求“会回答”。
RAG Prompt 追求“有依据地回答”。
RAG Prompt 的核心职责
RAG Prompt 不是为了让模型更会聊天,而是为了让模型更稳。
它至少要承担几类职责。
第一,明确答案必须基于检索资料。
模型不能随意补充资料里没有的事实。
比如知识库只写了“试用期员工年假按入职时间折算”,没有写具体天数。
模型就不应该擅自说“试用期满三个月后可以休 5 天年假”。
第二,明确资料不足时怎么回答。
很多系统最怕模型不知道装知道。
如果资料里没有答案,正确行为应该是说明:
当前资料中没有找到明确说明。而不是编一个听起来合理的答案。
第三,要求模型区分事实和推断。
如果资料里有明确事实,就直接回答。
如果只能根据资料做有限推断,就应该说明“根据现有资料推断”。
如果无法推断,就应该拒绝给确定结论。
第四,要求模型保持答案结构清晰。
用户不是来阅读一堆原文拼接的。
模型需要把资料整理成清晰答案。
比如:
结论: 依据: 注意事项:第五,要求模型引用来源。
如果检索结果里带有文档标题、段落编号、链接、更新时间,Prompt 就应该要求模型在答案中引用这些来源。
这能提高用户信任,也方便排查问题。
第六,要求模型处理冲突资料。
真实知识库里可能有旧制度和新制度。
如果资料冲突,模型不能随便挑一个回答。
它应该说明存在冲突,并优先参考更高优先级或更新版本的资料。
这些职责看起来像是细节。
但它们决定了 RAG 系统能不能从“能答”走向“可信”。
一个基础 RAG Prompt 应该包含什么?
一个可用的 RAG Prompt 通常不应该只是一句话。
它至少可以拆成几个部分。
第一部分是角色说明。
告诉模型它现在不是普通聊天助手,而是基于资料回答问题的知识库助手。
示例:
你是一个企业知识库问答助手,需要严格基于提供的资料回答用户问题。第二部分是回答规则。
这是 RAG Prompt 里最重要的部分。
示例:
回答规则: 1. 只能基于提供的资料回答,不要使用资料之外的信息。 2. 如果资料中没有答案,请明确说明“当前资料中没有找到明确依据”。 3. 不要编造制度、数字、时间、金额、接口参数或流程步骤。 4. 如果资料存在冲突,请指出冲突,并说明无法给出唯一结论。 5. 回答应简洁清晰,优先给出结论,再说明依据。第三部分是检索上下文。
这里放入经过 Rerank 和压缩后的资料。
最好不要只放纯文本。
应该保留必要的来源信息。
比如:
资料 1: 标题:员工休假管理办法 版本:2026-01 内容:试用期员工年休假按入职时间折算。 资料 2: 标题:考勤管理补充说明 版本:2025-11 内容:年休假申请需提前在系统中提交审批。第四部分是用户问题。
示例:
用户问题: 试用期员工能不能休年假?第五部分是输出格式。
如果没有输出格式,模型每次回答可能都不一样。
可以要求:
请按以下格式回答: 结论: 依据: 补充说明: 来源:这能让答案更稳定,也方便前端展示。
把这些部分组合起来,一个基础 Prompt 可以是:
你是一个企业知识库问答助手,需要严格基于提供的资料回答用户问题。 回答规则: 1. 只能基于提供的资料回答,不要使用资料之外的信息。 2. 如果资料中没有答案,请明确说明“当前资料中没有找到明确依据”。 3. 不要编造制度、数字、时间、金额、接口参数或流程步骤。 4. 如果资料存在冲突,请指出冲突,并说明无法给出唯一结论。 5. 回答应简洁清晰,优先给出结论,再说明依据。 检索资料: {context} 用户问题: {question} 请按以下格式回答: 结论: 依据: 补充说明: 来源:这只是一个基础版本。
不同场景可以继续调整。
但它已经比“请根据以下资料回答问题”稳定很多。
为什么一定要写“资料不足就说不知道”?
RAG 系统很容易遇到一种情况:
检索结果和问题有点相关,但没有真正答案。
比如用户问:
远程办公每个月最多可以申请几天?检索结果里只有:
员工如需远程办公,应提前向直属主管提交申请。这段资料说明了申请流程,但没有说明最多几天。
如果 Prompt 没有限制,模型可能会补一个常见数字:
每个月最多可以申请 3 天。这就是典型幻觉。
它看起来很自然,但资料中没有依据。
RAG 系统里,这种错误比“不知道”更危险。
因为用户会把答案当成公司制度、接口规范、产品说明或业务规则。
所以 Prompt 里必须明确:
如果资料中没有直接依据,请不要推测。或者:
如果无法从资料中得到答案,请回答“当前资料中没有找到明确依据”。这句话看似简单,但非常重要。
它给模型建立了一个边界:
不是所有问题都必须回答。
RAG 系统宁愿承认资料不足,也不要制造错误确定性。
不要让模型随便使用自己的知识
大模型本身有预训练知识。
这既是优势,也是风险。
在开放问答里,模型自己的知识可以帮助回答。
但在 RAG 场景里,模型自己的知识经常会干扰知识库资料。
比如用户问:
POST /orders 的 quantity 参数是不是必填?模型可能根据常见订单接口经验推断:
quantity 通常是必填字段。但你的接口文档里可能写的是:
quantity 字段在单品订单中必填,在套餐订单中由系统自动计算。如果模型自由发挥,就会把“通用经验”当成“当前系统规则”。
所以 RAG Prompt 里要明确限制:
不要使用资料之外的常识、经验或外部知识补充答案。这不是说模型不能理解资料。
模型当然需要理解、归纳和组织资料。
但它不能把资料之外的内容当成事实。
可以允许模型做有限归纳。
比如资料里写:
试用期员工年休假按入职时间折算。用户问:
试用期员工是否完全不能休年假?模型可以回答:
不是完全不能休。资料说明试用期员工年休假按入职时间折算。这是基于资料的合理归纳。
但不能进一步编出具体天数。
这就是 RAG Prompt 需要控制的边界。
输出格式会影响答案稳定性
很多人只关注 Prompt 内容,却忽略输出格式。
实际上,输出格式对 RAG 答案稳定性很重要。
如果不指定格式,模型可能这次先讲背景,下次先给结论,再下次写成一段长文。
这对用户体验和系统集成都不友好。
更稳定的做法是,为不同场景设计固定输出结构。
比如制度问答可以用:
结论: 依据: 注意事项: 来源:接口文档问答可以用:
结论: 参数说明: 示例: 来源:排障类问答可以用:
可能原因: 排查步骤: 依据: 下一步建议:输出格式不是为了让答案显得整齐。
它的真正作用是约束模型思考和表达。
比如要求先输出“结论”,可以避免模型绕太久。
要求输出“依据”,可以促使模型回到资料。
要求输出“来源”,可以增强可追溯性。
要求输出“资料不足”,可以减少硬编。
所以在 RAG 里,Prompt 模板不只是提示语,也是答案结构设计。
引用来源应该怎么设计?
RAG 系统里,引用来源非常重要。
用户不只想知道答案,也想知道答案从哪里来。
尤其是企业知识库、政策制度、技术文档、客服知识库和接口文档场景。
如果答案没有来源,用户很难判断它是否可信。
要让模型引用来源,前提是检索结果里要带来源信息。
比如每个 Chunk 不应该只有正文,还应该带:
document_id title section version updated_at url chunk_id然后在 Prompt 的上下文里保留这些信息。
示例:
[资料 1] 来源:员工休假管理办法 / 第 3 章 / 2026-01 版 内容:试用期员工年休假按入职时间折算。 [资料 2] 来源:考勤系统操作手册 / 年假申请 / 2025-11 版 内容:年休假申请需提前在考勤系统中提交审批。再要求模型:
回答中需要引用资料编号,例如“根据资料 1”。这样输出就可以是:
结论: 试用期员工不是完全不能休年假,资料说明年休假按入职时间折算。 依据: 根据资料 1,试用期员工年休假按入职时间折算。 来源: 资料 1:员工休假管理办法 / 第 3 章 / 2026-01 版需要注意的是,不要只让模型“随便引用来源”。
最好要求它只引用实际使用过的资料。
否则模型可能把没有支撑答案的资料也列出来。
可以在 Prompt 里写:
来源只列出实际支撑答案的资料,不要列出未使用的资料。引用来源设计好了,RAG 系统会更像一个可信的知识助手,而不是一个只会生成文本的聊天框。
多条资料冲突时怎么办?
真实知识库不是永远干净的。
旧制度、新制度、草稿、正式版、不同部门文档可能同时存在。
这会导致检索结果出现冲突。
比如资料 1 写:
远程办公每月最多 2 天。资料 2 写:
远程办公每月最多 4 天。如果 Prompt 没有规则,模型可能直接选择其中一个。
但这并不安全。
更好的做法是提前定义冲突处理规则。
比如:
如果资料冲突: 1. 优先使用版本更新的资料。 2. 优先使用正式制度,而不是草稿或历史记录。 3. 如果无法判断优先级,请明确说明资料存在冲突,不能给出唯一结论。然后让检索结果带上版本和状态:
资料 1: 标题:远程办公管理办法 状态:历史版本 更新时间:2025-03 内容:远程办公每月最多 2 天。 资料 2: 标题:远程办公管理办法 状态:正式版本 更新时间:2026-01 内容:远程办公每月最多 4 天。这样模型就能更稳定地回答:
结论: 远程办公每月最多 4 天。 依据: 资料 2 是 2026-01 的正式版本,优先级高于资料 1 的历史版本。如果没有版本和状态信息,模型就应该保守:
当前资料中存在冲突:一处写每月最多 2 天,另一处写每月最多 4 天。资料中没有提供版本或优先级信息,因此无法给出唯一结论。这类回答虽然不够“漂亮”,但它是可信的。
RAG 系统不能只追求流畅,还要追求边界清楚。
常见错误 Prompt 写法
第一个错误是规则太少。
比如:
请根据资料回答问题。这没有约束模型不要编,也没有说明资料不足怎么办。
第二个错误是规则太虚。
比如:
请准确回答用户问题。“准确”对模型来说不够具体。
应该写成可执行规则:
不要编造资料中没有的数字、日期、金额、接口字段和流程步骤。第三个错误是上下文没有来源。
只传入正文,不传标题、版本、时间、来源 ID。
这样模型即使回答对了,也很难给出可追溯引用。
第四个错误是把太多无关内容塞进 Prompt。
Prompt 再好,也挡不住上下文太乱。
如果检索和 Rerank 没做好,模型看到大量干扰内容,答案仍然可能不稳定。
第五个错误是让模型过度总结。
比如要求:
请充分发挥,给出全面建议。这类提示很容易让模型跳出资料范围。
RAG 里更适合写:
请只基于资料回答,不要补充资料外建议。第六个错误是所有场景共用一个 Prompt。
制度问答、接口问答、排障问答、客服问答、法律条款问答,对答案结构和风险边界的要求不同。
一个 Prompt 模板很难覆盖所有场景。
更好的做法是按场景维护多个 Prompt 模板。
Prompt 模板应该工程化管理
在 Demo 里,Prompt 经常直接写在代码里。
比如:
prompt = f"请根据以下资料回答问题:{context},问题:{question}"这在早期没问题。
但系统变复杂后,Prompt 应该像代码一样管理。
至少要做到几件事。
第一,模板集中管理。
不要散落在不同业务代码里。
可以放在配置文件、模板文件或 Prompt 管理模块中。
第二,模板版本化。
每次修改 Prompt,都应该知道改了什么。
因为 Prompt 改动可能影响答案行为。
第三,支持不同场景模板。
比如:
policy_qa_prompt api_doc_prompt troubleshooting_prompt customer_service_prompt summary_prompt第四,记录实际使用的 Prompt 版本。
当用户反馈答案错误时,需要知道当时使用的是哪个 Prompt。
第五,用测试集回归。
Prompt 不能只靠人工感觉调。
每次修改 Prompt 后,都应该用同一批问题测试:
是否更少幻觉 是否引用正确来源 是否能在资料不足时拒答 是否保持答案结构稳定第六,和检索日志一起记录。
一个完整的 RAG 调试记录应该包括:
用户问题 召回资料 Rerank 结果 最终上下文 Prompt 模板版本 最终 Prompt 模型回答 引用来源这样才能定位问题。
如果答案错了,可能是检索错了,也可能是 Rerank 错了,也可能是 Prompt 没约束住模型。
没有记录,就只能猜。
一个更完整的 Prompt 示例
下面给一个更完整的 Prompt 示例。
它不是唯一标准,但可以作为工程起点。
你是一个知识库问答助手,需要严格基于提供的检索资料回答用户问题。 回答规则: 1. 只能使用检索资料中的信息回答,不要使用资料之外的知识。 2. 如果资料中没有明确答案,请回答“当前资料中没有找到明确依据”。 3. 不要编造数字、日期、金额、版本号、接口字段、审批流程或制度条款。 4. 如果资料存在冲突,请说明冲突内容;如果无法判断优先级,不要给出唯一结论。 5. 回答应先给结论,再给依据。 6. 来源只列出实际支撑答案的资料。 7. 如果只能做有限推断,请明确说明这是基于现有资料的推断。 检索资料: {context} 用户问题: {question} 请按以下格式输出: 结论: 依据: 补充说明: 来源:对于很多 RAG 场景,这个模板已经能覆盖基本边界。
但如果是接口文档场景,还可以调整为:
结论: 参数说明: 请求示例: 注意事项: 来源:如果是排障场景,可以调整为:
可能原因: 排查步骤: 判断依据: 下一步建议: 来源:Prompt 不应该一成不变。
它应该服务于具体业务场景。
RAG Prompt 和前面模块的关系
Prompt 很重要,但它不是万能补丁。
如果文档切分很差,模型拿到的上下文就是碎的。
如果 Embedding 选型不合适,正确资料可能召回不到。
如果 Hybrid Search 没做好,编号、参数、版本号可能漏掉。
如果 Rerank 没做好,正确资料可能排在很后面。
如果上下文里混入大量无关资料,Prompt 也很难稳定控制模型。
所以 RAG Prompt 要放在完整链路里看。
一个更合理的流程是:
文档解析 ↓ 文档切分 ↓ Embedding ↓ 向量检索 + 关键词检索 ↓ Metadata Filter ↓ Rerank ↓ 上下文压缩 ↓ Prompt 约束 ↓ 模型生成 ↓ 答案与来源Prompt 是最后一道约束层。
它不能替代前面的检索质量。
但当前面的资料准备好了,Prompt 决定模型是否会基于这些资料稳定输出。
落地建议
如果你正在做 RAG 系统,可以按下面方式优化 Prompt。
第一,不要只写一句“根据资料回答”。
至少要写清楚回答规则、资料不足处理方式和输出格式。
第二,明确禁止编造关键事实。
尤其是制度、金额、时间、参数、版本、接口字段、流程步骤。
第三,要求引用来源。
前提是检索结果里要带来源信息。
第四,按场景设计模板。
不要让制度问答、接口问答、排障问答都共用一个模板。
第五,记录 Prompt 版本。
方便后续排查和回归。
第六,建立小型测试集。
包含正常问题、资料不足问题、冲突资料问题、相似但错误资料问题。
第七,把 Prompt 优化和检索优化一起看。
如果上下文本身不对,单纯改 Prompt 很难解决根因。
总结
RAG 的 Prompt 不是简单把资料和问题拼在一起。
它的核心作用,是约束模型基于资料回答,并在资料不足时保持诚实。
普通 Prompt 追求自然回答,RAG Prompt 追求有依据、可追溯、边界清楚。
一个可用的 RAG Prompt,应该包含角色说明、回答规则、检索上下文、用户问题和输出格式。
其中最重要的规则,是不要使用资料之外的信息,不要编造资料中没有的事实。
如果资料不足,系统应该明确说明没有找到依据,而不是强行给出答案。
如果资料冲突,系统应该说明冲突,而不是随便选择一个结论。
引用来源可以提升用户信任,也能帮助工程排查。
Prompt 模板也应该工程化管理,包括集中维护、版本记录、场景拆分和回归测试。
从 RAG 链路来看,Prompt 是生成前的最后一道约束层。
它不能替代文档切分、检索和 Rerank,但它决定模型是否会在正确资料基础上稳定输出。
下一篇文章,可以继续讨论复杂问题如何处理。
因为真实用户的问题经常不是一句简单查询,而是需要 Query Rewrite、多路查询甚至多步检索才能回答。