diffium-db: 实时查看AI代理对数据库的变更差异(9分钟阅读)
摘要
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
Diffsmith 是一个工具,让你可以在 AI 代理的代码上添加评论并协作进行更改。
差异只是摘要,会话跟踪才是实际发生的过程。
一篇文章强调,AI智能体会话跟踪揭示了最终PR差异中缺失的隐藏操作(例如未声明的密钥、范围蔓延),并警告大多数开发者只审查差异,而不审查完整跟踪,导致未审查的风险。
[项目更新] Dunetrace:实时监控您的生产环境 AI Agent
Dunetrace 是一款专为生产环境 AI Agent 设计的开源实时监控工具。此次更新增加了跨 Agent 模式分析、与 Langfuse 的深度分析集成,以及对自定义 Agent 的支持。
Show HN: DeepSQL – 一款用于Postgres和MySQL的可自托管DBA代理
DeepSQL是一款可自托管的AI DBA代理,能够监控、优化和管理Postgres和MySQL数据库,旨在降低成本并提升性能。
用 Rust 和 Durable Objects 为智能体构建细粒度版本控制
Zed Industries 推出了 DeltaDB,这是一套面向智能体上下文的细粒度版本控制系统,能够将人类和智能体的编辑实时流式写入一个单调递增的因果图中,确保每一次代码变更都能追溯到产生它的对话。文章详细介绍了其架构:基于存储在 SQLite 中的 CRDT,以及参考 Eg-walker 论文构建的有向无环图(DAG)。