AI 问答不再"一本正经地胡说":30 轮提示词迭代,沉淀 4 条防幻觉铁律
面向读者的快速结论:让 AI 助手不乱编,关键不在"换个更大的模型",而在提示词里把"不知道时怎么办"的路径写死 。经过生产环境 30+ 轮迭代,我把它收敛成 4 条可复制的工程铁律------每条都有落地写法和反面教材。文末的
validator.py静态校验器,能把其中最容易回归的两条变成 CI 自动检查,改提示词时违规直接拦下。
一、事故现场:AI 编了个 75.6MW
"你看它答的------当前负荷 75.6MW,处于偏高水平,建议降低负荷。"
我把这条回答截图发给值班人员核对,对面回了一句:"我们机组现在压根没在满发,负荷率才 75%,你 AI 从哪看出'偏高'了?"
这是我给某火电企业做 AI 数据助手时遇到的第一起"幻觉事故"。助手接通了实时数据接口,本应只回答查到的数------但它自己脑补了两层:
- 把 75.6% 的负荷率 当成了 75.6MW 的负荷(数值串台);
- 又基于这个错误数值补了一句"处于偏高水平"的判断(无依据推断)。
单看任何一层都"像那么回事",叠在一起就是误导运维决策的错误答案。
更糟的是另一类:助手接入了企业知识库(12 篇运维文档),当文档里没有答案时,它会自编一句"据文档记载..."------文档里根本没有这句话。知识库问答一旦开始编,整个产品的可信度就归零:用户不知道哪句能信。
三个高发场景摆在一起,规律很明显:
| 场景 | 幻觉表现 | 后果 |
|---|---|---|
| 数值问答 | 编造"当前负荷 75.6MW" | 一线按错误数据操作 |
| 报表问答 | 对查询结果做无依据的"异常判断" | 误导运维决策 |
| 知识库问答 | 无答案时自编"据文档记载..." | 产品整体信誉受损 |
二、病根:不是模型笨,是提示词给了它"自由发挥"的空间
第一反应是换模型。试过更大参数的版本,幻觉照样出------因为根因不在模型能力,而在提示词结构:
早期提示词里写着"你可以结合专业知识补充说明当前工况"。 这一句"补充说明",就是幻觉的入口:模型分不清"哪些可以说、哪些必须查了才能说",于是顺着训练数据里的常识自由发挥。
模型本质是"下一个词预测器",你不给它"不知道时怎么办"的强制路径,它就自己编一条。这和人的行为一样:被问倒又没人规定怎么回答时,大部分人选择"先编个像样的"。
所以方向从"调模型"转成"改提示词":把回答的边界用规则钉死。这一改,就是 30+ 轮迭代。
三、30 轮迭代,收敛成 4 条铁律
迭代过程很枯燥:加一条规则 → 跑一轮测试用例 → 发现新漏洞 → 再加规则。测试集从十几条涨到 100+ 条,提示词从 1.0 版改到封版。最后真正留下来的,不是几十条琐碎禁令,而是 4 条能互相咬合的铁律。
铁律一:未查询,不得断言
规则:任何数据类问题,必须先完成工具调用拿到返回值,才允许输出数值结论。回答中出现的每个数值,必须能在最近一次工具返回值里找到。
落地写法:
text
回答中出现的所有数值,必须来自最近一次工具调用返回值;
未查询到的指标,明确输出「未查询到」,禁止用历史经验或常识补充。
反面教材:
text
你可以结合专业知识补充说明当前工况。
"补充说明"四个字就是幻觉入口------模型会顺着知识库/常识自由发挥。把它换成"未查询到就直说",数值编造当场断根。
铁律二:写规则,不写死数据
规则 :提示词只描述"如何获取数据",不写死任何具体数值、指标名、模型名。数据一律通过 {{占位符}} / {tool_result} 动态注入,指标列表在运行时从工具返回值匹配。
落地写法:
text
指标列表、单位、量纲一律以工具返回值为准;
用户提到本系统未注册的指标时,反馈「未找到该指标」,并列出可用指标来源。
反面教材:
text
本系统常用指标:负荷率、煤耗、主汽温度、给水流量...
写死列表有两个致命问题:① 新指标上线,提示词不更新就漏答;② 模型把"列表"当"全集",列表外的指标直接拒答或编造。写死的知识一天后就过期,规则十年不过期------这是整轮迭代里踩得最深的一个坑。
铁律三:没有依据的推断,一个字不写
规则:允许给建议,但必须显式区分「数据结论」(来自工具返回值)与「经验建议」(来自模型推理),且经验建议不得伪装成数据结论。
落地写法:
text
输出分两段:
① 数据结论:仅陈述工具返回值,不做好坏评价;
② 建议:以「建议」为前缀输出经验性判断,禁止把建议表述为数据事实。
反面教材(就是开头的 75.6MW 事故):
text
当前负荷 75.6MW,处于偏高水平,建议降低负荷。
"处于偏高水平"是推断,和"75.6MW"混在一句里,用户无法区分。真实事故就是模型把 75.6% 负荷率误判成"异常偏高"------数据与推断不分离,错一个就连坐错一片。
铁律四:引用来源,让答案可回溯
规则:知识库类回答必须标注来源文档;数值类回答标注来源接口/测点;无来源时明确声明。
落地写法:
text
引用知识库内容时,以「[来源] 文档名/章节」标注;
数值来自实时接口时标注「(实时)」,来自报表接口时标注「(报表,统计周期)」。
反面教材:
text
据运维手册记载,凝汽器真空应在 -90kPa 以上。
不写来源 = 无法验证 = 无法追责。写出来源后,哪怕答案错了,也能快速定位是哪份文档、哪条链路出的问题------把"AI 撒谎"降级成"链路 bug",问题立刻可修。
四、把铁律变成机器检查:validator.py
文字规则最大的敌人是回归:改提示词加功能时,顺手写死一个阈值,四铁律立刻破功,而人很难注意到。
所以我把最容易被破坏的铁律二、四转成了静态校验器 validator.py(仓库 prompts/ 内可直接跑):
| 规则 | 检查内容 | 对应铁律 |
|---|---|---|
| R1 裸数字 | 正文出现阈值/百分比/固定参数 | 铁律二 |
| R2 写死实体 | 命中内置业务指标/模型黑名单 | 铁律二 |
| R3 缺占位符 | 动态占位符 {{...}} 数量不足 |
铁律一/三 |
| R4 缺铁律 | 未包含「未查询不得断言/引用来源/禁止编造」等约束 | 铁律四 |
实测效果:
bash
$ python validator.py
扫描 3 个文件:违规 0 项,警告 0 项
[✅ 通过] agent_base.md
[✅ 通过] kb_ops_agent.md
[✅ 通过] report_query_agent.md
$ python validator.py -f examples/bad_prompt.md --ci
扫描 1 个文件:违规 17 项,警告 0 项
[⚠️ 警告] bad_prompt.md
ERROR R1: 正文出现裸数字「80%」...(写死阈值)
ERROR R2: 写死业务指标「负荷率」「煤耗」...(写死实体)
ERROR R3: 动态占位符仅 0 个(缺注入点)
ERROR R4: 防幻觉铁律关键词仅命中 0/3(缺约束)
退出码: 2 ← CI 直接拦下
接入工作流的姿势很轻:新 Agent 上线 复制模板改占位符 → 跑一次校验;每次改提示词 跑一遍防回归;再往前一步,python validator.py --ci 挂进提交流水线,违规直接红。
五、收尾:规则 + 测试的闭环
30+ 轮迭代最后封版时,靠的不是"感觉这版更稳了",而是一套可重复的验证:提示词每改一版,跑一遍 100+ 条测试用例,四类问答场景(实时查询/调整建议/报表问答/知识库)逐一回归。封版的标准是:同一批曾出过幻觉的问题,不再复现。
如果把这段经历压缩成一句话给做 AI 应用的同行:
别指望模型"懂事",要在提示词里把"不知道时怎么办"钉死;再把这些规则变成测试用例和 CI 检查------让幻觉没有回归的机会。
整套资产(4 条铁律方法论 + 3 份落地模板 + 校验器 + 反面教材)已开源在 engineering-delivery-playbook,欢迎 clone 下来跑一遍 validator.py 感受下。防幻觉没有银弹,但至少有章可循。
本文为脱敏改写,不涉及任何真实业务数据与客户信息。欢迎 Star、Issue 交流。