diffium-db: 实时查看AI代理对数据库的变更差异(9分钟阅读)

TLDR AI 工具

摘要

diffium-db是一款开源终端UI工具,提供由AI代理引起的数据库变更的实时差异显示,使用Bun和Postgres构建。

diffium-db是一个实时时终端用户界面,显示用户数据库中的变化,当代理、迁移或其他人工作时。用户只需将其指向一个数据库,获取基线,然后保持打开状态。diffium-db将显示一个窗格显示变更内容,另一个窗格显示变更本身,变更实时显示。
查看原文
查看缓存全文

缓存时间: 2026/09/01 23:41

# diffium-db:实时显示智能体对数据库操作的差异 来源:https://denislavgavrilov.com/diffium-db-live-database-diff > 以下文章是我在使用Claude Code构建diffium-db过程的回顾。虽然内容由AI生成,但我仔细检查了全文以确保没有偏差——所有内容都完整保留了我开发diffium-db的真实过程。若想直接与我讨论此项目的相关问题,可通过[\[email protected\]](https://denislavgavrilov.com/cdn-cgi/l/email-protection#8aeeefe4e4e3f9caebb8fda4e3e5)或x.com/@kuberdenis联系我。 备注二:本项目是我另一个用于查看差异的项目的直接延续——github.com/kubeden/diffium。我允许智能体运行数据库迁移。这就是当前的工作流程:你描述需求,智能体生成SQL,你审阅后批准,几秒钟后数据库结构就发生了变化。但接下来的十分钟才是真正的问题。`git diff`能显示迁移文件,却无法展示迁移实际执行的操作,更不会记录智能体在过程中顺手更新的某行数据——因为当时更新看起来是合理的。 现有的数据库结构差异工具很多,但工作原理大同小异:事后运行工具,对比两个数据库,返回差异结果。而工作进行时,没有任何工具能实时展示变化。于是我开发了**diffium-db**——一个需要保持打开状态的终端UI。 ## 资源 - kubeden/diffium-db (https://github.com/kubeden/diffium-db):核心仓库(MIT协议) - kubeden/diffium (https://github.com/kubeden/diffium):本项目所参考的文件差异终端工具 - OpenTUI (https://github.com/anomalyco/opentui):项目构建所用的终端框架 --- ## 功能介绍 将其连接至Postgres数据库,创建基线并保持监控状态。此后所有变更都会显示在左侧栏,具体变更内容展示在右侧栏,系统每秒重新扫描一次数据库。 此为捕获迁移过程的示例:当我在查看`demo.users`表时,新增了两个列和一个索引: *左侧栏显示自基线以来的所有变更项,右侧栏展示选中对象的前后对比。* 该工具监控范围包括:表(列、默认值、约束、索引、触发器)、视图、物化视图、枚举类型和函数。同时也监控**行数据**——这部分实现尤为精妙,后文将详细说明。 工具包含四个命令:`watch`启动终端UI,`snapshot`创建基线,`baselines`列出已有基线,`diff`输出变更后退出。最后这个命令支持`--exit-code`参数,当存在变更时返回状态码1,可用于中断CI任务或阻止智能体执行下一步操作。 --- ## 安装配置 需要Bun (https://bun.sh/)1.3或更高版本,以及被监控的Postgres数据库。除核心依赖`@opentui/core`外无其他依赖项,安装过程非常快捷: ```bash git clone https://github.com/kubeden/diffium-db && cd diffium-db bun install export DATABASE_URL='postgresql://...' ``` 随后创建基线并启动监控: ```bash bun run src/index.ts snapshot bun run src/index.ts watch ``` 仓库内置了演示案例,无需等待智能体操作即可观察效果: `examples/demo/01-baseline.sql`创建包含用户与项目的`demo`模式, `examples/demo/02-agent-change.sql`模拟智能体执行"添加计费计划并清理数据"的操作。 分两个终端操作: **终端一**: ```bash psql "$DATABASE_URL" -f examples/demo/01-baseline.sql bun run src/index.ts snapshot --schema demo bun run src/index.ts watch --schema demo ``` **终端二**(保持监控运行状态): ```bash psql "$DATABASE_URL" -f examples/demo/02-agent-change.sql ``` 屏幕上会立即显示五项变更:`demo.users`表新增枚举类型、两个列和一个索引;`demo.projects`表删除一个索引;一条记录插入及一条记录删除。使用`j`/`k`键导航变更项,`s`键切换侧边/行内显示模式,`e`键将完整差异导出到文件。 --- ## 使用场景建议 演示环境仅作示例,实际工作中请勿指向生产数据库。本工具的核心价值在于允许智能体运行操作后查看其执行结果,因此应选择可随时销毁的测试环境。 我通常为智能体创建独立分支。在Neon数据库中只需两条命令(需提供项目ID,因为我有多个项目): ```bash neonctl branches create --project-id --name agent-run neonctl connection-string agent-run --project-id ``` 将`DATABASE_URL`指向第二条命令的输出地址,在该分支创建基线,让智能体在此分支操作。该分支采用写时复制技术,能完全继承生产环境的数据库结构和数据。我实测分支创建仅需1.2秒。空闲分支会自动暂停计算资源,避免遗忘删除的分支持续消耗资源。 确认迁移结果符合预期后,再将其应用至生产环境。若智能体操作失误,损失仅限于可删除的分支。本文的所有演示内容都运行在测试项目分支上,演示数据库状态仍保持原样。 任何Postgres兼容数据库均可使用,工具本身不依赖Neon特性。分支功能使每次操作成本极低,无需仅在必要时才谨慎执行。 --- ## 行数据差异验证 结构对比相对简单,行数据对比才是真正的挑战。要识别行数据变更,必须记录原始状态。对实际系统而言,存储全部行数据并不可行,因此diffium-db采用指纹记录方案:存储主键、整行数据的`md5(t::text)`哈希值及简短预览。 这种方法在数据库中计算和存储成本都很低,且能精准区分插入、更新和删除操作: - 新主键 → 插入操作 - 主键消失 → 删除操作 - 主键相同但哈希值变化 → 更新操作 该方案在表结构变更时会出现问题:新增列会导致整表所有哈希值改变,传统工具会错误地报告所有行被更新。实际上无人修改数据,只是表结构变化了。 diffium-db通过以下方式规避此问题: *左侧面板显示`~3?`,顶部注释说明原因。工具检测到列变更,标记该表,并明确提示哪部分数据可信。* 计数显示为`~3?`而非`~3`,差异报告首行会解释原因:新增两列导致全表行数据读数变化,更新计数是工具无法确信的数据部分。插入和删除统计仍然精确(基于主键识别,不受结构变化影响),仅更新计数存在不确定性。直接输出不确定数据会降低报告可信度。 无主键的表和超过`--row-limit`(默认5000)的表仅显示行数统计,不提供详细变更报告。同样的原则:宁可少报,不可错报。 --- ## 结构差异的文本化处理 核心设计理念决定了工具行为:每个数据库对象都被渲染为具有固定行序的规范文本块。例如表对象的渲染顺序固定为:列 → 约束 → 索引 → 触发器。 结构差异本质上就是这些文本块的行级对比。这种设计带来了显著优势:新增列仅显示为新增行,而非模糊的"表结构变更";侧边视图自动获得`+2 -0`计数和长默认值的横向滚动功能。 *相同变更的行内显示模式(按`s`键切换),避免窗格边缘截断内容。`w`键控制换行显示,两种设置都会在会话间保持。* 代价是:diffium-db展示的是当前数据库状态,而非生成该状态所需的DDL语句。对于实时监控工具而言,这是合理的权衡。如果需要生成迁移脚本,则需要其他解决方案。 --- ## 基线存储机制 基线是持久化的快照值而非实时连接,因此可以随时创建并与未来状态对比。支持多个命名基线,也可将基线文件与迁移脚本一同提交。 默认存储路径为`.diffium-db/snapshots/`(JSON格式)。使用`--store neon --store-url`参数可将基线存储在Postgres的`diffium_db`模式中。当CI环境与本地开发环境需要共享基线时,建议采用此方式。 监控工具不会访问自身的存储模式,因此存储地址与监控地址可以指向同一数据库。结合前述的分支方案,基线可以存储在描述对象所在的分支上。分支即完整实验环境,删除分支时基线数据一并清除。 --- ## 后续计划 v1版本尚未实现的功能(按优先级排序): **无ORM识别能力** 当前版本仅能显示列变更,无法追溯具体迁移文件或模型定义。ORM映射关系识别将是下一个重点开发方向,`src/orms/`目录已预留但暂未实现。 **仅支持Postgres** 目录读取逻辑封装在`src/pg/`中,上层代码无需关心目录结构细节。支持其他数据库方言的扩展点已明确预留,但尚未实现。 **不监控序列** 所有`bigserial`类型的列都会创建序列,每次插入都会变更序列值。除非用户主动查询,否则这些变更属于无意义噪音。 **采用轮询而非复制** 当前每秒全量扫描一次数据库。对于大型数据库,逻辑复制的性能开销更低。若轮询机制成为性能瓶颈,将优先转向复制方案。 以下功能永远不会加入:diffium-db不会向被监控数据库写入数据。唯一写入操作仅限自身存储库(且仅在配置专用存储时触发)。 --- ## 结语 项目源代码约2,200行,测试用例900行。其中64项测试无需数据库即可运行(包括终端界面测试),因为OpenTUI支持内存渲染并验证屏幕输出。这意味着布局调整会触发测试失败,而非在未重新截图的情况下默默显示错误。 我始终坚持实现行数据对比功能。直接输出每张表的数字统计更简单,但显示"此数据无法验证"的版本虽然视觉上不够完美,我仍认为这是正确选择。作为智能体的监控工具,必须比智能体本身更严谨。 项目已遵循MIT协议开源至GitHub。若使用过程中发现任何错误,请提交Issue。感谢阅读。

相似文章

Diffsmith

Product Hunt

Diffsmith 是一个工具,让你可以在 AI 代理的代码上添加评论并协作进行更改。

差异只是摘要,会话跟踪才是实际发生的过程。

Reddit r/AI_Agents

一篇文章强调,AI智能体会话跟踪揭示了最终PR差异中缺失的隐藏操作(例如未声明的密钥、范围蔓延),并警告大多数开发者只审查差异,而不审查完整跟踪,导致未审查的风险。

用 Rust 和 Durable Objects 为智能体构建细粒度版本控制

Lobsters Hottest

Zed Industries 推出了 DeltaDB,这是一套面向智能体上下文的细粒度版本控制系统,能够将人类和智能体的编辑实时流式写入一个单调递增的因果图中,确保每一次代码变更都能追溯到产生它的对话。文章详细介绍了其架构:基于存储在 SQLite 中的 CRDT,以及参考 Eg-walker 论文构建的有向无环图(DAG)。