# AI 工作台统一意图识别框架设计

## 背景

AI 工作台当前的输入识别分散在多个前端 flow 中：申请预览、报销草稿、单据查询、草稿删除提示各自判断输入。这样的结构能快速修复单点问题，但会让“删除 3 天前的草稿”“审核合规没有风险的申请”这类组合型请求继续变成关键词补丁。

本设计把自然语言输入先统一解析成结构化 `IntentFrame`，再根据目标是否明确、安全等级和业务边界决定下一步动作。

## 目标

- 让工作台所有自然语言输入先进入统一意图框架，不再在各业务 flow 中散落判断。
- 支持动作、对象、筛选条件、上下文指代、安全等级的组合识别。
- 对删除、审核、驳回等高风险动作固定走“筛选候选 + 详情确认”，禁止自然语言直接执行。
- 保留当前会话内的快速指代能力，例如“删除刚才那个草稿”能定位最近创建的草稿。
- 对带筛选条件的请求，例如“删除 3 天前的草稿”“审核无风险申请”，先展示思考过程和候选列表。

## 非目标

- 第一版不引入 LangGraph，也不把前端本地识别迁到后端状态机。
- 第一版不做自然语言直接批量删除、批量审核或批量驳回。
- 第一版不改后端审批、删除接口的权限模型。
- 第一版不重写现有申请预览和报销草稿流程，只把入口识别前置统一。

## 总体架构

统一意图识别分三层：

1. `IntentFrame Parser`：把用户输入解析为结构化意图。
2. `Target Resolver`：结合当前会话、最近动作和筛选条件，判断目标是否唯一。
3. `Action Policy`：根据动作风险决定直接查询、展示候选、要求澄清或阻断。

输入链路应调整为：

```text
用户输入
  -> IntentFrame Parser
  -> Action Policy
  -> Target Resolver
  -> 业务 flow
       - 查询候选
       - 打开详情确认
       - 进入申请/报销流程
       - 要求补充条件
```

## IntentFrame 数据结构

```js
{
  action: 'query' | 'delete' | 'approve' | 'reject' | 'create' | 'update' | 'ask_policy',
  objectType: 'draft' | 'application' | 'reimbursement' | 'approval_task' | 'receipt' | 'document',
  filters: {
    timeRange: null,
    status: null,
    risk: null,
    documentType: null,
    amount: null,
    keyword: null
  },
  targetMode: 'current_context' | 'filtered_candidates' | 'ambiguous',
  safetyLevel: 'read_only' | 'confirm_required' | 'blocked',
  confidence: 0,
  normalizedQuery: ''
}
```

### 字段含义

- `action` 表示用户想做什么，例如查、删、审核、驳回、创建或咨询规则。
- `objectType` 表示动作对象，例如草稿、申请单、报销单、待审任务或票据。
- `filters` 表示筛选条件，必须可以复用到单据查询 flow。
- `targetMode` 表示目标定位方式：
  - `current_context`：明确指向当前会话最近对象。
  - `filtered_candidates`：需要查询候选列表。
  - `ambiguous`：条件不足，需要澄清。
- `safetyLevel` 表示动作安全级别：
  - `read_only`：可直接查询或解释。
  - `confirm_required`：只展示候选或详情入口，不直接执行。
  - `blocked`：存在批量破坏性风险或越权风险，必须阻断。
- `normalizedQuery` 是给现有查询 flow 使用的可读查询句，例如“我的 3 天前草稿单据”。

## 识别策略

### 动作识别

- 查询：查、看、列出、有哪些、找一下。
- 删除：删除、删掉、移除、作废、撤销。
- 审核：审核、审批、处理待办、去审批。
- 驳回：驳回、退回、拒绝。
- 创建：新建、发起、申请、我要报销。
- 更新：补充、修改、改成、填入。
- 规则咨询：怎么走、能不能、规则、制度、政策、标准。

### 对象识别

- 草稿：草稿、未提交、刚才保存的单据。
- 申请单：申请、申请单、出差申请、费用申请。
- 报销单：报销、报销单、费用报销。
- 待审任务：待办、待我审核、待审批、审核单。
- 票据：发票、票据、附件、图片。

### 筛选条件识别

- 时间：今天、昨天、3 天前、近 7 天、上周、本月、具体日期、日期范围。
- 状态：草稿、审批中、已通过、已驳回、待补充。
- 风险：无风险、低风险、中风险、高风险、合规、异常、超标。
- 金额：超过 1000、500 以下、100 到 300。
- 关键词：地点、事由、人员、部门、单号等自由文本。

## 目标解析规则

### 当前上下文直达

当用户使用“刚才那个”“当前”“这个”“上面那个”这类指代，并且当前会话中能找到最近的可操作对象时，`targetMode` 为 `current_context`。

例子：

