# 免唤醒判决日志

> "免唤醒"指车机上不需要每次说"小爱同学"的免唤醒指令模式（如开/关空调、调温度）。每次请求都会经过免唤醒判决——是否让这条 query 直接执行而不是走闲聊/拒识。

## 三个视角，两张表

| # | 业务视角 | 日志位置 | 命令 |
| - | ------- | ------- | ---- |
| 1 | **拒识模块视角**：每次请求拒识模块整体输出（含所有子策略，含调用免唤醒的结果） | `aiservice_duplex_rejection_lcs_log*` 整条 `rejectInfo` | `--preset reject` |
| 2 | **拒识里的免唤醒子字段**：拒识调免唤醒那一次的入参出参 | 同表，`rejectInfo.strategy_info.reject.KEY_WORD_FREE_RESTRIC` | `--preset reject --json-path rejectInfo.strategy_info.reject.KEY_WORD_FREE_RESTRIC` |
| 3 | **免唤醒模块视角**：免唤醒模块**被后处理调到时**自己写的日志（独立的另一张表） | `nlp_post_processing_lcs-*` 中 `moduleName=keyword-free-log` | `--preset kwfree` |

1 和 2 同表同条记录，2 只是取子字段；3 是完全独立的另一张表。

## 关键字段

### 视角 2：拒识里的免唤醒子字段

路径前缀 `rejectInfo.strategy_info.reject.KEY_WORD_FREE_RESTRIC`：
- `process` — 是否走到免唤醒判决（true / false）
- `skipped_reason` — 被跳过原因（如 `post_processing_takeover` 表示让后处理接管，进入视角 3）
- `keywordFreeType`
- `isCodeMatch`
- `getProcessedQuery`
- `Function List`

### 视角 3：后处理免唤醒模块自身

JSON 字段 `message` 顶层：
- `process` — 是否实际走到处理
- `skipReason` — 未处理原因（如 `rejectedByOtherStrategy` 已被其他策略先拒）
- `route.flow` / `route.enableFullMigration` / `route.clawEnabled`
- `request.query`
- `request.keywordFreeType`（如 `INSTRUCTION_KEY_WORD_FREE`）
- `request.zone`（如 `DRIVER`）
- `request.appId` / `maskUid` / `maskDeviceId`
- `fallback.oldRejectType` / `fallback.oldDomain`

## 排查 Playbook

**问题：免唤醒为什么没生效？**

1. 先查视角 2，看拒识有没有调到免唤醒：
   ```bash
   python elk_query.py <rid> --preset reject \
     --json-path rejectInfo.strategy_info.reject.KEY_WORD_FREE_RESTRIC
   ```
   - `process=true` → 走到免唤醒判决了，看 `keywordFreeType` 等子字段
   - `process=false` → 没走到，看 `skipped_reason`：
     - `post_processing_takeover` → 进视角 3 看后处理免唤醒
     - 其他原因 → 拒识自己挡了

2. 视角 3——后处理免唤醒模块自身：
   ```bash
   python elk_query.py <rid> --preset kwfree --json-path message
   ```
   - `process=false` 时看 `skipReason`（`rejectedByOtherStrategy` 表示已被先拒）

## 字段 schema

完整 schema 见 [`../INDEX_CATALOG.md`](../INDEX_CATALOG.md) 中 `aiservice_duplex_rejection_lcs_log*` 和 `nlp_post_processing_lcs-*` 两节。
