# PRD_需求文档_P2级功能增强

## 基本信息

| 项目 | 内容 |
|------|------|
| 文档类型 | 需求文档 |
| 创建日期 | 2026-07-14 |
| 最后更新 | 2026-07-14 |
| 负责人 | 研发组（Claude 协助） |
| 优先级 | P2 🟠 |
| 状态 | 待开始 |

> 父任务：P2 级功能增强（语义搜索升级 + 移动端响应式适配）
> 来源：`Docs/PRD_需求文档_项目优化方向.md` §2.2 / §3.2 / §3.3

---

## 一、背景与目标

### 1.1 问题背景

P1 级代码质量优化已全部完成（异常处理规范化 / 131 单元测试 / 三层架构重构 + 收尾三项），系统稳定运行于 `192.168.5.60:8088`。但在功能层面仍有两类短板影响使用体验与匹配质量：

| 序号 | 短板 | 现状 | 影响 |
|------|------|------|------|
| 1 | 搜索召回率不足 | `search_engine.py` 基于 TF-IDF + 关键词匹配，依赖 `tokenize` 的正则分词（2-4 字中文片段） | 同义词/近义词/口语化描述无法召回；"门禁刷不开" 召不到 "门禁识别失败"；估算匹配准确率偏低 |
| 2 | 仅桌面端可用 | `templates/index.html` 为桌面单页设计，表单/弹窗/Markdown 渲染区未做移动端断点 | 现场工程师手机浏览器访问体验差，无法移动办公 |

### 1.2 修复目标

1. **语义搜索升级**：引入 Embedding 向量搜索，复用现有 OpenAI 兼容 API 生成向量，**预计算固化入库**，使搜索能理解语义相似性，目标匹配准确率 +20%，同时保留 TF-IDF 作为降级兜底。
2. **移动端响应式适配**：对 `index.html` 增加移动端断点与触控优化，支持主流移动浏览器现场访问，扩大使用场景。

---

## 二、需求详情

### 2.1 P2-1：语义搜索升级（TF-IDF → Embedding 向量搜索）

#### 2.1.1 问题描述

当前 `SearchEngine.search()` 流程：`tokenize(query)` → `compute_tfidf(query)` → 遍历文档算 `cosine_similarity` → 加关键词匹配加分 + 项目匹配加分 → 排序返回。

局限：

- 正则分词无法理解语义（"识别失败" ≠ "刷不开"）
- TF-IDF 只看词频，词不重合即相似度为 0
- 现场问题描述口语化、术语不统一，召回率低

#### 2.1.2 问题位置

| 文件 | 位置 | 说明 |
|------|------|------|
| `skill/code/web/search_engine.py` | `tokenize` / `compute_tfidf` / `cosine_similarity` / `SearchEngine.search` | TF-IDF 核心逻辑，**公开接口勿改** |
| `skill/code/web/search_engine.py` | `SearchEngine.__init__` | 初始化加载索引，需扩展为加载向量索引 |
| `skill/code/web/search_engine.py` | `find_search_index` | 索引路径查找，需补向量文件路径 |
| `skill/code/web/container.py` | `get_search_engine` / `reset_search_engine` | 单例容器，向量索引加载需接入 |
| `skill/code/web/services/record_service.py` | `rebuild_search_index` | 重建索引子进程，需同步重建向量 |

> ⚠️ 约束：`SearchEngine` 类与 `search()` 函数签名**不改公开接口**（P1-2 的 34 个 `test_search_engine.py` 用例依赖）。新增向量能力以**内部字段 + 可选参数**形式扩展，TF-IDF 路径作为降级保留。

#### 2.1.3 需求规格

| 项 | 规格 |
|----|------|
| Embedding 后端 | 复用现有 OpenAI 兼容 API（`CLAUDE_API_BASE` / `CLAUDE_API_KEY`），调用 `/v1/embeddings` |
| 向量模型 | `text-embedding-3-small`（1536 维），通过 `config.json` 可配置 |
| 向量存储 | 预计算固化入库 —— 357 条记录的向量写入 `搜索向量.json`，随索引文件部署 |
| 加载方式 | `SearchEngine.__init__` 优先加载向量文件；文件缺失时**降级 TF-IDF**，不阻塞启动 |
| 查询流程 | query 走 API 实时生成向量 → 与文档向量算余弦相似度 → 排序；API 失败降级 TF-IDF |
| 降级策略 | API 不可用 / 向量文件缺失 / 向量维度不匹配 → 自动回退现有 TF-IDF 路径，服务可用 |
| 公开接口 | `SearchEngine.search(query, top_k, project_filter, category_filter)` 签名不变 |
| 缓存 | query 向量可加内存缓存（LRU），避免重复 query 重复调 API |
| 配置项 | `config.json` 新增：`embedding_model` / `embedding_enabled` / `embedding_api_timeout` |

