# AI 知识库系统 V2 部署手册

## 适用范围

本文档用于 V2 当前版本的部署交接。当前版本包含：

- 后端：FastAPI
- 用户端 H5：Vue 3
- 管理后台：Vue 3 + Element Plus
- 数据库：MySQL 8.x

## 部署前检查

1. 确认服务器已经安装 Docker 和 Docker Compose。
2. 确认 MySQL 数据目录有持久化卷或外部数据库。
3. 确认以下密钥不再使用开发默认值：
   - `JWT_SECRET_KEY`
   - `BOOTSTRAP_ADMIN_PASSWORD`
   - 模型 API Key
   - 飞书检索服务凭证或适配服务密钥
4. 确认防火墙只开放必要端口。
5. 确认已经执行数据库备份。

## 本地开发启动

```bash
cd ai_knowledge_base_v2
docker compose -f docker-compose.dev.yml up --build
```

## 生产环境启动

生产环境必须使用 `docker-compose.prod.yml`。先复制根目录 `.env.example` 为 `.env`，替换其中全部示例密码和密钥，再执行：

```bash
docker compose -f docker-compose.prod.yml config --quiet
docker compose -f docker-compose.prod.yml up -d --build
```

生产编排只向宿主机暴露统一网关端口；MySQL、Redis、后端、用户端和管理端均仅在容器网络内访问。用户端与管理端使用 Nginx 静态镜像，后端默认启动 4 个 worker。

`DATABASE_URL` 和 `REDIS_URL` 中的密码如包含 `@`、`:`、`/`、`#` 等特殊字符，必须先进行 URL 编码。`CONFIG_ENCRYPTION_KEY` 可通过以下命令生成，生成后必须妥善备份且不能随意更换：

```bash
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
```

如果用户端问答需要直读飞书知识库，优先在管理后台“系统设置 / 外部服务”中配置飞书 AppID 和 AppSecret，保存后即可生效，不需要重建容器。

也可以在启动前通过后端运行环境变量配置，作为系统设置为空时的兜底：

```bash
export FEISHU_APP_ID=你的飞书应用AppID
export FEISHU_APP_SECRET=你的飞书应用AppSecret
docker compose -f docker-compose.dev.yml up -d --build backend user-client admin-web
```

也可以在 `ai_knowledge_base_v2/.env` 中配置 `FEISHU_APP_ID`、`FEISHU_APP_SECRET` 和 `FEISHU_SEARCH_URL`。后台“知识库管理”只维护 SpaceID、NodeID 和启用状态；飞书应用凭证在后台“系统设置”维护，不存放在知识库记录中。若使用独立飞书检索适配服务，则在后台“系统配置”填写飞书检索服务地址，后端会优先调用该地址。

默认地址：

- 统一入口：`http://127.0.0.1:8080/`
- 用户端 H5：`http://127.0.0.1:8080/`
- 管理后台：`http://127.0.0.1:8080/login`
- 后端健康检查：`http://127.0.0.1:8080/api/health`
- 用户端直连调试：`http://127.0.0.1:5173/`
- 管理后台直连调试：`http://127.0.0.1:5174/login/`
- 后端直连调试：`http://127.0.0.1:8100/api/health`
- MySQL：`127.0.0.1:3307`

## 单域名访问

当前编排新增 `gateway` 服务作为统一入口。内网穿透时建议只穿透 `gateway:80`，域名路径分流如下：

```text
https://qa.huiyushuyuan.cn/        用户端 H5
https://qa.huiyushuyuan.cn/login   管理后台登录页
https://qa.huiyushuyuan.cn/api/... 后端 API
```

`.env` 中推荐配置：

```bash
FRP_PROXY_NAME=qa-web
FRP_LOCAL_IP=gateway
FRP_LOCAL_PORT=80
FRP_CUSTOM_DOMAINS=qa.huiyushuyuan.cn
```

## 本地开发初始化账号

用户端：

