# PRD：智能定位准确率提升 - 聚焦核心快速见效

> **文档版本**: v1.0
> **创建日期**: 2026-08-06
> **作者**: Claude
> **状态**: 待评审

---

## 一、项目背景

### 1.1 现状问题

当前智能定位功能（`/api/element/smart-locate`）定位准确率约 **60%**，无法满足实际测试需求。主要表现为：

1. **关键词提取缺陷**：暴力替换导致语义丢失，2-gram产生噪声，单字关键词无区分度
2. **评分体系问题**：累加膨胀无归一化，包含匹配优先级过高，精确匹配被淹没
3. **选择器生成缺陷**：只生成单一维度选择器，缺乏组合选择器，区分度不足
4. **Claude增强局限**：只在多候选时触发，Prompt上下文不足，候选信息丢失
5. **微前端支持不完善**：iframe元素选择器在主页面无效，无法穿透操作
6. **Playwright语义定位器未使用**：完全依赖CSS选择器，未利用Playwright原生的getByRole/getByText等稳定定位器

### 1.2 典型失败场景

| 场景 | 失败原因 | 涉及模块 |
|------|----------|----------|
| "点击新增"在列表页 | "新增"匹配到多个元素，评分无法区分 | keyword_matcher |
| "点击展开"/"点击系统设置" | 修饰词被移除导致关键词为空 | keyword_matcher |
| "输入会议名称：xxx" | extract_value正则不支持中文值 | keyword_matcher |
| iframe内的按钮 | selector在主页面上下文无效 | keyword_matcher + smart_locate_service |
| 对话框内的"确定"按钮 | 多个"确定"按钮无上下文区分 | keyword_matcher + claude_service |
| 表格中的操作按钮 | 每行都有"编辑"/"删除"，text匹配返回多个 | keyword_matcher |
| Claude单候选直接使用 | 第一个候选未必正确，无Claude验证 | smart_locate_service |

### 1.3 技术调研结论

经过对行业方案（Testim/Mabl/Healenium/Playwright官方推荐）的调研，确定以下改进策略：

| 改进方向 | 预期效果 | 优先级 |
|---------|---------|--------|
| Playwright语义定位器 | 选择器稳定性+30-50% | P0 |
| 关键词提取优化（jieba分词） | 准确率+10-15% | P0 |
| 评分归一化 | 准确率+5% | P0 |
| 组合选择器生成 | 区分度提升 | P1 |
| Claude Prompt优化 | 单候选验证+上下文增强 | P1 |
| iframe选择器穿透 | 微前端支持完善 | P1 |

---

## 二、需求目标

### 2.1 总体目标

将智能定位准确率从 **~60%** 提升至 **≥80%**，重点解决关键词提取、评分体系、选择器生成、Claude增强四大核心问题。

### 2.2 量化指标

| 指标 | 当前值 | 目标值 |
|------|--------|--------|
| 简单页面访问验证用例定位准确率 | ~75% | ≥95% |
| 二级菜单导航定位准确率 | ~70% | ≥90% |
| 表单填写定位准确率 | ~40% | ≥75% |
| 微前端内元素定位准确率 | ~30% | ≥65% |
| 智能定位API平均耗时 | ~45s/用例 | ≤30s/用例 |
| Claude调用成功率 | ~80% | ≥95% |

### 2.3 不包含的范围

- **自愈合机制**：选择器失效自动修复，属于中期目标，本次不实施
- **DOM指纹**：需额外数据库表，本次不实施
- **视觉定位（CV/OCR）**：长期目标，本次不实施
- **本地LLM部署**：基础设施投入大，本次不实施

---

## 三、功能需求

### 3.1 需求1：关键词提取优化

**模块**: `backend/app/services/keyword_matcher.py`

#### 3.1.1 引入jieba分词替代暴力替换

**当前问题**：
- `str.replace(word, "")` 不考虑词边界，"点击信息发布"中"信息"被移除后变成"发布"
- 2-gram产生跨中英文边界的无意义关键词（如"名a"、"ad"）
- 单字关键词（"用"、"户"、"名"）无区分度

**改进方案**：
1. 引入jieba分词库，按词边界精确分词
2. 分词后按词性过滤：保留名词(n/nr/ns/nz)、动词(vn)，去除代词/副词/介词
3. 保留【】内完整词组作为高优先级关键词
4. 去除2-gram和单字关键词生成逻辑

