AI 写代码「看起来对」但跑不通?先查这 4 类幻觉

0 阅读5分钟

@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

怎么查:

  1. 跳转到定义(Go to Definition)。跳不过去,基本就是假的。
  2. 对照你们仓库里已有的调用,别对照它「回忆」的文档。
  3. 对外 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。你们还见过哪些「特别像真的」幻觉案例,欢迎评论区贴,我好补进清单。