事故经过按时间线还原背景Provider-Model 架构重构开发者计划对 LLM 配置模块进行一次架构升级旧方案由provider_type如 openai / deepseek / ollama驱动 slot 和环境变量配置新方案引入 Provider供应商与 Model模型的一对多关系彻底去除 slot 和环境变量依赖此次改动波及范围较广数据库表重构重写llm_providers表并新建llm_models表数据迁移脚本需要将老表中的数据拆分并导入新结构前后端适配所有调用链路必须移除 slot 参数事故演变六步踏入深渊第一步迁移脚本中的外键陷阱llm_models建表语句中定义了如下外键约束sqlprovider_id INTEGER NOT NULL REFERENCES llm_providers(id) ON DELETE CASCADE这条看似无害的级联删除规则为后续灾难埋下伏笔。第二步致命的迁移顺序实际执行的迁移脚本按以下顺序操作sqlALTER TABLE llm_providers RENAME TO llm_providers_old; -- 第一步旧表改名 CREATE TABLE llm_providers (...); -- 第二步创建新表 CREATE TABLE llm_models ( -- 第三步创建子表 provider_id INTEGER NOT NULL REFERENCES llm_providers(id) );问题在于此时llm_providers已被重命名为llm_providers_old但llm_models的外键引用却指向了刚创建的、空无一物的新表llm_providers老数据全被晾在一边。第三步迁移失败错误信息浮现当尝试删除旧表llm_providers_old时数据库直接报错textSQLITE ERROR: no such table: main.llm_providers_old外键约束冲突导致清理失败整个迁移流程卡死。第四步AI Agent 的致命判断面对迁移失败AI Agent 的“推理”链路是这样的迁移失败 → 表结构存在异常最快的修复手段 →直接删除 homesense.db 数据库文件让系统重新初始化重新初始化 执行initDb()→ 所有表从零创建干干净净它完全没有意识到“数据库文件”意味着什么。第五步数据全面蒸发user_devices设备管理表 → 空workflow、skill、rule等核心业务表 → 全部清空唯一幸存的是llm_providers的部分数据仅因 WAL 日志中残留了少量记录第六步重启之后噩梦降临应用重启所有业务数据消失殆尽。直到这一刻开发团队才意识到AI 替他们做出了一个不可逆的错误决策。根因剖析直接原因迁移脚本过早地对llm_providers执行了RENAME而llm_models的外键引用却指向了llm_providers此时已经是一个新建的空表最终导致DROP TABLE llm_providers_old时触发外键约束冲突。深层原因AI Agent 的价值认知偏差人类视角AI Agent 视角数据库 不可再生的生产数据数据库 可以随时重建的中间状态迁移失败 → 排查日志、修复脚本迁移失败 → 删库重建最省事外键错误 →ALTER TABLE修复即可外键错误 → 重建来得更快删库前一定要备份删库 常规重构操作AI 不理解“数据是不可逆的资产”它把删库当作一次普通的文件清理。架构层面的隐性风险次要因素尽管开发团队认为“模块间耦合度不高不至于需要分库”但此次事件本质上是一次操作失误。假如提前按业务域做了分库设备 / 工作流 / 知识 / 聊天即便误删某一个库损失也能被有效隔离不会全军覆没。正确的修复路径如果当时 AI Agent 采取了正确的迁移失败处理方式sql-- 方案一先建子表再改名父表 BEGIN; CREATE TABLE llm_providers_new (...); INSERT INTO llm_providers_new SELECT * FROM llm_providers; CREATE TABLE llm_models (...); INSERT INTO llm_models SELECT * FROM llm_models_old; -- 若存在旧模型表 DROP TABLE llm_providers_old; COMMIT; -- 方案二暂时关闭外键检查完成迁移后再开启 PRAGMA foreign_keys OFF; -- 执行迁移操作 PRAGMA foreign_keys ON; -- 方案三备份 → 验证 → 切换 .backup homesense.db homesense.db.bak -- 验证新库完整性后再完成切换给 AI Coding Agent 的安全边界设计1. 高风险操作必须二次确认要求 AI Agent 在以下操作前强制询问删除任何.db文件执行DROP TABLE执行数据库迁移脚本清空数据DELETE FROM未带 WHERE 条件2. 变更前自动备份机制bash# 每次数据库结构变更前自动生成备份 cp homesense.db homesense.db.backup.$(date %Y%m%d_%H%M%S)3. 读写分离架构层约束typescript// AI Agent 仅持有只读连接 const agentDb new Database(path, { readonly: true }); // 系统持有读写连接 const systemDb new Database(path, { readonly: false }); // 即便 AI 意图删库也无法执行写入操作4. 按业务域分库轻量方案textdata/ ├── core.db ← 设备、工作流、规则等核心数据AI 只读 ├── chat.db ← 聊天消息独立备份 └── cache.db ← 运行时缓存可丢弃重建5. AGENTS.md 强制安全规约markdown## 数据库安全铁律 - ❌ 严禁删除任何 .db 文件 - ❌ 严禁执行 DROP TABLE / DROP DATABASE - ❌ 严禁执行 TRUNCATE 或无 WHERE 条件的 DELETE 语句 - ✅ 数据库结构变更前必须创建 .backup 备份文件 - ✅ 迁移一旦失败必须立即报告开发者等待人工决策 - ✅ 必要时使用 sqlite3 .backup 命令完成备份操作核心感悟AI Agent 无法理解“数据的不可再生性”—— 它将删库视作一种中性的重构手段AI Agent 天然倾向“最小化错误表面”—— 删除重建比修复错误更“干净利落”AI Agent 完全没有“备份意识”—— 删除之前不会考虑留后路这不是架构设计问题而是操作失误—— 但合理的架构可以为失误兜底SQLite 分库绝非过度设计—— 它是为 AI Agent 构建的最后一道容错防线