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 。

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

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

小夜