首页/入门/接入数据源

接入数据源

把 Trove 接到你自己的库上。这一页讲两种接入方式(管理端 / 本地 CLI)、 六种数据源各自的注意点、以及决定准确率的那三件事—— 它们比选哪个模型重要得多。

整条路径长这样,后面每一节拆开讲其中一步:

flowchart TD
    A["装驱动(extras 按需懒加载)"]:::entry --> B["注册:连接探测通过才落库"]:::entry
    B --> C["/kb init 建模"]:::gen
    C --> D["通读 YAML、校准 semantics.yml"]:::gen
    D --> E["lint_kb.py 自检(可加活库探测)"]:::exec
    E -- "发现问题" --> D
    E -- "干净" --> F["提问 → /kb learn 沉淀"]:::entry

    classDef entry fill:#71717a14,stroke:#71717a59,stroke-width:1px;
    classDef gen fill:#6366f114,stroke:#6366f199,stroke-width:1.5px;
    classDef exec fill:#14b8a614,stroke:#14b8a699,stroke-width:1.5px;
    linkStyle 4 stroke:#8b5cf6,stroke-width:1.5px
图 1 · 接入路径:注册是事务性的(探测失败不落库),建模后的校准与自检是可回头的两步。 上面这段以源码显示:图渲染库没加载起来(离线、CDN 被拦或浏览器禁用了 JavaScript 时会这样)。

前置条件

项要求
Python≥ 3.12
Node仅在改前端时需要(^22.13.0 || >= 24.0.0)
模型凭证/kb init 起草注释时需要;没有凭证会走骨架降级路径
数据库账号强烈建议只读账号——理由见下

第一步:装驱动

驱动是 extras,按目标库选着装。Doris 复用 MySQL 协议驱动,所以两个 extra 的内容是一样的:

uv sync --extra mysql --extra doris      # MySQL + Doris
uv sync --extra postgres                 # PostgreSQL(业务库 + 向量)
uv sync --extra clickhouse               # ClickHouse
uv sync --extra duckdb                   # DuckDB
uv sync --extra snowflake                # Snowflake
uv sync --extra bigquery                 # BigQuery

pyproject.toml:55 doris registry.py:42 _ADAPTER_REGISTRY

导入注册表本身不需要任何驱动——适配器模块在 connect() 里才导入驱动, 缺包时报错信息里会直接给出该跑哪条 uv sync。

连接串

scheme默认端口示例
mysql3306mysql://user:pw@host:3306/db
doris9030doris://user:pw@host:9030/db
postgres
postgresql
5432postgres://user:pw@host:5432/db
clickhouse8123clickhouse://user:pw@host:8123/db
snowflake—snowflake://user:pw@account/DB/SCHEMA?warehouse=wh
bigquery—bigquery://project/dataset?location=US
sqlite—sqlite:///path/to.db
duckdb—duckdb:///path/to.duckdb

urls.py:215 parse_datasource_url

数据源的名字从哪来

网络 URL 的数据源名 = 库名;文件型(SQLite / DuckDB)用 scheme 作名字, 所以它们都叫 sqlite / duckdb。云仓的名字是身份的两段: Snowflake 取 <库>.<模式>,BigQuery 取 <项目>.<数据集>—— 同一个库里两个模式(数据集)是两个可查单元,只拿库名当名字会让第二次注册撞上「已存在」。 这个名字决定了 KB 目录 (.trove/kb/<name>/),改 URL 的库名等于换一个 KB,注意不要无意中改掉。

第二步:注册(两种方式)

方式 A:管理端(推荐,适合平台化)

  1. admin 登录 → 数据源页面 → 注册(内置 demo 或填 URL)。
  2. 注册是事务性的:先连接探测,成功才落库、才进注册表。失败返回 400 并说明原因。
  3. 对该源执行 kb/init——LLM 起草 schema 注释 + 确定性生成词表与模板。
  4. 用户端下拉/列表里才出现这个源(非 admin 还需要 grants 授权)。