#### 2.1.4 测试用例规划

| 模块 | 新增用例数 | 覆盖点 |
|------|-----------|--------|
| `test_search_engine.py` | ~12 | 向量加载/缺失降级、维度不匹配降级、query 向量缓存命中、API 失败降级 TF-IDF、配置开关关闭时走 TF-IDF |
| `test_routes_troubleshoot.py` | ~3 | `/api/search` 在向量模式与降级模式下均返回结构一致的结果 |

> 测试通过 mock `requests.post`（embedding API 调用）实现，不真实联网。

#### 2.1.5 验收标准

- [ ] `SearchEngine` 公开接口签名不变，原 34 用例全绿
- [ ] 向量文件存在时，搜索走 Embedding 路径，召回同义/近义描述
- [ ] 向量文件缺失时，自动降级 TF-IDF，服务正常启动不报错
- [ ] Embedding API 调用失败时，单次 query 降级 TF-IDF，不影响后续 query
- [ ] `config.json` 的 `embedding_enabled=false` 时完全走 TF-IDF，不发起任何 API 请求
- [ ] query 向量内存缓存生效（相同 query 二次不重复调 API）
- [ ] `rebuild_search_index` 同步重建向量文件
- [ ] 预计算向量文件 `搜索向量.json` 入库并纳入部署清单

---

### 2.2 P2-2：移动端响应式适配

#### 2.2.1 问题描述

`templates/index.html` 当前 CSS 面向桌面端：

- 固定宽度容器 / 多列网格在窄屏挤压错位
- 表单输入框、下拉框在手机上偏小
- 弹窗（提交记录 / 缓存管理）宽度固定，手机上溢出
- AI 分析结果 Markdown 渲染区无横向滚动兜底，长代码溢出
- 按钮触控热区偏小，现场戴手套难点击

#### 2.2.2 问题位置

| 文件 | 位置 | 说明 |
|------|------|------|
| `skill/code/web/templates/index.html` | `:root` CSS 变量 / `.container` / `.form-grid` / `.modal` / `.btn` | 全局样式，需加断点 |
| `skill/code/web/templates/index.html` | `<meta name="viewport">` | 当前可能缺失或未优化，需补 `width=device-width, initial-scale=1` |
| `skill/code/web/templates/login.html` | 登录页样式 | 同步适配，保证登录入口移动可用 |

#### 2.2.3 需求规格

| 项 | 规格 |
|----|------|
| 断点策略 | 移动端 ≤768px 单列布局；769–1024px 平板二列；>1024px 桌面原样 |
| viewport meta | `width=device-width, initial-scale=1, maximum-scale=5` |
| 触控热区 | 按钮 / 输入框最小高度 44px（iOS HIG / Material 规范） |
| 弹窗适配 | 移动端弹窗宽度 92vw、最大高度 85vh、内容区纵向滚动 |
| 代码块 | Markdown 渲染的 `<pre>` 加 `overflow-x:auto`，长代码横向滚动不撑破布局 |
| 字号 | 移动端基础字号 ≥14px，避免 iOS Safari 自动放大 |
| SSE/流式 | 流式输出区域移动端跟随滚动到底部，键盘弹起不遮挡 |
| 兼容浏览器 | Chrome / Safari (iOS) / 微信内置浏览器 |

#### 2.2.4 验收标准

- [ ] iPhone Safari / Android Chrome / 微信浏览器访问，布局无错位溢出
- [ ] 表单可在手机上正常输入提交，下拉框/textarea 触控顺畅
- [ ] 弹窗在手机上不超出屏幕，可滚动关闭
- [ ] AI 分析结果长代码块横向可滚动，不撑破卡片
- [ ] 流式输出在手机上自动滚动跟随，键盘弹起时输入框可见
- [ ] `login.html` 同步适配，移动端可完成登录
- [ ] 桌面端（>1024px）外观与行为零回归

---

## 三、影响范围

### 3.1 涉及文件

