预定义查询智能检查校正机制解析
配好查数语句之后,系统会检查什么、和对话里查数失败有什么关系。
来源 docs/技术博客/预定义查询智能检查校正机制解析.md
表述:本文面向 工作区管理员与开发/运维,说明 Cadau 在配置 HR 等数据连接的 预定义查询(
query.run)时,「智能检查校正」具体做什么、依赖哪些真实库表信息、与对话里工具调用失败的关系。用户侧「生成员工画像」操作见 对话生成员工画像操作指南;rilong 连接参数对照见docs/data-connection-templates/caretop-employee-profile/。
日期:2026-07-12 相关代码:backend/internal/datasource/query_defs_review.go、query_def_schema.go、query_def_sql_fix.go、query_run_params.go、backend/internal/api/handlers/workspace_data_sources.go
结论
Cadau 的 预定义查询智能检查校正 不是单纯的「JSON 排版」或「参数格式校验」,而是一套 逐条流水线:
| 阶段 | 输入 | 输出 |
|---|---|---|
| 本地规范 | 单条 QueryDef | ? 占位、@param 消除、少量 HR 硬规则 |
| 表结构校正(须选数据连接) | SQL 涉及表 + information_schema 列名 | WHERE =? 绑定处列名自动对齐(如 empId→emp_id) |
| AI 逐条审查 | 上一步结果 + 真实列名清单 + 全库表名列表 | 校正后的 query_def 与中文 note |
关键前提:管理端调用检查接口时必须带上 data_source_id,平台才会连上该数据连接拉列结构;否则 AI 只能做格式层修正,无法可靠修正栏位名。
对话侧另有 query.run 运行时容错(平级参数并入内层、id/empId/emp_id 别名互认),与检查校正互补,见 §5。
1. 背景:为什么需要机制而不只靠 AI
1.1 典型故障(以 rilong / 员工画像为例)
在一次真实对话中,智能体对 rilong 连接发起了大量 query.run,失败集中在两类:
| 错误信息 | 根因 |
|---|---|
缺少参数 id / emp_id / empId | 绑定值与 query_id 平级传入,未放在内层 params |
Unknown column 'empId' in 'where clause' | SQL WHERE 写了 empId,表列实为 emp_id |
第二类错误说明:仅有表名列表时,AI 无法知道列名;本地若只做 JSON/? 规范,也修不掉列名错误。
1.2 设计目标
- 可验证:尽可能以数据库 真实列元数据 为依据,而不是模型猜测。
- 可解释:每条查询返回
note,写明本地与 AI 做了哪些校正。 - 可渐进:连库失败或未选连接时,降级为格式校正,不阻断流程。
2. 入口与权限
2.1 API
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/v1/workspaces/{id}/data-sources/review-query-defs | 一次性返回校正结果 |
| POST | /api/v1/workspaces/{id}/data-sources/review-query-defs/stream | SSE 逐条进度(local → llm → done) |
请求体(管理员):
{
"query_defs_json": "[{\"id\":\"eaemp_by_id\",\"name\":\"...\",\"sql\":\"SELECT ... WHERE empId = ?\", \"params\":[{\"name\":\"id\",\"required\":true}]}]",
"data_source_id": "<工作区数据连接 UUID>"
}
data_source_id强烈建议填写:用于拉取库名、表列表,并 连库读列结构。- 须 工作区管理员;平台须开启数据连接能力且配置 LLM。
2.2 响应
{
"query_defs_json": "[...]",
"note": "[eaemp_by_id] 按表结构校正列名:empId→emp_id\n[...]",
"changed": true,
"warnings": []
}
管理员将 query_defs_json 写回数据连接配置并保存后,对话中的 query.run 才使用校正后的 SQL。
3. 流水线架构
flowchart TB
subgraph Input
A[query_defs_json]
B[data_source_id]
end
subgraph Enrich
C[库名 + ListTables]
D[QueryDefsReviewSchema 连接信息]
end
subgraph PerQuery["逐条 QueryDef"]
L1[本地规范 normalizeQueryDefLocal]
L2[拉取涉及表列名 ListColumns]
L3[本地列名校正 fixQueryDefColumnsFromSchema]
L4[AI 审查 reviewQueryDefItem]
end
subgraph Output
O[校正后 JSON + note + warnings]
end
A --> PerQuery
B --> Enrich
Enrich --> L2
L1 --> L2 --> L3 --> L4 --> O核心类型:QueryDefsReviewInput(query_defs_review.go)在原有 QueryDefsJSON、TableNames、DatabaseName 上增加:
Schema *QueryDefsReviewSchema // Engine + Conn,用于 ListColumns
Handler enrichQueryDefsInputFromDataSource 在传入 data_source_id 时填充上述字段(workspace_data_sources.go)。
4. 三阶段校正详解
4.1 阶段一:本地规范(normalizeQueryDefLocal)
不连库,对单条查询做确定性改写:
| 规则 | 示例 |
|---|---|
@param → ? | WHERE empName = @empName → WHERE empName = ? |
| HR 硬编码 WHERE 替换 | empId = ? → emp_id = ?(query_def_sql_fix.go) |
按 query_id 的 empName 替换 | mostayentry*by_empname 类:empName = ? → emp_name = ? |
这一阶段解决 占位符与少数已知惯例,不读取 information_schema。
4.2 阶段二:表结构校正(query_def_schema.go)
条件:QueryDefsReviewInput.Schema != nil(即请求带了有效 data_source_id 且能连库)。
步骤:
ExtractTablesFromSelectSQL:从 SQL 的FROM/JOIN解析表名(adhoc_select.go)。ListColumns:对每张表查information_schema.columns(MySQL / PostgreSQL 各有实现)。fixQueryDefColumnsFromSchema:用正则匹配WHERE … col = ?,若col不在列清单中,则尝试 camelCase → snake_case(empId→emp_id)并在列清单中解析 canonical 列名后替换。
示例:
-- 校正前
SELECT * FROM rt_emergency_contact WHERE empId = ?
-- 列清单含 emp_id、不含 empId
-- 校正后
SELECT * FROM rt_emergency_contact WHERE emp_id = ?
note 中会记录:[rt_emergency_contact_by_empid] 按表结构校正列名:empId→emp_id。
列名缓存:同一检查任务内按表名缓存列清单,避免重复查库。
4.3 阶段三:AI 逐条审查(reviewQueryDefItem)
将以下内容拼进 user payload(buildQueryDefsReviewItemPayload):
| 块 | 内容 |
|---|---|
| 数据库名 | Conn.Database |
| 库中实际表名 | ListTables 全量列表(校正 FROM/JOIN 表名) |
| 涉及表的实际列名 | 阶段二已拉取的每张表列清单(校正 SELECT/WHERE 字段) |
| 待检查 JSON | 当前 QueryDef |
System prompt 硬性要求(节选):
- 若提供了 涉及表的实际列名,SELECT/WHERE 字段 必须与列名列表一致,禁止臆造。
- 常见纠错示例:
empId→emp_id、empName→emp_name(以列名列表为准)。 - 表名/列名列表为空时,仅做 JSON/SQL 规范校正。
AI 输出单条 query_def + note;若 JSON 不合法则保留阶段二结果并写入 warnings。
5. 与 query.run 运行时容错的关系
检查校正解决的是 配置落盘时的 SQL/params 定义;对话执行时另有运行时层(query_run_params.go、invoke.go):
| 能力 | 作用 |
|---|---|
normalizeQueryRunArgs | 把与 query_id 平级的 id/emp_id/empId 并入内层 params |
resolveQueryParam | 按查询定义的 params[].name 解析时,对员工主键/姓名做别名互认 |
因此:
- 检查校正:让 SQL 列名、params 定义尽量正确,减少上线后错误。
- 运行时容错:减轻智能体 调用形状 错误(嵌套、别名),不能修复 SQL 里写错的列名或缺失的表。
两者应同时存在;不应指望仅靠运行时容错掩盖错误 SQL。
6. 与员工画像场景的对照
rilong 连接上,同一 query_id 的内层参数名 并不统一(须以 query.list 或检查后的定义为准),例如:
| query_id | 内层 params 键 |
|---|---|
eaemp_by_id | id |
eabasicinfo_by_empid | emp_id |
eaworkexperience_by_empid | empId |
智能检查 不会 统一全库参数命名(避免破坏已有 SQL),但会:
- 在
note中暴露列名修正; - 把真实列名交给 AI,减少 SELECT 列表、WHERE 中 栏位 写错;
- 配合技能文档要求画像流程 先
query.list再按 pipeline 取数。
详细对照表:docs/data-connection-templates/caretop-employee-profile/PARAMS-REFERENCE.md。
7. 边界与已知限制
| 场景 | 行为 |
|---|---|
未传 data_source_id | 无 Schema,跳过阶段二;AI 无列名清单,栏位校正不可靠 |
| 连库失败 | warnings 记录原因,降级为格式 + AI(无列名块) |
| SQL 中表不存在 | ListColumns 失败,该条 warning,不阻塞其余条 |
| SELECT 列表错列名 | 当前 本地规则主要校正 WHERE col = ?;SELECT 字段依赖 AI + 列名块 |
| 无试跑 | 检查流程 不 自动 query.run 试执行;保存后须人工或对话验证 |
| 子查询 / 复杂 SQL | ExtractTablesFromSelectSQL 仅解析顶层 FROM/JOIN;复杂 SQL 可能拉不全列 |
8. 推荐使用方式(管理员)
- 在 数据集成 → 数据连接 中编辑 HR 连接(如
rilong),粘贴或维护query_defs_json。 - 点击 智能检查校正(确保请求带上当前连接 ID)。
- 阅读返回
note:关注按表结构校正列名与 AI 说明。 - 保存 连接配置。
- 用固定
empId(如892)对关键query_id各执行一次query.run验证。 - 再让用户在对话中说「生成某某的员工画像」。
对话中可向工作智能体说:
请对 rilong 数据连接执行预定义查询智能检查,保存后列出仍有 SQL 错误的 query_id
9. 实现对照索引
| 模块 | 路径 | 职责 |
|---|---|---|
| 审查编排 | datasource/query_defs_review.go | 逐条流水线、SSE 进度、LLM prompt |
| 表结构 | datasource/query_def_schema.go | 列缓存、fixQueryDefColumnsFromSchema |
| HR 硬规则 | datasource/query_def_sql_fix.go | 本地 empId/empName 替换 |
| 运行时参数 | datasource/query_run_params.go | query.run 平级/别名容错 |
| SQL 表解析 | datasource/adhoc_select.go | ExtractTablesFromSelectSQL |
| 列元数据 | datasource/mysql.go、postgres.go | ListColumns |
| HTTP | handlers/workspace_data_sources.go | ReviewQueryDefs、enrichQueryDefsInputFromDataSource |
| SSE | handlers/workspace_data_sources_review_stream.go | 流式进度 |
测试:query_def_schema_test.go、query_run_params_test.go、query_defs_review_test.go。
10. 演进方向(未实现)
以下能力可按需迭代,当前 不在 检查流水线内:
- 对 SELECT 列表、JOIN ON 条件做列名静态校验与自动替换;
- 检查完成后对每条查询 自动试跑(带默认参数或
EXPLAIN); - 将校正结果写回前生成 diff 预览 与按
query_id的回滚; - 与「从文档合成预定义查询」(
SynthesizeQueryDefsFromDocument)共用同一 schema 上下文。
相关阅读
- 对话生成员工画像操作指南 — 用户侧话术与 pipeline 流程
docs/data-connection-templates/caretop-employee-profile/README.md— rilong 参数与 SQL 修复清单examples/employee-profile-pipeline/data-connection/query-defs.example.json— 标准 pipeline 查询范例