# 提取策略体系升级改造总结

## [AC-MRS-07-UPGRADE] 提取策略链改造

---

## 一、改造目标

将槽位定义的提取策略从"单选（extract_strategy）"升级为"可排序策略链（extract_strategies）"，并在运行时按顺序执行，直到成功提取并通过校验。

### 核心改进
- ✅ 支持策略链配置，如 `[user_input, rule, llm]`
- ✅ 运行时按优先级顺序执行
- ✅ 统一失败分类和日志追踪
- ✅ 完全兼容旧数据

---

## 二、改造范围

### 1. 数据库层
**文件**: `scripts/migrations/009_add_extract_strategies.sql`

- 新增 `extract_strategies` JSONB 字段
- 数据迁移：将旧 `extract_strategy` 转换为数组格式
- 保留旧字段用于兼容读取

### 2. 后端实体层
**文件**: `app/models/entities.py`

- 新增 `ExtractFailureType` 枚举（4种失败类型）
- `SlotDefinition` 模型新增 `extract_strategies` 字段
- 添加 `get_effective_strategies()` 方法（兼容读取）
- 添加 `validate_strategies()` 方法（校验策略链）
- 更新 `SlotDefinitionCreate` 和 `SlotDefinitionUpdate` Schema

### 3. 后端服务层
**文件**: `app/services/slot_definition_service.py`

- 新增 `_validate_strategies()` 方法
- 新增 `_normalize_strategies()` 方法
- 创建/更新时支持策略链校验和处理
- 同时保存新旧字段

**文件**: `app/services/mid/slot_strategy_executor.py` (新增)

- `SlotStrategyExecutor` 策略链执行器
- `StrategyChainResult` 执行结果
- `StrategyStepResult` 单步结果
- `ExtractContext` 提取上下文
- 支持 4 种失败类型分类
- 详细的执行日志追踪

### 4. 后端 API 层
**文件**: `app/api/admin/slot_definition.py`

- 更新 `_slot_to_dict()` 返回策略链字段

**文件**: `app/schemas/metadata.py`

- 更新 `SlotDefinitionResponse` 响应模型
- 更新 `SlotDefinitionCreateRequest` 请求模型
- 更新 `SlotDefinitionUpdateRequest` 请求模型

**文件**: `app/services/mid/role_based_field_provider.py`

- 更新 `get_slot_definitions_by_role()` 返回策略链字段

### 5. 前端类型层
**文件**: `ai-service-admin/src/types/slot-definition.ts`

- 新增 `ExtractFailureType` 类型
- 更新 `SlotDefinition` 接口
- 更新 `SlotDefinitionCreateRequest` 接口
- 更新 `SlotDefinitionUpdateRequest` 接口
- 新增 `StrategyStepResult` 接口
- 新增 `StrategyChainResult` 接口
- 新增 `validateExtractStrategies()` 函数
- 新增 `getEffectiveStrategies()` 函数

### 6. 前端页面层
**文件**: `ai-service-admin/src/views/admin/slot-definition/index.vue`

- 表格列改为显示策略链（带序号）
- 新增策略链编辑器组件
  - 拖拽排序（vuedraggable）
  - 添加/删除策略
  - 策略去重校验
- 表单提交时校验策略链

---

## 三、执行语义

### 策略链执行流程
```
1. 按数组顺序执行策略
2. 某一步成功提取且校验通过 -> 停止并返回结果
3. 当前策略失败 -> 记录失败原因，继续下一策略
4. 全部失败 -> 返回结构化失败结果，并使用 ask_back_prompt
```

### 失败分类（统一）
| 失败类型 | 说明 |
|---------|------|
| `EXTRACT_EMPTY` | 提取结果为空 |
| `EXTRACT_PARSE_FAIL` | 解析失败 |
| `EXTRACT_VALIDATION_FAIL` | 校验失败 |
| `EXTRACT_RUNTIME_ERROR` | 运行时错误 |

### 日志追踪
每步执行都有可追踪日志：
```
[SlotStrategyExecutor] Starting strategy chain for slot 'grade': strategies=['rule', 'llm'], tenant=xxx
[SlotStrategyExecutor] Executing step 1/2: slot_key=grade, strategy=rule
[SlotStrategyExecutor] Step 1 failed: slot_key=grade, strategy=rule, failure_type=EXTRACT_EMPTY, reason=...
[SlotStrategyExecutor] Strategy chain succeeded at step 2: slot_key=grade, strategy=llm, total_time_ms=123.45
```