```text
手机号：任意 11 位手机号
验证码：123456
```

管理后台本地开发环境可通过环境变量初始化首个管理员，例如：

```text
账号：admin
密码：admin123456
```

生产环境不允许使用上述开发密码。正式部署前必须在 `.env` 或服务器环境变量中配置安全的 `BOOTSTRAP_ADMIN_USERNAME` 和 `BOOTSTRAP_ADMIN_PASSWORD`，并确认管理后台登录页不会预填账号密码。

## 数据库迁移

后端容器启动时会执行：

```bash
alembic upgrade head
```

如果需要手工执行：

```bash
cd apps/backend
alembic upgrade head
```

## 备份

备份脚本会生成压缩 SQL 和 SHA-256 校验文件，默认保留 14 天。密码只通过环境变量传入，不写入命令参数：

```bash
cd ai_knowledge_base_v2
MYSQL_PASSWORD='数据库密码' BACKUP_DIR=./backups ./scripts/mysql_backup.sh
```

恢复前应停止用户流量并再次备份当前数据库。恢复脚本要求显式确认，并会先验证校验和与压缩文件完整性：

```bash
MYSQL_PASSWORD='数据库密码' \
BACKUP_FILE='./backups/ai_knowledge_base_v2_YYYYMMDD_HHMMSS.sql.gz' \
RESTORE_CONFIRM=YES \
./scripts/mysql_restore.sh
```

恢复后必须检查迁移版本、`/api/ready`、管理员登录、用户登录和一次真实问答。备份文件与 `CONFIG_ENCRYPTION_KEY` 必须分别保存；只有数据库备份而没有对应加密密钥时，敏感配置无法解密。

## 周期报告后台任务

周期报告使用数据库保存任务状态，Redis 只用于限制多进程并发。服务重启后，等待中的任务会继续执行，超过 30 分钟仍处于执行中的任务会自动恢复并重试。

默认调度规则：

- 每周一 02:00（Asia/Shanghai）生成上一自然周周报；
- 每月 1 日 03:00（Asia/Shanghai）生成上一自然月月报；
- 只处理权益已开启周期报告、账号有效且该周期存在成功主题摘要的用户；
- 单个任务最多自动执行 3 次，失败后可在后台用户详情中手动重新生成。

可通过以下环境变量关闭或调整：

```text
PERIODIC_REPORT_WORKER_ENABLED=true
PERIODIC_REPORT_WEEKLY_ENABLED=true
PERIODIC_REPORT_MONTHLY_ENABLED=true
PERIODIC_REPORT_TIMEZONE=Asia/Shanghai
PERIODIC_REPORT_POLL_SECONDS=5
PERIODIC_REPORT_STALE_MINUTES=30
PERIODIC_REPORT_MAX_ATTEMPTS=3
```

## 主题沉淀后台任务

用户点击“沉淀本主题”后，接口只结束当前主题并创建持久化任务，不再等待模型生成主题摘要和近期实修回顾。用户可以立即继续聊天、切换会话或关闭页面。

任务状态保存在 `sys_topic_summary`：

- `pending`：等待后台执行；
- `running`：正在生成主题摘要和近期实修回顾；
- `success` / `fallback`：沉淀完成；
- `failed`：达到最大重试次数后仍失败，可在后台用户详情中手动重试。

多进程部署时 Redis 用于限制同一时间只有一个主题沉淀 Worker 执行，MySQL 负责持久化任务、幂等和失败重试。服务中断超过配置时间后，任务会自动恢复，不需要用户重复结束主题。

```text
TOPIC_SETTLEMENT_WORKER_ENABLED=true
TOPIC_SETTLEMENT_POLL_SECONDS=2
TOPIC_SETTLEMENT_STALE_MINUTES=30
TOPIC_SETTLEMENT_MAX_ATTEMPTS=3
```

## 多模型分流

模型管理现在区分两个概念：

