dsh-plugin-dbgraph:把数据库目录索引到本地,让智能体写查询前就知道每张表每个字段

前言

在 DSH(DeepSeek Harness,一切皆插件)里,给智能体接一个数据库,最常见的做法是把连接信息交给它,让它自己用 SHOW TABLES、DESCRIBE 去摸结构。这条路有两个代价:一是每次探结构和每次猜错都要消耗一轮模型回合,一轮就是几秒;二是结构信息没有边界,几百行 SHOW/DESCRIBE 结果很容易把上下文烧掉。

dbgraph 的思路不同:插件先把远程数据库的 catalog——表、列、注释、主键、索引、枚举字面量的有界采样——写进本地 SQLite 索引,智能体读索引(以及直接塞进 system prompt 的摘要)就知道结构,真正取数据只发一次网络调用。

下面介绍 CC19990113/dsh-plugin-dbgraph。

这是什么

  • 名称:CC19990113/dsh-plugin-dbgraph
  • 维护者:CC19990113
  • 分类:记忆
  • GitHub 星标:1
  • 许可证:MIT
  • 一句话定位:为 DeepSeek Harness 索引数据库结构,让智能体在写查询前知道每一张表和每一列,然后用一次工具调用拿到答案。

结构本地,数据在线

放哪 理由
表、列、注释、主键、索引、枚举采样、行数估计 本地索引 零网络,可离线,问「这列是什么意思」不需要任何凭证
实际行值 始终走服务端 缓存密码不是快密码,是错的密码

真正来自业务数据的东西不会被持久化。唯一的、带数据形态的字段是 enum_values_json,它是一次 SELECT DISTINCT … LIMIT n 的采样,用来告诉模型 status 存的是 'paid' 还是 1。

核心功能

  1. 索引远程数据库的 catalog,覆盖每张表、每列、注释、主键、索引,以及有界的枚举字面量样本。
  2. 结果写入本地 SQLite 索引,位置在 ~/.dsh/dbgraph。
  3. 模型读这个索引,外加一段直接放进 system prompt 的摘要,而不是反复发 SHOW TABLES 和 DESCRIBE。
  4. 真正取值时只发一次网络调用。

status.json 和索引放在一起,里面的 digest 被 system-prompt 段落同步读取。原因很实际:每个模型请求都会拼这一段,在这里打开 SQLite会是每一步都要付的成本,插件不接受这个代价。

索引格式

每个连接一个 SQLite 文件,每次运行整体替换(先写临时文件 <index>.<pid>-<nonce>.tmp,再改名)。nonce 每次运行不同,所以两次运行不会共用临时文件。这一个决定就去掉了增量 diff、删除和半更新索引的问题。

meta      key/value: engine, database, schemaVersion, l1IndexedAt, l2IndexedAt
objects   one row per table / view / collection / key pattern
columns   ordinal, type, type_class, nullability, default, comment, pk/unique, enum sample
edges     fk | index | view_ref | code_ref
terms     normalized words + Chinese bigrams + alias expansion, for semantic lookup
search    FTS5 (contentless) over object and column names and comments

两个层级

Level 内容 位置
L1 对象和列名、声明的类型 内联,几秒内,立即可用
L2 注释、外键、索引、行数估计、枚举样本 后台任务

L1 充实失败不会丢掉结构快照:能回答「有哪些列」的索引已经值回大部分成本。

工具

工具 超时 做什么
dbgraph 30 s connections schema objects columns find sql impact refs
dbgraph_index 300 s 建立或刷新一个连接(l1 / l2 / full);大的运行交给后台任务

find 是最关键的一个:它离线把词解析到表和列,然后跑一条参数化 SELECT。遇到不确定时返回 ambiguous 并给出排好序的候选,而不是猜;遇到「这个用户」这种没有谓词的说法时返回 missing_predicate,而不是去扫一张表。

敏感列掩码

敏感列(password、passwd、pwd、secret、token、salt、id_card 等)默认返回 [REDACTED]。没有这层保护,一个粗心的问题就会把密码送进 transcript,而这个 harness 会持久化 transcript 并对它们做索引。按连接设 sensitiveColumns: 'show' 可以关掉。

凭证不会写进 connections.json:一个连接存的是凭证引用,实际凭证不落库。

写路径为什么用 Rust

node:sqlite 是同步 API。通过它写一万个列,事件循环会阻塞到写完为止。crates/dbgraph-indexer 把规范化、term 生成和 SQLite 写入都放到 libuv 线程池上,重建索引就不会拖住宿主。

README 给出同机、同目录、同固定时钟下的测量(500 张表 / 10,000 列):

