# PRD 计划执行文档 — 离线部署方案

> 版本：2.0 ｜ 日期：2026-07-15 ｜ 分支：troubleshoot-ai-assistant

---

## 执行步骤总览

| 步骤 | 内容 | 优先级 | 预估改动 |
|------|------|--------|----------|
| 1 | config.json 新增 `offline_mode` 配置 | P0 | 1 行 |
| 2 | container.py 加载 `offline_mode` 默认值 | P0 | 2 行 |
| 3 | ai_service.py 新增 `build_offline_analysis()` | P0 | ~60 行 |
| 4 | routes/troubleshoot.py 三处路由 + health 适配 | P0 | ~30 行 |
| 5 | index.html 前端离线适配 | P0 | ~40 行 |
| 6 | 单元测试补充离线模式用例 | P1 | ~30 行 |
| 7 | Dockerfile + docker-compose.yml | P1 | 新建 2 文件 |
| 8 | deploy 脚本适配容器化部署 | P2 | 修改 |

---

### 步骤 1：config.json 新增配置

**文件**：`skill/code/web/config.json`

```json
{
  "offline_mode": false,
  ...
}
```

---

### 步骤 2：container.py 加载默认值

**文件**：`skill/code/web/container.py`

在 `load_config()` 的默认返回值中补充 `"offline_mode": False`。

---

### 步骤 3：ai_service.py 新增离线分析函数

**文件**：`skill/code/web/services/ai_service.py`

新增函数：

```python
def build_offline_analysis(query, matched_cases):
    """离线模式：从匹配案例构建排查建议（不调 AI）

    参数：
      query: 用户问题描述
      matched_cases: SearchEngine.search() 返回的匹配案例列表

    返回：
      {
        "mode": "offline",
        "summary": "基于知识库匹配的排查参考",
        "cases": [...],  # 完整案例记录
        "note": "当前为离线模式，结果基于历史知识库匹配"
      }
    """
```

实现逻辑：
1. 遍历 `matched_cases`，从 `record` 中提取 `project`、`title`、`phenomenon`、`solution`、`file`
2. 按相似度降序排列
3. 生成离线排查建议文本（Markdown 格式，可直接渲染）
4. 返回结构化数据

**注意**：不修改 `call_claude_api` / `call_claude_api_stream` 签名。

---

### 步骤 4：routes/troubleshoot.py 适配离线

**文件**：`skill/code/web/routes/troubleshoot.py`

三处路由加离线分支：

1. **`POST /api/troubleshoot`**（行 57-114）：
   ```python
   if container.get_config().get('offline_mode', False):
       analysis = build_offline_analysis(query, matched_cases_data)
       return jsonify({
           'success': True,
           'response': analysis['text'],
           'matched_cases': format_matched_cases(matched_cases_data),
           'offline': True,
       })
   # 否则走原有在线逻辑...
   ```

2. **`POST /api/analyze`**（行 150-）：
   同样加离线分支。

3. **`POST /api/analyze_stream`**：
   离线模式下不返回 SSE 流式，直接返回完整 JSON。

4. **`GET /api/health`**：
   加 `'offline_mode': config.get('offline_mode', False)`。

---

### 步骤 5：index.html 前端适配

**文件**：`skill/code/web/templates/index.html`

适配点：

1. **响应解析**：检测 `data.offline === true`
2. **标题切换**：
   - 在线：`🤖 AI 分析结果`
   - 离线：`📋 离线排查参考（基于知识库匹配）`
3. **横幅提示**：离线模式下在结果区顶部显示提示横幅
4. **流式输出**：离线模式下跳过 SSE 流式，直接渲染 JSON 响应
5. **案例展示**：离线模式下展示完整案例记录（标题 + 现象 + 解决方案 + 文件路径）

---

### 步骤 6：单元测试

**文件**：`skill/code/tests/test_routes_troubleshoot.py`

补充用例：

- `test_troubleshoot_offline_mode` — offline_mode=True 时返回 `offline: true`，不调 AI
- `test_troubleshoot_online_mode` — offline_mode=False 时走原逻辑
- `test_health_offline_mode` — health 接口返回 offline_mode 字段

**conftest.py**：可能需要加 fixture 注入 `offline_mode` 配置。

---

### 步骤 7：Dockerfile + docker-compose.yml

**新建文件**：项目根目录

**Dockerfile**：
```dockerfile
FROM python:3.10-slim
WORKDIR /app
RUN pip install flask scikit-learn scipy numpy jieba gunicorn werkzeug paramiko
COPY skill/code/web/ /app/web/
COPY skill/code/SKILL.md /app/SKILL.md
COPY deploy/搜索索引.json /app/搜索索引.json
EXPOSE 8088
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8088", "--chdir", "/app/web", "server:app"]
```

**docker-compose.yml**：
```yaml
version: '3.8'
services:
  troubleshoot:
    build: .
    ports:
      - "8088:8088"
    restart: always
    volumes:
      - ./config.json:/app/web/config.json:ro
      - ./users.json:/app/web/users.json:ro
      - ./logs:/app/logs
    environment:
      - PYTHONIOENCODING=utf-8
```

---

### 步骤 8：deploy 脚本适配容器化

**文件**：`deploy/upload_to_server.py`

新增：
- Docker 镜像构建命令
- `docker save` 导出镜像
- 或直接 `docker compose up -d --build`

---

## 变更文件清单

| 文件 | 操作 | 说明 |
|------|------|------|
| `skill/code/web/config.json` | 修改 | 新增 `offline_mode: false` |
| `skill/code/web/container.py` | 修改 | `load_config` 默认值补 `offline_mode` |
| `skill/code/web/services/ai_service.py` | 修改 | 新增 `build_offline_analysis` |
| `skill/code/web/routes/troubleshoot.py` | 修改 | 三处路由 + health 离线分支 |
| `skill/code/web/templates/index.html` | 修改 | 离线模式前端展示 |
| `skill/code/tests/test_routes_troubleshoot.py` | 修改 | 离线用例 |
| `Dockerfile` | **新建** | 容器化构建文件 |
| `docker-compose.yml` | **新建** | 容器编排 |

---

## 验证

1. `cd skill/code && python -m pytest -v` — 全绿
2. 在线模式验证：`offline_mode: false`，排查流程调 AI 正常
3. 离线模式验证：`offline_mode: true`，排查返回搜索结果 + `offline: true`，无 AI 调用
4. `/api/health` 返回 `offline_mode` 字段
5. Docker 构建：`docker build -t troubleshoot .` 成功
6. Docker 运行：`docker run -p 8088:8088 troubleshoot`，访问正常