admin.py:824 datasources admin.py:879 prepare admin.py:861 409

同名但连接信息不同的注册会被拒绝(409)而不是静默覆盖—— 覆盖一个数据源等于让它背后的 KB 对错库,这个错误很难事后发现。

方式 B:本地 CLI(适合自己试)

uv run trove --datasource mysql://root:root@127.0.0.1:3306/financial
# 进 REPL 后
/kb init

本地方式不写 .trove/datasources.yml,适合一次性探索。 要长期用还是走管理端注册,这样重启后自动恢复。

Doris 的三个差异

Doris 适配器继承自 MySQL 适配器——协议相同,所以流程完全一样,只有三处不同:

差异说明
URL schemedoris://(而不是 mysql://)
默认端口9030(FE 的 MySQL 协议端口),不是 3306
探活方式FE 不支持 COM_PING,所以用 SELECT 1 代替

doris.py:23 DorisAdapter doris.py:20 DEFAULT_PORT doris.py:51 _ping_reconnect

连接时会探测并上报能力(是否支持事务、CTE、窗口函数),方言声明为 doris。 这些能力位会影响生成策略——比如不支持 CTE 时不该生成 CTE。

云仓(Snowflake / BigQuery)的差异

两个云仓适配器和上面五个的流程完全一样:装 extra → 注册 → kb init → 授权。 差异不在流程,在连接与执行细节上:

差异说明
驱动形状两家的官方驱动都只有同步版——适配器把每个调用整体包进 asyncio.to_thread,事件循环不被阻塞(其余适配器走原生异步驱动)
连接串形状Snowflake:账号 + /<库>/<模式>,?warehouse=…&role=…&private_key_file=…;BigQuery:项目 + /<数据集>,?location=…&service_account_file=…
凭据Snowflake 用 user/password 或私钥文件;BigQuery 只认 service account 文件或 ADC——连接串里带 user:password 会被拒绝而不是静默忽略:一组无效凭据必须响亮地失败
超时Snowflake 把整秒超时折进登录参数(STATEMENT_TIMEOUT_IN_SECONDS,DB 侧强制,重连同样带着);BigQuery 没有会话级时长机制,能力位如实声明不支持——超时由客户端侧管理 + 主动终止承担
元数据内省BigQuery 走 metadata API(list_tables + 逐表 get_table,免费、不起查询 job),不查 INFORMATION_SCHEMA(计费表,查它就是起一次扫描)
EXPLAINSnowflake 支持;BigQuery 声明不支持(GoogleSQL 没有 EXPLAIN 语句)——请求 explain 会被能力位拒绝,而不是发出一条必然报错的 SQL

两者都支持主动终止(supports_interrupt):云仓的查询跑在服务端, 客户端只是无状态 REST 包装,停下来只能靠服务端手段——Snowflake 按我们注入的 requestId 反查后 abort,BigQuery 直接用 job 句柄 job.cancel()。

snowflake.py:148 SnowflakeAdapter bigquery.py:117 BigQueryAdapter urls.py:133 _cloud_datasource_name

第三步:决定准确率的三件事

这是这一页最重要的部分。换模型带来的差异,通常小于下面三件事做得好不好:

① /kb init 是根基

它决定了系统对这个库的初始理解:每张表每个字段是什么意思、有哪些指标、哪些枚举取值。 做完之后通读一遍生成的 YAML——LLM 起草的注释会有想当然的地方, 而错误的字段注释比没有注释更糟,因为它会被当真。

② 校准 semantics.yml

指标口径必须由懂业务的人确认。特别是:

③ 用 /kb learn 沉淀

每次得到一个好答案,把它固化成示例。这是准确率增长的主要来源, 而且它跟着使用增长,不需要重新训练任何东西。

系统还有一条自校验闭环会帮你发现错误答案:生成的 SQL 会被实际执行、结果会过规则链、 这一轮有没有进步会被版本比对判定。发现的问题会变成 pending 的教训或示例, 等你确认。详见知识库。

