feat: 新增label快慢分流skill全套配置与校验脚本
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
---
|
||||
name: label-fast-slow-routing
|
||||
description: 依据 XA4.1 2026.6 新标准,对单条或批量 query、带会话上下文的请求和快慢分流评测数据进行“快 / 慢 / 模糊”三档可解释打标,给出默认路由、原因码、证据、置信度和复核标记,并在需要时兼容旧 FAST_DIRECT / SLOW_* 评测标签。用于快慢系统策略标注、旧评测集重标、边界 case 仲裁、标注 Prompt 编写、标签一致性检查和 badcase 分析;可结合相邻 label-master skill 判断业务领域、候选标签、复杂度、多指令和自动任务,但不得把这些辅助维度直接等同于快慢标签。
|
||||
---
|
||||
|
||||
# 快慢分流打标
|
||||
|
||||
## 目标
|
||||
|
||||
按用户对响应速度和结果质量的预期判断语义标签,不按当前系统能力反推标签。始终分开输出:
|
||||
|
||||
- `label`:`快`、`慢`、`模糊`。
|
||||
- `default_route`:三档标签的默认系统策略。
|
||||
- `fast_system_pending`:已确认的快系统能力缺口。
|
||||
- 业务标签及 `complex`、多指令、自动任务等辅助维度。
|
||||
|
||||
## 加载知识
|
||||
|
||||
1. 每次打标前读取 [references/policy.md](references/policy.md)。
|
||||
2. 处理边界 case、校准标注员或编写 Prompt 时,再读取 [references/golden-examples.md](references/golden-examples.md)。
|
||||
3. 迁移旧评测集、输出 `FAST_DIRECT` / `SLOW_*`、设计评测集或做质检时,再读取 [references/legacy-eval-and-quality.md](references/legacy-eval-and-quality.md)。
|
||||
4. 需要业务领域、业务标签、候选标签或结构维度时,按“结合 label-master”一节渐进加载相邻知识;不要一次读取整个知识库。
|
||||
|
||||
## 遵守真源优先级
|
||||
|
||||
按以下顺序处理冲突:
|
||||
|
||||
1. 用户在当前任务中明确给出的已批准新口径。
|
||||
2. 《【XA4.1】快慢分流新标准-2026.6》最终汇总(物理页 7–10)。
|
||||
3. 同文档的垂域调研细则(物理页 2–7),仅补充最终汇总未覆盖的场景。
|
||||
4. 《快慢系统分发-评测集构建》的旧八类标签,仅用于原因解释、旧数据迁移和评测方法。
|
||||
5. `label-master` 的业务标签与正交维度,仅用于辅助理解。
|
||||
|
||||
明确处理以下冲突:
|
||||
|
||||
- 把“导航去附近评分 4.5 以上的泰国菜”标为 `快`,不要沿用旧的筛选即慢。
|
||||
- 把“那个压线噔噔的声音关掉”标为 `快`,前提是功能可唯一识别且动作明确。
|
||||
- 把纯静态产品知识、故障诊断、设备或环境状态查询标为 `模糊`,不要直接沿用旧的快或慢。
|
||||
- 把多个全部明确的设备控制动作标为 `快`;不要仅因多指令就标慢。
|
||||
- 不要使用“长度不超过 5 字默认快”。它只是旧候选挖掘捷径,不是语义规则。
|
||||
|
||||
## 执行工作流
|
||||
|
||||
### 1. 整理输入
|
||||
|
||||
提取并保留:
|
||||
|
||||
- 当前 `query`。
|
||||
- 已提供的前轮、系统回复、时间窗口、设备、端侧和场景。
|
||||
- 用户要求的输出格式和旧标签兼容要求。
|
||||
- 已提供的快系统能力清单;没有清单时不要猜测能力支持状态。
|
||||
|
||||
只使用可见上下文。缺少会改变结论的上下文时,保留不确定点并设置 `review_required=true`。
|
||||
|
||||
### 2. 判断业务与结构辅助信息
|
||||
|
||||
需要时使用 `label-master` 判断:
|
||||
|
||||
- 业务领域和 2–5 个候选业务标签。
|
||||
- 是否为多指令、自动任务或 `complex`。
|
||||
- 当前轮是否真正依赖上文。
|
||||
|
||||
保持这些结果与快慢标签正交。特别注意:
|
||||
|
||||
- `complex=true` 不自动等于 `慢`。
|
||||
- 多指令不自动等于 `慢`。
|
||||
- 自动任务要结合端侧专项策略。
|
||||
- 业务标签不自动决定快慢。
|
||||
|
||||
### 3. 按三档策略裁决
|
||||
|
||||
使用 [references/policy.md](references/policy.md) 的完整决策树。执行以下最小顺序:
|
||||
|
||||
1. 先区分纯信息获取和带副作用的执行请求。
|
||||
2. 对执行请求,先检查是否必须反推意图、映射场景、消歧、补槽、依赖上下文或规划多步;命中则倾向 `慢`。
|
||||
3. 再检查动作和目标能否直接识别、是否无需先决定“做什么”;满足则标 `快`。
|
||||
4. 对纯闲聊、开放问答、产品知识、故障诊断、设备或环境状态查询标 `模糊`。
|
||||
5. 无法可靠归入快或慢、或速度和质量预期同时明显存在时标 `模糊`,不要把“模型自己不确定”伪装成确定标签。
|
||||
6. 聚合多个子请求时使用 `慢 > 模糊 > 快`;多个全部明确的设备控制动作使用 `快`特例。
|
||||
|
||||
同时做反证检查:说明为什么没有选择另外两档。不要只凭关键词命中一个规则。
|
||||
|
||||
### 4. 确定默认路由和能力状态
|
||||
|
||||
按固定映射填写:
|
||||
|
||||
- `快` → `default_route="快系统"`。
|
||||
- `慢` → `default_route="慢系统"`。
|
||||
- `模糊` → 默认 `default_route="慢系统"`;只有用户另给细分部署策略时才在下游覆盖,语义标签保持 `模糊`。
|
||||
|
||||
仅在有明确能力清单或验证结果证明“语义上应为快,但当前快系统尚不支持”时填写 `fast_system_pending=true`。没有检查能力时填 `null`,不要填 `false` 假装已验证。
|
||||
|
||||
### 5. 生成可审查结果
|
||||
|
||||
默认每条样本输出一个符合 [schemas/label-record.schema.json](schemas/label-record.schema.json) 的 JSON 对象:
|
||||
|
||||
```json
|
||||
{
|
||||
"query": "太冷了,调一下空调",
|
||||
"label": "快",
|
||||
"default_route": "快系统",
|
||||
"primary_reason_code": "DIRECT_ACTION",
|
||||
"reason_codes": ["DIRECT_ACTION"],
|
||||
"reason": "用户明确给出调节动作和空调对象,无需反推要操作什么。",
|
||||
"evidence": ["“调一下空调”同时包含动作和可识别对象"],
|
||||
"counterevidence": ["含感受词“太冷”,但感受词不覆盖明确执行目标"],
|
||||
"domain_label": "设备控制",
|
||||
"candidate_domain_labels": ["设备控制", "车载控制"],
|
||||
"structural_signals": {
|
||||
"complex": null,
|
||||
"multi_instruction": false,
|
||||
"auto_task": false
|
||||
},
|
||||
"context_used": false,
|
||||
"fast_system_pending": null,
|
||||
"legacy_eval_label": "FAST_DIRECT",
|
||||
"confidence": "high",
|
||||
"review_required": false,
|
||||
"uncertainties": [],
|
||||
"policy_version": "XA4.1-2026.6"
|
||||
}
|
||||
```
|
||||
|
||||
使用 `null` 表示未评估,不要用猜测值补齐辅助字段。用户只要求简表时至少保留 `query`、`label`、`primary_reason_code`、`reason` 和 `review_required`;落盘数据仍使用完整契约。
|
||||
|
||||
### 6. 校验后再落盘
|
||||
|
||||
对单条结果执行:
|
||||
|
||||
```bash
|
||||
python skills/label-fast-slow-routing/scripts/validate_label.py \
|
||||
--record '{"query":"开空调","label":"快","default_route":"快系统","primary_reason_code":"DIRECT_ACTION","reason_codes":["DIRECT_ACTION"],"reason":"动作和对象明确。","evidence":["开+空调"],"context_used":false,"fast_system_pending":null,"confidence":"high","review_required":false,"uncertainties":[],"policy_version":"XA4.1-2026.6"}'
|
||||
```
|
||||
|
||||
对 JSON、JSONL 文件执行:
|
||||
|
||||
```bash
|
||||
python skills/label-fast-slow-routing/scripts/validate_label.py \
|
||||
--file output/fast_slow_labels.jsonl
|
||||
```
|
||||
|
||||
出现 `valid=false` 时先修正结构和不变量,再写入训练集或评测集。校验器只保证结构和跨字段一致性,不能替代语义复核。
|
||||
|
||||
## 结合 label-master
|
||||
|
||||
需要业务标签时按以下最短路径读取:
|
||||
|
||||
1. 读取 `../label-master/knowledge/决策流程.md`。
|
||||
2. 读取 `../label-master/knowledge/索引/候选召回索引.md` 和 `../label-master/knowledge/标签总览.md`。
|
||||
3. 从 `../label-master/knowledge/索引/标签索引.md` 召回 2–5 个候选。
|
||||
4. 命中高频混淆时读取对应边界卡,再读取候选标签卡。
|
||||
5. 只在任务需要时读取复杂度、多指令或自动任务文件。
|
||||
|
||||
复用它的“候选召回 → 边界比较 → 排除理由 → 不确定点”方法,不复用它的 `Agent` / function target 作为快慢输出。
|
||||
|
||||
当 `label-master` 与本策略冲突时:
|
||||
|
||||
- 保留其业务标签与结构维度结论。
|
||||
- 按本 skill 的真源优先级独立重算快慢标签。
|
||||
- 在 `counterevidence` 中记录冲突,不静默覆盖。
|
||||
|
||||
## 批量与评测集要求
|
||||
|
||||
- 保留原始 ID、query、上下文和来源,不修改原始数据。
|
||||
- 逐条执行完整语义判断,不按字数、关键词或既有类别比例直接定标。
|
||||
- 对同一 session 使用相同的上下文截取规则;缺上下文样本单独标记。
|
||||
- 把 `模糊` 保留为语义标签;需要二值评测时另派生默认路由,不要覆盖原标签。
|
||||
- 旧八类标签只写入 `legacy_eval_label`;无法无损映射时填 `null` 并解释。
|
||||
- 对高流量、高分歧、高风险误分样本优先双人盲标并仲裁。
|
||||
- 分别统计三档标签、垂域、端侧和方向性错误;不要只看总准确率。
|
||||
|
||||
## 复核门禁
|
||||
|
||||
满足任一情况时设置 `review_required=true`:
|
||||
|
||||
- 缺少会改变标签的前轮、设备或端侧信息。
|
||||
- 快慢规则同时有强证据,且优先级无法消解。
|
||||
- 只能依赖未确认的系统能力或白名单。
|
||||
- 旧标签无法无损迁移到新三档。
|
||||
- `confidence="low"`。
|
||||
|
||||
`模糊` 不自动等于需要人工复核。产品知识或状态查询可以高置信地标为 `模糊`。
|
||||
|
||||
## 禁止事项
|
||||
|
||||
- 不要因快系统当前不支持而把 `快`改成 `慢`。
|
||||
- 不要把 `complex=true`、长 query、联网、搜索、排序、模糊词或多轮中的任一项当成单独硬触发器。
|
||||
- 不要把非标准叫法等同于真实歧义;先判断对象能否唯一识别。
|
||||
- 不要脑补前轮、设备位置、说话人位置或能力清单。
|
||||
- 不要把旧评测集的样本占比当成先验配额。
|
||||
- 不要输出没有证据或排除理由的裸标签。
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "快慢分流打标"
|
||||
short_description: "依据 2026.6 新标准完成快、慢、模糊三档可解释打标"
|
||||
default_prompt: "Use $label-fast-slow-routing to label these queries as 快、慢或模糊并给出可复核依据。"
|
||||
@@ -0,0 +1,61 @@
|
||||
# 黄金边界样例
|
||||
|
||||
使用这些样例校准规则,不要把词面模板机械迁移到所有场景。`来源`中的页码为 PDF 物理页码;“推导”表示按规则组合得到,不是文档逐字给出的标签。
|
||||
|
||||
| # | query / 上下文 | label | 主原因码 | 边界说明 | 来源 |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 1 | 开空调 | 快 | `DIRECT_ACTION` | 动作和对象明确 | 新标准 p8 |
|
||||
| 2 | 太冷了,调一下空调 | 快 | `DIRECT_ACTION` | 感受词不覆盖明确动作和对象 | 新标准 p8,规则推导 |
|
||||
| 3 | 我感觉好冷快冻死了,帮我调一下 | 慢 | `INTENT_INFERENCE` | 未说明要调什么,需反推动作 | 新标准 p9 |
|
||||
| 4 | 调一个浪漫点的氛围灯 | 快 | `DIRECT_ACTION` | 风格是简单修饰,功能目标明确 | 新标准 p8–9 |
|
||||
| 5 | 帮我把房间布置得舒适温馨一些 | 慢 | `SCENE_GOAL_MAPPING` | 需把目标状态映射成动作组合 | 新标准 p9 |
|
||||
| 6 | 导航去附近评分 4.5 以上的泰国菜 | 快 | `DIRECT_ACTION` | 最终汇总覆盖调研版“筛选即慢” | 新标准 p2 与 p8 |
|
||||
| 7 | 导航去附近最大的停车场 | 快 | `DIRECT_ACTION` | 单目标、单一简单排序可直接满足 | 旧评测 p3 与新标准 p8,规则推导 |
|
||||
| 8 | 推荐一家安静、亲子、评分高、停车方便且别排太久的酒店 | 慢 | `COMPLEX_REASONING` | 多个主观/实时条件需权衡 | 旧评测 p3,新标准规则推导 |
|
||||
| 9 | 导航去大裤衩,再沿途找充电站,并看看终点附近哪里好停车 | 慢 | `MULTI_STEP_PLANNING` | 多地点、多步骤路线编排 | 新标准 p9 |
|
||||
| 10 | 删除途经点 | 快 | `DIRECT_OPERATION_FLOW` | 导航操作流中的直接动作 | 新标准 p8 |
|
||||
| 11 | 把空调调到 24 度,然后打开座椅加热 | 快 | `EXPLICIT_DEVICE_MULTI_ACTION` | 多个动作全部为明确设备控制 | 新标准 p8 |
|
||||
| 12 | 查天气再决定要不要开窗 | 慢 | `MULTI_STEP_PLANNING` | 查询结果决定后续控制 | 旧评测 p4 |
|
||||
| 13 | 那个压线噔噔的声音关掉 | 快 | `DIRECT_ACTION` | 名称不标准但目标可唯一识别且动作明确 | 新标准 p4 与 p9 |
|
||||
| 14 | 打开那个灯(场景中有多个灯) | 慢 | `TRUE_DISAMBIGUATION` | 存在真实多候选,需澄清 | 旧评测 p3,新标准规则推导 |
|
||||
| 15 | 导航到那个像大裤衩一样的楼 | 慢 | `TRUE_DISAMBIGUATION` | 需先识别隐含地标再定位 | 旧评测 p3 |
|
||||
| 16 | 播放周杰伦的歌 | 快 | `DIRECT_ACTION` | 明确播放意图和资源 | 新标准 p8 |
|
||||
| 17 | 播放最近短视频里很火的那首歌 | 慢 | `TRUE_DISAMBIGUATION` | 资源身份不确定且依赖外部热点 | 旧评测 p3,新标准内容细则 |
|
||||
| 18 | 找王菲在春晚与别人合唱的歌,再用网易云播放 | 慢 | `MULTI_STEP_PLANNING` | 外部检索后跨步骤播放 | 新标准 p9 |
|
||||
| 19 | 现在几点了 | 快 | `DIRECT_DETERMINISTIC_QUERY` | 高频、唯一、确定性工具查询 | 旧评测 p3 |
|
||||
| 20 | 帮我定明天早上 9 点的闹钟 | 快 | `DIRECT_ACTION` | 时间和动作明确 | 新标准 p8 |
|
||||
| 21 | 小米 SU7 支持哪些驾驶模式 | 模糊 | `PRODUCT_KNOWLEDGE` | 纯静态产品知识 | 新标准 p10 |
|
||||
| 22 | 我的车怎么突然没声音了 | 模糊 | `FAULT_DIAGNOSIS` | 纯故障原因/诊断请求 | 新标准 p4 与 p10 |
|
||||
| 23 | 现在胎压是多少 | 模糊 | `DEVICE_OR_ENV_STATE_QUERY` | 最终模糊档覆盖调研版简单动态查询快 | 新标准 p4 与 p10,规则推导 |
|
||||
| 24 | 家里哪个房间最热 | 模糊 | `DEVICE_OR_ENV_STATE_QUERY` | 环境状态查询,无控制副作用 | 新标准 p10 |
|
||||
| 25 | 给我讲个笑话 | 模糊 | `OPEN_CHAT_OR_QA` | 闲聊/开放内容 | 新标准 p10 |
|
||||
| 26 | 做一个介绍 AI4S 的 PPT | 慢 | `MULTI_STEP_PLANNING` | 复杂产物生成与内容组织 | 新标准 p9 |
|
||||
| 27 | 音箱端:每天晚上 8 点开灯开空调 | 慢 | `AUTOMATION_SLOW_POLICY` | 音箱家庭自动化专项默认慢 | 新标准 p7 |
|
||||
| 28 | 车载端:车速超过 70 提醒我减速 | 快 | `DIRECT_ACTION` | 车载闹钟/提醒专项走快 | 新标准 p7 |
|
||||
| 29 | 前轮慢系统询问“确认开启湿滑模式吗”;当前轮“帮我开启” | 慢 | `CONTEXT_REQUIRED` | 继承慢确认链路 | 新标准 p4 |
|
||||
| 30 | 仅当前轮“帮我开启”,无任何前轮 | 慢 | `MISSING_REQUIRED_SLOT` | 无法确定开启对象;低置信并复核 | 新标准规则推导 |
|
||||
| 31 | 自动帮我设置一下(端侧未知) | 模糊 | `POLICY_UNCERTAIN` | 端侧会改变正式自动化策略;默认慢并复核 | 新标准 p7,规则推导 |
|
||||
|
||||
## 最小对照组
|
||||
|
||||
校准时至少同时检查以下紧邻对:
|
||||
|
||||
```text
|
||||
太冷了,调一下空调 -> 快
|
||||
我感觉好冷快冻死了,帮我调一下 -> 慢
|
||||
|
||||
调一个浪漫点的氛围灯 -> 快
|
||||
帮我把房间布置得浪漫一点 -> 慢
|
||||
|
||||
导航去附近评分 4.5 以上的泰国菜 -> 快
|
||||
帮我综合挑一家不踩雷、少排队、停车方便的餐厅 -> 慢
|
||||
|
||||
那个压线噔噔的声音关掉 -> 快
|
||||
打开那个灯(存在多个候选) -> 慢
|
||||
|
||||
现在几点 -> 快
|
||||
现在胎压多少 -> 模糊
|
||||
|
||||
开空调并打开座椅加热 -> 快
|
||||
查天气再决定是否开窗 -> 慢
|
||||
```
|
||||
@@ -0,0 +1,153 @@
|
||||
# 旧评测标签迁移与质量控制
|
||||
|
||||
## 目录
|
||||
|
||||
- [文档定位](#文档定位)
|
||||
- [旧八类标签](#旧八类标签)
|
||||
- [迁移到新三档](#迁移到新三档)
|
||||
- [关键口径变化](#关键口径变化)
|
||||
- [评测集构建](#评测集构建)
|
||||
- [质检门禁](#质检门禁)
|
||||
- [禁止固化的旧信息](#禁止固化的旧信息)
|
||||
|
||||
## 文档定位
|
||||
|
||||
《快慢系统分发-评测集构建》是早期策略、评测集项目计划和一次候选挖掘实验的混合文档。其项目日期早于 2026.6 新标准。
|
||||
|
||||
使用它:
|
||||
|
||||
- 解释复杂性原因。
|
||||
- 迁移旧 `FAST_DIRECT` / `SLOW_*` 数据。
|
||||
- 复用候选挖掘、人工盲标、主动学习和流量回放方法。
|
||||
|
||||
不要使用它覆盖新三档语义标准。
|
||||
|
||||
## 旧八类标签
|
||||
|
||||
| 旧标签 | 旧定义 |
|
||||
| --- | --- |
|
||||
| `FAST_DIRECT` | 当前轮可直接、安全、确定性满足 |
|
||||
| `SLOW_FILTER_RANK` | 候选筛选、排序、优化或推荐 |
|
||||
| `SLOW_DISAMBIGUATE` | 目标身份不确定,需先消歧 |
|
||||
| `SLOW_GOAL_STATE` | 给目标状态,需反推参数 |
|
||||
| `SLOW_WORKFLOW` | 多动作、多工具或显式多步骤 |
|
||||
| `SLOW_CONTEXT_DEPENDENT` | 复杂性主要来自上文或记忆 |
|
||||
| `SLOW_UNCLEAR` | 结合必要上下文仍不明确 |
|
||||
| `SLOW_ADVANCED_CAPABILITY` | 不在旧快系统白名单的高级能力 |
|
||||
|
||||
旧文档没有给多原因冲突优先级。迁移时允许先保留多个原因,再选择决定性主因。
|
||||
|
||||
## 迁移到新三档
|
||||
|
||||
不要做固定的一对一映射。先按 2026.6 语义重标,再按需要回填最接近的旧标签。
|
||||
|
||||
| 旧标签 | 新标准处理 |
|
||||
| --- | --- |
|
||||
| `FAST_DIRECT` | 通常为快;仍检查它是否属于新标准明确列出的模糊信息型 |
|
||||
| `SLOW_FILTER_RANK` | 简单单目标条件搜索可改为快;复杂权衡、推荐、外部验证仍慢 |
|
||||
| `SLOW_DISAMBIGUATE` | 非标准称呼但可唯一识别且动作明确可改为快;真实多候选仍慢 |
|
||||
| `SLOW_GOAL_STATE` | 只有目标状态、需反推动作时慢;动作和对象已明确时可能改为快 |
|
||||
| `SLOW_WORKFLOW` | 多步/跨工具仍慢;多个全部明确的设备控制动作改为快 |
|
||||
| `SLOW_CONTEXT_DEPENDENT` | 真正依赖上文推理时慢;已建立快操作流中的简单直接续接可快 |
|
||||
| `SLOW_UNCLEAR` | 执行意图需澄清时慢;若缺端侧导致政策无法确定,可标模糊并复核 |
|
||||
| `SLOW_ADVANCED_CAPABILITY` | 废除按能力白名单直接定语义;按用户预期重判,能力缺口另记 |
|
||||
|
||||
兼容输出规则:
|
||||
|
||||
- 只有新结论能被旧标签无损表达时才填写 `legacy_eval_label`。
|
||||
- `模糊`通常无法无损映射到旧二值标签,默认填 `null`。
|
||||
- 业务方明确要求旧二值路由时,可从 `default_route` 派生,但不要覆盖新 `label`。
|
||||
- 不要把 `complex_task=true` 与 `慢`画等号。
|
||||
|
||||
## 关键口径变化
|
||||
|
||||
| 维度 | 旧评测文档 | 2026.6 新标准 |
|
||||
| --- | --- | --- |
|
||||
| 核心视角 | 快系统白名单与能力边界 | 用户等待预期 |
|
||||
| 标签空间 | 1 个 FAST + 7 个 SLOW | 快 / 慢 / 模糊 |
|
||||
| 简单筛选 | 普遍视为 `SLOW_FILTER_RANK` | 目标明确、无需多步时可快 |
|
||||
| 模糊称呼 | 普遍视为 `SLOW_DISAMBIGUATE` | 可唯一识别且动作明确时可快 |
|
||||
| 多动作 | 普遍视为 `SLOW_WORKFLOW` | 全部明确设备控制是快特例 |
|
||||
| 产品知识/故障/状态 | 快慢二分 | 正式标为模糊 |
|
||||
| 能力不支持 | `SLOW_ADVANCED_CAPABILITY` | 标签不变;快能力缺口标待承接 |
|
||||
| 边界 case | 短期一律慢 | 保留模糊语义,默认路由慢 |
|
||||
| 短 query | 实验中 ≤5 字默认快 | 禁止作为语义规则 |
|
||||
|
||||
内部冲突也要处理:
|
||||
|
||||
- 新标准物理页 2 把“评分 4.5 以上的泰国菜”列入导航慢,物理页 8 又明确列为快;使用最终汇总的快。
|
||||
- 新标准垂域调研把“压线噔噔的声音关掉”归入模糊功能指代慢,物理页 9 明确改为快;使用最终汇总的快。
|
||||
- 新标准调研把静态知识、故障和部分状态查询直接分快慢,物理页 10 统一为模糊;保留模糊标签。
|
||||
|
||||
## 评测集构建
|
||||
|
||||
复用旧文档的闭环:
|
||||
|
||||
```text
|
||||
候选挖掘
|
||||
-> LLM 预打标
|
||||
-> 人工背靠背盲标
|
||||
-> 分歧仲裁与规则回灌
|
||||
-> 种子模型
|
||||
-> 主动学习
|
||||
-> 真实流量回放
|
||||
-> 覆盖分析
|
||||
```
|
||||
|
||||
候选来源:
|
||||
|
||||
1. 线上真实流量。
|
||||
2. 明确功能点 TopQuery。
|
||||
3. 现有快慢评测集。
|
||||
4. LLM 生成或改写的紧邻边界对。
|
||||
|
||||
建议数据记录至少保留:
|
||||
|
||||
- 原始 ID、query、session 和上下文。
|
||||
- 端侧、设备、来源和时间。
|
||||
- 新三档语义标签及默认路由。
|
||||
- 原因码、证据、置信度、复核状态。
|
||||
- 可选旧标签和结构维度。
|
||||
- 标注员、规则版本和仲裁结果。
|
||||
|
||||
## 质检门禁
|
||||
|
||||
### 标注一致性
|
||||
|
||||
- 使用同一份边界基准集校准 Prompt 和标注员。
|
||||
- 对高分歧样本执行两名标注员背靠背盲标。
|
||||
- 计算 IAA,并把分歧原因回灌规则和黄金样例。
|
||||
- 把人机分歧与人人分歧分开分析。
|
||||
|
||||
### 数据完整性
|
||||
|
||||
- 对同一 session 使用一致的上下文窗口。
|
||||
- 区分真实流量、旧集迁移和合成改写来源。
|
||||
- 对 session 去重,并隔离训练集和评测集。
|
||||
- 保留 `模糊`,不要在语义真值中提前二值化。
|
||||
|
||||
### 覆盖与指标
|
||||
|
||||
- 按快/慢/模糊、原因码、垂域、端侧和来源分层统计。
|
||||
- 单独统计慢误分为快的高风险错误,以及快误分为慢的延迟损失。
|
||||
- 同时报告宏平均、各类召回和混淆矩阵,不只报告总准确率。
|
||||
- 不使用旧实验分布作为目标配额。
|
||||
|
||||
### 两道门
|
||||
|
||||
1. 语义门:人工或模型是否依据当前规则得出正确结论。
|
||||
2. 结构门:记录是否通过 `scripts/validate_label.py`。
|
||||
|
||||
结构校验通过不代表语义正确。
|
||||
|
||||
## 禁止固化的旧信息
|
||||
|
||||
不要把以下内容写成新策略:
|
||||
|
||||
- “≤5 字默认快”。
|
||||
- “上轮慢则次轮必慢”的无条件继承。
|
||||
- “边界一律慢”的永久语义规则。
|
||||
- 旧快系统白名单或 `SLOW_ADVANCED_CAPABILITY`。
|
||||
- 旧实验中任一类别占比。
|
||||
- 2K/3K 种子规模、5K/1W 最终规模等互相冲突的项目目标。
|
||||
- 95%/98% 等未统一口径的验收数字。
|
||||
@@ -0,0 +1,332 @@
|
||||
# XA4.1 2026.6 快慢分流策略
|
||||
|
||||
## 目录
|
||||
|
||||
- [真源与概念](#真源与概念)
|
||||
- [三档标签](#三档标签)
|
||||
- [决策树](#决策树)
|
||||
- [快的规则](#快的规则)
|
||||
- [慢的规则](#慢的规则)
|
||||
- [模糊的规则](#模糊的规则)
|
||||
- [上下文、多指令和聚合](#上下文多指令和聚合)
|
||||
- [垂域补充](#垂域补充)
|
||||
- [原因码](#原因码)
|
||||
- [能力与默认路由](#能力与默认路由)
|
||||
|
||||
## 真源与概念
|
||||
|
||||
使用《【XA4.1】快慢分流新标准-2026.6》的最终汇总作为主真源。该文档物理页 7–10 的最终汇总高于物理页 2–7 的垂域调研草案;更早的《快慢系统分发-评测集构建》只提供旧原因分类和评测方法。
|
||||
|
||||
判断核心问题:
|
||||
|
||||
> 用户说出这句话时,心里能接受等多久?
|
||||
|
||||
不要用“当前快系统能不能做”代替这个问题。
|
||||
|
||||
保持以下概念正交:
|
||||
|
||||
- 语义标签:快、慢、模糊。
|
||||
- 默认路由:快系统或慢系统。
|
||||
- 能力承接:当前快系统是否已支持。
|
||||
- 业务标签:导航、车控、产品问答等。
|
||||
- 结构维度:complex、多指令、自动任务、上下文依赖。
|
||||
|
||||
## 三档标签
|
||||
|
||||
| 标签 | 用户预期 | 默认策略 |
|
||||
| --- | --- | --- |
|
||||
| 快 | 立即响应,通常期望 2–3 秒内得到动作或确定结果 | 快系统 |
|
||||
| 慢 | 愿意等几秒换取规划、推理或高质量结果 | 慢系统 |
|
||||
| 模糊 | 对速度和质量都有要求,或难以可靠归入快/慢 | 默认慢系统,可由明确细分策略覆盖 |
|
||||
|
||||
`模糊` 是正式语义标签,不是模型置信度。高置信产品知识问答仍可标为 `模糊`;低置信执行请求不一定因此成为 `模糊`,还要看是否需要澄清或补上下文。
|
||||
|
||||
## 决策树
|
||||
|
||||
按顺序执行:
|
||||
|
||||
```text
|
||||
1. query 是否包含要产生副作用的执行请求?
|
||||
否:
|
||||
a. 闲聊/开放问答/产品静态知识/故障诊断/
|
||||
设备或环境状态查询 -> 模糊
|
||||
b. 高频、唯一、确定性的工具或导航流查询 -> 快
|
||||
c. 需要多步分析、换算、聚合或生成复杂产物 -> 慢
|
||||
|
||||
是:
|
||||
a. 只有感受/意向,无法确定要做什么 -> 慢
|
||||
b. 只有目标状态/场景,需映射动作组合 -> 慢
|
||||
c. 真实歧义、缺关键槽位、需依赖上文才可决定 -> 慢
|
||||
d. 需规划、多步、多工具、复杂比较或跨源推理 -> 慢
|
||||
e. 动作与目标直接可识别,无需先决定“做什么” -> 快
|
||||
|
||||
2. 多个子请求:
|
||||
a. 全部是明确设备控制动作 -> 快
|
||||
b. 其他情况按 慢 > 模糊 > 快 聚合
|
||||
|
||||
3. 仍无法归类,或端侧缺失导致策略确实不同 -> 模糊,
|
||||
default_route=慢系统,review_required=true
|
||||
```
|
||||
|
||||
“快系统当前不支持”不出现在语义决策树中。
|
||||
|
||||
## 快的规则
|
||||
|
||||
命中以下一类且没有更高优先级慢条件时标 `快`:
|
||||
|
||||
### 明确直接动作
|
||||
|
||||
- 有明确操作目标。
|
||||
- 动作和设备、对象或资源可直接识别。
|
||||
- 不需要先推断用户到底想做什么。
|
||||
|
||||
例:
|
||||
|
||||
- 开空调。
|
||||
- 把温度调到 24 度。
|
||||
- 关车窗。
|
||||
- 播放周杰伦的歌。
|
||||
- 帮我定明天早上 9 点的闹钟。
|
||||
|
||||
感受词不覆盖明确目标:
|
||||
|
||||
- “太冷了,调一下空调”仍是快。
|
||||
- “调一个浪漫点的氛围灯”仍是快。
|
||||
|
||||
### 简单条件与非标准称呼
|
||||
|
||||
- 单一明确目标可以带位置、距离、评分、附近、风格等简单修饰。
|
||||
- 非标准称呼只要能唯一映射到对象,并且动作明确,仍为快。
|
||||
|
||||
例:
|
||||
|
||||
- 导航去附近评分 4.5 以上的泰国菜。
|
||||
- 导航去附近最大的停车场。
|
||||
- 那个压线噔噔的声音关掉。
|
||||
|
||||
不要把“有筛选词”或“名称不标准”直接当成慢。只有需要权衡多个方案、外部事实验证、真实澄清或多步规划时才转慢。
|
||||
|
||||
### 操作流中的直接动作
|
||||
|
||||
- 删除途经点。
|
||||
- 切换导航播报。
|
||||
- 切换路线。
|
||||
- 下一首、暂停、声音调大。
|
||||
- 高频且答案唯一的工具查询,例如“现在几点”。
|
||||
|
||||
### 多个明确设备控制
|
||||
|
||||
多个动作全部为明确设备控制时仍标快:
|
||||
|
||||
- 把空调调到 24 度,然后打开座椅加热。
|
||||
- 关客厅灯并打开空调。
|
||||
|
||||
跨工具编排、查询后再决定、先推荐再执行不适用该特例。
|
||||
|
||||
## 慢的规则
|
||||
|
||||
命中以下任一决定性条件时标 `慢`:
|
||||
|
||||
### 意向反推
|
||||
|
||||
用户只表达主观感受、身体状态、情绪、不满或潜在需求,没有给出可直接识别的操作目标,系统必须反推要做什么。
|
||||
|
||||
例:
|
||||
|
||||
- 我感觉好冷快冻死了,帮我调一下。
|
||||
- 脚底下好冷,腿快冻麻了。
|
||||
- 屏幕太亮有点刺眼,帮我弄一下。
|
||||
|
||||
对照:
|
||||
|
||||
- “太冷了,调一下空调”有明确对象和动作,标快。
|
||||
|
||||
### 场景或目标状态映射
|
||||
|
||||
用户描述结果应是什么样,而不是要执行什么动作;系统必须把场景映射为一个或多个功能。
|
||||
|
||||
例:
|
||||
|
||||
- 后排宝宝睡着了,把车里调成适合睡觉的状态。
|
||||
- 今天情人节,帮我营造点节日氛围。
|
||||
- 帮我把房间布置得舒适温馨。
|
||||
|
||||
### 规划、推理和多步编排
|
||||
|
||||
需要先决定方案,再执行;或需要多步计算、数值换算、跨源聚合、复杂比较、多工具承接。
|
||||
|
||||
例:
|
||||
|
||||
- 导航到主目的地,路上找充电站,再看看终点附近哪里好停车。
|
||||
- 找王菲在春晚与别人合唱的歌,再用网易云播放。
|
||||
- 查天气再决定要不要开窗。
|
||||
- 做一个介绍 AI4S 的 PPT。
|
||||
|
||||
### 真实消歧、补槽和上下文推理
|
||||
|
||||
- 存在多个可行对象,必须追问才能选择。
|
||||
- 缺少执行所必需且不能稳定默认的槽位。
|
||||
- 当前短句必须结合前轮才能确定对象或字段。
|
||||
- 上一轮慢系统已发起确认,当前轮为确认、取消或继续。
|
||||
|
||||
例:
|
||||
|
||||
- “打开那个灯”,且场景里存在多个灯。
|
||||
- 前轮慢系统询问是否开启湿滑模式;当前轮“帮我开启”。
|
||||
|
||||
不要把非标准称呼、口语改口或简单补充一律视为真实消歧。
|
||||
|
||||
### 复杂选择
|
||||
|
||||
单个简单筛选条件可快;需要综合主观体验、实时状态、风险、外部事实或多个相互权衡的条件时标慢。
|
||||
|
||||
例:
|
||||
|
||||
- 推荐一家安静、适合亲子、评分高、停车方便且别排太久的酒店。
|
||||
- 找一个冷门但不能踩雷、出餐快且人不多的餐厅。
|
||||
|
||||
## 模糊的规则
|
||||
|
||||
### 纯信息型
|
||||
|
||||
以下纯信息请求标 `模糊`:
|
||||
|
||||
- 闲聊、聊天和开放问答。
|
||||
- 产品功能、规格、概念、规则、使用方法等静态知识。
|
||||
- 报异常、问故障、问原因、要排查建议。
|
||||
- 设备状态或环境信息查询,无控制副作用。
|
||||
|
||||
例:
|
||||
|
||||
- 给我讲个笑话。
|
||||
- 为什么天空是蓝色的?
|
||||
- 小米 SU7 支持哪些驾驶模式?
|
||||
- 哨兵模式是什么意思?
|
||||
- 我的车怎么突然没声音了?
|
||||
- 家里哪个房间最热?
|
||||
- 空调已经开了多久?
|
||||
|
||||
### 不要扩大模糊档
|
||||
|
||||
- 现在几点、高频导航状态等唯一且期望即时的工具查询可标快。
|
||||
- 需要制作复杂产物或多步分析的信息任务标慢。
|
||||
- 执行对象不明且需要澄清时通常标慢,不要仅因“有歧义”就标模糊。
|
||||
|
||||
### 策略不完整
|
||||
|
||||
如果缺失的端侧或场景信息会导致正式规则给出不同标签,可标 `模糊`,并设置低置信和人工复核。不要把普通的模型犹豫都标成模糊。
|
||||
|
||||
## 上下文、多指令和聚合
|
||||
|
||||
### 上下文
|
||||
|
||||
- 只在输入真实提供前轮时使用。
|
||||
- 区分“继承已建立的直接操作流”和“必须推理上文才能理解”。
|
||||
- 上一轮慢系统主动追问后的确认/取消继续走慢。
|
||||
- 上一轮快时,当前简单直接动作可继续快;复杂补充转慢。
|
||||
- 缺少前轮而当前短句不可独立理解时,标慢并复核;若端侧政策本身不确定,可标模糊并复核。
|
||||
|
||||
### 多指令
|
||||
|
||||
- 全部为明确设备控制动作:快。
|
||||
- 含查询后判断、跨 App、跨工具、规划或生成:慢。
|
||||
- 可独立拆分路由时先对子请求分别标注,再保留聚合标签。
|
||||
|
||||
### 聚合
|
||||
|
||||
默认使用风险主导顺序:
|
||||
|
||||
```text
|
||||
慢 > 模糊 > 快
|
||||
```
|
||||
|
||||
只对“全部为明确设备控制动作”应用快特例。
|
||||
|
||||
## 垂域补充
|
||||
|
||||
### 导航和生活服务
|
||||
|
||||
- 单地点、目标明确、简单条件筛选:快。
|
||||
- 地图操作和高频导航问答:快。
|
||||
- 多地点、多动作路线编排、复杂综合决策、外部事实定位:慢。
|
||||
- “评分 4.5 以上的泰国菜”按最终汇总标快,覆盖调研草案中的慢标签。
|
||||
|
||||
### 车控、系统控制和 IoT
|
||||
|
||||
- 明确设备、功能和动作:快。
|
||||
- 只有感受、场景目标、复杂排除或位置集合推理:慢。
|
||||
- 非标准功能名但可唯一识别且动作明确:快。
|
||||
- 设备或环境状态查询:模糊。
|
||||
|
||||
### 内容和媒体
|
||||
|
||||
- 精确播放、明确资源、直接播控:快。
|
||||
- 描述性搜歌、歌词片段、场景推荐、歌单编排、收藏搜索、复杂内容承接:慢。
|
||||
- 纯内容知识问答按信息型处理,通常模糊。
|
||||
|
||||
### 通用工具
|
||||
|
||||
- 原子化且结果唯一的查询或控制:快。
|
||||
- 多步换算、结合外部信息再加工、缺关键槽位、开放生成:慢。
|
||||
- 不要仅因需要联网或 parser 暂不支持就标慢。
|
||||
|
||||
### 自动化
|
||||
|
||||
- 音箱端家庭自动化默认慢。
|
||||
- 音箱定时任务和意向化自动化慢。
|
||||
- 车载闹钟或提醒按文档专项策略可快。
|
||||
- 缺端侧且端侧会改变标签时,标模糊并复核。
|
||||
|
||||
## 原因码
|
||||
|
||||
每条记录选择一个决定性的 `primary_reason_code`,并在 `reason_codes` 中补充其他命中原因。
|
||||
|
||||
### 快
|
||||
|
||||
| 原因码 | 含义 |
|
||||
| --- | --- |
|
||||
| `DIRECT_ACTION` | 动作和目标直接可识别 |
|
||||
| `DIRECT_DETERMINISTIC_QUERY` | 高频、唯一、确定性的直接查询 |
|
||||
| `EXPLICIT_DEVICE_MULTI_ACTION` | 多个动作全部为明确设备控制 |
|
||||
| `DIRECT_OPERATION_FLOW` | 已建立操作流中的直接操作或播控 |
|
||||
|
||||
### 慢
|
||||
|
||||
| 原因码 | 含义 |
|
||||
| --- | --- |
|
||||
| `INTENT_INFERENCE` | 从感受或不满反推动作 |
|
||||
| `SCENE_GOAL_MAPPING` | 将场景或目标状态映射为动作组合 |
|
||||
| `MULTI_STEP_PLANNING` | 多步骤、多工具或任务编排 |
|
||||
| `COMPLEX_REASONING` | 换算、聚合、外部验证或复杂比较 |
|
||||
| `TRUE_DISAMBIGUATION` | 存在真实多候选,必须消歧 |
|
||||
| `CONTEXT_REQUIRED` | 必须依赖前轮才能决定 |
|
||||
| `MISSING_REQUIRED_SLOT` | 缺关键且不可默认的执行槽位 |
|
||||
| `AUTOMATION_SLOW_POLICY` | 命中明确的慢自动化专项策略 |
|
||||
|
||||
### 模糊
|
||||
|
||||
| 原因码 | 含义 |
|
||||
| --- | --- |
|
||||
| `OPEN_CHAT_OR_QA` | 闲聊或开放问答 |
|
||||
| `PRODUCT_KNOWLEDGE` | 产品静态知识 |
|
||||
| `FAULT_DIAGNOSIS` | 故障、异常、原因或排查建议 |
|
||||
| `DEVICE_OR_ENV_STATE_QUERY` | 无副作用的设备或环境状态查询 |
|
||||
| `POLICY_UNCERTAIN` | 缺少会改变正式策略的端侧或规则信息 |
|
||||
|
||||
## 能力与默认路由
|
||||
|
||||
固定派生:
|
||||
|
||||
| label | default_route |
|
||||
| --- | --- |
|
||||
| 快 | 快系统 |
|
||||
| 慢 | 慢系统 |
|
||||
| 模糊 | 慢系统 |
|
||||
|
||||
`fast_system_pending`:
|
||||
|
||||
- `true`:已有证据证明本应为快,但快系统尚未承接。
|
||||
- `false`:已有能力清单或验证证明已承接。
|
||||
- `null`:未评估能力;默认使用该值。
|
||||
|
||||
不得因为 `fast_system_pending=true` 修改 `label` 或 `default_route`。
|
||||
@@ -0,0 +1,293 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://local.skills/label-fast-slow-routing/label-record.schema.json",
|
||||
"title": "快慢分流打标记录",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"query",
|
||||
"label",
|
||||
"default_route",
|
||||
"primary_reason_code",
|
||||
"reason_codes",
|
||||
"reason",
|
||||
"evidence",
|
||||
"context_used",
|
||||
"fast_system_pending",
|
||||
"confidence",
|
||||
"review_required",
|
||||
"uncertainties",
|
||||
"policy_version"
|
||||
],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": ["string", "number", "null"]
|
||||
},
|
||||
"query": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"label": {
|
||||
"enum": ["快", "慢", "模糊"]
|
||||
},
|
||||
"default_route": {
|
||||
"enum": ["快系统", "慢系统"]
|
||||
},
|
||||
"primary_reason_code": {
|
||||
"$ref": "#/$defs/reasonCode"
|
||||
},
|
||||
"reason_codes": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"$ref": "#/$defs/reasonCode"
|
||||
}
|
||||
},
|
||||
"reason": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"evidence": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"counterevidence": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"domain_label": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"candidate_domain_labels": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"structural_signals": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["complex", "multi_instruction", "auto_task"],
|
||||
"properties": {
|
||||
"complex": {
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"multi_instruction": {
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"auto_task": {
|
||||
"type": ["boolean", "null"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"context_used": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"fast_system_pending": {
|
||||
"type": ["boolean", "null"]
|
||||
},
|
||||
"legacy_eval_label": {
|
||||
"enum": [
|
||||
"FAST_DIRECT",
|
||||
"SLOW_FILTER_RANK",
|
||||
"SLOW_DISAMBIGUATE",
|
||||
"SLOW_GOAL_STATE",
|
||||
"SLOW_WORKFLOW",
|
||||
"SLOW_CONTEXT_DEPENDENT",
|
||||
"SLOW_UNCLEAR",
|
||||
"SLOW_ADVANCED_CAPABILITY",
|
||||
null
|
||||
]
|
||||
},
|
||||
"confidence": {
|
||||
"enum": ["high", "medium", "low"]
|
||||
},
|
||||
"review_required": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"uncertainties": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"policy_version": {
|
||||
"const": "XA4.1-2026.6"
|
||||
}
|
||||
},
|
||||
"allOf": [
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"label": {
|
||||
"const": "快"
|
||||
}
|
||||
},
|
||||
"required": ["label"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"default_route": {
|
||||
"const": "快系统"
|
||||
},
|
||||
"primary_reason_code": {
|
||||
"enum": [
|
||||
"DIRECT_ACTION",
|
||||
"DIRECT_DETERMINISTIC_QUERY",
|
||||
"EXPLICIT_DEVICE_MULTI_ACTION",
|
||||
"DIRECT_OPERATION_FLOW"
|
||||
]
|
||||
},
|
||||
"reason_codes": {
|
||||
"items": {
|
||||
"enum": [
|
||||
"DIRECT_ACTION",
|
||||
"DIRECT_DETERMINISTIC_QUERY",
|
||||
"EXPLICIT_DEVICE_MULTI_ACTION",
|
||||
"DIRECT_OPERATION_FLOW"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"label": {
|
||||
"const": "慢"
|
||||
}
|
||||
},
|
||||
"required": ["label"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"default_route": {
|
||||
"const": "慢系统"
|
||||
},
|
||||
"fast_system_pending": {
|
||||
"enum": [false, null]
|
||||
},
|
||||
"primary_reason_code": {
|
||||
"enum": [
|
||||
"INTENT_INFERENCE",
|
||||
"SCENE_GOAL_MAPPING",
|
||||
"MULTI_STEP_PLANNING",
|
||||
"COMPLEX_REASONING",
|
||||
"TRUE_DISAMBIGUATION",
|
||||
"CONTEXT_REQUIRED",
|
||||
"MISSING_REQUIRED_SLOT",
|
||||
"AUTOMATION_SLOW_POLICY"
|
||||
]
|
||||
},
|
||||
"reason_codes": {
|
||||
"items": {
|
||||
"enum": [
|
||||
"INTENT_INFERENCE",
|
||||
"SCENE_GOAL_MAPPING",
|
||||
"MULTI_STEP_PLANNING",
|
||||
"COMPLEX_REASONING",
|
||||
"TRUE_DISAMBIGUATION",
|
||||
"CONTEXT_REQUIRED",
|
||||
"MISSING_REQUIRED_SLOT",
|
||||
"AUTOMATION_SLOW_POLICY"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"label": {
|
||||
"const": "模糊"
|
||||
}
|
||||
},
|
||||
"required": ["label"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"default_route": {
|
||||
"const": "慢系统"
|
||||
},
|
||||
"fast_system_pending": {
|
||||
"enum": [false, null]
|
||||
},
|
||||
"primary_reason_code": {
|
||||
"enum": [
|
||||
"OPEN_CHAT_OR_QA",
|
||||
"PRODUCT_KNOWLEDGE",
|
||||
"FAULT_DIAGNOSIS",
|
||||
"DEVICE_OR_ENV_STATE_QUERY",
|
||||
"POLICY_UNCERTAIN"
|
||||
]
|
||||
},
|
||||
"reason_codes": {
|
||||
"items": {
|
||||
"enum": [
|
||||
"OPEN_CHAT_OR_QA",
|
||||
"PRODUCT_KNOWLEDGE",
|
||||
"FAULT_DIAGNOSIS",
|
||||
"DEVICE_OR_ENV_STATE_QUERY",
|
||||
"POLICY_UNCERTAIN"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"confidence": {
|
||||
"const": "low"
|
||||
}
|
||||
},
|
||||
"required": ["confidence"]
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"review_required": {
|
||||
"const": true
|
||||
}
|
||||
},
|
||||
"required": ["review_required"]
|
||||
}
|
||||
}
|
||||
],
|
||||
"$defs": {
|
||||
"reasonCode": {
|
||||
"enum": [
|
||||
"DIRECT_ACTION",
|
||||
"DIRECT_DETERMINISTIC_QUERY",
|
||||
"EXPLICIT_DEVICE_MULTI_ACTION",
|
||||
"DIRECT_OPERATION_FLOW",
|
||||
"INTENT_INFERENCE",
|
||||
"SCENE_GOAL_MAPPING",
|
||||
"MULTI_STEP_PLANNING",
|
||||
"COMPLEX_REASONING",
|
||||
"TRUE_DISAMBIGUATION",
|
||||
"CONTEXT_REQUIRED",
|
||||
"MISSING_REQUIRED_SLOT",
|
||||
"AUTOMATION_SLOW_POLICY",
|
||||
"OPEN_CHAT_OR_QA",
|
||||
"PRODUCT_KNOWLEDGE",
|
||||
"FAULT_DIAGNOSIS",
|
||||
"DEVICE_OR_ENV_STATE_QUERY",
|
||||
"POLICY_UNCERTAIN"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate fast/slow/ambiguous label records without external dependencies."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
POLICY_VERSION = "XA4.1-2026.6"
|
||||
|
||||
REASON_CODES_BY_LABEL: dict[str, set[str]] = {
|
||||
"快": {
|
||||
"DIRECT_ACTION",
|
||||
"DIRECT_DETERMINISTIC_QUERY",
|
||||
"EXPLICIT_DEVICE_MULTI_ACTION",
|
||||
"DIRECT_OPERATION_FLOW",
|
||||
},
|
||||
"慢": {
|
||||
"INTENT_INFERENCE",
|
||||
"SCENE_GOAL_MAPPING",
|
||||
"MULTI_STEP_PLANNING",
|
||||
"COMPLEX_REASONING",
|
||||
"TRUE_DISAMBIGUATION",
|
||||
"CONTEXT_REQUIRED",
|
||||
"MISSING_REQUIRED_SLOT",
|
||||
"AUTOMATION_SLOW_POLICY",
|
||||
},
|
||||
"模糊": {
|
||||
"OPEN_CHAT_OR_QA",
|
||||
"PRODUCT_KNOWLEDGE",
|
||||
"FAULT_DIAGNOSIS",
|
||||
"DEVICE_OR_ENV_STATE_QUERY",
|
||||
"POLICY_UNCERTAIN",
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_ROUTE_BY_LABEL = {
|
||||
"快": "快系统",
|
||||
"慢": "慢系统",
|
||||
"模糊": "慢系统",
|
||||
}
|
||||
|
||||
LEGACY_LABELS = {
|
||||
"FAST_DIRECT",
|
||||
"SLOW_FILTER_RANK",
|
||||
"SLOW_DISAMBIGUATE",
|
||||
"SLOW_GOAL_STATE",
|
||||
"SLOW_WORKFLOW",
|
||||
"SLOW_CONTEXT_DEPENDENT",
|
||||
"SLOW_UNCLEAR",
|
||||
"SLOW_ADVANCED_CAPABILITY",
|
||||
}
|
||||
|
||||
CONFIDENCE_VALUES = {"high", "medium", "low"}
|
||||
|
||||
REQUIRED_FIELDS = {
|
||||
"query",
|
||||
"label",
|
||||
"default_route",
|
||||
"primary_reason_code",
|
||||
"reason_codes",
|
||||
"reason",
|
||||
"evidence",
|
||||
"context_used",
|
||||
"fast_system_pending",
|
||||
"confidence",
|
||||
"review_required",
|
||||
"uncertainties",
|
||||
"policy_version",
|
||||
}
|
||||
|
||||
OPTIONAL_FIELDS = {
|
||||
"id",
|
||||
"counterevidence",
|
||||
"domain_label",
|
||||
"candidate_domain_labels",
|
||||
"structural_signals",
|
||||
"legacy_eval_label",
|
||||
}
|
||||
|
||||
|
||||
def _is_nonempty_string(value: Any) -> bool:
|
||||
return isinstance(value, str) and bool(value.strip())
|
||||
|
||||
|
||||
def _check_string_list(
|
||||
value: Any,
|
||||
*,
|
||||
field: str,
|
||||
errors: list[str],
|
||||
require_nonempty: bool = False,
|
||||
unique: bool = False,
|
||||
) -> None:
|
||||
if not isinstance(value, list):
|
||||
errors.append(f"{field} 必须是数组")
|
||||
return
|
||||
if require_nonempty and not value:
|
||||
errors.append(f"{field} 至少包含一项")
|
||||
if any(not _is_nonempty_string(item) for item in value):
|
||||
errors.append(f"{field} 的每一项都必须是非空字符串")
|
||||
if unique and all(isinstance(item, str) for item in value):
|
||||
if len(value) != len(set(value)):
|
||||
errors.append(f"{field} 不允许重复项")
|
||||
|
||||
|
||||
def validate_record(record: Any, index: int) -> dict[str, Any]:
|
||||
errors: list[str] = []
|
||||
warnings: list[str] = []
|
||||
|
||||
if not isinstance(record, dict):
|
||||
return {
|
||||
"index": index,
|
||||
"valid": False,
|
||||
"errors": ["记录必须是 JSON 对象"],
|
||||
"warnings": [],
|
||||
}
|
||||
|
||||
if "__parse_error__" in record:
|
||||
return {
|
||||
"index": index,
|
||||
"valid": False,
|
||||
"errors": [str(record["__parse_error__"])],
|
||||
"warnings": [],
|
||||
}
|
||||
|
||||
missing = sorted(REQUIRED_FIELDS - set(record))
|
||||
if missing:
|
||||
errors.append(f"缺少必填字段: {', '.join(missing)}")
|
||||
|
||||
unknown = sorted(set(record) - REQUIRED_FIELDS - OPTIONAL_FIELDS)
|
||||
if unknown:
|
||||
errors.append(f"存在未知字段: {', '.join(unknown)}")
|
||||
|
||||
query = record.get("query")
|
||||
if not _is_nonempty_string(query):
|
||||
errors.append("query 必须是非空字符串")
|
||||
|
||||
label = record.get("label")
|
||||
if label not in REASON_CODES_BY_LABEL:
|
||||
errors.append("label 必须是 快、慢、模糊 之一")
|
||||
|
||||
default_route = record.get("default_route")
|
||||
expected_route = DEFAULT_ROUTE_BY_LABEL.get(label)
|
||||
if expected_route is not None and default_route != expected_route:
|
||||
errors.append(f"label={label} 时 default_route 必须是 {expected_route}")
|
||||
|
||||
primary_reason_code = record.get("primary_reason_code")
|
||||
reason_codes = record.get("reason_codes")
|
||||
allowed_reasons = REASON_CODES_BY_LABEL.get(label, set())
|
||||
if primary_reason_code not in allowed_reasons:
|
||||
errors.append(
|
||||
f"primary_reason_code={primary_reason_code!r} 与 label={label!r} 不兼容"
|
||||
)
|
||||
|
||||
if not isinstance(reason_codes, list):
|
||||
errors.append("reason_codes 必须是数组")
|
||||
else:
|
||||
if not reason_codes:
|
||||
errors.append("reason_codes 至少包含一项")
|
||||
if all(isinstance(code, str) for code in reason_codes):
|
||||
if len(reason_codes) != len(set(reason_codes)):
|
||||
errors.append("reason_codes 不允许重复")
|
||||
invalid_reason_codes = [
|
||||
code
|
||||
for code in reason_codes
|
||||
if not isinstance(code, str) or code not in allowed_reasons
|
||||
]
|
||||
if invalid_reason_codes:
|
||||
rendered_codes = ", ".join(repr(code) for code in invalid_reason_codes)
|
||||
errors.append(f"reason_codes 包含与 label 不兼容的值: {rendered_codes}")
|
||||
if primary_reason_code not in reason_codes:
|
||||
errors.append("primary_reason_code 必须同时出现在 reason_codes 中")
|
||||
|
||||
if not _is_nonempty_string(record.get("reason")):
|
||||
errors.append("reason 必须是非空字符串")
|
||||
|
||||
_check_string_list(
|
||||
record.get("evidence"),
|
||||
field="evidence",
|
||||
errors=errors,
|
||||
require_nonempty=True,
|
||||
)
|
||||
|
||||
if "counterevidence" in record:
|
||||
_check_string_list(
|
||||
record.get("counterevidence"),
|
||||
field="counterevidence",
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
if "domain_label" in record:
|
||||
domain_label = record.get("domain_label")
|
||||
if domain_label is not None and not _is_nonempty_string(domain_label):
|
||||
errors.append("domain_label 必须是非空字符串或 null")
|
||||
|
||||
if "candidate_domain_labels" in record:
|
||||
_check_string_list(
|
||||
record.get("candidate_domain_labels"),
|
||||
field="candidate_domain_labels",
|
||||
errors=errors,
|
||||
unique=True,
|
||||
)
|
||||
|
||||
structural_signals = record.get("structural_signals")
|
||||
if structural_signals is not None:
|
||||
if not isinstance(structural_signals, dict):
|
||||
errors.append("structural_signals 必须是对象")
|
||||
else:
|
||||
expected_keys = {"complex", "multi_instruction", "auto_task"}
|
||||
actual_keys = set(structural_signals)
|
||||
if actual_keys != expected_keys:
|
||||
errors.append(
|
||||
"structural_signals 必须且只能包含 "
|
||||
"complex、multi_instruction、auto_task"
|
||||
)
|
||||
for key in expected_keys:
|
||||
value = structural_signals.get(key)
|
||||
if value is not None and not isinstance(value, bool):
|
||||
errors.append(f"structural_signals.{key} 必须是布尔值或 null")
|
||||
|
||||
if not isinstance(record.get("context_used"), bool):
|
||||
errors.append("context_used 必须是布尔值")
|
||||
|
||||
fast_system_pending = record.get("fast_system_pending")
|
||||
if fast_system_pending is not None and not isinstance(fast_system_pending, bool):
|
||||
errors.append("fast_system_pending 必须是布尔值或 null")
|
||||
if fast_system_pending is True and label != "快":
|
||||
errors.append("只有 label=快 时 fast_system_pending 才能为 true")
|
||||
|
||||
legacy_eval_label = record.get("legacy_eval_label")
|
||||
if (
|
||||
"legacy_eval_label" in record
|
||||
and legacy_eval_label is not None
|
||||
and legacy_eval_label not in LEGACY_LABELS
|
||||
):
|
||||
errors.append("legacy_eval_label 不是受支持的旧八类标签")
|
||||
if label == "模糊" and legacy_eval_label is not None:
|
||||
warnings.append("模糊档通常无法无损映射到旧二值标签,请确认迁移依据")
|
||||
|
||||
confidence = record.get("confidence")
|
||||
if confidence not in CONFIDENCE_VALUES:
|
||||
errors.append("confidence 必须是 high、medium、low 之一")
|
||||
|
||||
review_required = record.get("review_required")
|
||||
if not isinstance(review_required, bool):
|
||||
errors.append("review_required 必须是布尔值")
|
||||
if confidence == "low" and review_required is not True:
|
||||
errors.append("confidence=low 时 review_required 必须为 true")
|
||||
|
||||
_check_string_list(
|
||||
record.get("uncertainties"),
|
||||
field="uncertainties",
|
||||
errors=errors,
|
||||
)
|
||||
uncertainties = record.get("uncertainties")
|
||||
if isinstance(uncertainties, list) and uncertainties and review_required is False:
|
||||
warnings.append("uncertainties 非空但 review_required=false,请确认不确定点不影响标签")
|
||||
|
||||
if record.get("policy_version") != POLICY_VERSION:
|
||||
errors.append(f"policy_version 必须是 {POLICY_VERSION}")
|
||||
|
||||
return {
|
||||
"index": index,
|
||||
"id": record.get("id"),
|
||||
"valid": not errors,
|
||||
"errors": errors,
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
|
||||
def _load_records_from_file(path: Path) -> list[Any]:
|
||||
text = path.read_text(encoding="utf-8-sig")
|
||||
if path.suffix.lower() == ".jsonl":
|
||||
records: list[Any] = []
|
||||
for line_number, line in enumerate(text.splitlines(), start=1):
|
||||
if not line.strip():
|
||||
continue
|
||||
try:
|
||||
records.append(json.loads(line))
|
||||
except json.JSONDecodeError as exc:
|
||||
records.append(
|
||||
{
|
||||
"__parse_error__": (
|
||||
f"JSONL 第 {line_number} 行解析失败: {exc.msg}"
|
||||
)
|
||||
}
|
||||
)
|
||||
return records
|
||||
|
||||
payload = json.loads(text)
|
||||
if isinstance(payload, list):
|
||||
return payload
|
||||
if isinstance(payload, dict) and isinstance(payload.get("records"), list):
|
||||
return payload["records"]
|
||||
return [payload]
|
||||
|
||||
|
||||
def _parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="校验 XA4.1-2026.6 快慢分流打标 JSON/JSONL"
|
||||
)
|
||||
source_group = parser.add_mutually_exclusive_group(required=True)
|
||||
source_group.add_argument("--record", help="单条 JSON 对象字符串")
|
||||
source_group.add_argument("--file", type=Path, help="JSON 或 JSONL 文件路径")
|
||||
parser.add_argument(
|
||||
"--strict",
|
||||
action="store_true",
|
||||
help="把 warning 也视为校验失败",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = _parse_args()
|
||||
try:
|
||||
if args.record is not None:
|
||||
records = [json.loads(args.record)]
|
||||
else:
|
||||
records = _load_records_from_file(args.file)
|
||||
except (OSError, json.JSONDecodeError) as exc:
|
||||
result = {
|
||||
"valid": False,
|
||||
"total": 0,
|
||||
"invalid": 1,
|
||||
"warning_count": 0,
|
||||
"errors": [str(exc)],
|
||||
"results": [],
|
||||
}
|
||||
print(json.dumps(result, ensure_ascii=False, indent=2))
|
||||
return 1
|
||||
|
||||
results = [validate_record(record, index) for index, record in enumerate(records)]
|
||||
invalid = sum(not result["valid"] for result in results)
|
||||
warning_count = sum(len(result["warnings"]) for result in results)
|
||||
valid = invalid == 0 and (not args.strict or warning_count == 0)
|
||||
summary = {
|
||||
"valid": valid,
|
||||
"total": len(records),
|
||||
"invalid": invalid,
|
||||
"warning_count": warning_count,
|
||||
"results": results,
|
||||
}
|
||||
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
||||
return 0 if valid else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user