**示例**：
```
输入: "点击【新建会议】按钮"
当前: keywords=["新建", "会议"]  (暴力替换后丢失关联)
改进: keywords=["新建会议"]     (【】内完整保留，高优先级)

输入: "输入会议名称：自动化新建会议"
当前: keywords=["会议", "名称", "自动", "动化", "化新", "新建", "建会", "会议"]  (2-gram噪声)
改进: keywords=["会议名称", "自动化", "新建会议"]  (jieba分词，有意义的名词)

输入: "点击展开"
当前: keywords=[]  (修饰词"展开"被移除，关键词为空)
改进: keywords=["展开"]  (jieba识别为动词，保留)
```

#### 3.1.2 修饰词列表精简

**当前问题**：
- `modifier_words` 包含 '展开'、'分类'、'操作'、'系统' 等在特定场景下是按钮/菜单名称的词
- 过于激进的移除导致关键词为空

**改进方案**：
1. 修饰词仅保留真正的无意义修饰词：'的', '了', '着', '过', '一下', '是否', '正确', '是否成功'
2. 移除可能是元素名称的词：'展开'、'分类'、'操作'、'系统'、'页面'、'数据'、'成功'
3. 这些词由jieba分词后根据词性自动决定是否保留

#### 3.1.3 extract_value正则增强

**当前问题**：
- `[\w@.\-]+` 不支持中文值（如"输入备注：这是一个测试备注"）

**改进方案**：
```python
# 旧正则
r'(?:输入|填写|填入|键入|写入)\s*[^：:]*[：:]\s*([\w@.\-]+)\s*$'

# 新正则 - 支持中文值、空格、特殊字符
r'(?:输入|填写|填入|键入|写入)\s*[^：:]*[：:]\s*(.+?)\s*$'
```

---

### 3.2 需求2：评分体系归一化

**模块**: `backend/app/services/keyword_matcher.py`

#### 3.2.1 评分归一化到[0,1]区间

**当前问题**：
- score是累加的，无上限，多维度弱匹配可能超过单维度强匹配
- 例如：ID弱匹配0.4 + placeholder弱匹配0.3 = 0.7 > text精确匹配0.5

**改进方案**：
1. 改为加权评分，每个维度的贡献有上限
2. 精确匹配（完全相等）加分远高于包含匹配（子串包含）
3. 最终score归一化到[0,1]

**新评分规则**：

| 匹配维度 | 精确匹配 | 包含匹配 | 权重 |
|---------|---------|---------|------|
| data-testid | 1.0 | 0.3 | 0.20 |
| ID | 0.9 | 0.3 | 0.18 |
| name | 0.85 | 0.25 | 0.15 |
| placeholder | 0.8 | 0.25 | 0.15 |
| aria-label | 0.8 | 0.25 | 0.12 |
| text内容 | 0.9 | 0.3 | 0.15 |
| 动作类型适配 | 0.3 | - | 0.05 |

**归一化公式**：
```python
final_score = sum(dimension_score * weight) / sum(matched_weights)
```

#### 3.2.2 精确匹配 vs 包含匹配

**当前问题**：
- 所有匹配都用 `if kw.lower() in text.lower()`，无法区分"新增"匹配到"新增"（精确）和"新增会议"（包含）

**改进方案**：
```python
def match_score(keyword, target_text):
    if keyword == target_text:
        return EXACT_MATCH_SCORE  # 精确匹配 1.0
    elif keyword in target_text:
        return CONTAINS_MATCH_SCORE  # 包含匹配 0.3
    else:
        return 0  # 不匹配
```

#### 3.2.3 动作类型适配优化

**当前问题**：
- click对INPUT的减分 `score *= 0.3` 力度不够
- fill默认返回第一个输入框，无法区分

**改进方案**：
1. click动作：INPUT减分 `score *= 0.1`（更激进），BUTTON/DIV/A/LI加分0.2
2. fill动作：结合placeholder/label与关键词的语义距离，选择最相关的输入框
3. check动作：优先匹配checkbox组件（`.el-checkbox`, `input[type="checkbox"]`）

---

### 3.3 需求3：Playwright语义定位器支持

**模块**: `backend/app/executors/playwright_executor.py`, `backend/app/services/selector_extractor.py`

#### 3.3.1 新增语义定位器格式

**当前问题**：
- 所有选择器都是CSS或XPath格式
- 未利用Playwright原生的getByRole/getByText等语义定位器

**改进方案**：
- 在选择器中支持新的格式前缀：

