npx skills add ...
npx skills add senclaw-cdn.italent.cn/beisen-data-query
北森 HR 通用数据查询引擎。本 Skill 通过 beisen-cli staffservice 子命令集(sceneTool / searchFormTool / businessDataTool,以及 sceneToolMessageForCLI、menuSearch)实现自然语言到业务数据的 6 步查询流水线。当用户询问假期余额、考勤异常、下属信息、绩效情况、任职信息、组织架构等个人或团队业务数据时触发。本 Skill 是 beisen-employee-profile、beisen-attendance-leave、beisen-organization 三个业务域 Skill 的共享查询底层。
npx skills add senclaw-cdn.italent.cn/beisen-data-query
CRITICAL — 开始前 MUST 读取 ../beisen-shared/SKILL.md
CLI 调用方式:本 Skill 中工具通过
beisen-cli staffservice的子命令调用:
beisen-cli staffservice employeeData sceneToolbeisen-cli staffservice employeeData searchFormTool --params '{"intentionId":"<id>"}'beisen-cli staffservice employeeData businessDataTool --data '{"intentionId":"<id>","search":[...]}'beisen-cli staffservice employeeData sceneToolMessageForCLI --params '{"intentionId":"<id>"}'下文流水线中以逻辑名
SceneTool/SearchFormTool/BusinessDataTool/SceneToolMessage指代上述子命令。
本 Skill 是 beisen-cli 所有 read-only 数据查询场景的统一入口。 其他业务域 Skill(beisen-employee-profile、beisen-attendance-leave、beisen-organization)中的场景查询通过引用本 Skill 实现。
你输出的每个字用户都看得见,不存在"内部思考/过程说明"通道。
根据用户输入判断是否为数据查询意图。数据查询意图必须具备明确的数据询问结构,即包含以下特征之一及以上:
询问结构以整句为单位判定:整句必须是向系统求取数据的疑问或请求表达;若整句是名词性短语、标题或描述性文案,即使内部嵌有形似"主体+指标"的片段(如描述文案里的"我有这个视图权限")或数量词字样,也不构成数据询问结构。
分类处理:
SceneTool 获取租户已配置的查询场景列表:SceneTool返回的 sceneLabel、description 判断是否命中。命中标准为强命中,需同时满足两个条件:
intentionId 调用 SceneToolMessage 获取输出要求和关联菜单:intentionId 调用 SearchFormTool,获取本场景支持筛选的字段:前置检查(门控):检查返回字段中是否存在 fieldDataType = "部门单选" 的字段——
存在:本场景支持组织范围查询(场景 A/B/C 可用),可传 businessParameters.userFindOrgType 和部门字段 value → 进入第 4 点走 7 级决策表
不存在:本场景仅支持查本人(优先级 1)/权限范围(优先级 2)/指定人(优先级 3)。若用户问法属于以下组织范围查询(A/B/C/所在 类),一律静默退出,交由菜单唤起或知识问答处理,不输出任何文案、不降级为查指定人:
| 用户问法类型 | 判定条件 | 示例 | 处理 |
|---|---|---|---|
| A 类 | 他人+范围词+无具体部门名 | "麦店长负责的部门的休假情况" | 静默退出 |
| B 类 | 无具体人名+具体部门名 | "一体化产品部的休假情况" | 静默退出 |
| C 类 | 他人+范围词+具体部门名 | "麦店长负责的一体化产品部休假" | 静默退出 |
| 所在类 | 他人+所在+具体部门名 | "麦店长所在的一体化产品部休假" | 静默退出 |
若用户问法仅涉及本人/权限范围/指定人(如"我的休假情况""麦店长的休假"),则正常进入第 3 点提取参数
根据字段信息和用户问题提取筛选参数,详细提取规则见 references/business-rules.md [blocked] 的"参数提取规则"章节。身份判定只依据用户原文的显性表达,禁止结合登录用户身份信息推断某称谓指向当前用户。 日期字段严禁默认推断:仅当用户原文出现明确时间表达(本月/上周/7月/最近N天等)时才传入日期字段;用户未提及时间(如"查询我的团队排班情况")→ 日期字段一律不传,禁止自行默认本周/本月/近30天等任何范围。日期 value 格式硬约束:必须严格为 yyyy/MM/dd-yyyy/MM/dd(如 2026/06/01-2026/06/30),日期分隔符只用 /,起止之间只用 -,禁止 ~、至、- 分隔日期、单位数月日等任何其他形态(详见 business-rules.md"日期格式硬约束")。
查询主体与组织范围判定(仅当第 2 点确认部门单选字段存在时执行;完整规则见 references/business-rules.md [blocked] 的"员工字段"与"部门单选字段"章节):按以下 7 级穷举决策表确定员工字段 value、businessParameters.userFindOrgType、部门字段 value 三个参数取值,按优先级从高到低逐一匹配,命中即停止。范围限定词包括:团队、下属、部门(泛指)、管理、负责、所在、他们组、下面、组等(完整列表见 business-rules.md)。第一人称 + 任何范围词 → 一律优先级 2,不传 userFindOrgType。"所在"在无部门名时降级为优先级 4(有部门名时降级为 5)。部门名从用户输入中剥离查询词和虚词后、以部门后缀(部/中心/处/科/室/组/团队/部门)结尾的文本提取,多个部门用英文逗号分隔,原样透传不做增删改。
| 优先级 | 判定条件 | 员工 value | userFindOrgType | 部门 value |
|---|---|---|---|---|
| 1 | 第一人称+无范围词+无部门名 | "当前用户" | 不传 | 不传 |
| 2 | 第一人称+范围词+无部门名 | 不传 | 不传 | 不传 |
| 3 | 他人+无范围词+无部门名 | 原文透传 | 不传 | 不传 |
| 4 | 他人+范围词+无具体部门名 | 原文透传 | 2 | 不传 |
| 5 | 无具体人名+具体部门名 | 不传 | 不传 | 部门名透传 |
| 6 | 他人+范围词(负责/管理)+具体部门名 | 原文透传 | 2 | 部门名透传 |
| 7 | 他人+范围词(所在)+具体部门名 | 不传 | 不传 | 部门名透传 |
将 intentionId 和提取的筛选条件传入 BusinessDataTool。search 数组中仅传入有值的字段;businessParameters.userFindOrgType 仅在优先级 4(A) 和 6(C) 时传 2,其余优先级不传 businessParameters 对象。字段编码和序号从 SearchFormTool 返回值中透传,禁止修改:
返回结构:
dataList 中每条记录的 key 为视图列的中文字段名,可直接阅读理解。字段名由租户视图配置决定,不同场景、不同租户的字段名不同。生成回答时:只取与用户问题相关的字段组织答案,无关字段忽略;值为空字符串的字段省略不提。
code 非 "200" → 输出固定文案(见 references/business-rules.md [blocked] 固定文案表"查询失败"行),流程结束dataList 为空或不存在 → 视为无数据dataList.length === 100 → 视为"返回量触顶":单次查询最多返回前 100 条(休假类记录仅近 30 天),实际数据可能多于 100 条。此时禁止对全量数据下绝对结论(如"没有异常""全部正常""无请假记录"),必须按 business-rules.md "大数据量与返回边界提示"章节追加边界提示,并将结论限定为"已返回的记录中"。length < 100 时不追加任何提示,保持现状体验有数据时:结合用户问题、返回的业务数据和场景的 outputPromptWords,组织为自然、可读的答案。遵循以下思路:
yyyy/MM/dd-yyyy/MM/dd 形态(无 ~/至、无 - 分隔日期、月日两位补零、两个日期均带完整年份)?⑤ dataList.length 是否为 100,若是,是否已追加边界提示且未下绝对结论?⑥ 展示结构是否匹配问题意图——异常判断型是否聚焦异常、正常一笔带过(无异常直接给结论不铺全部记录)?整体概览型是否按人分组、有无长表刷屏?⑦ userFindOrgType=2 是否仅出现在优先级 4(A) 和 6(C)?出现在 1/2/3/5/7 则违规 ⑧ 部门 value 是否仅在用户原文提及具体部门名时才传入?未提及却传了则违规 ⑨ "所在的"场景是否已正确降级(有部门名→B 不传员工/userFindOrgType;无部门名→A 传员工/userFindOrgType)?⑩ 员工 value 是否与决策表一致(本人→"当前用户"、泛指→不传、他人→原文透传、A/C→原文透传、B/降级B→不传)?⑪ 若 SearchFormTool 未返回部门单选字段,且用户问法命中 A/B/C/所在 类组织范围查询——是否已按第 2 点静默退出?仍在调用 BusinessDataTool 或传 userFindOrgType=2 或部门 value 或员工 value 则违规 ⑫ 拼入 --data 前,用户原文中的 \、"、' 等特殊字符是否已按"用户输入转义"章节完成 JSON 转义和 shell 单引号转义?未转义直接拼接则违规 任一项不满足必须重写答案或重判优先级 ⑬ BusinessDataTool 的 search 数组中每个 fieldName 是否都来自本次 SearchFormTool 对该 intentionId 的返回?若来自记忆中其他场景的 SearchFormTool 返回、或跳过了 SearchFormTool 直接拼入,则违规,必须重新调用 SearchFormTool无数据时:输出固定文案(见固定文案表"无数据匹配"行),不返回关联菜单。
检查步骤二中获取的 menus:
有关联菜单 → 先用 menuSearch 查询每个菜单的 menuName 和 menuLink,然后在答案末尾追加"你可以在这里查看:",以 Markdown 链接列表输出:
输出规则:
menuName(菜单名称),URL 使用 menuLink(完整跳转地址)menuLink 必须从 menuSearch 返回中提取,严禁编造 URL无关联菜单 → 仅展示答案文本
dataList.length === 100(已触顶,后续可能仍有数据未返回)"小辛"(原文透传)。禁止因登录用户名为"董纪辛"而推断"小辛"是用户自称、填 "当前用户"——系统中可能确有名为"小辛"的员工,一律以原文为准search=[{"fieldName":"员工","num":"1","value":"王欣欣"}],businessParameters={"userFindOrgType":2}search=[{"fieldName":"部门","num":"2","value":"一体化产品部"}],不传 businessParameterssearch=[{"fieldName":"员工","num":"1","value":"王欣欣"},{"fieldName":"部门","num":"2","value":"一体化产品部"}],businessParameters={"userFindOrgType":2}search=[{"fieldName":"部门","num":"2","value":"一体化产品部"}],不传 businessParameterssearch=[{"fieldName":"员工","num":"1","value":"王欣欣"}],businessParameters={"userFindOrgType":2}search=[{"fieldName":"员工","num":"1","value":"王欣欣"}],businessParameters={"userFindOrgType":2}fieldDataType = "部门单选" 字段 → 前置检查判定:用户问法为 A 类(他人"麦店长" + 范围词"负责" + 无具体部门名)→ 场景不支持组织范围查询 → 静默退出,交由菜单唤起或知识问答处理--params 或 --data 前必须执行)将用户原文(人名、部门名、昵称等)拼入 --params '{"..."}' 或 --data '{"..."}' 的 JSON 字符串前,必须依次完成两层转义,否则会导致 JSON 结构损坏或 shell 命令注入(RCE 风险)。
转义顺序(先 JSON 转义,再 shell 包裹):
\ → \\" → \"\n,制表符 → \t,回车符 → \r\u00XX' → '\''(先闭合当前单引号,插入转义单引号 \',再重开单引号继续)--params '{"key":"escaped_value"}'王'欣欣(含单引号)
王'欣欣(单引号不影响 JSON 字符串值)--params '{"search":[{"value":"王'\''欣欣"}]}'--params '{"search":[{"value":"王'欣欣"}]}'(未转义的单引号使 shell 单引号提前闭合,后续 欣欣 被 shell 当作独立 token,导致语法错误或更严重的安全问题)--params "{\"search\":[{\"value\":\"王\\\"欣欣\"}]}"(用双引号包裹 JSON 并转义内部双引号——可行但极易出错,禁止使用)提示:大多数中文人名不含特殊字符,但防御必须覆盖所有输入。即使当前用户输入看起来安全,也必须执行上述转义流程,不得依赖"大概率无特殊字符"跳过转义。
本 Skill 中各步骤间通过 intentionId、menuId、fieldName、num 等标识符串联。必须严格遵守以下规则:
intentionId、menuId、fieldName、num 等标识符,只允许直接复制工具返回 content 中真实存在的值。intentionId、menuId 或 fieldName 不在刚刚 tool 返回的内容中,禁止调用工具,向用户报错说明缺少 ID。intentionId 必须完全和 SceneTool/SceneToolMessage/SearchFormTool 返回 JSON 字符串中的字符完全一致,大小写、符号不能修改。intentionId 链路中,每一步的 intentionId 必须来自上一步的返回。intentionId,停止工具调用,告知用户"没有找到你想要的数据,请换个描述试试。"TenantBase.EstimationResult.UserID 传入当前场景的 BusinessDataTool,导致字段不匹配、返回错误数据):search 数组中的 fieldName 和 num 必须且只能来自本次查询中 SearchFormTool 对该 intentionId 的返回结果。不同场景的 fieldName 不同(如绩效考核是 EstimationResult.UserID,任职信息是 EmploymentRecord.UserID),严禁从同一会话中其他场景的 SearchFormTool 返回中复制 fieldName,严禁凭记忆构造 fieldName。每次场景命中后都必须重新调用 SearchFormTool。yyyy/MM/dd-yyyy/MM/dd(如 2026/06/01-2026/06/30);日期分隔符只用 /,起止之间只用 -,月日必须两位补零、均带完整年份;禁止 2026-06-01\~2026-06-30、2026/06/01至2026/06/30、2026-06-01-2026-06-30 等任何其他形态,用户原文用了其他连接符也必须归一化length < 100 时保持现状不追加提示businessParameters.userFindOrgType=2;优先级 1/2/3/5/7 均不传;禁止在无范围词时传 userFindOrgType(如"王欣欣的出勤"是查指定人,不是查负责部门)fieldDataType = "部门单选" 字段时,用户问法若命中 A/B/C/所在 类组织范围查询(如"麦店长负责的部门""一体化产品部""麦店长所在的一体化产品部"),一律静默退出交由菜单处理,禁止降级为查指定人后返回个人数据,禁止传 userFindOrgType=2 或部门 value- [menuName](menuLink)),不得用其他格式beisen-cli staffservice employeeData sceneToolMessageForCLI --params '{"intentionId":"<id>"}'{
"code": "200",
"data": {
"outputPromptWords": "输出要求",
"menus": ["菜单ID1", "菜单ID2"]
}
}beisen-cli staffservice employeeData searchFormTool --params '{"intentionId":"<id>"}'{
"code": "200",
"data": [
{
"fieldName": "字段编码",
"fieldText": "字段显示名",
"fieldDataType": "字段类型",
"num": "字段序号",
"dataSourceItems": [{"id1": "value1"}, {"id2": "value2"}],
}
]
}[
{"fieldName": "字段编码", "num": "字段序号", "value": "筛选值"}
]beisen-cli staffservice employeeData businessDataTool --data '{"intentionId":"<id>","search":[...]}'{
"intentionId": "场景意图ID",
"search": [
{"fieldName": "员工字段编码", "num": "序号", "value": "王欣欣"},
{"fieldName": "部门字段编码", "num": "序号", "value": "一体化产品部"}
],
"businessParameters": {
"userFindOrgType": 2
}
}{
"code": "200",
"message": null,
"data": {
"dataList": [
{"考勤日期": "2026/06/21 星期日", "考勤状态": "正常", "员工": "王雪", "缺勤时长(分钟)": "0 分钟", "备注": "", "异常原因": "", "出勤状态": ""}
]
}
}