大模型总爱编答案?幻觉抑制攻略
作者:程序员马丁
Ragent AI —— 从 0 到 1 纯手工打造企业级 Agentic RAG,拒绝 Demo 玩具!AI 时代,助你拿个offer。
上一篇讲完检索策略,咱们已经能通过混合检索 + 重排序拿到高质量的 Top-K chunk 了。到这一步,很多人觉得 RAG 的核心问题已经解决了——检索到了对的内容,大模型自然能给出对的答案。
但实际跑起来,你会发现事情没这么简单。
假设你在维护一个电商客服知识库,用户问:iPhone 16 Pro Max 拆封后还能退吗?
经过混合检索 + 重排序,Top-1 返回的 chunk 是:
iPhone 16 Pro Max 因屏幕定制工艺,拆封后不支持七天无理由退货。如需退货,需经售后检测确认存在质量问题。
chunk 找得很准,完全命中了用户的问题。但你把这个 chunk 和用户问题一起丢给大模型,模型的回答有可能是:
可以退货的。根据消费者权益保护法,您购买的商品在七天内都可以无理由退货。建议您联系客服办理退货手续。
我通过千问 Qwen3-Flash 模型测试了下,结果如下:

chunk 明明说:不支持七天无理由退货,模型却回答:可以退货——它用自己训练时学到的通用知识覆盖了检索到的具体规则。
这就是 RAG 系统的最后一公里问题:检 索只是一半,生成才是最终交付。chunk 质量再高,如果 Prompt 设计不好,模型照样会给出错误答案。
这一篇咱们就来聊聊怎么设计 Prompt,让大模型老老实实基于检索结果回答问题。
从检索到生成:最后一公里的质量问题
1. 好 chunk + 烂 Prompt = 烂答案
上面 iPhone 退货的例子不是个例。再看几个典型的翻车场景:
场景一:凭空捏造细节
用户问:退货运费谁承担?
chunk 内容:质量问题退货,运费由商家承担;非质量问题退货,运费由买家承担。
模型回答:退货运费由商家承担,一般会在 3-5 个工作日内退还到您的账户,退款金额包含商品价格和运费。
chunk 里只说了运费由商家承担,没提退款时效和退款范围,但模型自己补了 3-5 个工作日和退款金额包含商品价格和运费这些细节。如果实际退款时效是 7-15 个工作日,这个回答就会误导用户。
场景二:张冠李戴
用户问:AirPods Pro 的保修期是多久?
检索返回了两个 chunk:
- chunk 1:AirPods Pro 保修期为 1 年,自购买之日起计算。
- chunk 2:AppleCare+ 服务计划可将保修期延长至 2 年,并提供意外损坏保修。
模型回答:AirPods Pro 的保修期为 2 年,自购买之日起计算。
模型把 chunk 2 的 2 年和 chunk 1 的自购买之日起计算混在一起了。实际上 2 年是 AppleCare+ 的延长保修,不是默认保修期。
场景三:答非所问
用户问:我的订单什么时候发货?
chunk 内容:标准订单在付款成功后 48 小时内发货,预售商品以详情页标注的发货时间为准。
模型回答:我们的物流合作伙伴包括顺丰、圆通、中通等,全国大部分地区可实现次日达。如需查询物流信息,请登录 APP 查看订单详情。
用户问的是:什么时候发货,chunk 里有明确答案(48 小时内),但模型跑去介绍物流合作伙伴了。
2. RAG 生成阶段的核心挑战
看完这几个例子,你会发现 RAG 生成阶段面临三个核心挑战:
| 挑战 | 表现 | 后果 |
|---|---|---|
| 幻觉(Hallucination) | 模型编造 chunk 里没有的信息,或者篡改 chunk 的内容 | 用户拿到错误答案,严重时引发客诉甚至法律风险 |
| 答非所问 | 模型没有聚焦用户的具体问题,回答了相关但不对口的内容 | 用户体验差,需要反复追问 |
| 缺乏可追溯性 | 用户不知道答案的依据是什么,无法验证对错 | 信任度低,企业级场景无法通过合规审计 |
这三个问题的根源都指向同一个地方——Prompt 设计。接下来咱们就从 Prompt 的结构开始,一步步解决这些问题。
RAG Prompt 的三段式结构
RAG 场景下的 Prompt 不是随便写一句请回答用户的问题就行的。一个设计良好的 RAG Prompt 通常由三段组成:
- 系统指令(System Prompt):告诉模型你是谁、你该怎么做、你不能做什么
- 检索上下文(Retrieved Context):把检索到的 Top-K chunk 喂给模型
- 用户问题(User Query):用户的原始提问
打个比方,系统指令像是给新员工的岗位手册(你的职责是什么、红线在哪里),检索上下文像是给他的参考资料(回答问题只能基于这些材料),用户问题就是客户的来电。
1. 系统指令(System Prompt):定义模型的角色和行为边界
系统指令是整个 Prompt 的总纲,决定了模型的行为模式。在 RAG 场景下,系统指令最核心的任务是:让模型只基于检索到的上下文回答问题,不要用自己的知识自由发挥。
1.1 一个基础版 System Prompt
先给一个可以直接用的模板,然后逐条解释:
你是一名专业的电商客服助手。你的任务是根据【参考资料】中的信息,准确回答用户的问题。
请严格遵守以下规则:
1. 只基于【参考资料】中的内容回答问题,不要使用你自己的知识。
2. 如果【参考资料】中没有足够的信息来回答用户的问题,请明确回答:"根据现有资料,暂时无法回答该问题。建议您联系人工客服获取更多帮助。"
3. 不要编造任何【参考资料】中没有提到的信息,包括数字、日期、金额等具体细节。
4. 回答时请引用参考资料的编号,格式为 [1]、[2] 等,标注在相关句子的末尾。
5. 如果多条参考资料的信息存在冲突,请指出冲突并告知用户以最新的资料为准。
6. 用简洁、友好的语气回答,避免过于官方或生硬的表述。
逐条拆解一下每条指令的作用:
| 规则 | 作用 | 解决的问题 |
|---|---|---|
| 规则 1:只基于参考资料回答 | 限制模型的知识来源,防止它用训练数据里的通用知识覆盖检索结果 | 幻觉——篡改事实 |
| 规则 2:信息不足时明确告知 | 给模型一个"兜底出口",不知道就说不知道 | 幻觉——凭空捏造 |
| 规则 3:不要编造具体细节 | 强调数字、日期、金额这些容易被编造的信息 | 幻觉——捏造细节 |
| 规则 4:引用参考资料编号 | 让答案可追溯,用户能验证 | 缺乏可追溯性 |
| 规则 5:处理信息冲突 | 多个 chunk 说法不一致时,模型不要自己选一个,而是告知用户 | 张冠李戴 |
| 规则 6:语气要求 | 控制回答风格,符合客服场景 | 答非所问(间接) |
使用后效果立竿见影,同样的问题和模型,效果如下:

