# 执行计划 — 智能定位 Claude 语义增强

> **文档版本**: v1.0  
> **创建日期**: 2026-08-06  
> **作者**: Claude Code  
> **关联PRD**: `_PRD_智能定位Claude语义增强.md`  
> **状态**: 待确认

---

## 一、执行概览

### 1.1 目标

为智能定位功能增加 Claude CLI 语义理解能力，提升元素定位精确度。

### 1.2 范围

- 后端新增 Claude 集成模块
- 改造智能定位服务
- 新增配置项和日志

### 1.3 预估工时

| 阶段 | 工时 |
|------|------|
| Phase 1: Claude CLI 集成 | 2 小时 |
| Phase 2: 智能定位服务改造 | 2 小时 |
| Phase 3: 测试与验证 | 1 小时 |
| **总计** | **5 小时** |

---

## 二、Phase 1: Claude CLI 集成

### 2.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 1.1 | 创建 Claude 服务模块 | `backend/app/services/claude_service.py` | 封装 Claude CLI 调用逻辑 |
| 1.2 | 设计 Prompt 模板 | `backend/app/services/claude_service.py` | 元素选择 Prompt |
| 1.3 | 实现候选元素序列化 | `backend/app/services/claude_service.py` | 将元素信息转为 JSON |
| 1.4 | 实现容错机制 | `backend/app/services/claude_service.py` | 超时、异常、格式错误处理 |
| 1.5 | 添加配置项 | `backend/app/config.py` | Claude 相关配置 |

### 2.2 详细设计

#### 1.1 创建 Claude 服务模块

**文件**: `backend/app/services/claude_service.py`

**类设计**:

```python
class ClaudeService:
    """Claude CLI 语义增强服务"""
    
    def __init__(self):
        self.enabled = settings.CLAUDE_ENABLED
        self.timeout = settings.CLAUDE_TIMEOUT
        self.model = settings.CLAUDE_MODEL
    
    def rank_candidates(
        self,
        step_name: str,
        action: str,
        params: dict,
        candidates: List[Dict]
    ) -> Tuple[int, float, str]:
        """
        对候选元素进行语义排序
        
        Args:
            step_name: 步骤名称
            action: 动作类型
            params: 步骤参数
            candidates: 候选元素列表
            
        Returns:
            (选中索引, 置信度, 选择理由)
        """
        pass
    
    def _build_prompt(self, step_info: dict, candidates: List[Dict]) -> str:
        """构建 Claude Prompt"""
        pass
    
    def _call_claude_cli(self, prompt: str) -> dict:
        """调用 Claude CLI"""
        pass
    
    def _parse_response(self, response: str) -> dict:
        """解析 Claude 响应"""
        pass
```

#### 1.2 Prompt 模板

```python
ELEMENT_SELECTION_PROMPT = """
你是一个 UI 自动化测试专家。请根据步骤描述，从候选元素中选择最匹配的一个。

## 步骤信息
- 步骤名称: {step_name}
- 动作类型: {action}
- 参数: {params}

## 候选元素列表
{candidates_json}

## 选择标准
1. 元素类型匹配动作类型（如 fill 需要 input/textarea）
2. 文本内容语义匹配步骤描述
3. 元素位置合理（如按钮应在可操作区域）

## 输出格式
只返回 JSON，不要其他内容:
{{"selected_index": 0, "confidence": 0.95, "reason": "选择理由"}}
"""
```

#### 1.3 Claude CLI 调用

```python
def _call_claude_cli(self, prompt: str) -> dict:
    """调用宿主机 Claude CLI"""
    try:
        import subprocess
        import json
        
        # 通过 SSH 或本地调用 Claude CLI
        # 服务器上已安装 Claude CLI
        result = subprocess.run(
            ['claude', '--print', prompt],
            capture_output=True,
            text=True,
            timeout=self.timeout
        )
        
        if result.returncode != 0:
            raise Exception(f"Claude CLI 错误: {result.stderr}")
        
        return self._parse_response(result.stdout)
        
    except subprocess.TimeoutExpired:
        raise Exception("Claude CLI 超时")
    except Exception as e:
        raise Exception(f"Claude CLI 调用失败: {e}")
```

#### 1.5 配置项

**文件**: `backend/app/config.py`