写入方 写入耗时 索引文件 最长事件循环阻塞
JavaScript 1992 ms 8.46 MiB 1992 ms(整段写入)
Rust(AsyncTask) 218 ms 8.41 MiB 33.6 ms

两个写入方互相校验,而不是各自信任:给定同一个目录和同一个固定 now,objects、columns、edges、terms、search(含 rowid)必须逐行一致,只有 meta.writer 可以不同。夹具期望是跑一遍 JavaScript 写入方生成的,不是手写的,所以任一侧改动没镜像到另一侧,构建就会失败。

JavaScript 写入方因此不是优化回退,而是一致性参考和降级路径(没有 Rust 工具链、没有 addon、调用抛错、报告读不出来都会回退到它,且只回退一次)。已知差异只有一处:JavaScript 写入方会把 dangling edge(指向快照里不存在的表)计入 report.warnings,native 写入方静默丢弃它;存储的数据完全相同,只有这一行 warning 不同。

选型与落盘细节

dbgraph_index 接受 writer: 'auto' | 'js' | 'rust':

  • js 始终用 JavaScript 写入方,不碰 addon。
  • rust 只用 native 写入方;缺产物或调用抛错会让整次运行失败,而不是悄悄产出更慢的索引。
  • auto(默认)在可用时用 native;缺产物、调用被拒、报告读不出来时,每个进程只记一次日志,然后回退到 JavaScript。

DSH_DBGRAPH_RUST_ADDON 显式指向某个产物:既是降级路径的测试钩子,也是「addon 放在 crates/ 之外」这种部署的逃生口。默认指向 crates/dbgraph-indexer/artifacts/dbgraph-indexer.<platform>-<arch>.node。

两个实测结论写进了 README,属于踩过的坑:

  • node:sqlite 的 contentless FTS5 存的内容读不出来:每个列(包括 UNINDEXED 的)都返回 NULL,只有 rowid 和 rank 活下来。所以索引用 contentful 表,其中 object_id UNINDEXED 能逐字读回。另外 FTS5 的列语法是 column-name [UNINDEXED],前面带类型名会直接 parse error。
  • unicode61 把一段中文当成一个 token:原样存 广告点击,MATCH '广告' 什么都找不到。所以 text 存的是预分词后的流——ASCII 按 camel/数字边界切,CJK 切 bigram——查询也走同一个分词器,用 OR 连接(空格表示短语,不是「任一」)。

典型用法

README 给的对照很直接。没有索引时,回答「张三的密码是什么」要走五步,四次模型往返、四次网络往返、两次猜错,还会往 transcript 里塞 2,000 行;有 dbgraph 后:

dbgraph find {entity:'用户', fields:['密码'], where:{name:'张三'}}

一行拿到结果,回答里会说明它用了哪张表、哪一列。

结构层面的命令入口是 dbgraph(查询)和 dbgraph_index(建立或刷新、分 l1 / l2 / full、大任务进后台)。

安装与启用

这个项目发布形态是一套 bundle:packages/bundle/cordis.patch.yml 把各模块挂成一个 profile 层,packages/service 提供 ctx.dbgraph 的词汇表、方言注册表和索引协议,packages/catalog 每种引擎一个 DatabaseDialect(已实现 SQLite、MySQL;PostgreSQL/MongoDB/Redis 在计划中)。

README 没有给出独立的一键安装命令,也没有写 dsh plugin add github:... 这类用法。要启用,需要把它作为 bundle / patch 挂进你的 DSH profile。仓库根目录的 package.json 里,dsh.bundle.patch 指向 ./packages/bundle/cordis.patch.yml,这是它的挂载入口。请以仓库当前内容为准确认具体启用方式,不要凭插件名猜测命令。

适用场景与注意

适合给需要读数据库结构的 DSH 智能体用:结构探索零网络、可离线,取值只发一次调用;中文列名和中文注释靠预分词 + bigram 做语义检索;敏感列默认掩码。

注意三点:

  1. 插件以当前 DSH 进程的权限运行,挂进 profile 前先读一遍源码。
  2. 许可证是 MIT,仓库当前为公开仓库。
  3. 仓库还很新(创建于 2026-11-05,写作时为 1 星),大规模使用前建议自己跑一遍 dbgraph_index 并核对 status.json 里的 digest,确认索引和真实 catalog 一致再放开。

写在最后

dbgraph 要解决的不是「数据库慢」,而是「模型回合贵」:把结构咨询从每次请求里拿出来,只保留一次必要取值。目录页在 https://www.skillhub.cn/plugins/CC19990113/dsh-plugin-dbgraph ,代码在 https://github.com/CC19990113/dsh-plugin-dbgraph 。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