Files

398 lines
17 KiB
Markdown
Raw Permalink Normal View History

# 快速回复规则后台管理 — 部署文档
> **需求编号**: REQ-通用-002
> **版本**: v1.22026-07-28 管理后台 UI 去重调整)
> **日期**: 2026-07-27(初版) / 2026-07-28v1.1 整改、v1.2 UI 调整)
> **状态**: [已评审]
> **作者**: Simon
> **部署服务器**: itsupport.servyou.com.cn (10.90.5.110)
>
> **关联文档**(按规范要求补全):
> - PRD`01-产品文档/00-产品规划/PRD-REQ-通用-002-快速回复规则后台管理-v1.2.md`
> - 技术方案:`02-技术文档/技术方案-REQ-通用-002-快速回复规则后台管理.md`
> - 原型图:`01-产品文档/01-02产品设计/快速回复规则后台管理-原型图.html`
> - 上游依赖:Alembic 055 迁移(`alembic upgrade 055`)、`scripts/init_quick_rules.sql`
>
> **命名规范说明**:按 `docs/00-产品开发流程与文档管理规范.md` 2.3.3 节,标准命名应为
> `DEPLOY-REQ-通用-002-快速回复规则后台管理-v1.0.md`,应放置在 `04-运维文档/部署运维/` 子目录下。
> 本次保留历史文件名/位置以避免破坏现有内部引用;**后续同类文档请按规范命名**。
---
## 0. 前置条件(部署前必须 100% 确认)
| 检查项 | 要求 | 验证方式 |
|--------|------|----------|
| 关联 PRD | 已评审、当前为 [已评审] 状态 | `Read docs/01-产品文档/00-产品规划/PRD-REQ-通用-002-快速回复规则后台管理-v1.2.md` |
| 关联技术方案 | 已评审 | `Read docs/02-技术文档/技术方案-REQ-通用-002-快速回复规则后台管理.md` |
| 关联原型图 | 已评审(本次涉及 6 个新页面,必须有) | 打开 `docs/01-产品文档/01-02产品设计/快速回复规则后台管理-原型图.html` |
| Alembic 迁移文件 | `alembic/versions/055_*.py` 已存在 | `ls alembic/versions/ | grep -i quick` |
| 初始化 SQL | `scripts/init_quick_rules.sql` 已就绪且 ≥ 53 条 | `wc -l scripts/init_quick_rules.sql` |
| jumpserver-V2 skill | 已登录且缓存有效 | 跑 `v2_ops.py status` |
| 服务器 `.env` | `.env` 已同步 `QUICK_RULE_*` 类变量(见 §1.3 | `grep -E "^QUICK_RULE_" .env` |
| 后端镜像 | `--workers 1` 已写入 `docker-compose.yml` | `grep -E "workers" docker-compose.yml` |
| 部署窗口 | 已与值班坐席同步,选低峰期 | 口头/IM 通知 |
---
## 1. 部署概览
### 1.1 部署范围
| 模块 | 状态 | 说明 |
|------|------|------|
| 数据库表 | 新增 2 张 | `quick_rules``quick_rule_audit_log` |
| 后端 API | 新增 12 个 | `/api/admin/quick-rules/*`(见技术方案 §3 |
| 前端页面 | 新增 6 个 | `/quick-rules/*`admin 端 1 个 H5/坐席端不涉及) |
| 现有代码改造 | 2 处 | `ai_handler.py``routing_service.py`(向后兼容:DB 为空时回退硬编码) |
| **本版本不涉及** | - | agent 端、H5 端、terminal 端无需重新打包 |
### 1.2 规则类型与初始数量(单一权威来源,§5 验证时直接引用此处)
| rule_type | 初始条数 | 兜底硬编码条数 |
|-----------|----------|----------------|
| `greeting` | 12 | 1 条("你好" → 引导描述问题) |
| `routing_prefilter` | 33 | 3 条 |
| `routing_target` | 6 | 2 条 |
| **合计** | **51** | **6** |
### 1.3 `.env` 变量变更清单(配置同步铁律,必须同步)
> 部署铁律:修改 `config.py` 默认值 ≠ 配置生效,必须同步更新服务器 `.env`。
| 变量名 | 用途 | 默认值 | 来源 |
|--------|------|--------|------|
| `QUICK_RULE_AUTO_APPLY_THRESHOLD` | 智能体自动应用规则的置信度阈值 | `0.85` | config.py |
| `QUICK_RULE_AUDIT_REVIEW_THRESHOLD` | 落入待审核的阈值 | `0.5` | config.py |
| `QUICK_RULE_CACHE_TTL_SECONDS` | Redis 缓存 TTL | `300` | config.py |
服务器部署完成后必须执行:
```bash
# 通过 v2_ops.py 上传 .env 增量文件
v2_ops.py upload .env.production-increment .env.production-increment
# 远端追加(注意:此处禁用 $(date),用预生成时间戳文件名)
ssh-via-jms 'cat /tmp/.env.production-increment >> /opt/wecom-it-desk/.env'
# 重载后端使新变量生效
docker compose --env-file .env restart backend
```
### 1.4 部署顺序(部署铁律)
```
DB migrationalembic upgrade)→ .env 同步 → 后端 coderestart)→ 前端 adminpsftp + restart nginx)→ 端到端验证 → 灰度
```
---
## 2. 数据库迁移
### 2.1 备份(v2_ops.py / psftp 双通道)
```bash
# 1. 登录堡垒机(jumpserver-V2 skill
v2_ops.py login
# 2. 服务器端生成备份文件名(禁用 $(...),预生成)
TIMESTAMP=$(date +%Y%m%d_%H%M%S) # 本地 PowerShell 生成后再传入
ssh-via-jms "docker exec wecom_it_postgres pg_dump -U postgres -d wecom_it_desk -Fc > /opt/wecom-it-desk/backups/before-quickrule-${TIMESTAMP}.dump"
```
### 2.2 执行迁移(按部署铁律:DB migration 只能逐版降)
```bash
# 1. 检查当前版本
ssh-via-jms "docker exec wecom_it_backend alembic current"
# 2. 升级到目标版本(升级用 head,向前兼容)
ssh-via-jms "docker exec wecom_it_backend alembic upgrade 055"
# 3. 验证:checkfirst 自动建表是否成功(主要依赖 alembic,但作为冗余验证)
ssh-via-jms "docker exec wecom_it_postgres psql -U postgres -d wecom_it_desk -c '\\dt quick_rules*'"
# 期望输出:
# quick_rule_audit_log
# quick_rules
# 4. 插入初始化数据(psftp 通道,禁用 elFinder
v2_ops.py upload scripts/init_quick_rules.sql init_quick_rules.sql
ssh-via-jms "cat /tmp/init_quick_rules.sql | docker exec -i wecom_it_postgres psql -U postgres -d wecom_it_desk -v ON_ERROR_STOP=1"
```
> ⚠️ **降级路径**(回滚时使用):蓝绿共用同一 PG,本次只能逐版降
> ```bash
> ssh-via-jms "docker exec wecom_it_backend alembic downgrade -1"
> # 重复执行直到 quick_rules 表消失
> ssh-via-jms "docker exec wecom_it_postgres psql -U postgres -d wecom_it_desk -c '\\dt quick_rules*'"
> ```
### 2.3 验证
```sql
-- 单一权威断言:本表数字一旦修改,§1.2 同步修改
SELECT rule_type, COUNT(*) FROM quick_rules WHERE is_active = true GROUP BY rule_type ORDER BY rule_type;
-- 期望:greeting=12, routing_prefilter=33, routing_target=6
```
---
## 3. 后端部署
### 3.1 部署(卷挂载 → restart 即可)
```bash
# 后端代码统一源:/opt/wecom-it-desk/app/(卷挂载)
# .py 变更仅 restart,不必 rebuild
v2_ops.py upload src/backend/app/models/quick_rule.py /tmp/quick_rule.py
v2_ops.py upload src/backend/app/models/quick_rule_audit_log.py /tmp/quick_rule_audit_log.py
v2_ops.py upload src/backend/app/services/quick_rule_service.py /tmp/quick_rule_service.py
v2_ops.py upload src/backend/app/api/admin/quick_rules.py /tmp/quick_rules.py
v2_ops.py upload src/backend/app/services/ai_handler.py /tmp/ai_handler.py
v2_ops.py upload src/backend/app/services/routing_service.py /tmp/routing_service.py
ssh-via-jms 'for f in quick_rule.py quick_rule_audit_log.py quick_rule_service.py quick_rules.py ai_handler.py routing_service.py; do
if [ -f /tmp/$f ]; then
cp /tmp/$f /opt/wecom-it-desk/app/$(echo $f | sed "s|^|models/|; s|quick_rule_audit_log.py|models/&|; s|quick_rule_service.py|services/&|; s|quick_rules.py|api/admin/&|; s|ai_handler.py|services/&|; s|routing_service.py|services/&|")
fi
done'
# 必须保证 workers=1(部署铁律:多 worker 会致 WS 消息丢失)
ssh-via-jms "docker compose --env-file .env up -d --force-recreate --no-deps backend"
# 或:ssh-via-jms "docker compose restart backend"
# 探活
sleep 5
ssh-via-jms "docker exec wecom_it_backend python -c \"from app.models.quick_rule import QuickRule; print('OK', QuickRule.__tablename__)\""
```
### 3.2 启动期验证
```bash
# 1. 后端探活(外部)
curl -fsS http://itsupport.servyou.com.cn/health
# 2. Swagger 文档(确认 quick-rules 路由注册)
curl -fsS http://itsupport.servyou.com.cn/docs | grep quick-rules
# 3. 后端日志:必须看到 QuickRuleService.load_all 成功
ssh-via-jms "docker logs wecom_it_backend --tail 200 2>&1 | grep -i 'quick_rule\\|loaded.*rules'"
# 期望:loaded 51 rules (12 greeting, 33 routing_prefilter, 6 routing_target)
```
### 3.3 业务侧验证(端到端、容器外,验证铁律)
```bash
# 获取 token
TOKEN=$(curl -s -X POST http://itsupport.servyou.com.cn/api/admin/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"simon","password":"<OTP>"}' | jq -r .data.token)
# 1. stats 接口
curl -fsS http://itsupport.servyou.com.cn/api/admin/quick-rules/stats \
-H "Authorization: Bearer $TOKEN" | jq .
# 期望:{ "code":0, "data":{ "greeting":12, "routing_prefilter":33, "routing_target":6, "total":51 } }
# 2. 列表接口(greeting
curl -fsS "http://itsupport.servyou.com.cn/api/admin/quick-rules?rule_type=greeting&limit=5" \
-H "Authorization: Bearer $TOKEN" | jq '.data | length'
# 期望:5
```
---
## 4. 前端部署(仅 admin 端)
### 4.1 本地构建(ASCII 路径,前端构建 SOP)
```bash
# 本地路径必须纯 ASCIID:\资料\路径下 pnpm install 会卡死)
cd D:\dev\wecom\src\frontend-admin
# 多路径同步铁律:中文路径下 D:\资料\03-项目开发\wecom_it_smart_desk 也要同步改
# 否则 vite build 用的是 ASCII 路径下的旧代码
npm install # 不要用 pnpm install
npm run build # 产物在 dist/
Compress-Archive -Path dist -DestinationPath dist-quickrules-v1.0.zip
```
### 4.2 上传与部署(psftp 通道,禁止 elFinder
```bash
# 1. 上传 zip
v2_ops.py upload D:\dev\wecom\src\frontend-admin\dist-quickrules-v1.0.zip dist-quickrules-v1.0.zip
# 2. 服务器端解压到 bind mount 目录(unzip 会直接产出 assets/ + index.html
ssh-via-jms 'cd /opt/wecom-it-desk/frontend-admin/dist-new && unzip -o /tmp/dist-quickrules-v1.0.zip'
ssh-via-jms 'rm -rf /opt/wecom-it-desk/frontend-admin/dist && mv /opt/wecom-it-desk/frontend-admin/dist-new /opt/wecom-it-desk/frontend-admin/dist'
# 3. ★ 必须显式重启 nginxbind mount 不会自动刷新新文件)
ssh-via-jms 'docker restart wecom_it_nginx'
# 4. 验证
curl -fsS http://itsupport.servyou.com.cn/itadmin/quick-rules | head -c 200
# 期望:HTML 200 OKtitle 含 "快速回复"
```
### 4.3 浏览器自测(agent-browser skill
```bash
# 走 agent-browser 技能自动化测试,至少覆盖:
# 1) /itadmin/quick-rules 列表加载
# 2) /itadmin/quick-rules/greeting 编辑一条规则、断言持久化
# 3) /itadmin/quick-rules/audit 审计日志可见
# 4) 模拟"用户你好"→ 期望 AI 引导描述(不调用 Dify)
```
---
## 5. 端到端回归验证(验证铁律:容器内通过≠外部可用)
| # | 场景 | 输入 | 期望输出 | 验证方式 |
|---|------|------|----------|----------|
| T1 | 打招呼走 quick_rule,不调用 Dify | Mock 用户发"你好" | AI 回复引导描述问题,diffy_call_count=0 | WebSocket mock + logs |
| T2 | 路由触发命中 quick_rule | Mock 用户发"打印机连不上" | 命中 prefilter→target,发送名片卡片 | 卡片 payload + 路由日志 |
| T3 | 普通问题走 Dify(兼容路径) | Mock 用户发"电脑蓝屏了" | 走 Dify 主推理,diffy_call_count=1 | Dify 调用日志 |
| T4 | 兜底:清空 DB → 重启后仍可用 | `DELETE FROM quick_rules; docker compose restart backend` | 行为不中断,加载日志 "fallback to hardcoded" | 启动日志 + 业务接口 |
| T5 | 缓存刷新 | POST `/api/admin/quick-rules/refresh` | 60s 内 Redis keys 变化 | `redis-cli KEYS quick_rules:*` |
具体执行命令见配套测试用例 `TC-快速回复规则后台管理.md`**待补,需建**)。
---
## 6. 灰度上线
### 6.1 灰度开关(env + 代码双层)
| 开关 | 默认 | 启用时效果 |
|------|------|-----------|
| `QUICK_RULE_ENABLED`(env,**本次新增,必须加**) | `true` | `false` 时完全走硬编码兜底 |
| `QUICK_RULE_AUTO_APPLY_THRESHOLD` | `0.85` | 调高(如 `0.99`)等于关闭自动应用 |
| `QUICK_RULE_AUDIT_REVIEW_THRESHOLD` | `0.5` | 调高(如 `0.9`)等于全部走待审核 |
### 6.2 灰度策略
| 阶段 | 时长 | 动作 | 监控重点 |
|------|------|------|----------|
| Phase 1 观察期 | 1-3 天 | 启用新规则,日志标 `quick_rule.hit` | API 成功率、命中占比 |
| Phase 2 人工编辑期 | 4-7 天 | 运营通过后台编辑 | 误判率、日志异常 |
| Phase 3 完全替代 | 7 天+ | 保留硬编码兜底 | 同上 |
### 6.3 回滚(完整三路回滚)
```bash
# Step 1:DB 回滚(降级,按部署铁律:只 downgrade 不 drop 备份)
ssh-via-jms "docker exec wecom_it_backend alembic downgrade -1"
# Step 2:清空规则(保留表结构,使代码加载硬编码兜底)
ssh-via-jms "docker exec -i wecom_it_postgres psql -U postgres -d wecom_it_desk -c \"DELETE FROM quick_rules;\""
# Step 3:后端代码回滚(git)
ssh-via-jms "cd /opt/wecom-it-desk && git log --oneline -5"
ssh-via-jms "cd /opt/wecom-it-desk && git revert --no-edit HEAD"
# Step 4:前端 dist 回滚
v2_ops.py upload archives/frontend-admin-dist-v*.zip rollback.zip
ssh-via-jms 'cd /opt/wecom-it-desk/frontend-admin && rm -rf dist && mkdir dist && cd dist && unzip /tmp/rollback.zip'
ssh-via-jms 'docker restart wecom_it_nginx'
# Step 5:环境变量回滚(可选,但建议保持 0 风险)
# 在 .env 中 QUICK_RULE_ENABLED=falserestart backend
```
---
## 7. 监控指标
### 7.1 关键指标(明确阈值,可告警)
| 指标 | 采集方式 | 告警阈值 | 通知渠道 |
|------|---------|----------|----------|
| `/api/admin/quick-rules/*` 调用成功率 | nginx access log 5xx 占比 | > 1% | 企微机器人 |
| 规则加载耗时(启动期) | `docker logs wecom_it_backend` | > 3s | 日志告警 |
| 缓存命中率 | `INFO logs/smart_desk.log``quick_rule.hit / quick_rule.miss` | < 70%24h 均值) | 企微机器人 |
| 兜底触发次数 | 日志 `quick_rule.fallback` | 24h 内 > 100 | 企微机器人 |
| 自动应用次数突增 | `quick_rule_audit_log` | 1h 内 > 50 | 企微机器人 |
| Alembic 迁移失败 | 启动日志 | 任意 1 次 ERROR | P1 告警 |
### 7.2 日志查询 SOP
```bash
# 启动期规则加载
ssh-via-jms "docker logs wecom_it_backend --since 10m 2>&1 | grep -i 'quick_rule'"
# 命中/兜底实时监控
ssh-via-jms "tail -f /opt/wecom-it-desk/logs/wecom-it-desk.log | grep quick_rule"
# Redis 缓存
ssh-via-jms "docker exec wecom_it_redis redis-cli KEYS 'quick_rules:*'"
```
---
## 8. 常见问题
### Q1:数据库表已存在错误(原文"数据库插件已存在错误"为错别字)
```text
错误:relation "quick_rules" already exists
原因:alembic 055 已成功建表,重复执行会触发
解决:属正常现象,跳过或继续下一步
```
### Q2:初始化数据重复插入失败
```text
错误:duplicate key value violates unique constraint
原因:脚本已使用 ON CONFLICT DO NOTHING,重复执行安全
解决:直接忽略;如需强制重置,先 TRUNCATE quick_rules
```
### Q3:缓存未刷新
```bash
curl -X POST "http://itsupport.servyou.com.cn/api/admin/quick-rules/refresh" \
-H "Authorization: Bearer $TOKEN"
# 或直接清 Redis
ssh-via-jms "docker exec wecom_it_redis redis-cli DEL $(docker exec wecom_it_redis redis-cli KEYS 'quick_rules:*' | tr '\n' ' ')"
```
### Q4:规则加载后业务侧未生效
```text
排查路径:
1) docker logs wecom_it_backend | grep "loaded.*rules" 确认 51 条加载
2) curl /api/admin/quick-rules/stats 确认 DB 与 API 一致
3) tail logs/wecom-it-desk.log | grep quick_rule.fallback 看是否走兜底
4) REDIS 缓存是否过期(TTL 默认 300s),可手动 DEL 后重试
```
### Q5:缓存验证时找不到 admin token
```bash
TOKEN=$(curl -s -X POST http://itsupport.servyou.com.cn/api/admin/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"simon","password":"<OTP>"}' | jq -r .data.token)
```
### Q6:前端 dist 更新后页面没刷新
```text
原因:bind mount 不会自动同步;nginx 也不会主动重读
解决:必须 docker restart wecom_it_nginx
```
---
## 9. 变更记录
| 日期 | 版本 | 变更内容 | 变更人 | 变更原因 | 影响范围 |
|------|------|----------|--------|----------|----------|
| 2026-07-27 | v1.0 | 初版 | Simon | 新功能首次上线 | - |
| 2026-07-28 | v1.1 | 整改:补全头部模板/关联文档/前置条件/.env变更清单/回滚三路方案/灰度开关/可执行验证命令;修复 `ssh sxn@``$(date)`、elFinder 三处命令级错误;命名规范说明追加 | Simon | 复盘发现不符合规范 §2.3/§5.2 + 命令违反部署铁律 | 本文档全部重写,零代码变更 |
| 2026-07-28 | v1.2 | 管理后台 `/quick-rules` 顶部 3 张重复统计卡片移除,仅保留标签导航及 count 徽标;后端 stats 接口与部署流程保持不变 | Simon | 页面信息冗余 | 仅管理后台前端展示,部署位置与流程不变 |