提交 37c508e0 authored 作者: 陈泽健's avatar 陈泽健

docs(handoff): 新增问题排查助手与服务监测模块会话交接文档

- trouble_handoff.md:问题排查助手模块交接(离线 Q&A 模式 + 容器化落地,含关键设计决策/坑点/隔离边界/T6-T7 待办)
- Docs/需求文档/服务监测/monitor_handoff.md:服务监测模块交接
Co-Authored-By: 's avatarClaude <noreply@anthropic.com>
上级 c552a6b3
此差异已折叠。
# 问题排查助手模块 — 会话交接文档(trouble_handoff)
> 模块:问题排查助手(troubleshoot) | 分支:troubleshoot-ai-assistant
> 交接日期:2026-07-17 | 上次会话末态 commit:`b94d0230`(离线方案落地)
> 范围说明:本文档**仅覆盖问题排查助手模块**。service_monitor / service_manage 模块的进展见各自交接文档。命名 `trouble_handoff.md` 以区分模块。
---
## 1. 模块定位
问题排查助手是运行维护平台的三个模块之一,其余两个为服务管理、服务监测。
- **核心功能**:用户输入问题描述 → TF-IDF 搜索知识库(357 条历史案例)→ 调 Claude API 生成只读排查步骤与根因分析
- **本次交付**:在 `OFFLINE_MODE=true` 时跳过 Claude API,直接返回 TF-IDF 匹配结果(离线 Q&A 模式)+ Docker 容器化部署能力
- **运行环境**:Flask 进程,与 service_monitor / service_manage 同进程共 Blueprint(见 §6 隔离边界)
---
## 2. 本期完成事项(b94d0230 提交内容)
### 2.1 离线 Q&A 模式
| 文件 | 变更 | 说明 |
|------|------|------|
| `skill/code/web/utils/offline_config.py` | 新增 | `is_offline_mode()``OFFLINE_MODE` env,进程级缓存;`reset_for_test()` 测试重置 |
| `skill/code/web/services/ai_service.py` | 修改 | 新增 `build_offline_response(matched_cases)`,兼容两种输入格式(原始 record / 已格式化 dict) |
| `skill/code/web/routes/troubleshoot.py` | 修改 | 4 处离线分支:`/api/troubleshoot``/api/analyze``/api/analyze/stream``/api/health` |
**关键设计决策**(务必记住,避免下次返工):
1. **离线搜索用 TF-IDF,不用向量搜索**——向量预计算要联网调 `/v1/embeddings` API 扣费,离线环境做不了。TF-IDF 纯本地零费用。
2. **流式接口 `/api/analyze/stream` 保留 SSE 协议**——离线模式单帧推送完整结果后 `close`,前端解析逻辑无需改动。
3. **离线跳过缓存读写**——离线 <1s 响应,`cache_manager` 空跑无意义,离线分支直接 return 不走 cache。
4. **`OFFLINE_MODE` 走环境变量**(与 SECRET_KEY 一致),不从 config.json 读。启动时读一次,改了要重启容器。
5. **`build_offline_response` 接收「已格式化 dict 列表」**——troubleshoot 路由先调 `format_matched_cases()` 再传入;analyze 路由入参已是格式化格式,直接传入。两路由复用同一函数,不各自重写。
### 2.2 容器化部署
| 文件 | 说明 |
|------|------|
| `Dockerfile` | python:3.10-slim,WORKDIR `/app/web`,gunicorn `-w 4` 加载 `server:app` |
| `docker-compose.yml` | restart always,records/users/config 只读挂载,logs 持久化 |
| `.dockerignore` | **排除 `搜索向量.json`**(强制容器走 TF-IDF,避免 SearchEngine 静默走向量模式)+ 排除测试/缓存/临时 |
| `requirements.txt`(仓库根) | 镜像依赖,含 cryptography/paramiko(见 §6) |
| `.env.example` | 补 `OFFLINE_MODE=true` 说明 |
### 2.3 文档
| 文件 | 说明 |
|------|------|
| `Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手.md` | PRD v2.2(含 §4.6 同进程依赖耦合说明) |
| `Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手_计划执行.md` | 执行计划,T1-T8 任务表 |
### 2.4 测试
- 新增 `skill/code/tests/test_offline_mode.py`**22 用例全绿**
- 覆盖:offline_config 解析(11 参数化用例)/ build_offline_response(4 用例)/ 路由离线分支(含 SSE)/ 在线模式回归
- 全量回归 **218 用例全绿**(问题排查助手 167 + service_monitor 51)
---
## 3. 当前状态快照
### 3.1 代码层
- `server.py:107` 已有模块级 `app = create_app()` → gunicorn `server:app` 可直接加载,无需改
- 三个被测模块(`search_engine.py` / `safety_filter.py` / `cache_manager.py`)公开接口**未动**
- 离线改造**未碰** `service_manage.py` / `service_monitor.py`(隔离红线遵守)
### 3.2 测试基线
```
cd skill/code && python -m pytest -v
# 期望:218 passed
# 离线专项:python -m pytest tests/test_offline_mode.py -v → 22 passed
```
### 3.3 Git 状态
- 分支 `troubleshoot-ai-assistant`
- 最近提交:
- `b94d0230` feat(offline): 问题排查助手离线 Q&A 模式和容器化部署 ← **本模块本次交付**
- `c552a6b3` feat(service-monitor): 落地服务监测模块(service_monitor 组,非本模块)
- 工作区:本次交接时干净
---
## 4. 待办 / 下一步
| # | 事项 | 优先级 | 说明 |
|---|------|--------|------|
| 1 | **本地容器构建验证(T6)** | 中 | 需要 Docker 环境。`docker build -t troubleshoot:offline .` → run → 验 `/api/health` 返回 `offline_mode:true``search.mode:tfidf` |
| 2 | **部署到 5.60(T7)** | 中 | 5.60 已装 Docker,但当前会话网络不可达。`docker save | gzip` → scp → `docker load``docker compose up -d` |
| 3 | **前端适配 `offline:true`** | 低 | 后端已就绪,前端 index.html 需读 `offline:true` 显示「当前为离线模式」横幅;`analysis:null` 显示「无 AI 分析」提示。本期后端就绪即可,前端另行处理 |
| 4 | **gunicorn WORKDIR 实测** | 中 | Dockerfile WORKDIR 设为 `/app/web` 是推算值,T6 构建后看 `docker run` 启动日志确认能加载 `server` 模块 |
| 5 | **requirements 版本在 5.60 实测** | 低 | 现版本 `cryptography==46.0.7` / `paramiko==4.0.0` 以本地实测为准,5.60 构建时若解析失败再调 |
---
## 5. 关键坑点(踩过,不要再踩)
1. **向量文件静默降级**`搜索向量.json` 存在时 SearchEngine 会静默走 vector 模式,与「离线用 TF-IDF」矛盾。离线镜像**必须排除该文件**(.dockerignore 已处理)。部署后务必查 `/api/health``search.mode` 确认是 `tfidf`。详见 CLAUDE.md 避坑第 7 条。
2. **同进程依赖连累**:service_monitor 的 `utils/crypto.py` 模块级 `from cryptography.fernet import Fernet`,在 `create_app()` 阶段执行。镜像若缺 cryptography,**问题排查助手也起不来**。故 requirements 必须含 cryptography/paramiko(已补,见 §6)。
3. **analyze 与 troubleshoot 的 matched_cases 格式不同**:analyze 收前端传来的已格式化 dict(含 rank/score/project/title/file/phenomenon,**无 solution**);troubleshoot 是 engine.search() 原始结构(含 record,有 solution)。`build_offline_response` 已兼容两者,但改这个函数时要注意两条路径都测。
4. **`/api/analyze/stream` 是 GET 不是 POST**:参数走 URL query string。PRD 早期误写成 POST `/api/analyze_stream`,实际路由是 GET `/api/analyze/stream`。改路由时别改错。
5. **gunicorn 找模块靠 WORKDIR**`server:app` 要求 gunicorn 进程 CWD 在含 `server.py` 的目录(`/app/web`)。WORKDIR 设错会报 `Failed to find application object 'app'`
6. **offline_config 是进程级缓存**:改 `OFFLINE_MODE` env 后,已运行的进程不会感知,必须重启。测试时用 `reset_for_test()` 刷新。
---
## 6. 模块隔离边界(与 service_monitor 的关系)
**部署层隔离,非进程隔离**——这是最重要的架构事实。
- **代码层**:问题排查助手(`routes/troubleshoot.py` + `services/ai_service.py` + `utils/offline_config.py`)与 service_monitor 子包**无任何相互 import**。删掉 service_monitor,离线测试 22 用例不受影响(已验证)。
- **运行时**:同处一个 Flask 进程(`server.py::create_app()` 一次性注册全部 Blueprint)。邻居模块导入失败会连累整个进程启动。
- **依赖**:service_monitor 的 cryptography(模块级)/ paramiko(延迟)依赖必须随镜像一起提供,已补入仓库根 `requirements.txt`
- **PRD §4.6** 如实记录了这个设计妥协:部署层隔离 ≠ 进程隔离。
**隔离红线**(下次改离线功能时仍要遵守):
1. 改动范围仅限 `routes/troubleshoot.py``services/ai_service.py``utils/offline_config.py`
2. `OFFLINE_MODE` 只作用于问题排查助手路由,不影响 service_manage / service_monitor
3. 共享 `utils/*` / `auth.py` / `platform.py` 改动须对三模块无差别兼容
4. **禁止改** `service_manage.py` / `service_monitor.py`
---
## 7. 关键文件速查
```
问题排查助手代码:
skill/code/web/utils/offline_config.py # 离线开关
skill/code/web/services/ai_service.py # build_offline_response()
skill/code/web/routes/troubleshoot.py # 4 处离线分支
skill/code/tests/test_offline_mode.py # 22 用例
容器化:
Dockerfile / docker-compose.yml / requirements.txt / .dockerignore (仓库根)
文档:
Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手.md # PRD v2.2
Docs/离线部署方案/PRD_需求文档_离线部署方案_问题排查助手_计划执行.md # 执行计划
```
---
## 8. 环境变量清单(问题排查助手相关)
| 变量 | 用途 | 默认 |
|------|------|------|
| `OFFLINE_MODE` | 离线开关(true/1/yes → 离线) | 未设=在线 |
| `SECRET_KEY` | Flask session 密钥 | 未设则随机生成(生产必须设) |
| `CLAUDE_API_BASE` | Claude API 地址(在线模式用) | — |
| `CLAUDE_API_KEY` | Claude API key(在线模式用) | — |
| `FLASK_DEBUG` | 调试模式(1=开) | 1 |
---
## 9. 上次会话遗留的待确认项
- **无未决问题**。离线方案所有设计决策已在 PRD v2.2 闭合,代码已提交 b94d0230,测试全绿。
- 唯一悬而未决的是 **T6/T7 的部署验证**——等 Docker 环境就绪即可执行,不阻塞代码层。
---
> 本文档由问题排查助手模块开发者视角输出,便于下次会话追溯。service_monitor 模块的进展不在此列。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论