```python
class Settings:
    # ... 现有配置 ...
    
    # Claude 配置
    CLAUDE_ENABLED: bool = os.getenv("CLAUDE_ENABLED", "true").lower() == "true"
    CLAUDE_TIMEOUT: int = int(os.getenv("CLAUDE_TIMEOUT", "10"))  # 秒
    CLAUDE_MODEL: str = os.getenv("CLAUDE_MODEL", "claude-sonnet-5")  # 默认模型
    CLAUDE_MAX_CANDIDATES: int = int(os.getenv("CLAUDE_MAX_CANDIDATES", "10"))  # 最大候选数
```

### 2.3 验收标准

- [ ] Claude 服务模块可独立调用
- [ ] Prompt 能正确传递步骤信息
- [ ] 超时、异常能正确处理
- [ ] 日志记录完整

---

## 三、Phase 2: 智能定位服务改造

### 3.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 2.1 | 改造关键词匹配 | `backend/app/services/keyword_matcher.py` | 返回候选列表而非单一元素 |
| 2.2 | 集成 Claude 排序 | `backend/app/services/smart_locate_service.py` | 在候选筛选后调用 Claude |
| 2.3 | 增强 API 响应 | `backend/app/services/smart_locate_service.py` | 返回 Claude 增强信息 |
| 2.4 | 添加开关控制 | `backend/app/services/smart_locate_service.py` | `use_claude` 参数 |

### 3.2 详细设计

#### 2.1 改造关键词匹配

**修改**: `match_element_by_keywords()` 函数

**当前行为**:
```python
# 返回第一个匹配的元素
return elements[0], selectors
```

**改造后**:
```python
# 返回所有候选元素（按置信度排序）
return elements[:MAX_CANDIDATES], all_selectors
```

**新增函数**: `get_candidate_details()`

```python
def get_candidate_details(
    page,
    elements: List[Any]
) -> List[Dict[str, Any]]:
    """
    获取候选元素的详细信息
    
    Returns:
        [
            {
                "index": 0,
                "tag": "BUTTON",
                "text": "新建会议",
                "selector": "button:has-text('新建会议')",
                "attributes": {...},
                "position": {...}
            },
            ...
        ]
    """
    pass
```

#### 2.2 集成 Claude 排序

**文件**: `backend/app/services/smart_locate_service.py`

**修改**: `_locate_single_step()` 方法

```python
def _locate_single_step(self, step: Dict) -> Dict:
    # ... 现有关键词匹配逻辑 ...
    
    # 获取候选元素
    elements, selectors = match_element_by_keywords(page, keywords, action)
    
    # 新增：Claude 增强排序
    if self.use_claude and len(elements) > 1:
        candidates = get_candidate_details(page, elements)
        
        try:
            claude_service = ClaudeService()
            selected_idx, confidence, reason = claude_service.rank_candidates(
                step_name=step['name'],
                action=step['action'],
                params=step.get('params', {}),
                candidates=candidates
            )
            
            # 使用 Claude 选择的结果
            result['selectors'] = {
                'primary': selectors[selected_idx]['value'],
                'candidates': selectors,
            }
            result['claude_enhanced'] = True
            result['claude_reason'] = reason
            result['params']['selector'] = selectors[selected_idx]['value']
            
        except Exception as e:
            # 回退到第一个候选
            logger.warning(f"Claude 增强失败，回退到关键词匹配: {e}")
            result['selectors'] = {'primary': selectors[0]['value'], 'candidates': selectors}
            result['claude_enhanced'] = False
    
    # 单候选：直接使用
    elif len(elements) == 1:
        result['selectors'] = {'primary': selectors[0]['value'], 'candidates': selectors}
        result['claude_enhanced'] = False
    
    # 无候选：定位失败
    else:
        result['success'] = False
        result['message'] = f'未找到匹配元素: {step["name"]}'
```

#### 2.4 添加开关控制

```python
def locate_steps(
    self,
    steps: List[Dict],
    auto_login: bool = True,
    navigate_menu: str = "",
    page_url: str = "https://192.168.5.44",
    use_claude: bool = True  # 新增参数
) -> List[Dict]:
    self.use_claude = use_claude and settings.CLAUDE_ENABLED
    # ... 后续逻辑 ...
```

### 3.3 验收标准

- [ ] 多候选时自动调用 Claude 排序
- [ ] 单候选时不调用 Claude
- [ ] Claude 失败时正确回退
- [ ] API 响应包含 `claude_enhanced` 字段

---

## 四、Phase 3: 测试与验证

### 4.1 单元测试

