传软按代码生成预定义查询并导入 Cadau
传软按列表查询和功能模块生成预定义查询 JSON,导入 Cadau 数据连接即可问数。可按基础、功能模块、客户定制分组,导入后按组顺序查找。
来源 docs/技术博客/传软按代码生成预定义查询.md
表述:本文面向 传软(旧有业务系统)的后端与业务管理员,说明怎样从传软自己的列表查询、功能元数据或数据访问层 生成预定义查询 JSON,再导入 Cadau 数据连接,让嵌入助手按固定口径问数。Cadau 不现场写 SQL;SQL 以传软生成的定义为准。
用户侧操作见 数据连接与预定义查询;嵌入架构见 传软接入 Cadau。
日期:2026-09-01 状态:已实现 关联帮助:数据连接与预定义查询 相关机制:数据连接问数准确性
结论(先看这个)
| 谁做什么 | 要点 |
|---|---|
| 传软 | 根据本系统已有的列表/详情查询、功能表(如 part / partfield)、DAO 或存储过程,生成 只读 SELECT 的预定义查询 JSON |
| Cadau | 工作区管理员把 JSON 导入数据连接 并保存;助手按查询编号取数,不把业务 SQL 交给模型现场拼 |
| 导入就能用的前提 | 数据连接已指向传软业务库;SQL 里的表名、列名与该库一致;参数用 ? 占位 |
一句话:问数口径写在传软代码里,Cadau 只执行已导入的查询。 传软发一版查询包,Cadau 导入对应组即可上线或给某客户定制。
1. 为什么要从传软代码生成
助手在对话里问业务数据时,Cadau 不允许临时拼任意 SQL。日常问数走数据连接上的 预定义查询:每条对应一种业务问法(按姓名查人、按部门查在职、本月考勤等)。
这些问法的真值在传软:
- 列表页、详情页已经在用的 WHERE 条件
- 功能元数据(业务名、表名、字段名)
- 现成的查询服务 / Mapper
若在 Cadau 里手工再写一遍,容易和传软代码漂移。正确做法是:
- 传软按模块 生成 JSON(基础组、某功能模块组、某客户定制组)
- 在 Cadau 数据集成 → 数据连接 → 预定义查询 里导入
- 点 保存;建议再跑 智能检查校正,并 生成技能 让助手选对查询
行与字段谁能看,仍由数据连接上的策略执法(host_actor),不要指望把权限写进 SQL 注释。策略说明见 sdk/host-embed/宿主增强-AgentRun与数据权限.md。
2. 导入文件格式(传软生成器请按此输出)
Cadau 接受三种 JSON,传软按需要选用。推荐按组导出,与「基础 / 模块 / 客户定制」一致。
2.1 一组查询(推荐日常交付)
文件名建议:{产品}-{模块}-query-defs.json。
{
"kind": "cadau.query_def_group",
"version": 1,
"group": {
"id": "hr_core",
"name": "人事基础",
"description": "在职人员、部门、主档;对应传软人事核心模块",
"queries": [
{
"id": "staff_by_name",
"name": "按姓名查在职人员",
"description": "用户说某人姓名、要基本信息或「还有没有这个人」时用。多条时须让用户确认。",
"sql": "SELECT id, empNo, empName, deptId FROM eaemp WHERE empName = ? AND state = 0",
"params": [
{ "name": "empName", "type": "string", "required": true }
],
"max_rows": 20
}
]
}
}
在 Cadau 中:打开目标数据连接 → 预定义查询 → 选中一组或点 导入全部 → 选该文件 → 保存。
- 导入到 当前组:查询合并进正在编辑的那一组
- 作为新组:列表末尾多一组,可用上移/下移调整查找顺序
2.2 全部分组(推荐版本发布)
一次带上基础 + 各模块 + 可选客户定制。文件名建议:{产品}-query-defs.json。
{
"kind": "cadau.query_def_catalog",
"version": 1,
"groups": [
{
"id": "base",
"name": "基础",
"description": "各客户通用的主档与组织查询",
"queries": []
},
{
"id": "attendance",
"name": "考勤模块",
"description": "开通考勤后追加;未开通则不要导入本组",
"queries": []
},
{
"id": "customer_acme",
"name": "客户定制·某司",
"description": "仅该客户口径;需要优先于基础时,导入后把本组移到列表最前",
"queries": []
}
]
}
Cadau 导入全部时:
- 合并:同组 id 或同组名则把查询写入已有组,新组追加到末尾
- 覆盖全部:用文件替换当前所有组(会清掉未出现在文件里的组,需确认)
组在列表里的顺序 = 智能体查找顺序:先在排在前面的组里找,找不到才用后面的组。客户定制要盖过标准口径时,把定制组排到最前。
2.3 兼容:只有查询数组
没有分组包装时,仍可导入(会进入当前组,或「导入全部」时作为一组追加):
[
{
"id": "staff_by_name",
"name": "按姓名查在职人员",
"sql": "SELECT id, empName FROM eaemp WHERE empName = ?",
"params": [{ "name": "empName", "type": "string", "required": true }]
}
]
新生成器请优先输出 2.1 / 2.2,便于按模块发版。
3. 一条查询怎么写(字段约定)
每条 queries[] 元素:
| 字段 | 必填 | 说明 |
|---|---|---|
id | 是 | 查询编号。仅字母、数字、下划线,且以字母或下划线开头。智能体调用时用。建议稳定,不要随发版乱改(技能、报表会写死编号) |
name | 是 | 给人看的短名称,如「按姓名查在职人员」 |
description | 建议 | 什么时候用、要什么条件、多条怎么处理。助手按名称+说明匹配问法,写清楚比再调一轮模型更准 |
sql | 是 | 只能是 一条 SELECT;禁止 ; 以及 INSERT/UPDATE/DELETE/DROP 等 |
params | 与 ? 一致 | 参数名、类型、是否必填;个数和顺序必须与 SQL 里的 ? 一致 |
max_rows | 否 | 最多返回行数;未填时用平台默认(约 200),且不超过平台上限(约 500) |
不要输出 review_verified 等检查标记,那是 Cadau 智能检查写入的。
3.1 SQL 与参数(传软生成时最容易错)
| 正确 | 错误 |
|---|---|
WHERE empName = ?,params 里一项 empName | WHERE empName = @empName(导入/保存会被拒绝) |
两个 ? 配两项 params | SQL 有 2 个 ? 但只声明 1 个参数 |
| 一张业务口径一条查询 | 为每张表机械生成「全表 SELECT *」 |
参数 type 建议:string / int / date。required: true 表示执行前必须有值。
同一参数在 SQL 中出现几次,? 就要几次,params 也要几项(可同名重复,或拆成 keyword 用三次——以 ? 个数为准)。例如模糊匹配写了三个 ?,就要三个参数位。
PostgreSQL 由 Cadau 把 ? 转成 $1,$2,…,传软仍按 ? 生成即可。
3.2 编号与命名建议
| 项 | 建议 |
|---|---|
id | {实体}_{动作}_{条件},如 eaemp_by_name、attendance_by_emp_id_month |
| 模块前缀 | 与传软模块或表前缀一致,避免人事、考勤都叫 list_by_name |
name | 用户能听懂的问法,不要只写表名 |
组 id | 如 base、attendance、payroll、customer_{客户代号} |
同一编号出现在多组时,排在前面的组里的那条生效。客户定制若要覆盖标准查询,用同一个 id 写在定制组,并把定制组排到最前。
3.3 按人收窄时把编号参数留下
员工自助「只能看本人」靠数据连接 行策略 强制 empId = {{host_actor.employee_id}} 等,不靠模型自觉。生成查询时:
- 按人筛选的 SQL 要有对应参数(如
empId) - 不要把身份写死在 SQL 字面量里
- 列名以业务库为准(
empId/emp_id不要混用)
导入后由工作区管理员配置或生成行与字段策略;生成器不必输出策略 JSON。
4. 建议怎么从传软代码生成
不必一次生成全库。按 用户会怎么问 映射到 已有查询。
4.1 从哪里抽
| 传软侧来源 | 生成什么 |
|---|---|
| 列表页 / 查询服务(按姓名、部门、日期) | 一条带相同条件的 SELECT,参数与页面筛选项对齐 |
| 详情页(按主键) | *_by_id,参数为业务主键 |
功能元数据(如 part.title + part.partName + partfield) | 先「按业务名找功能」,再「按功能 id 列字段」——见仓库 docs/data-connection-templates/caretop-part-metadata/ |
| 报表 SQL / 存储过程中的只读 SELECT | 改成参数化 ?,去掉过程名调用(Cadau 禁止 CALL) |
| 客户补丁包、项目定制分支 | 单独一组 customer_*,不要改基础组编号除非有意覆盖 |
4.2 生成流水线(建议)
1. 枚举模块 → 决定 groups[] 顺序(基础在前或客户定制在前,按产品策略)
2. 每个列表/详情查询 → 一条 QueryDef
3. 校验:id 合法、仅 SELECT、无分号、? 个数 = params 长度、无 @param
4. 写出 cadau.query_def_group 或 cadau.query_def_catalog
5. 在测试库对每条 query 用真实参数跑一遍(行数、空结果、多条)
6. 把 JSON 交给 Cadau 工作区管理员导入并保存
伪代码(示意):
for each 传软查询规格 Q:
emit {
id: slug(Q.module + "_" + Q.key),
name: Q.uiTitle, // 页面上的查询名称
description: Q.whenToUse, // 产品/交互说明里「用于什么问法」
sql: rewriteNamedParamsToQuestionMark(Q.sql),
params: Q.filters.map(f => { name, type, required }),
max_rows: min(Q.pageSize or 200, 500)
}
4.3 按模块分组(和 Cadau 界面一致)
| 组 | 典型内容 | 何时导入 |
|---|---|---|
| 基础 | 员工主档、部门、组织 | 每个客户都要 |
| 某功能模块 | 考勤、合同、薪资摘要 | 客户开通该模块才导入该组 |
| 某客户定制 | 只在该客户成立的口径或同编号覆盖 | 导入后视需要把组移到最前 |
Cadau 侧:上移/下移 即调整智能体查找顺序;每组可单独导入导出,与传软按模块发补丁一致。
5. 在 Cadau 里导入(管理员)
- 工作区 → 数据集成 → 打开已指向传软库的 数据连接(先 测试连接)
- 打开 预定义查询
- 按包选择:
- 单模块文件 → 选目标组点 导入,或 导入全部 选「作为新组」 - 全部分组文件 → 导入全部 → 合并或覆盖
- 需要客户优先时,把定制组 上移 到最前
- 点 保存(不保存则对话里仍是旧目录)
- 建议:智能检查校正(当前组)→ 应用后再保存
- 建议:生成技能,把各查询的用途写入工作区技能,便于助手选对编号
导入只改表单;保存后 成员对话才能用到新查询。目标库表名与 JSON 不一致时,先导入再校正 SQL,不要指望改表名自动映射。
6. 导入后如何确认可用
| 检查 | 期望 |
|---|---|
| 对话:「按姓名查某某」 | 助手选用对应预定义查询,回复里能看出查什么、按什么条件 |
query.list(管理员/助手工具) | 能看到分组;顺序与界面一致 |
| 员工自助账号问「我的工号」 | 只返回本人(策略生效,不是 SQL 里写死了一个人) |
| 未开通的模块 | 不要导入该组,避免助手匹配到不存在的表 |
问数仍对不上时:先看 name/description 是否像用户原话;再看是否排错组(前一组弱匹配会挡住后一组)。
7. 传软生成器检查清单
发布 JSON 前请自检:
- [ ]
kind为cadau.query_def_group或cadau.query_def_catalog(或兼容的查询数组) - [ ] 每条
id合法且跨模块尽量不撞名(有意覆盖除外) - [ ]
sql以SELECT开头,无;,无写操作关键字,参数仅为? - [ ]
?个数 =params长度 - [ ]
name、description写清适用问法,不是只写表名 - [ ]
max_rows合理(名单类可 100~200,详情类 1~20) - [ ] 组
id/name稳定,便于下次 合并 而不是每次覆盖全部 - [ ] 已在与 Cadau 数据连接相同的库上试跑
- [ ] 不含数据库账号、密码、连接串
8. 最小可运行示例
把下面存成 hr-core-query-defs.json,在 Cadau 对人事库连接 导入到一组 后保存,即可用「按姓名查在职人员」做联调(表名请改成传软真实表):
{
"kind": "cadau.query_def_group",
"version": 1,
"group": {
"id": "hr_core",
"name": "人事基础",
"queries": [
{
"id": "staff_by_name",
"name": "按姓名查在职人员",
"description": "用户给出姓名,查在职人员编号与部门。",
"sql": "SELECT id, empNo, empName, deptId FROM eaemp WHERE empName = ? AND state = 0",
"params": [{ "name": "empName", "type": "string", "required": true }],
"max_rows": 20
},
{
"id": "staff_by_id",
"name": "按人员编号查主档",
"description": "已有员工编号时取主档;行策略可强制本人编号。",
"sql": "SELECT id, empNo, empName, deptId, state FROM eaemp WHERE id = ?",
"params": [{ "name": "empId", "type": "int", "required": true }],
"max_rows": 1
}
]
}
}
更完整的人事画像类示例见仓库 examples/employee-profile-pipeline/data-connection/query-defs.example.json(导入时用 2.3 数组格式,或自行包进 group.queries)。
实现对照(给生成器作者)
| 项 | 位置 |
|---|---|
| 查询字段与校验 | backend/internal/datasource/types.go、validate.go、query_placeholder.go |
| 分组导入导出 | backend/internal/datasource/query_def_catalog.go;Web client/web/src/queryDefGroups.ts |
| 按组顺序查找 | ResolveQueryInGroups(前一组匹配即用) |
| 界面 | 数据连接表单「预定义查询」:新增一组、上移/下移、导入/导出本组或全部 |
相关文档
- 数据连接与预定义查询 — 管理员在 Cadau 里怎么配、怎么查
- 传软接入 Cadau — 嵌入、身份、数据连接策略
- 技能与应用导入导出与预定义查询 — 技能包带走查询依赖(与本文「从传软生成再导入」互补)
- 预定义查询智能检查校正 — 导入后检查 SQL 与表列