---

## 四、数据兼容性

### 读取兼容
```python
# 优先使用 extract_strategies，如果不存在则兼容读取 extract_strategy
def get_effective_strategies(self) -> list[str]:
    if self.extract_strategies and len(self.extract_strategies) > 0:
        return self.extract_strategies
    if self.extract_strategy:
        return [self.extract_strategy]
    return []
```

### 写入策略
- 新数据：同时写入 `extract_strategies` 和 `extract_strategy`
- 旧数据：通过 migration 自动转换

---

## 五、测试覆盖

### 新增测试文件
**文件**: `tests/test_slot_strategy_executor.py`

- ✅ 第一步成功时停止
- ✅ 第一步失败，第二步成功
- ✅ 所有策略都失败
- ✅ 校验失败的情况
- ✅ 运行时错误处理
- ✅ 空策略链处理
- ✅ 未知策略处理
- ✅ 结果转换为字典
- ✅ 便捷函数测试
- ✅ 上下文创建测试

### 现有测试
- ✅ `tests/test_slot_definition_service.py` - 16个测试全部通过
- ✅ `tests/test_role_based_field_provider.py` - 11个测试全部通过

**总计**: 38个测试全部通过 ✅

---

## 六、前端界面预览

### 列表页
- 提取策略链列显示带序号的策略标签
- 如：`1. 规则提取` `2. LLM推断`

### 编辑页
- 策略链编辑器支持：
  - 拖拽调整顺序
  - 添加策略（下拉选择，自动去重）
  - 删除策略
  - 清空策略链
- 实时校验策略链有效性

---

## 七、使用示例

### 创建带策略链的槽位定义
```python
from app.models.entities import SlotDefinitionCreate

slot_create = SlotDefinitionCreate(
    slot_key="grade",
    type="string",
    required=True,
    extract_strategies=["rule", "llm", "user_input"],  # 策略链
    ask_back_prompt="请告诉我您的年级",
)
```

### 执行策略链提取
```python
from app.services.mid.slot_strategy_executor import execute_extract_strategies

result = await execute_extract_strategies(
    strategies=["rule", "llm", "user_input"],
    tenant_id="tenant-123",
    slot_key="grade",
    user_input="我想了解初一语文课程",
    validation_rule=r"^初[一二三]$",
)

if result.success:
    print(f"提取成功: {result.final_value} (使用策略: {result.final_strategy})")
else:
    print(f"提取失败，需要追问: {result.ask_back_prompt}")
    for step in result.steps:
        print(f"  {step.strategy}: {step.failure_type} - {step.failure_reason}")
```

---

## 八、迁移步骤

1. **执行数据库迁移**
   ```bash
   psql -d your_database -f scripts/migrations/009_add_extract_strategies.sql
   ```

2. **重启后端服务**
   - 自动加载新模型和API

3. **刷新前端页面**
   - 自动显示策略链编辑器

---

## 九、文件变更清单

### 新增文件
- `scripts/migrations/009_add_extract_strategies.sql`
- `app/services/mid/slot_strategy_executor.py`
- `tests/test_slot_strategy_executor.py`
- `docs/extract-strategy-upgrade-summary.md`

### 修改文件
- `app/models/entities.py`
- `app/schemas/metadata.py`
- `app/services/slot_definition_service.py`
- `app/api/admin/slot_definition.py`
- `app/services/mid/role_based_field_provider.py`
- `ai-service-admin/src/types/slot-definition.ts`
- `ai-service-admin/src/views/admin/slot-definition/index.vue`

---

## 十、验证清单

- [x] 数据库迁移脚本可执行
- [x] 后端实体模型支持策略链
- [x] 后端API支持策略链CRUD
- [x] 运行时策略链执行器工作正常
- [x] 失败分类和日志追踪完整
- [x] 旧数据兼容读取
- [x] 前端界面支持策略链排序配置
- [x] 前端构建成功
- [x] 所有测试通过（38个）

---

**改造完成时间**: 2026-03-06
**改造状态**: ✅ 全部完成
