全部文章
更新日期

传软按代码生成预定义查询并导入 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 里手工再写一遍,容易和传软代码漂移。正确做法是:

  1. 传软按模块 生成 JSON(基础组、某功能模块组、某客户定制组)
  2. 在 Cadau 数据集成 → 数据连接 → 预定义查询 里导入
  3. 保存;建议再跑 智能检查校正,并 生成技能 让助手选对查询

行与字段谁能看,仍由数据连接上的策略执法(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 里一项 empNameWHERE empName = @empName(导入/保存会被拒绝)
两个 ? 配两项 paramsSQL 有 2 个 ? 但只声明 1 个参数
一张业务口径一条查询为每张表机械生成「全表 SELECT *」

参数 type 建议:string / int / daterequired: true 表示执行前必须有值。

同一参数在 SQL 中出现几次,? 就要几次,params 也要几项(可同名重复,或拆成 keyword 用三次——以 ? 个数为准)。例如模糊匹配写了三个 ?,就要三个参数位。

PostgreSQL 由 Cadau 把 ? 转成 $1,$2,…,传软仍按 ? 生成即可。

3.2 编号与命名建议

建议
id{实体}_{动作}_{条件},如 eaemp_by_nameattendance_by_emp_id_month
模块前缀与传软模块或表前缀一致,避免人事、考勤都叫 list_by_name
name用户能听懂的问法,不要只写表名
idbaseattendancepayrollcustomer_{客户代号}

同一编号出现在多组时,排在前面的组里的那条生效。客户定制若要覆盖标准查询,用同一个 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 里导入(管理员)

  1. 工作区 → 数据集成 → 打开已指向传软库的 数据连接(先 测试连接
  2. 打开 预定义查询
  3. 按包选择:

- 单模块文件 → 选目标组点 导入,或 导入全部 选「作为新组」 - 全部分组文件 → 导入全部 → 合并或覆盖

  1. 需要客户优先时,把定制组 上移 到最前
  2. 保存(不保存则对话里仍是旧目录)
  3. 建议:智能检查校正(当前组)→ 应用后再保存
  4. 建议:生成技能,把各查询的用途写入工作区技能,便于助手选对编号

导入只改表单;保存后 成员对话才能用到新查询。目标库表名与 JSON 不一致时,先导入再校正 SQL,不要指望改表名自动映射。


6. 导入后如何确认可用

检查期望
对话:「按姓名查某某」助手选用对应预定义查询,回复里能看出查什么、按什么条件
query.list(管理员/助手工具)能看到分组;顺序与界面一致
员工自助账号问「我的工号」只返回本人(策略生效,不是 SQL 里写死了一个人)
未开通的模块不要导入该组,避免助手匹配到不存在的表

问数仍对不上时:先看 name/description 是否像用户原话;再看是否排错组(前一组弱匹配会挡住后一组)。


7. 传软生成器检查清单

发布 JSON 前请自检:

  • [ ] kindcadau.query_def_groupcadau.query_def_catalog(或兼容的查询数组)
  • [ ] 每条 id 合法且跨模块尽量不撞名(有意覆盖除外)
  • [ ] sqlSELECT 开头,无 ;,无写操作关键字,参数仅为 ?
  • [ ] ? 个数 = params 长度
  • [ ] namedescription 写清适用问法,不是只写表名
  • [ ] 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.govalidate.goquery_placeholder.go
分组导入导出backend/internal/datasource/query_def_catalog.go;Web client/web/src/queryDefGroups.ts
按组顺序查找ResolveQueryInGroups(前一组匹配即用)
界面数据连接表单「预定义查询」:新增一组、上移/下移、导入/导出本组或全部

相关文档