你的编程 Agent 记错的库版本
Diff 看起来很干净。Agent 导入了正确的模块,调用了看起来正确的函数,TypeScript 也没有报错。PR 描述甚至引用了文档。随后 CI 中的构建开始运行,调用却由于 TypeError: x is not a function 而崩溃 —— 这是因为该函数在八个月前的一次小版本更新中被拆分成了两个,而 Agent 是根据其训练数据中存在的库版本生成的代码,而不是你 package.json 中安装的版本。
这并不是“LLM 会产生幻觉”这一框架能让你做好准备的那种故障。模型并不是在发明一个从未存在的 API。它是在记忆一个曾经存在但现在已不存在的 API。Agent 进行推理的心智模型是一个冻结在训练时的快照。世界在向前发展。代码库在向前发展。而 Agent 却一无所知,因为没人告诉它。
最近的评估为这一问题提供了确凿的数据。一项 2025 年 ICSE 的研究发现,在七个受评估的 LLM 中,生成的代码中弃用 API 的使用率在 25% 到 38% 之间。另一项针对 Python 库的基准测试显示,模型对训练截止日期前存在的 API 的准确率从 56.1% 下降到对之后引入的 API 的 32.5% —— 这种 24 个百分点的断崖式下跌是模型自身无法察觉的。训练截止日期漂移(Training-cutoff drift)不是一种长尾风险;它是生产环境中每个编程 Agent 的结构性属性。
训练截止日期漂移并非通用的幻觉
标准的幻觉框架 —— 模型对自己从未了解过的事情表现出迷之自信的错误 —— 忽略了这里发生的情况。模型曾经知道。它学习过你的库。它可以背诵函数签名、参数顺序、返回类型,甚至更早的边界情况。它不知道的是,这些事实中哪些仍然是真的。
将此视为“模型编造了一些东西”会导致团队选用错误的工具。他们会收紧系统提示词。他们会增加一个验证步骤,要求模型复核自己的输出。这两种干预措施都假设 Agent 有办法识别其记忆与现实世界之间的差距。它没有。从模型的角度来看,每一个回忆起的 API 都同样生动;被弃用的 API 和当前的 API 占据着相同的激活邻域。
将此称为“版本漂移”(version drift)更为精准。模型是根据生态系统中一个过时的快照进行推理的,而它接触到的每个库都有其自身的漂移率。一个三年未发布破坏性变更的“沉睡库”几乎不会产生漂移。而一个正处于重写中期的框架则会在生成的每一行代码中产生漂移。Agent 无法感知自己处于哪个库中,并以同样的自信对待两者。
这在操作层面上很重要,因为缓解策略是不同的。通用的幻觉通过“落地”(grounding)来减少 —— 给模型提供更多相关的上下文,它编造的东西就会减少。训练截止日期漂移则需要通过特定的“时效性落地”(recency grounding)来减少:需要向模型展示自截止日期以来发生了什么变化,而不仅仅是今天存在什么。如果不标记差异(delta)而只展示当前文档,会让它对看起来熟悉的部分进行模式匹配,并用其先验知识悄悄覆盖它们。
隐藏在眼皮底下的失效模式
几种特定的模式会产生在代码审查中难以捕捉的漂移。
能编译但已损坏的调用。 在运行时重命名后,TypeScript 类型定义通常会长时间保留历史形状。某个函数在一次小版本更新中被弃用;旧名称作为别名继续存在两个小版本;类型定义全程保留旧名称。Agent 生成了对旧名称的调用。编译器没有报错。但运行时会报错,且仅在执行该分支时报错 —— 而 tsc 通过是大多数团队信任 Agent 输出的信号。在这种失效模式下,直到测试运行该路径之前,Agent 看起来都是胜任的。
看似正确的 package.json。 通过读取 package.json 来进行落地的编程 Agent 表现往往比忽略它的 Agent 更差。Agent 看到 "react": "^18.2.0",识别出这是一个它见过很多示例的版本,并生成了匹配该范围内略有不同的修订版本的代码。它甚至不是在幻觉版本 —— 它正确地识别了主版本,并过度自信地填充了次版本。版本约束变成了一种从记忆中生成的许可,而不是验证的提示。
传递性形状携带者。 一个你没有直接导入的库重新导出了你直接导入的库中的一个类型。该类型的形状在上游库中发生了变化。你的直接依赖项仍然暴露旧的形状,因为它尚未更新其对等依赖(peer dependency)。Agent 根据它学到的权威上游文档生成代码。传递的形状不一致。错误消息指向的不是这两个库中的任何一个,团队花了一个下午去寻找一个本不该由他们编写的 Bug。
“已删除”的配置键。 配置键特别容易产生漂移,因为它们存在于类型系统不监管的 YAML 或 JSON 中。一个键在小版本更新中被重命名;新键是必需的;旧键被默默忽略。Agent 输出了旧键。应用程序启动了。该键本应启用的功能毫无反应。生产环境显示“部署成功”,因为没有发生崩溃,而当客户询问为什么某些功能失效时,回归问题才被发现。
这四种模式的共同特征是故障表面背离了 Agent。崩溃发生在用户代码中,类型检查器通过了,Lint 通过了,而审阅者略读的链接自历史记录的文档描述了被弃用的行为。Agent 是最后被怀疑的对象,因为 Agent 看起来是正确的。
弥合差距的实际表现
在高负载下仍然有效的模式是:将智能体(Agent)接触到的每个库的已安装版本视为不可信的上下文,必须在每个相关轮次开始时重新确立。具体而言,有四项干预措施可以叠加使用。
生成前的版本前奏。 在智能体向导入库 X 的文件中写入调用之前,它必须明确说明安装了哪个版本的 X,以及它预计会遇到哪些与其训练时知识不同的差异。这不是一个可以敷衍了事的步骤——模型必须承诺具体的细节(“安装了 react 19.0.2;主版本升级删除了隐式的 children 属性类型,并更改了 Suspense 边界语义”),因为承诺细节会迫使它识别自己何时实际上并不了解。其成本是每个库增加一个额外的轮次,每个工作区会话仅需支付一次。
限定于实际安装版本的文档检索。 这是一个检索步骤,用于获取智能体即将使用的特定符号的当前 API 参考,并将其版本锁定为已安装的版本。2025 年的 RAG 基准测试显示,这能将知识截止日期后的准确率提升约 13.5 个百分点——这很有意义,但并非万能。对于任何针对第三方库编写代码的智能体来说,这足以成为标准步骤;但仅靠这一项干预措施是不够的。
更新日志指纹识别。 文档中最昂贵的部分很少是真正重要的部分。真正重要的是增量——即自模型知识截止以来发生了哪些变化。建立一个预构建索引,给定库和截止日期,返回更名、删除和签名变更的符号列表。每当这些库出现在工作区中时,就将该列表加载到智能体的上下文中,这给了模型一个正确的锚点:“这些特定的东西和你记忆中不同。”这比完整文档的 Token 效率更高,且在行为上更有效,因为它直接针对失败模式,而不是寄希望于覆盖范围。
生成后的类型定义交叉检查。 在智能体编写代码后,进行一次静态扫描:遍历 AST,识别对导入的第三方符号的每一次调用,并根据实际安装的类型定义(而非智能体记忆中的定义)通过 grep 检查调用形状。这捕获了“能编译但已损坏”的模式。它成本低廉、具有确定性,并且完全不需要模型参与。
这四项措施单独看都不完美,但结合在一起可以封闭大部分的漂移覆盖面。如果团队只发布其中一项——通常是文档检索,因为它听起来像是标准答案——他们会获得质量提升,但仍会以一种他们无法解释的速度持续产生弃用 API 的回归问题。
构建衡量漂移而非仅衡量准确率的评估集
大多数编程智能体的评估集(Evals)从早于模型截止日期的快照中选择问题。这不像过拟合那样属于方法论缺陷,而是一种测量差距,它美化了每个模型,却没能给团队提供关于他们在生产环境中实际会遇到的失败模式的信号。
感知漂移的评估需要刻意构建。选取一组在模型训练截止日期后发布了已知破坏性变更的库。构建一些场景,其中正确的生成需要识别出 API 已经改变。评分标准不仅在于生成是否正确,还在于智能体是否 检测到了偏差——它是否询问了、是否获取了文档、是否标记了不确定性——而不是充满自信地按照旧形状生成代码。
这比组建通用的代码生成评估集更难,因为随着模型的迭代,评估集会过时,而且“正确”的行为在某种程度上是一种主观判断(智能体何时该询问,何时该直接查找)。但这是衡量你的生产智能体失败原因的唯一评估方式。没有漂移评估集的团队,本质上是选择通过用户事故来发现漂移。
另一个值得监测的相关信号是智能体对 接近截止日期符号的弃权率。一个对看到的每个符号(无论库的新旧程度如何)都能自信生成的智能体,即使生成结果凑巧正确,也是校准失调的。对于在截止日期后升级了大版本的库,正确的行为应该是放慢速度、获取文档并验证,而不是流畅地生成。衡量弃权率为团队提供了一个跨模型版本都有效的领先指标。
架构上的觉醒
更深层次的一点是:LLM 对它见过的每个库的知识都固定在某个特定时刻,而那个时刻与智能体正在生成的时刻并不相同。每个编程智能体都是来自其训练截止日期的时空旅行者,而过去与现在之间的差距充满了破坏性变更,智能体无法仅凭其权重发现这些变化。
内化了这一点的团队不再试图让模型对“版本更聪明”,而是开始将时效性视为一种显式的上下文输入,就像处理模型不具备的任何其他状态一样。已安装的版本进入系统上下文。截止日期以来的更新日志进入系统上下文。“允许模型假设什么”的边界被划定在截止日期,而团队的工具链负责填补差额。
不这样做的团队发布的智能体,会不断地将昨天的代码写进明天的分支——充满自信、行云流水,却错误百出——并在一场接一场的生产事故中逐渐发现这一差距。修复方法不是换一个更好的模型,而是给模型一个途径,让它学习自上次观察以来发生了什么变化。
- https://arxiv.org/html/2406.09834v3
- https://yebof.github.io/assets/pdf/wang2025icse.pdf
- https://arxiv.org/html/2604.09515v1
- https://arxiv.org/pdf/2503.16922
- https://arxiv.org/pdf/2511.21022
- https://aclanthology.org/2025.naacl-long.348.pdf
- https://assets.amazon.science/8f/83/7407a5634a80a39e82b52ae935fe/on-mitigating-code-llm-hallucinations-with-api-documentation.pdf
- https://blog.google/innovation-and-ai/technology/developers-tools/gemini-api-docsmcp-agent-skills/
- https://otterly.ai/blog/knowledge-cutoff/
- https://github.com/HaoooWang/llm-knowledge-cutoff-dates