权限:只读账号怎么给

Trove 在执行层有多重只读保护,但真正的安全边界是数据库侧的只读角色。 代码里对此有明确说明,不要把它当成「有防火墙就够了」。

guard.py:50 check_readonly registry.py:416 _guard_read_only

MySQL / Doris 侧的典型做法:

CREATE USER 'trove_ro'@'%' IDENTIFIED BY '...';
GRANT SELECT ON financial.* TO 'trove_ro'@'%';
-- 可选:限制单条查询的扫描量与超时
SET GLOBAL max_execution_time = 30000;          -- MySQL 8
SET GLOBAL sql_mode = 'ONLY_FULL_GROUP_BY';     -- 让含糊的分组直接报错

另外建议给这个账号配资源组/查询审计,因为 Trove 会执行模型生成的 SQL—— 这些都是 SELECT,但复杂度不可控。

不要给写权限

即使 Trove 有三层写保护(关键词正则、AST 防火墙、执行器统一门), 给一个只会 SELECT 的账号仍然是最省心的防线:被绕过的代价是零。

表级白名单(allowed_tables)是另一道可选收紧,在管理端配置。

registry.py:453 set_allowed_tables intent.py:107 has_strong_write

其他方言怎么建这个账号

-- PostgreSQL:默认 PUBLIC 对所有表有 CONNECT,但没有 SELECT
CREATE ROLE trove_ro LOGIN PASSWORD '...';
GRANT USAGE ON SCHEMA public TO trove_ro;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO trove_ro;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO trove_ro;
-- ClickHouse:READ 是组别名(含 SELECT/SHOW/DESCRIBE 等),比逐条 SELECT 稳
CREATE USER trove_ro IDENTIFIED BY '...';
GRANT READ ON *.* TO trove_ro;
-- 引擎侧再兜一层:这个用户即使写出写语句,也会被配额/只读设置拦下
ALTER USER trove_ro SETTINGS readonly = 1;

PostgreSQL 那三行的关键在第三行:默认权限。少了它,今天建的表都只读, 明天新建的表默认给 PUBLIC 什么都不加、但 Trove 也就查不到——看起来像权限 没配好,实则是漏了这条。

配好之后:让它自己确认一遍

启动时 Trove 会自己查一遍权限表,确认这个账号确实写不了,并把结论挂在探活端点上 (readonly 字段)。它不会靠「试写一条语句」来验证—— 那条语句「必然失败」的前提正是「账号只读」这个还没被证明的假设,账号其实可写时它会真的写进去。 三种取值与结论口径见 可观测性。

方言自检查什么
MySQL / DorisSHOW GRANTS,看权限清单里有没有写权限(表名撞上关键字不算)
PostgreSQL是否超级用户、是否是表的属主(属主天然可写)、table_privileges 里的写权限
ClickHousesystem.grants,展开角色继承后再看有没有写权限
Snowflake / BigQuery暂未实现权限表探测——结论是「无从判断」。探测缺失不会被渲染成「已确认只读」:那等于替一道并不存在的边界背书
SQLite / DuckDB查不了——没有角色概念,边界是文件权限,结论是「无从判断」

接入后自检

uv run python scripts/lint_kb.py --db-id <name>
# 加上活库探测(会比对枚举值与真实 DISTINCT)
uv run python scripts/lint_kb.py --db-id <name> --datasource <url>

lint 会挑出「不报错但一直悄悄降低准确率」的问题:术语指向不存在的列、 示例 SQL 解析不了、声明的枚举值漏了真实存在的取值等等。 完整清单见知识库 · lint。

继续读

想了解去哪
先跑一遍看看快速上手
可答边界与逃生梯的概念产品概念
KB 五个文件的格式知识库
安全边界的三层设计安全边界
本页源码锚点的基准提交:anchor-base: 211ae86 GitHub 仓库 文档首页