1.2 常见的 System Prompt 设计误区
误区一:太短,没有约束
你是一个客服助手,请回答用户的问题。
这种 Prompt 等于没有约束。模型会用自己的知识自由发挥,检索到的 chunk 只是参考,不是依据。
误区二:太长,指令冲突
有些团队恨不得把所有能想到的规则都塞进去,写了几十条指令。结果指令之间互相矛盾——比如一条说“回答要详细”,另一条说“回答要简洁”。模型不知道听哪个,表现反而不稳定。
经验法则:System Prompt 控制在 5~8 条核心规则,每条规则聚焦一个明确的行为约束。
但是经过我实际测试,对于复杂场景,5~8条远远不够,这个时候就需要大量测试,看是否有左右互搏的情况存在。
误区三:没有兜底指令
如果不告诉模型“不知道的时候该怎么办”,它会默认“尽力回答”——也就是开始编造。兜底指令是抑制幻觉最关键的一条,不能省。
2. 检索上下文(Retrieved Context):把 chunk 喂给模型
拿到 Top-K chunk 之后,怎么组装成上下文喂给模型?这里有几个关键决策。
2.1 上下文的组装格式
推荐的格式是:每个 chunk 带编号、带来源信息,用明确的分隔符隔开。
【参考资料】
[1] 来源:退货政策文档 | 更新时间:2026-01-15
iPhone 16 Pro Max 因屏幕定制工艺,拆封后不支持七天无理由退货。如需退货,需经售后检测确认存在质量问题。
[2] 来源:通用退货规则 | 更新时间:2026-01-10
标准商品在签收后 7 天内可申请无理由退货,商品需保持完好,不影响二次销售。
[3] 来源:退货运费规则 | 更新时间:2026-02-01
质量问题退货,运费由商家承担;非质量问题退货,运费由买家承担。
这个格式有几个设计要点:
- 编号 [1] [2] [3]:方便模型在回答时引用,也方便后端解析引用关系
- 来源信息:告诉模型(和用户)这条信息从哪来的,提升可追溯性
- 更新时间:当多条 chunk 信息冲突时,模型可以根据时间判断哪条更新
- 明确的分隔符:用空行隔开每个 chunk,避免模型把相邻 chunk 的内容混在一起理解
来源信息和更新时间来自元数据(Metadata),这就是咱们在元数据管理那一篇讲的回答可引用和回溯纠错的实际应用。
2.2 上下文窗口的限制与应对
大模型的上下文窗口是有限的。虽然现在很多模型支持 128K 甚至更长的上下文,但塞太多 chunk 进去并不是好事:
- 关键信息被稀释:模型需要在大量文本中找到和问题最相关的部分,chunk 越多,噪音越大,模型越容易被不相关的内容干扰
- 迷失在中间(Lost in the Middle):研究表明,大模型对上下文中间位置的信息关注度较低,排在中间的 chunk 容易被忽略
- 成本增加:输入 token 越多,API 调用费用越高,响应延迟也越大
经验法则:
| 场景 | 推荐 chunk 数量 | 理由 |
|---|---|---|
| 简单事实问答(如退货政策) | 3~5 个 | 答案通常在 1~2 个 chunk 里,多给几个做补充 |
| 复杂问题(如对比多个产品) | 5~8 个 | 需要综合多个 chunk 的信息 |
| 总结类问题(如某个品类的所有规则) | 8~10 个 | 需要覆盖更多内容,但要注意去重 |
如果你用了重排序(Reranker),Top-K 的质量已经很高了,通常 3~5 个 chunk 就够用。宁可少给几个高质量的,也不要多给一堆低质量的。
3. 用户问题(User Query):原始问题还是改写后的问题
最简单的做法是直接用用户的原始问题。对于大多数场景,这就够了。
用户问题:iPhone 16 Pro Max 拆封后还能退吗?
但有些场景下,用户的原始问题可能不够清晰或者有歧义。比如用户问“退货怎么弄”,这个问题太模糊——是问退货流程?退货条件?还是退货运费?
这种情况可以通过 Query 改写(Query Rewriting)来优化,比如把“退货怎么弄”改写成“请问退货的具体流程和条件是什么”。但 Query 改写本身是一个独立的话题,涉及到多轮对话上下文理解、意图识别等,这一篇先不展开,后续篇章再详细讲。