| 格式 | 示例 | Playwright API |
|------|------|---------------|
| `role:` | `role:button[name="登录"]` | `page.get_by_role("button", name="登录")` |
| `text:` | `text:新建会议` | `page.get_by_text("新建会议")` |
| `placeholder:` | `placeholder:请输入会议名称` | `page.get_by_placeholder("请输入会议名称")` |
| `label:` | `label:用户名` | `page.get_by_label("用户名")` |
| `testid:` | `testid:submit-btn` | `page.get_by_test_id("submit-btn")` |

#### 3.3.2 执行器支持语义定位器

**改进方案**：
- 在 `playwright_executor.py` 的 `_resolve_selectors` 中识别语义定位器格式
- 在 `_do_click`、`_do_fill`、`_do_wait` 等方法中根据格式选择对应的Playwright API
- 语义定位器优先级高于CSS选择器

#### 3.3.3 智能定位输出语义选择器

**改进方案**：
- `selector_extractor.py` 优先提取语义选择器（role/text/placeholder/label/testid）
- `keyword_matcher.py` 的匹配结果中包含语义选择器候选

---

### 3.4 需求4：组合选择器生成

**模块**: `backend/app/services/selector_extractor.py`

#### 3.4.1 生成组合选择器提高区分度

**当前问题**：
- 只生成单一维度选择器（如 `button:has-text("确定")`）
- 页面上多个"确定"按钮时无法区分

**改进方案**：
- 当单一选择器区分度不足时，自动生成组合选择器：

| 策略 | 示例 | 场景 |
|------|------|------|
| 父容器+按钮 | `.el-dialog button:has-text("确定")` | 弹窗内的确定按钮 |
| 表单+输入框 | `form:has-text("会议") input[placeholder*="名称"]` | 表单内的输入框 |
| 区域+元素 | `.meeting-card:has-text("北京") .edit-btn` | 特定卡片内的编辑按钮 |
| Tab+内容 | `.el-tabs [aria-selected="true"] .content` | 当前Tab下的内容 |

#### 3.4.2 选择器优先级体系统一

**当前问题**：
- `selector_extractor.py` 和 `keyword_matcher.py` 的优先级定义不一致

**改进方案**：
- 统一优先级定义到 `selector_extractor.py` 的 `SELECTOR_PRIORITY`

| 优先级 | 选择器类型 | 稳定性 |
|--------|-----------|--------|
| 1 | 语义定位器（role/text/placeholder） | ⭐⭐⭐⭐⭐ |
| 2 | data-testid | ⭐⭐⭐⭐⭐ |
| 3 | 组合选择器 | ⭐⭐⭐⭐ |
| 4 | ID | ⭐⭐⭐⭐ |
| 5 | name/placeholder | ⭐⭐⭐ |
| 6 | aria-label | ⭐⭐⭐ |
| 7 | 文本选择器 | ⭐⭐⭐ |
| 8 | class | ⭐⭐ |
| 9 | XPath | ⭐ |

---

### 3.5 需求5：Claude语义增强优化

**模块**: `backend/app/services/claude_service.py`, `backend/app/services/smart_locate_service.py`

#### 3.5.1 单候选也调用Claude验证

**当前问题**：
- 只有多个候选时才调用Claude，单候选直接使用
- 第一个候选未必正确（如"登录"匹配到装饰性DIV而非登录BUTTON）

**改进方案**：
- 所有候选（包括单候选）都经过Claude验证
- Claude判断当前候选是否匹配步骤描述
- Claude返回 `confirmed: true/false` + `reason`
- 如果confirmed=false，尝试下一个候选

#### 3.5.2 Prompt上下文增强

**当前问题**：
- Prompt只有3条选择规则，缺乏页面上下文
- 候选信息过度简化，丢失class/position/placeholder等关键信息

**改进方案**：
- 增强Prompt内容：
  1. 页面当前URL/路由信息
  2. 前后步骤描述（步骤上下文）
  3. 候选元素的完整信息（tag/class/position/placeholder/aria-label/父容器信息）
  4. 候选元素的可见性和交互状态
- 增加选择规则：
  1. 优先选择可见且可交互的元素
  2. 优先选择在当前活动区域（弹窗/抽屉/Tab）内的元素
  3. 如果步骤描述包含特定区域关键词（如"弹窗"、"对话框"），优先在对应区域查找

#### 3.5.3 Claude索引对齐修复