| 文件 / 目录 | 变更类型 | 说明 |
|------------|---------|------|
| `skill/code/web/search_engine.py` | 修改 | 加向量加载/查询/降级逻辑，公开接口不变 |
| `skill/code/web/container.py` | 修改 | 配置项读取 embedding 相关字段 |
| `skill/code/web/services/record_service.py` | 修改 | `rebuild_search_index` 同步重建向量 |
| `skill/code/web/utils/paths.py` | 修改 | 补向量文件路径常量 |
| `skill/code/web/config.json` | 修改 | 新增 embedding 配置项 |
| `skill/code/tests/test_search_engine.py` | 修改 | 新增 ~12 用例 |
| `skill/code/tests/test_routes_troubleshoot.py` | 修改 | 新增 ~3 用例 |
| `skill/code/tests/conftest.py` | 修改 | 补向量文件 fixture / mock embedding API |
| `skill/code/web/templates/index.html` | 修改 | 加移动端断点 / 触控优化 / viewport |
| `skill/code/web/templates/login.html` | 修改 | 同步移动端适配 |
| `deploy/搜索向量.json` | 新增 | 预计算向量文件（357 条 × 1536 维） |
| `deploy/upload_to_server.py` | 修改 | `FILES_TO_UPLOAD` 补向量文件 |
| `Docs/PRD_需求文档_项目优化方向.md` | 修改 | P2 状态同步 |

### 3.2 风险评估

| 风险项 | 等级 | 缓解措施 |
|--------|------|---------|
| Embedding API 不可用导致搜索不可用 | 🔴 高 | 三级降级：API 失败→TF-IDF；向量文件缺失→TF-IDF；配置关闭→TF-IDF |
| 向量文件未同步部署，生产降级 TF-IDF 静默运行 | 🟠 中 | 上传清单同步 + 健康检查暴露当前搜索模式（vector/tfidf） |
| 改 `search_engine.py` 破坏 P1-2 的 34 用例 | 🟠 中 | 公开接口零变更，新增能力以可选参数注入；改前先跑全量测试 |
| 向量预计算耗 API 额度 | 🟡 低 | 一次性 357 次调用，固化后不再重复；可离线脚本生成 |
| 移动端样式改动影响桌面端 | 🟠 中 | 断点隔离，>1024px 走原样式；改后桌面端回归验证 |
| 微信内置浏览器兼容差异 | 🟡 低 | viewport 兼容 + 关键流程真机验证 |

---

## 四、非功能需求

| 项 | 要求 |
|----|------|
| 性能 | 单次搜索 P95 < 3s（含 query 向量 API 调用）；向量加载 < 2s |
| 可用性 | Embedding 任何环节失败均降级 TF-IDF，服务不中断 |
| 兼容性 | 移动端覆盖 iOS Safari / Android Chrome / 微信浏览器 |
| 可维护性 | 向量后端可配置切换；不引入重型依赖（无 torch/sentence-transformers） |
| 安全 | Embedding API 复用现有凭据，不新增密钥；向量文件不含敏感信息 |
| 可观测 | `/api/health` 暴露当前搜索模式（vector/tfidf）与向量文件状态 |

---

## 五、时间估算

| 任务 | 工时 |
|------|------|
| P2-1 语义搜索升级 | 2 天 |
| P2-2 移动端响应式适配 | 1 天 |
| **合计** | **3 天** |

---

## 六、验收清单

### P2-1 语义搜索升级

- [ ] 向量文件 `搜索向量.json` 预计算生成并入库
- [ ] `SearchEngine` 加载向量文件，公开接口不变
- [ ] 查询走 Embedding，同义/近义描述可召回
- [ ] 三级降级（API 失败 / 文件缺失 / 配置关闭）均回退 TF-IDF
- [ ] query 向量内存缓存生效
- [ ] `rebuild_search_index` 同步重建向量
- [ ] `test_search_engine.py` 新增用例全绿，原 34 用例无回归
- [ ] `/api/health` 暴露搜索模式
- [ ] 部署清单同步向量文件

### P2-2 移动端响应式适配

- [ ] viewport meta 补齐
- [ ] 三档断点（移动/平板/桌面）布局正常
- [ ] 触控热区 ≥44px
- [ ] 弹窗移动端适配可滚动
- [ ] 代码块横向滚动不溢出
- [ ] 流式输出移动端滚动跟随
- [ ] `login.html` 同步适配
- [ ] 桌面端零回归

---

## 维护记录

| 日期 | 更新内容 | 更新人 |
|------|---------|--------|
| 2026-07-14 | 初版创建，定义 P2-1/P2-2 需求规格与验收 | 研发组 |