- “删除刚才那个草稿”
- “打开这个申请单”
- “继续刚才的报销草稿”

即便目标唯一，删除、审核、驳回仍然只打开详情页或确认入口。

### 筛选候选

当用户输入包含时间、风险、金额、状态、类型等筛选条件时，`targetMode` 必须为 `filtered_candidates`。

例子：

- “删除 3 天前的草稿”
- “审核合规没有风险的申请”
- “找一下上海相关的低风险待审申请”

这类请求必须进入单据查询 flow，展示候选结果，不能直接套最近草稿。

### 条件不足澄清

当动作高风险但目标既不唯一，也没有足够筛选条件时，`targetMode` 为 `ambiguous`。

例子：

- “把草稿删了”
- “帮我审核一下”
- “退回这个单”

系统应提示用户选择候选或补充条件。

## Action Policy

| 动作 | 安全等级 | 第一版行为 |
| --- | --- | --- |
| 查询 | `read_only` | 直接查询并展示结果 |
| 规则咨询 | `read_only` | 走政策/规则解释，不进入单据查询 |
| 删除 | `confirm_required` | 展示候选或打开详情页确认，不直接删除 |
| 审核通过 | `confirm_required` | 展示待审候选或打开审核详情，不直接通过 |
| 驳回/退回 | `confirm_required` | 展示待审候选或打开审核详情，不直接驳回 |
| 批量删除/批量审核 | `blocked` | 阻断并要求用户选择具体单据 |

## 用户可见思考过程

筛选型命令必须复用现有查询 thinking events，并补充动作意图说明：

1. 解析自然语言动作和筛选条件。
2. 判断操作风险和目标定位方式。
3. 查询业务单据接口。
4. 按条件组合筛选候选。
5. 展示候选卡片和下一步入口。

示例：

```text
解析：识别到“删除”是高风险动作，对象是“草稿”，时间条件是“3 天前”。
策略：不会直接删除，将先查询我的草稿候选。
结果：命中 2 张草稿，请打开详情页确认删除目标。
```

## 文件边界

- 新增 `workbenchIntentFrameModel.js`：负责解析用户输入到 `IntentFrame`。
- 新增 `workbenchIntentActionPolicy.js`：负责动作安全策略和下一步路由判断。
- 调整 `workbenchAiCommandIntentModel.js`：保留会话内最近草稿解析，但不再单独拥有顶层意图判断。
- 调整 `useWorkbenchAiCommandIntents.js`：基于 `IntentFrame` 分发到当前上下文直达或候选查询。
- 调整 `aiDocumentQueryIntent.js` 和 `aiDocumentQueryModel.js`：补充风险筛选、相对日期和筛选摘要。
- 补充前端测试，覆盖组合型输入和安全边界。

## 迁移步骤

1. 先为 `IntentFrame` 解析补测试：
   - “删除刚才那个草稿”解析为 `delete + draft + current_context + confirm_required`。
   - “删除 3 天前的草稿”解析为 `delete + draft + filtered_candidates + confirm_required`。
   - “审核合规没有风险的申请”解析为 `approve + application + risk:none + filtered_candidates + confirm_required`。
   - “审批规则怎么走”解析为 `ask_policy`，不进入单据查询。
2. 实现 `workbenchIntentFrameModel.js`，不接入 UI。
3. 实现风险和相对日期筛选能力，让查询 flow 能承接筛选型命令。
4. 接入 `useWorkbenchAiCommandIntents.js`：
   - 当前上下文直达：生成详情确认入口。
   - 筛选候选：调用 `handleAiDocumentQueryIntent(normalizedQuery, pendingMessage)`。
   - 条件不足：提示补充条件或查询可选候选。
5. 移除或降级旧的散落正则，让顶层输入先走统一框架。
6. 跑定向测试、相邻测试、前端构建和 5173 工作台烟测。

## 验收标准

- 输入“删除刚才那个草稿”时，系统定位当前会话最近草稿，并只打开详情确认入口。
- 输入“删除 3 天前的草稿”时，系统展示筛选思考过程和草稿候选，不使用最近草稿快捷路径。
- 输入“审核合规没有风险的申请”时，系统查询待我审核申请，并筛选无风险候选。
- 输入“审批规则怎么走”时，不进入单据查询。
- 删除、审核、驳回均不通过自然语言直接执行最终动作。
- 新增/调整测试全部通过，前端构建通过，`git diff --check` 无空白错误。

## 后续演进

- 当后端 steward planner 能稳定输出同等 `IntentFrame` 时，可以把 Parser 层迁到后端，前端只保留策略兜底。
- 如果需要跨会话目标记忆，可把最近创建/保存草稿写入会话快照，并附带过期时间和用户确认边界。
- 如果未来引入 LangGraph，应把它用于多步状态编排，而不是替代 `IntentFrame` schema 本身。
