结构化数据 RAG 负责从 H2、MySQL 等关系数据库中获取精确数据证据,适合回答:
其核心不是向量检索,而是:
自然语言问题
→ 选择或生成 SQL
→ 安全执行
→ 将表格结果包装为 RAG 证据
→ 交给回答模型解释
当前知识库绑定中配置了 defaultSql,因此工作台实际执行的是显式 SQL:
SELECT *
FROM rescue_forces
WHERE status = 'READY'
ORDER BY capacity DESC
LIMIT 10
虽然前端传入:
{
"allowTextToSql": true
}
但后端优先级是:
显式 sql/defaultSql
>
Vanna 自动 Text-to-SQL
因此当前工作台查询并没有实际调用 Vanna。
flowchart TD
Q["用户问题"] --> K["KnowledgeBaseRagRetriever"]
K --> S["StructuredDataRagRetriever"]
S --> E{"是否存在显式 SQL"}
E -->|是| X["使用 sql/defaultSql"]
E -->|否| A{"是否允许自动生成"}
A -->|否| W["返回 warning"]
A -->|是| V["VannaSqlGenerationService"]
V --> SC["读取表和字段 Schema"]
SC --> B["RAG AI Bridge /text2sql"]
B --> L["Vanna + LLM 生成 SQL"]
X --> G["SqlGuardService"]
L --> G
G --> DB["JDBC 只读执行"]
DB --> R["columns + rows"]
R --> EVIDENCE["SQL_RESULT 证据"]
EVIDENCE --> ANSWER["多源证据融合回答"]
结构化检索使用统一的 RagQuery:
{
"query": "查询当前可用且载员能力最高的救援力量",
"sourceIds": ["1"],
"topK": 5,
"filters": {
"allowTextToSql": true
}
}
| 字段 | 含义 |
|---|---|
query |
用户自然语言问题 |
sourceIds |
数据源 ID |
topK |
SQL 最大返回行数控制 |
allowTextToSql |
没有显式 SQL 时,是否允许 Vanna 自动生成 |
显式 SQL 可以来自请求:
{
"sql": "SELECT ..."
}
也可以来自知识库数据源绑定:
{
"defaultSql": "SELECT ..."
}
执行过程:
读取显式 SQL
→ 跳过 Vanna 和大模型
→ SQL Guard
→ JDBC 执行
→ 转换为 SQL_RESULT
优点是稳定、快速、低成本;缺点是不能根据每次用户问题调整查询条件。
例如当前用户即使询问 BUSY 状态,固定 SQL 仍可能查询 READY。
删除 defaultSql 后,如果满足以下任一条件:
allowTextToSql = true
retrievalMode = AUTO_GENERATE
系统会调用 VannaSqlGenerationService。
Java 根据数据源 ID 获取:
并拼装类似 DDL:
TABLE rescue_forces (
id BIGINT,
name VARCHAR,
type VARCHAR,
status VARCHAR,
capacity INTEGER
);
当前救援演示加入了业务口径:
rescue_forces.status 使用 READY 表示当前可用,BUSY 表示忙碌。
结构化数据源只查询可用救援力量。
任务阶段由图数据源回答,不要在 SQL 中查询或拼接任务阶段。
业务说明的作用是将数据库字段转换成模型能理解的业务语义。
问题:查询当前可用且载员能力最高的救援力量
SQL:
SELECT *
FROM rescue_forces
WHERE status = 'READY'
ORDER BY capacity DESC
LIMIT 1
Java 向 RAG AI Bridge 发送:
POST http://127.0.0.1:18733/text2sql
请求大致为:
{
"query": "查询当前可用且载员能力最高的救援力量",
"datasourceId": 1,
"dialect": "mysql",
"ddl": "TABLE rescue_forces (...)",
"documentation": "READY 表示当前可用……",
"examples": [
{"question": "……", "sql": "SELECT ..."}
],
"tableWhitelist": ["rescue_forces"],
"maxRows": 5
}
当前使用的是请求级 Vanna 上下文:
当前没有建立持久化的 Vanna 训练知识库,也没有通过向量检索动态选择相关 DDL、文档和历史 SQL。
因此当前自动模式可以准确描述为:
Java 构造当前数据源上下文,Vanna 组织上下文并调用 LLM 生成 SQL。
Bridge 负责:
SELECT 或 WITH;maxRows。SqlGuardService 再次检查:
SELECT、WITH、EXPLAIN;INSERT、UPDATE、DELETE、DROP、ALTER 等;数据库账号还应配置为只读账号,作为最终安全边界。
校验通过后,系统:
当前数据源名称为 MaritimeRescue,固定查询返回 READY 状态的救援力量,并按 capacity 降序排列。
执行结果封装为:
{
"sourceType": "STRUCTURED_DATA",
"evidenceType": "SQL_RESULT",
"title": "MaritimeRescue",
"content": "查询返回5行,列:id, name, type, capacity, status",
"score": 1.0,
"payload": {
"columns": ["id", "name", "type", "capacity", "status"],
"rows": [],
"rowCount": 5
},
"metadata": {
"sql": "SELECT ...",
"explicitSql": "SELECT ...",
"executionTimeMs": 0,
"warnings": []
}
}
判断 SQL 来源:
explicitSql:固定 SQL;generatedSql:Vanna 自动生成 SQL。score=1.0 不是相似度,而是数据库实际执行得到的确定性证据标记。
以问题“东海海上目标救援任务中,可用救援力量和任务阶段分别是什么?”为例:
| 子问题 | 数据源 | 查询方式 |
|---|---|---|
| 当前可用救援力量 | 关系数据库 | 显式 SQL 或 Vanna Text-to-SQL |
| 任务包含哪些阶段 | Neo4j | 显式 Cypher 或 Text-to-Cypher |
| 制度、背景和方案说明 | Milvus | BGE-M3 + BM25 |
结构化数据库负责精确数据,不应让 SQL 查询承担图关系或文档语义问题。
defaultSql 使 Vanna 无法实际参与工作台查询;EXPLAIN 预执行和扫描量控制;defaultSql,实际启用 Vanna;EXPLAIN、超时、扫描量和结果量限制;KnowledgeBaseRagRetriever:多源知识库调度;StructuredDataRagRetriever:结构化检索主入口;ExplicitSqlGenerationService:显式 SQL;VannaSqlGenerationService:自动 Text-to-SQL;RagAiBridgeClient:调用 /text2sql;SqlGuardService:Java 只读安全校验;SchemaExplorerServiceImpl:读取 Schema 并执行 SQL;DataSourceService:管理数据源和凭据。