@TOC
AI 生成代码最烦的一类问题,不是报错红线一大片——那种你一眼能看见。
真正费时间的是:能编译、能过 lint、命名也体面,一跑就炸;或者更糟,测试绿了,线上才发现调用了一个根本不存在的字段。
这就是幻觉:模型按「常见写法」补全,补出来的东西在训练集里像那么回事,在你的项目里却没有。
这篇不讲原理论文,只讲我实际在用的 4 类优先排查,加一段可复制核对 Prompt。
一、先建立态度:假设它会「合理地说谎」
把 AI 当同事可以,别把它当文档。
| 它擅长 | 它常撒谎的地方 |
|---|---|
| 常见模式、样板结构 | 冷门 SDK 的方法名 / 参数 |
| 把你给的片段改通顺 | 你们内部包的私有 API |
| 按注释意图补全 | 某版本才有、某版本已删的 API |
| 解释「这段大概在干什么」 | 编造「官方推荐」的配置项 |
所以流程应该是:生成 → 核对事实 → 再跑通,不是生成完就信。
二、四类幻觉(按出现频率)
1. 编造或不存在的包 / 模块
表现:
import/require了一个 registry 里搜不到的名字- 包名差一个字母、或把两个库的名字揉在一起
- 推荐「安装 xxx」但 PyPI / npm / Go module 根本没有
怎么查(选你的生态一条即可):
# Go
go list -m <module>@latest
# npm
npm view <package> version
# Python
pip index versions <package>
# 或: python -c "import importlib.util; print(importlib.util.find_spec('pkg'))"
红旗:AI 说「用这个很流行的库」,但你本地以前从没见过、同事也没听过——先查 registry,再 go get / npm i。
2. 编造方法、字段、配置开关
表现:
client.DoSomething()类型检查过不去,或运行时报undefined method- JSON / protobuf 字段在真实响应里不存在
- 配置里写了
enable_foo: true,框架根本不认这个 key
怎么查:
- 跳转到定义(Go to Definition)。跳不过去,基本就是假的。
- 对照你们仓库里已有的调用,别对照它「回忆」的文档。
- 对外 API:先打开真实 OpenAPI / proto / 抓一条真实响应,再让它写解析。
经验法则:没在本仓库或官方 schema 里出现过的符号,默认算嫌疑。
3. 版本错位(API「曾经有过」)
表现:
- 文档示例是 v2 的,你锁的是 v1
- 方法还在,但参数签名变了(多了一个必填、改了枚举)
- 弃用 API 仍被当成「最佳实践」推荐
怎么查:
- 看
go.mod/package.json/requirements里的实际版本 - 用该版本的源码或 godoc / typedoc,不要用「网上随便一篇 2022 教程」
- 让 AI 改代码时,把版本号写进 Prompt:
我们用 foo v1.4,不要用 v2 API
4. 逻辑幻觉:编译过、语义错
表现:
- 把
amountDue和amountPaid用反 - 「幂等」写成了「再试一次就再扣一次」
- 错误码映射表看起来整齐,但和业务约定对不上
这类最难自动发现。清单帮不上全部,但可以降风险:
- 用真实 fixture(抓过的响应、落盘的样例)测解析,别用 AI 编的假 JSON
- 关键路径至少手写 1~2 个断言:成功、权限失败、空数据
- Code review 时优先盯「钱、权限、状态机、删除」
三、可复制核对 Prompt
生成告一段落、准备提交前,把相关 diff 或文件丢进去:
你是事实核对员,不是风格评审员。
根据我提供的代码,只检查「可能不存在 / 可能用错」的事实问题。
请逐项输出:
1. 外部依赖:每个新引入的包/模块,标注「需人工在 registry 核实」或「仓库内已有引用可交叉验证」
2. 符号:列出所有对外部 SDK / 内部包的新调用(包.函数、结构体字段、配置 key)
3. 对每个符号给出:
- 依据:你是根据我贴的代码/文档得出,还是模型先验猜测?
- 若是猜测,明确写「未验证,可能是幻觉」
4. 版本风险:若代码依赖某库行为,指出需要对照的版本约束(从我贴的 go.mod/package.json 读)
5. 不要建议重命名、格式化;不要编造「官方文档链接」
规则:不确定就说不确定。禁止用「一般来说」「通常」掩盖未核实。
用法:
- 一次只核对本轮改动,别整仓扫描凑条数
- 它标「未验证」的项,你用 Go to Definition / registry 查,比跟它辩论快
- 我在 wescode 里习惯是:改完先本地编译 → 跑这段核对 → 再跑相关测试
四、三个容易误判的点
误判 1:把「本仓库私有封装」当成幻觉
AI 调了 internal/pkg/foo.Bar(),网上搜不到,但仓库里有——这是正常。以仓库为准,别以搜索引擎为准。
误判 2:生成代码里的示例密钥 / 假包名
文档示例里的 github.com/example/foo 本来就是假的。区分「示例占位」和「准备提交的 import」。
误判 3:类型还没索引完就判死刑
刚拉开项目、语言服务还在加载,跳转失败不一定是幻觉。等索引稳住,或命令行编译一次再定论。
五、什么时候可以少查一点
你非常熟的样板(改个字段名、加个日志)。扫一眼 import 即可。
纯删除、纯移动且编译已过。 幻觉主要出现在「新增调用」。
已经用真实 schema + 契约测试罩住的接口层。 解析层仍建议用真实 fixture,但不必每轮手搓四类全查。
小结
AI 编程的幻觉,本质是流畅的不可靠。
优先查这四类:不存在的包、不存在的符号、版本错位、语义张冠李戴。工具帮忙列嫌疑,registry、跳转定义、真实 fixture 负责宣判。
别跟模型比谁记得更「像官方」——以你仓库和锁文件里的事实为准。
上面的核对流程我是在日常 AI 编程里用的,编辑器侧用的是 wescode,官网是 weisyn.com。你们还见过哪些「特别像真的」幻觉案例,欢迎评论区贴,我好补进清单。