# PRD 需求文档 — 离线部署方案

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

---

## 1. 需求背景

运行维护平台部署到客户现场服务器时，通常处于**内网/离线环境**，无法访问外部 AI API（Claude）。当前问题排查助手依赖 Claude API 进行 AI 分析，在离线环境下不可用。

同时，现场部署采用**容器化（Docker）**方式，不直接部署在宿主机上。三个模块（问题排查助手、服务管理、服务监测）需要在容器化离线环境中稳定运行。

---

## 2. 现状分析

| 模块 | 外部依赖 | 离线可用性 | 备注 |
|------|----------|-----------|------|
| 问题排查助手 | Claude API + TF-IDF 搜索 | ❌ AI 不可用 | 搜索可用，AI 分析不可用 |
| 服务管理 | 无（占位） | ✅ | 后续走 SSH 连接内部系统 |
| 服务监测 | SSH（局域网） | ✅ | SSH 连接目标服务器 |
| 平台首页 / 认证 | 无（Flask 本地） | ✅ | — |

**核心卡点**：问题排查助手的 AI 分析功能依赖外网 API。

---

## 3. 离线方案设计

### 3.1 问题排查助手 — 离线 Q&A 模式

**原理**：跳过 Claude API 调用，直接将 TF-IDF 搜索匹配结果作为排查建议返回。

**流程对比**：

```
【在线模式】
用户提问 → TF-IDF 搜索 → 匹配结果 + 提问 → Claude API → AI 分析报告

【离线模式】
用户提问 → TF-IDF 搜索 → 匹配结果格式化 → 直接返回离线排查建议
```

**离线模式返回内容**：

| 区域 | 在线模式 | 离线模式 |
|------|---------|---------|
| 标题 | 🤖 AI 分析结果 | 📋 离线排查参考（基于知识库匹配） |
| 匹配案例列表 | 简要列表 | 完整记录（标题 + 现象 + 解决方案 + 相似度） |
| AI 分析 | Claude 生成 | 无（标注"离线模式，无 AI 分析"） |
| 响应时间 | 20-60 秒 | <1 秒 |
| 横幅提示 | 无 | "当前为离线模式，结果基于历史知识库匹配" |

**匹配案例展示格式（详细版）**：
```
案例1（相似度：92%）
  项目：厦门银行
  标题：门口屏 MQTT 绑定失败
  现象：门口屏绑定时报 MQTT 连接错误，无法完成绑定
  解决方案：升级门口屏到 5.0+ 版本，使用默认 MQTT 凭据
  参考文件：record_001.md

案例2（相似度：75%）
  项目：展厅
  标题：门口屏不显示会议信息
  现象：会议开始后门口屏不显示会议主题和参会人
  解决方案：检查 EMQX 容器状态，确认 docker ps -a | grep uemqx 有输出
  参考文件：record_002.md
```

### 3.2 配置开关

**文件**：`config.json`

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

- `offline_mode: false`（默认）— 在线模式，调 Claude API
- `offline_mode: true` — 离线模式，跳过 API，直接返回搜索结果

### 3.3 部署方式 — 容器化

现场服务器采用 Docker 容器化部署，不直接部署在宿主机：

```
宿主机
├── Docker
│   ├── troubleshooot 容器（运行维护平台）
│   │   ├── Flask/Gunicorn + Python
│   │   ├── 知识库（357 条记录）
│   │   └── 配置文件
│   └── 其他服务容器
```

**Dockerfile 要点**：
- 基础镜像：`python:3.10-slim`
- 依赖：Flask, scikit-learn, scipy, numpy, jieba（TF-IDF 搜索引擎所需）
- **不需要** requests 的 API 调用（离线模式），但保留以便在线模式切换
- 端口：8088
- 启动命令：`gunicorn -w 4 -b 0.0.0.0:8088 server:app`（生产）或 `python server.py`（调试）

**容器化优势**：
- 环境一致性：镜像打包后现场直接 `docker run`，无需手动安装 Python 依赖
- 进程守护：`docker restart policy = always`，容器挂了自动重启
- 资源隔离：不污染宿主机环境

### 3.4 API 行为变更

**`POST /api/troubleshoot`**：

| 场景 | 在线模式 | 离线模式 |
|------|---------|---------|
| 搜索 | TF-IDF | TF-IDF |
| AI 分析 | 调 Claude API | 跳过，格式化搜索结果 |
| 返回 | `{analysis, cases}` | `{analysis: null, cases, offline: true}` |
| 耗时 | 20-60 秒 | <1 秒 |

**`POST /api/analyze`**：同上。

**`POST /api/analyze_stream`**：

离线模式下不调用流式 API，直接返回完整 JSON（非 SSE），响应格式：

```json
{
  "success": true,
  "offline": true,
  "analysis": null,
  "matched_cases": [...]
}
```

### 3.5 /api/health 响应

新增 `offline_mode` 字段：

```json
{
  "status": "ok",
  "version": "1.4.0",
  "offline_mode": true
}
```

---

## 4. 容器化部署方案

### 4.1 Dockerfile

```dockerfile
FROM python:3.10-slim

WORKDIR /app

# 安装依赖
RUN pip install flask scikit-learn scipy numpy jieba gunicorn werkzeug

# 拷贝代码
COPY skill/code/web/ /app/web/
COPY skill/code/SKILL.md /app/SKILL.md

# 端口
EXPOSE 8088

# 启动
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8088", "server:app"]
```

### 4.2 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
      - ./records:/app/web/records:ro
      - ./logs:/app/logs
    environment:
      - PYTHONIOENCODING=utf-8
      - SECRET_KEY=${SECRET_KEY}
```

### 4.3 现场部署流程

```
# 1. 在线环境构建镜像
docker build -t troubleshoot:latest .

# 2. 导出镜像
docker save troubleshoot:latest | gzip > troubleshoot.tar.gz

# 3. 拷贝到现场服务器（U盘/内网传输）
scp troubleshoot.tar.gz user@field-server:/opt/

# 4. 现场服务器加载并启动
docker load < troubleshoot.tar.gz
docker compose up -d
```

---

## 5. 非功能需求

| 项目 | 要求 |
|------|------|
| 配置切换 | 改 config.json 的 `offline_mode` 即可，无需改代码 |
| 搜索质量 | 离线模式下 TF-IDF 搜索逻辑不变，纯本地运行 |
| 响应速度 | 离线模式排查 <1 秒（无 API 调用） |
| 前端适配 | 离线模式结果展示清晰标注"离线模式" |
| 容器化 | 提供 Dockerfile + docker-compose.yml |
| 进程守护 | Docker restart policy always + gunicorn 多 worker |
| 日志持久化 | 日志挂载到宿主机 volume |

---

## 6. 约束

- 离线模式下不提供 AI 分析和步骤建议，仅返回知识库匹配结果
- 离线模式不影响现有在线模式行为（配置开关隔离）
- 不修改 `search_engine.py` / `safety_filter.py` / `cache_manager.py` 公开接口
- Docker 镜像构建在在线环境完成，现场只需 `docker load` + `docker run`

---

## 7. 后续扩展（本期不做）

- **本地小模型推理**：Docker 内嵌 Ollama + 小参数模型
- **知识库离线导入**：支持通过平台界面上传离线 Q&A 文档
- **配置热更新**：修改 config.json 后无需重启容器