返回目錄

dsh-plugin-dbgraph

精選清單收錄維護狀態: 活躍

cc19990113/dsh-plugin-dbgraph

为 DSH 建立本地数据库结构索引,让智能体了解表与字段后再生成查询并返回结果。

前往 GitHub專案首頁
$ dsh plugin add dsh-plugin-dbgraph

安裝

dsh 沒有統一的安裝指令 —— 把該外掛 README 中的設定行加入你的 profile / patch 設定,然後重啟即可。

查看安裝教學

2

星數

0

Fork

TypeScript

語言

MIT

授權條款

2026-11-05

建立於

2026-11-11

最近推送

README

dsh-plugin-dbgraph

Database structure the agent already knows, so it answers with one tool call instead of five.

A DeepSeek Harness plugin that indexes a remote database's catalog — every table, column, comment, key, index, and a bounded sample of enum literals — into a local SQLite index under ~/.dsh/dbgraph. The model reads that index (and a digest of it placed directly in the system prompt) instead of spending round-trips on SHOW TABLES and DESCRIBE, then fetches the actual values with exactly one network call.

The problem it removes

Without an index, answering "what is 张三's password?" looks like this:

1. SHOW TABLES                      ← network round-trip
2. DESCRIBE sys_user                ← network round-trip
3. SELECT ... WHERE status = 1      ← wrong: status is a varchar
4. SELECT ... WHERE status = 'paid' ← guess corrected
5. 2,000 rows into the transcript   ← context burned

Four model round-trips, four network round-trips, two wrong guesses. The expensive part is not the database — it is the model's turns. Each one costs seconds; a 100 ms query does not.

With dbgraph:

1. dbgraph find {entity:'用户', fields:['密码'], where:{name:'张三'}}
← one row, and the answer says which table and column it used

Structure local, data online

Where Why
Tables, columns, comments, keys, indexes, enum samples, row estimates Local index Zero network, usable offline, no credential needed to ask what a column means
Actual row values Always the server A cached password is not a fast password, it is a wrong one

Nothing derived from business data is persisted. The one data-shaped field is enum_values_json, a SELECT DISTINCT … LIMIT n sample that teaches the model whether status holds 'paid' or 1.

Layout

packages/
  bundle     cordis.patch.yml — mounts everything as one profile layer
  service    ctx.dbgraph: the vocabulary, the dialect registry, the index protocol
  catalog    one DatabaseDialect per engine (SQLite, MySQL; PostgreSQL/MongoDB/Redis to follow)
  store      ~/.dsh/dbgraph: connections.json, the index writer, the reader, the resolver
  tool       the two model tools, /dbgraph, and the prompt digest
crates/
  dbgraph-indexer   the index write path in Rust (normalize + terms + SQLite)

Why the write path is Rust

node:sqlite is a synchronous API. Writing ten thousand columns through it blocks the event loop for as long as the write takes — this is the same wall dsh-plugin-codegraph and dsh-plugin-sessiongraph hit, and both moved their kernels behind napi AsyncTask to get past it. crates/dbgraph-indexer does the same: normalization, term generation, and the SQLite write run on libuv's thread pool, so a rebuild never stalls the host.

Measured on one machine, same catalog, same fixed clock — 500 tables / 10,000 columns:

writer write index file longest event-loop block
JavaScript 1992 ms 8.46 MiB 1992 ms (the whole write)
Rust (AsyncTask) 218 ms 8.41 MiB 33.6 ms

9.1× faster, and the blocking cost drops 59× — which is the number that matters, because a two-second stall is two seconds of the host doing nothing else.

The two writers are checked against each other rather than trusted: given the same catalog and the same fixed now, objects, columns, edges, terms, and search (rowids included) must match row for row, and only meta.writer may differ. Fixture expectations are generated by running the JavaScript writer, never hand-written, so a change on either side that is not mirrored fails the build.

The JavaScript writer is therefore not an optimization fallback — it is the parity reference and the degradation path (no Rust toolchain, no addon, a throwing call, an unparsable answer all fall back to it, once and quietly).

Two things that had to be measured, not assumed

  • node:sqlite contentless FTS5 stores nothing you can read back. Every column — UNINDEXED ones included — returns NULL; only rowid and rank survive. The index therefore uses a contentful table, where object_id UNINDEXED reads back verbatim. (The FTS5 column grammar is also column-name [UNINDEXED]: a type name in front is a parse error.)
  • unicode61 treats a run of Chinese as one token. Store 广告点击 verbatim and MATCH '广告' finds nothing. So text holds a pre-tokenized stream — camel/digit boundaries for ASCII, bigrams for CJK — and queries go through the same tokenizer, joined with OR (a space means phrase, not any of these).

Picking a writer

dbgraph_index takes writer: 'auto' | 'js' | 'rust':

  • js — the JavaScript writer, always. Never touches the addon.
  • rust — the native writer only; a missing artifact or a throwing call fails the run rather than quietly producing a slower index.
  • auto (default) — native when available; a missing artifact, a rejected call, or an unreadable report logs once per process and falls back to JavaScript.

DSH_DBGRAPH_RUST_ADDON points at an artifact explicitly: a test hook for the fallback path, and an escape hatch for a deployment that keeps the addon outside crates/. Resolution order is: that environment variable, then the platform package (dsh-plugin-dbgraph-indexer-<platform>, an optionalDependency that npm installs on the matching OS), then crates/dbgraph-indexer/artifacts/dbgraph-indexer.<platform>-<arch>.node for a working copy.

A platform package without its .node inside falls through to the next candidate rather than failing: a checkout that was never built and a published package always behave the same way to the caller. scripts/build-native.mjs builds the current platform into both places, and the five platform packages are workspace members until they are published.

在 GitHub 閱讀完整 README →

DSH Plugins 是獨立的 DeepSeek Harness 外掛目錄,與 DeepSeek 官方無關,也不代表官方背書。第三方外掛未經安全稽核,安裝前請審查原始碼。

每週取得最新的 DeepSeek Harness 外掛,絕不濫發。