当数据库迁移悄然摧毁 AI Agent 的世界模型
你的团队在周二执行了一次常规数据库迁移——将 last_login_date 重命名为 last_activity_ts,并扩展其语义以包含 API 调用。没有服务中断。测试通过。仪表盘更新。但你的 AI Agent——那个回答客户关于用户活跃度问题的 Agent——开始悄悄给出错误答案。没有报错,没有告警,没有堆栈跟踪。它只是自信地基于一个已经不存在的世界进行推理。
这就是 AI 工程中几乎无人关注的 Schema 迁移问题。你的 Agent 从工具描述、few-shot 示例和检索上下文中构建了一个隐式的数据模型。当底层 Schema 发生变化时,这个模型就变成了谎言——而 Agent 没有任何机制来检测这种矛盾。
Schema 与 Prompt 之间的隐形契约
每个接触结构化数据的 AI Agent 都在一个隐式契约下运行。工具定义说"这个数据库有一个名为 last_login_date 的 DATE 类型列"。Few-shot 示例演示了对该列的查询。系统提示可能在解释 Agent 能力时引用了它。
这个契约从未被记录、从未被版本控制、从未被测试。它散落在 prompt 模板、示例库、检索索引和工具 schema 中。当 DBA 重命名一个列或工程师添加一个枚举值时,他们会更新迁移文件、ORM 模型和应用代码。但他们不会更新 Agent 的 prompt。他们甚至不知道 Agent 的 prompt 存在。
结果是一类特别隐蔽的故障。传统的 Schema 变更会产生明确的错误——对重命名列的 SELECT 会抛出 undefined column 异常。但 AI Agent 并不总是大声失败。一个 text-to-SQL Agent 可能生成引用旧列名的查询,得到错误后"贴心地"重新构造一个查询,指向另一个恰好存在的列。Agent 返回一个看似合理的答案。它是错的,但没人知道。
为什么标准监控会遗漏这些问题
传统的可观测性能捕获简单的情况。如果一个列被完全删除而 Agent 试图引用它,你会在日志中看到 SQL 错误。但大多数 Schema 变更更加微妙:
- 重命名:
user_status变成了account_state。Agent 的 few-shot 示例仍然引用user_status。如果 Agent 足够智能,能在运行时检查 Schema,它可能会恢复。如果它基于缓存的上下文或静态示例工作,它会生成错误的查询或臆想一个映射。 - 语义漂移:一个列保持相同的名称但含义改变了。
transaction_amount以前是以分为单位,现在是以元为单位。Agent 对阈值和比较的推理偏差了 100 倍,但每个查询在语法上都是有效的。 - 枚举扩展:一个
status字段增加了一个新值pending_review。Agent 的决策逻辑基于只有三个状态值的示例训练,没有考虑第四个。它可能悄悄地将pending_review归类为pending,或者完全忽略这些行。 - 类型变更:
INTEGER变成BIGINT,或者VARCHAR(50)变成TEXT。通常无害,但如果 Agent 已经内化了类型约束(来自 Schema 描述或示例),它可能会应用现在已经不正确的验证逻辑。
这些都不会触发你设置的告警。错误率保持平稳。延迟看起来正常。唯一的信号在 Agent 输出的质量中——这需要大多数团队尚未构建的评估基础设施。
多 Agent 系统中的级联问题
当多个 Agent 共享数据时,Schema-Prompt 耦合问题会急剧恶化。考虑这样一个流水线:Agent A 查询数据库,Agent B 总结结果,Agent C 做出推荐。如果 Agent A 误解了一个重命名的列,它会将看似合理但不正确的数据传递给 Agent B,Agent B 自信地总结了错误的信息,Agent C 据此做出推荐。
Forrester 在 2025 年将这种级联称为"上下文漂移",称其为 AI 加速开发的隐形杀手。链中的每个 Agent 都在不质疑上游上下文的情况下处理收到的输入。错误不是在量级上放大——而是在置信度上放大。当人类看到最终输出时,它看 起来很权威。毕竟,三个 Agent 都同意了这个结果。
这与传统系统中 Schema 变更的传播方式根本不同。在微服务架构中,破坏性的 Schema 变更会在服务边界产生编译错误或运行时异常。错误在引入点被捕获。在 Agent 流水线中,"错误"是一个微妙的语义不匹配,它通过每个边界而不被检测到。
Agent-Schema 边界的契约测试
修复方案借鉴了 API 工程中的一个旧思路:契约测试。正如消费者驱动的契约测试验证 API 提供者仍然满足其消费者的期望一样,Schema-Prompt 契约测试验证数据库 Schema 仍然满足 Agent 的假设。
以下是实践中的做法:
1. 提取 Agent 的 Schema 假设。 解析你的 prompt 模板、few-shot 示例和工具定义,构建一个 Agent 依赖的每个列名、类型、枚举值和语义约束的清单。这就是 Agent 的"契约"——它假设为真的世界模型。
2. 将契约与实际 Schema 对比。 在每次迁移时,将 Agent 假设的 Schema 与迁移后的数据库 Schema 进行比较。标记 Agent 引用但已被重命名、改类型或删除的任何列。标记 Agent 示例使用但已不存在的任何枚举值。
3. 在 CI 中运行此对比。 Schema-Prompt 对比应该是迁移流水线中的阻断检查。如果迁移对 Agent 引用的列引入了破坏性变更,流水线就停止。编写迁移的开发人员现在知道他们需要在迁移发布之前更新 Agent 的 prompt、示例或工具定义。
4. 单独测试语义假设。 列名和类型是简单的部分。语义漂移——"分到元"的问题——需要不同的方法。维护一组断言查询:"transaction_amount 的最大值应小于 100000"或"status 列应该正好有这些值"。在迁移后运行这些断言。当它们失败时,标记受影响的 Agent 进行 prompt 审查。
构建 CI 门禁
实现并不复杂。你需要三个组件:
- Schema 快照:Agent 假设的 Schema 状态的 JSON 或 YAML 表示。将其与 prompt 模板一起存储。在同一仓库中进行版本控制。
- 迁移钩子:一个部署前或迁移后的脚本,将实时 Schema 与快照进行对比。
oasdiff(用于 API Schema)等工具或自定义的 SQL 内省查询可以在这里使用。 - 所有权映射:从数据库表和列到引用它们的 Agent 和 prompt 的映射。当一个列发生变化时,你需要知道哪些 prompt 需要更新。没有这个映射,你就只能寄希望于有人记得。
所有权映射是团队跳过的部分,也是最重要的部分。在实践中,这意味着为你的迁移文件添加注释,或使用跟踪哪些 AI 组件依赖哪些 Schema 元素的元数据目录。当迁移涉及 users.last_login_date 时,CI 门禁检查所有权映射,发现用户活跃度分析 Agent 在三个 few-shot 示例和一个工具定义中引用了这个列,并阻止合并直到这些内容被更新。
减少影响半径的实用模式
除了 CI 门禁之外,几种架构模式可以减少 Schema 和 Agent 之间的耦合:
- Schema 抽象层:不要让 Agent 直接查询原始表。暴露视图或 API 端点来提供稳定的接口。当底层 Schema 变化时,更新视图定义。Agent 永远看不到迁移。
- 动态 Schema 内省:不要在 prompt 中硬编码列名,让 Agent 在运行时检查 Schema。这自动处理重命名,但不能解决语义漂移——Agent 看到了新列名,但不知道它的含义有什么不同。
- 版本化示例库:存储 few-shot 示例时附带关于它们基于哪个 Schema 版本编写的元数据。当 Schema 超过示例的版本时,标记它进行审查或自动从 prompt 中排除。
- 语义锚定与描述:在 Schema 元数据中为列附加自然语言描述。当 Agent 看到
last_activity_ts: "用户与任何系统端点最近一次交互的时间戳,包括 API 调用、登录和 Webhook 触发"时,即使名称不熟悉,它也能推理列的含义。将这些描述的更新作为迁移流程的一部分。
组织层面的问题
这里最深层的挑战不是技术性的——而是组织性的。数据库迁移由后端工程师负责。Prompt 由 AI 工程师负责。Few-shot 示例可能由产品经理负责,或者根本没人负责。所有权映射不仅仅是一个技术产物;它是很少就同一产物相互交流的团队之间的沟通桥梁。
解决这个问题的团队有一个共同特征:他们像对待代码依赖一样对待 prompt 依赖。在 prompt 中引用的列就是一个依赖,就像在应用查询中引用的列一样。重命名它就是一个破坏性变更。破坏性变更需要协调更新。这不是新想法——这是依赖管理,应用于新的领域。
不舒服的事实是,大多数 AI 工程团队的运营成熟度相当于迁移框架出现之前的 Web 开发。他们在进行 Schema 变更并祈祷什么都不会坏。对于传统应用,行业在几十年前就用 ORM、迁移框架和类型系统解决了这个问题。对于 AI Agent,我们仍然处于"祈祷加 grep"的时代。
接下来会发生什么
在好转之前,Schema-Prompt 耦合问题会先变得更糟。随着 Agent 承担更复杂的任务——多步推理、跨数据库 join、长时间运行的工作流——它们的隐式 Schema 假设会增长。每个新的工具定义、每个新的 few-shot 示例、每个新的检索文档都会添加另一个对数据当前状态的隐形依赖。
能够良好应对的团队是那些现在就在构建反馈循环的团队:CI 中的 Schema-Prompt 契约测试、跨团队边界的所有权映射,以及在用户发现之前捕获语义漂移的评估流水线。工具大多是直接的——差异比较、断言、元数据目录。困难的部分是认识到你的 Agent 的世界模型是一个一等产物,值得与你的应用代码同等的工程纪律。
你的数据库迁移不仅仅是改变了一个列名。它改变了你的 Agent 所相信的关于世界的真相。问题是你是从 CI 门禁中发现,还是从客户那里发现。
- https://atlan.com/know/context-drift-detection/
- https://dev.to/kuldeep_paul/managing-ai-agent-drift-over-time-a-practical-framework-for-reliability-evals-and-observability-1fk8
- https://medium.com/google-cloud/the-six-failures-of-text-to-sql-and-how-to-fix-them-with-agents-ef5fd2b74b68
- https://pub.towardsai.net/architecting-state-of-the-art-text-to-sql-agents-for-enterprise-complexity-629c5c5197b8
- https://www.getmaxim.ai/articles/a-comprehensive-guide-to-preventing-ai-agent-drift-over-time/
- https://byaiteam.com/blog/2025/12/30/llm-model-drift-detect-prevent-and-mitigate-failures/
