# 快速回复规则后台管理 — 部署文档 > **需求编号**: REQ-通用-002 > **版本**: v1.2(2026-07-28 管理后台 UI 去重调整) > **日期**: 2026-07-27(初版) / 2026-07-28(v1.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 migration(alembic upgrade)→ .env 同步 → 后端 code(restart)→ 前端 admin(psftp + 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":""}' | 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 # 本地路径必须纯 ASCII(D:\资料\路径下 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. ★ 必须显式重启 nginx(bind 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 OK,title 含 "快速回复" ``` ### 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=false,restart 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":""}' | 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 | 页面信息冗余 | 仅管理后台前端展示,部署位置与流程不变 |