**当前问题**：
- Claude的selected_idx可能与selectors列表索引不一致

**改进方案**：
- `get_candidate_details` 和 `match_element_by_keywords` 共享同一个元素列表
- 统一索引，不跳过任何元素
- 如果元素信息提取失败，在两个列表中都标记为invalid而非跳过

---

### 3.6 需求6：iframe/微前端选择器穿透

**模块**: `backend/app/services/keyword_matcher.py`, `backend/app/services/selector_extractor.py`, `backend/app/executors/playwright_executor.py`

#### 3.6.1 生成包含frame路径的选择器

**当前问题**：
- iframe内元素的选择器（如`button:has-text("xxx")`）在主页面上下文无效
- 执行时`page.click(selector)`无法操作iframe内元素

**改进方案**：
- 选择器格式增加frame路径：`iframe[src="xxx"] >> button:has-text("xxx")`
- `selector_extractor.py` 生成选择器时记录frame信息
- `keyword_matcher.py` 匹配iframe元素时，在候选结果中标记frame_path

#### 3.6.2 执行器frame穿透优化

**当前问题**：
- `_find_element_in_frames` 每次操作都遍历所有iframe
- 不缓存frame引用，重复遍历开销大

**改进方案**：
- 首次成功定位iframe后缓存frame的name/url
- 后续步骤优先在已知的frame中查找
- 选择器含frame路径时直接定位到对应frame

---

## 四、非功能需求

### 4.1 性能要求

| 指标 | 要求 |
|------|------|
| 智能定位API响应时间 | ≤30s/用例（含登录+导航+定位） |
| Claude单次调用时间 | ≤15s |
| jieba分词加载时间 | ≤2s（首次），后续0ms（缓存） |
| 评分计算时间 | ≤100ms/步骤 |

### 4.2 兼容性要求

- 向后兼容：现有的CSS选择器和XPath格式必须继续支持
- 新增语义定位器格式为可选增强，不影响已有用例
- 数据库schema无变更

### 4.3 依赖要求

| 依赖 | 版本 | 用途 |
|------|------|------|
| jieba | ≥0.42.1 | 中文分词 |
| Playwright | ≥1.40.0 | 语义定位器API |

---

## 五、验收标准

### 5.1 功能验收

| 验收项 | 验收标准 |
|--------|---------|
| jieba分词 | 关键词提取不再出现语义丢失、空关键词、噪声关键词 |
| 评分归一化 | 精确匹配的元素排序高于包含匹配的元素 |
| 语义定位器 | 执行器支持role:/text:/placeholder:/label:/testid:格式 |
| 组合选择器 | 自动生成父容器+元素的组合选择器 |
| Claude增强 | 单候选也调用Claude验证，Prompt包含页面上下文 |
| iframe穿透 | 微前端内元素的选择器可正确执行 |

### 5.2 准确率验收

| 用例类型 | 验收标准 |
|---------|---------|
| 简单页面访问验证 | ≥95% 定位成功 |
| 二级菜单导航 | ≥90% 定位成功 |
| 表单填写 | ≥75% 定位成功 |
| 微前端内操作 | ≥65% 定位成功 |

### 5.3 回归验收

- 已有通过的系统设置用例（6/6步骤）必须继续通过
- 信息发布用例必须继续通过
- 已有的CSS选择器格式必须继续正常执行

---

## 六、风险评估

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| jieba分词对专业术语分词不准 | 中 | 中 | 维护自定义词典，添加项目特定术语 |
| 语义定位器格式与现有选择器冲突 | 低 | 高 | 使用明确的前缀（role:/text:等），不与CSS冲突 |
| Claude调用耗时增加（单候选也调用） | 高 | 中 | 单候选验证使用简化Prompt，减少token |
| iframe选择器格式不被所有执行路径支持 | 中 | 中 | 渐进式支持，优先在智能定位流程中支持 |

---

## 七、相关文档

| 文档 | 路径 |
|------|------|
| 元素定位方案对比分析 | `Docs/PRD/需求文档/用例管理/_分析报告_元素定位方案对比.md` |
| 智能定位Claude语义增强PRD | `Docs/PRD/需求文档/用例管理/_PRD_智能定位Claude语义增强.md` |
| 智能定位执行稳定性优化PRD | `Docs/PRD/需求文档/用例管理/_PRD_智能定位功能执行稳定性优化.md` |
| UI自动化交接文档 | `HANDOFF_UI自动化.md` |