- 可用模型：允许后台任务选择，可同时启用多个；
- 默认主模型：只能有一个，承担未分流的正式聊天、追问改写和检索重排。

周期实修回顾会选择“周期报告”能力已开启的可用模型，主题摘要和近期实修回顾会选择“摘要沉淀”能力已开启的可用模型。若找不到匹配模型，会自动回退默认主模型，不会因为分流配置缺失直接中断任务。

正式问答的分流规则在“系统配置 / AI 问答 / 正式问答模型分流规则”中配置：

- 关闭分流：全部正式问答使用默认主模型；
- 仅固定信息（升级后的默认值）：只有本轮最终召回并采用的知识全部属于固定信息类时，才选择“固定信息”能力模型；
- 保守分流：在上一条基础上，把短、明确、只命中课程/问答/通用知识，且不涉及个人感受、关系、建议或判断的问题交给“简单知识”能力模型。

混合固定信息、未命中、深度问题和个人化问题始终使用默认主模型。场景模型在尚未输出任何内容前调用失败，会自动重试默认主模型；已经输出部分内容后不会重新生成，避免重复内容。

部署迁移后，旧版本原来启用的模型会自动成为默认主模型。新增其他模型时建议按以下顺序操作：

1. 保存模型并执行“测试”；
2. 加入可用池；
3. 只勾选它实际承担的能力；
4. 如需让低成本模型承担某一场景，应取消默认主模型的对应能力，并在专用模型上开启该能力，避免默认模型优先命中；
5. 在数据看板“模型使用与成本”中核对实际模型和成本。

如线上发现分流模型质量或稳定性异常，可把“正式问答模型分流规则”改为“关闭分流”，下一次提问立即恢复为默认主模型，无需重新部署。后台 Agent 预览选择默认主模型时会复用正式分流规则；显式选择非默认模型时视为人工调试覆盖，不执行自动分流。旧版本的 `fixed_info_model_routing_enabled` 开关仍兼容，但保存新规则后以 `chat_model_routing_mode` 为准。

停用或删除唯一默认主模型会被后端拒绝，必须先启用并设置替代主模型。该限制用于避免生产聊天突然变成无模型可用。

## 回滚原则

1. 先停止新版本服务。
2. 切回上一版镜像或上一版 Git commit。
3. 如果数据库迁移不可逆，先从备份恢复。
4. 恢复后检查：
   - `/api/health`
   - 用户端登录
   - 用户端提问
   - 管理后台登录
   - 管理后台数据列表

## 监控与告警

应用提供两类探针：

- `/api/health`：进程存活检查，不访问外部依赖。
- `/api/ready`：流量就绪检查，同时验证 MySQL 和 Redis；任一必需依赖不可用时返回 HTTP 503。

建议上游监控系统每 30 秒访问一次 `/api/ready`，连续 3 次失败触发告警。日志采集系统按容器标准输出采集单行 JSON，并至少对以下情况告警：

- 5 分钟内 HTTP 5xx 比例超过 2%。
- `/api/ready` 连续失败。
- AI 请求超时或外部服务错误持续增长。
- 周期报告任务持续失败、长期停留在“生成中”或队列持续积压。
- 问答队列持续接近上限或频繁拒绝请求。
- MySQL、Redis 容器重启或磁盘使用率超过 80%。
- 定时备份任务失败、校验文件缺失或超过 24 小时没有新备份。

用户反馈错误时，优先获取响应头 `X-Request-ID`，再到日志平台检索同一请求 ID。发布完成后执行：

```bash
BASE_URL=https://qa.huiyushuyuan.cn ./scripts/production_smoke_test.sh
```

## 生产待补事项

- 在域名入口或上游反向代理配置 HTTPS 证书。
- 接入集中式结构化日志、主机与容器指标监控和异常告警。
- 根据正式流量压测结果调整 worker、数据库连接池和问答队列参数。
- 定期执行数据库备份和恢复演练，并单独备份 `CONFIG_ENCRYPTION_KEY`。