**文件**: `backend/tests/test_claude_service.py`

| 测试用例 | 说明 |
|---------|------|
| test_claude_service_init | 测试服务初始化 |
| test_build_prompt | 测试 Prompt 构建 |
| test_parse_response | 测试响应解析 |
| test_timeout_handling | 测试超时处理 |
| test_fallback | 测试回退逻辑 |

### 4.2 集成测试

**文件**: `backend/scripts/test_claude_enhanced_locate.py`

```python
def test_meeting_case():
    """测试会议管理用例的智能定位"""
    steps = [
        {"order": 8, "name": "点击会议预约分类", "action": "click", "params": {}},
        {"order": 9, "name": "点击新建会议按钮", "action": "click", "params": {}},
        {"order": 10, "name": "会议名称输入：自动化新建会议", "action": "fill", "params": {}},
    ]
    
    service = SmartLocateService()
    results = service.locate_steps(steps, auto_login=True, navigate_menu="会议预约")
    
    # 验证每个步骤的选择器是否正确
    assert results[0]['selectors']['primary'] != results[1]['selectors']['primary']
    assert "input" in results[2]['selectors']['primary'].lower()  # 应该是输入框
```

### 4.3 回归测试

使用现有 19 个 UI 用例进行批量测试：

| 用例类型 | 用例数量 | 预期通过率 |
|---------|---------|-----------|
| 页面访问验证 | 5 | 100% |
| 功能操作验证 | 14 | ≥ 85% |

### 4.4 验收标准

- [ ] 单元测试全部通过
- [ ] 集成测试通过
- [ ] 回归测试通过率 ≥ 85%
- [ ] 无新增 bug

---

## 五、部署计划

### 5.1 部署步骤

```bash
# 1. 上传代码到服务器
scp backend/app/services/claude_service.py ubains@192.168.5.60:/data/third_party/plat-auto-test/backend/app/services/
scp backend/app/services/keyword_matcher.py ubains@192.168.5.60:/data/third_party/plat-auto-test/backend/app/services/
scp backend/app/services/smart_locate_service.py ubains@192.168.5.60:/data/third_party/plat-auto-test/backend/app/services/
scp backend/app/config.py ubains@192.168.5.60:/data/third_party/plat-auto-test/backend/app/

# 2. 重启容器
docker compose -f /data/third_party/plat-auto-test/deploy/docker-compose.yml restart app

# 3. 验证服务
curl http://192.168.5.60/health
```

### 5.2 配置更新

**服务器环境变量**（可选）:

```bash
# 在 docker-compose.yml 中添加
environment:
  - CLAUDE_ENABLED=true
  - CLAUDE_TIMEOUT=10
  - CLAUDE_MODEL=claude-sonnet-5
```

### 5.3 回滚方案

```bash
# 如有问题，快速回滚
git checkout HEAD~1 -- backend/app/services/smart_locate_service.py
git checkout HEAD~1 -- backend/app/services/keyword_matcher.py
# 重新上传并重启
```

---

## 六、风险与缓解

| 风险 | 概率 | 影响 | 缓解措施 |
|------|------|------|---------|
| Claude CLI 调用失败 | 中 | 定位失败率上升 | 自动回退到关键词匹配 |
| 响应延迟高 | 中 | 用户体验下降 | 超时控制 10s |
| Prompt 效果不佳 | 低 | 精度不达预期 | 迭代优化 Prompt |
| 成本超预算 | 低 | 运营成本增加 | 监控 + 阈值告警 |

---

## 七、时间安排

| 日期 | 任务 | 负责人 |
|------|------|--------|
| Day 1 上午 | Phase 1: Claude 服务模块 | Claude Code |
| Day 1 下午 | Phase 2: 智能定位改造 | Claude Code |
| Day 2 上午 | Phase 3: 测试与验证 | Claude Code |
| Day 2 下午 | 部署与回归测试 | Claude Code |

---

## 八、交付物

- [ ] `backend/app/services/claude_service.py` — Claude 服务模块
- [ ] `backend/app/services/keyword_matcher.py` — 改造后的关键词匹配
- [ ] `backend/app/services/smart_locate_service.py` — 改造后的智能定位服务
- [ ] `backend/app/config.py` — 新增配置项
- [ ] `backend/tests/test_claude_service.py` — 单元测试
- [ ] 测试报告 — 回归测试结果

---

*本文档待用户确认后开始执行。*
