# 任务说明书 03 — 敏感词检测 v1.1(词库入库 + 后台 UI) > **任务编号**: v1.1 增量(关联任务 #81 延后项) > **版本**: v1.1 > **创建日期**: 2026-07-28 > **作者**: 宋献 > **关联 PRD**: `docs/01-产品文档/00-产品规划/PRD-REQ-通用-004-敏感词检测-v1.0.md` > **关联技术方案**: `docs/02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.md` > **关联测试用例**: `docs/03-测试文档/03-功能测试用例/TC-通用-004-敏感词检测.md` > **关联数据迁移**: `src/backend/alembic/versions/056_add_moderation_tables.py` > **关联源码**: `src/backend/app/services/content_moderation_service.py` > **基础版本**: v0.7.1(已上线,命中即 WARN,词库写死 4 条) --- ## 📋 任务概览 | 项目 | 内容 | |------|------| | **任务名** | 敏感词检测 v1.1 — 词库入库 + 后台 UI | | **目标** | 把 v0.7.1 写死的 4 条基础词和 4 类隐私正则,**迁移到 PostgreSQL 数据库**,并**开发管理后台 UI**,让运营可自主增删改查、可热加载、可配置命中动作 | | **优先级** | 🟠 P1(v0.7.1 已上线,**WARN 策略可接受**,v1.1 是优化) | | **类型** | 功能开发(数据库 + 后端 + 前端) | | **估时** | 1 人天(数据库 0.2d + 后端 0.4d + 前端 0.3d + 部署 0.1d) | | **阻塞项** | 无(#81 延后项已部分解决,剩余 UI 部分 v1.1 完成) | | **风险等级** | 🟡 中(DB 切换需双轨降级,避免业务中断) | --- ## 🎯 任务背景 ### 现状(v0.7.1) - ✅ 已上线:内容审核服务(`content_moderation_service.py`) - ⚠️ 写死 4 条敏感词:运营无法调整 - ⚠️ 写死 4 类隐私正则:无法扩展 - ⚠️ 命中动作固定 WARN:决策保留(v1.0 不升级 BLOCK) - ⚠️ 后台 UI 缺失:运营改词必须改代码 - ⚠️ 无审计日志:合规追溯缺失 - ⚠️ TC-202 P0 延后项"中文+号码"已修复验证(`(?`src/backend/app/models/privacy_pattern.py`
`src/backend/app/models/moderation_log.py` | SQLAlchemy ORM 模型 | | 1.4 | `__init__.py` 注册 | `src/backend/app/models/__init__.py` | **必须在 __init__.py 注册,否则 Alembic 检测不到**(参考 055 教训) | ### 2. 后端服务(0.4d) | # | 交付物 | 路径 | 说明 | |---|--------|------|------| | 2.1 | 重构内容审核服务 | `src/backend/app/services/content_moderation_service.py` | **双轨加载**:DB 有数据 → 加载 DB;DB 空 → 降级写死 4 词。**保留** v0.7.1 修复(数字边界 + 顺序调整) | | 2.2 | 敏感词管理服务 | `src/backend/app/services/admin/sensitive_word_service.py`(新) | 增删改查 + 批量导入 + 命中测试 | | 2.3 | 隐私正则管理服务 | `src/backend/app/services/admin/privacy_pattern_service.py`(新) | 增删改查 + 正则测试器 | | 2.4 | 审计日志查询服务 | `src/backend/app/services/admin/moderation_log_service.py`(新) | 分页查询 + 搜索过滤 | | 2.5 | 命中动作配置服务 | `src/backend/app/services/admin/moderation_config_service.py`(新) | GET/PUT 全局配置(v1.1 保留 WARN 不升级) | | 2.6 | 4 路由文件 | `src/backend/app/api/admin/sensitive_words.py`
`src/backend/app/api/admin/privacy_patterns.py`
`src/backend/app/api/admin/moderation_logs.py`
`src/backend/app/api/admin/moderation_config.py` | 共 12 端点 | | 2.7 | main.py lifespan 钩子 | `src/backend/app/main.py` | 启动时调用 `load_moderation_words()` 加载 DB 词库 | | 2.8 | pytest 15 用例 | `src/backend/tests/test_content_moderation.py` | **已补**:TC-202~207,**15/15 通过**(含 P0 延后项修复) | ### 3. 前端 UI(0.3d) | # | 交付物 | 路径 | 说明 | |---|--------|------|------| | 3.1 | API 封装 | `src/frontend-admin/src/api/sensitiveWord.ts` | 12 端点 + TypeScript 类型 | | 3.2 | 词库管理页 | `src/frontend-admin/src/views/admin/SensitiveWords.vue` | 表格 + 增删改查 + 命中测试输入框 | | 3.3 | 隐私正则页 | `src/frontend-admin/src/views/admin/PrivacyPatterns.vue` | 表格 + 正则测试器(实时匹配) | | 3.4 | 命中配置页 | `src/frontend-admin/src/views/admin/ModerationConfig.vue` | severity 1-3 档可视化配置(v1.1 锁 WARN) | | 3.5 | 审计日志页 | `src/frontend-admin/src/views/admin/ModerationLogs.vue` | 分页 + 搜索(按 agent_id/action/时间) | | 3.6 | 路由注册 | `src/frontend-admin/src/router/index.ts` | 4 路由 + sidebar 菜单项 | | 3.7 | 样式 | 复用快速回复规则后台卡片样式 | 避免重复设计 | ### 4. 部署与文档(0.1d) | # | 交付物 | 路径 | 说明 | |---|--------|------|------| | 4.1 | 部署 SOP | `docs/04-运维文档/部署运维/部署SOP-敏感词v1.1.md` | AST 校验 + jumpserver-V2 + alembic upgrade + restart + 验证 | | 4.2 | 本任务说明书 | `docs/07-项目管理/任务说明书/任务说明书-03-v1.1-敏感词词库入库+后台UI.md` | **当前文档** | | 4.3 | 任务 #81 状态更新 | `docs/07-项目管理/任务说明书/IT智能服务台-项目管理主文档.md` | 标 #81 部分完成(中文+号码修复 + bank_card 修复),v1.1 子任务完成 | --- ## ✅ 验证方式 ### 单元测试 ```bash cd src/backend pytest tests/test_content_moderation.py -v # 期望:15 passed ``` ### 数据库迁移验证 ```bash # 1. 升级迁移 alembic upgrade head # 期望:无错误 # 2. 验证表创建 psql -d wecom_it_db -c "\dt sensitive_words" psql -d wecom_it_db -c "\dt privacy_patterns" psql -d wecom_it_db -c "\dt moderation_logs" # 期望:3 表都存在 # 3. 验证初始数据 psql -d wecom_it_db -c "SELECT word, category, severity FROM sensitive_words WHERE is_active = TRUE" # 期望:4 行(投诉我/你爱找谁找谁/自己不会百度吗/这点小事) psql -d wecom_it_db -c "SELECT name, pattern FROM privacy_patterns WHERE is_active = TRUE" # 期望:4 行(phone/id_card/bank_card/personal_email) ``` ### 端到端测试(jumpserver-V2 部署后) 1. **坐席端发消息命中 WARN**(端到端必做) - Mock 登录坐席 - 发送"自己不会百度吗" - 期望:返回 WARN + matched_words 含该词 2. **后台 UI CRUD**(4 子页各做一次) - 词库管理:增 → 查 → 改 → 删 - 隐私正则:增(带正则测试器)→ 查 → 改 → 删 - 命中配置:GET / PUT(验证仍锁 WARN) - 审计日志:分页 + 搜索 3. **降级兜底测试**(关键) - 临时清空 `sensitive_words` 表(`UPDATE sensitive_words SET is_active = FALSE`) - 重启后端 - 期望:服务仍能审核(降级为写死 4 词) ### 灰度监控(上线后 24h) | 指标 | 阈值 | 告警方式 | |------|------|----------| | 词库加载日志 | "Loaded N sensitive words from DB" 出现 | 应用日志(grep) | | 降级告警 | "No sensitive words in DB, fallback to hardcoded" 不应出现 | 应用日志(告警) | | 命中率 | 0.5% < 命中率 < 5%(正常区间) | Prometheus(v1.1 加) | | 接口 P99 | < 100ms | 应用日志 | | 异常率 | < 0.1% | Prometheus | --- ## 🎯 完成标准 ### 必达项 - [x] pytest 15/15 通过(含 TC-202 中文+号码 P0 延后项) - [x] Alembic 056 迁移成功(3 表 + 4 词 + 4 正则初始数据) - [x] 启动时从 DB 加载词库(`Loaded 4 sensitive words from DB` 日志) - [x] DB 清空时降级为写死 4 词(业务不中断) - [x] 12 端点可访问(4 路由文件 + admin 权限校验) - [x] 4 前端子页可访问(路由 + sidebar 菜单) - [x] 命中动作仍锁 WARN(v0.7.1 决策保留,不升级 BLOCK) - [x] 审计日志写入 `moderation_logs` 表 - [x] 上线后 24h 监控无 ERROR 日志 ### 决策保留项(不达标但已接受) - [ ] 命中动作可配置(v1.1 锁 WARN,v1.2 再考虑可配置化) - [ ] 词库热加载(v1.1 仅启动加载,改词需重启;v1.2 加 60s 热加载) - [ ] 词库导入导出(v1.1 仅手动增删;v1.2 加 CSV 导入) ### 跨任务铁律 - [ ] 修改 .py 后 **AST 静态校验**(防语法错误导致容器启动失败) - [ ] 通过 **jumpserver-V2** 部署(不用 elFinder/base64 老通道) - [ ] 本地 Windows 路径(`D:\资料\...`)和 ASCII 路径(`D:\dev\wecom`)**两边都改** - [ ] 三处同步铁律:config.py 字段 + docker-compose.yml 注入 + .env.example 模板 --- ## ⚠️ 风险与降级 | 风险 | 等级 | 降级措施 | |------|------|----------| | **DB 切换导致服务挂掉** | 🟠 高 | **双轨加载**:DB 加载失败/为空 → 自动降级写死 4 词(与 v0.7.1 行为一致) | | **Alembic 056 迁移失败** | 🟡 中 | Init SQL 应急脚本(`scripts/init_moderation.sql`),手动执行 | | **运营误删所有词** | 🟡 中 | 双轨降级:DB 词库为空时仍可用 | | **正则改坏导致误报** | 🟡 中 | UI 提供"正则测试器",保存前必须看到命中结果 | | **审计日志爆炸增长** | 🟢 低 | 30 天后归档(v1.2 加) | | **前端改路由导致 404** | 🟡 中 | 部署前本地 build 验证(`npm run build`)+ curl `/itadmin/sensitive-words` 200 | | **多路径同步遗漏** | 🟠 高 | 部署前 diff 中文路径和 ASCII 路径,**必须两边都改**(工作记忆铁律) | ### 回滚方案 ```bash # 1. 回滚 Alembic 迁移 alembic downgrade -1 # 删除 sensitive_words / privacy_patterns / moderation_logs 3 表 # 2. 代码回滚 docker restart wecom_it_backend # v0.7.1 代码(已挂载卷,无需重建) # content_moderation_service.py 双轨加载逻辑会检测到表不存在,降级写死 4 词 # 3. 前端回滚 # 用 dist-*.zip 旧版(保留至少 2 个) ``` --- ## 📅 实施时间表(建议) | 时段 | 工作 | 产出 | |------|------|------| | Day 1 AM | 数据库(056 迁移 + 4 模型 + __init__ 注册) | 3 表 + 4 词 + 4 正则 | | Day 1 PM | 后端服务(重构 + 4 service + 4 路由) | 12 端点 + 双轨加载 | | Day 2 AM | 前端 UI(4 子页 + 路由 + API) | 4 页面可访问 | | Day 2 PM | 部署 + 验收(AST + jumpserver-V2 + E2E) | 生产上线 | | Day 3 | 24h 监控 + 收尾 | 任务关闭 | --- ## 📎 关联文档 | 文档 | 位置 | |------|------| | 关联 PRD | `docs/01-产品文档/00-产品规划/PRD-REQ-通用-004-敏感词检测-v1.0.md` | | 关联技术方案 | `docs/02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.md` | | 关联测试用例 | `docs/03-测试文档/03-功能测试用例/TC-通用-004-敏感词检测.md` | | 看板验真测试报告 | `docs/03-测试文档/04-版本测试报告/看板验真-测试报告-20260707.md` | | 快速回复规则 PRD(架构参考) | `docs/01-产品文档/00-产品规划/PRD-REQ-通用-002-快速回复规则后台管理-v1.2.md` | | 知识库迭代 §4(关键词匹配参考) | `docs/02-技术文档/技术架构/技术方案-REQ-知识-001-知识库迭代-v1.0.md` | | 当前服务源码 | `src/backend/app/services/content_moderation_service.py` | | 当前测试源码 | `src/backend/tests/test_content_moderation.py` | | 任务 #81(基础) | `docs/07-项目管理/任务说明书/任务说明书-01-新开发任务.md` §任务 6 | | 项目管理主文档 | `docs/07-项目管理/任务说明书/IT智能服务台-项目管理主文档.md` | --- ## 🔄 变更日志 | 版本 | 日期 | 变更 | 变更人 | |------|------|------|--------| | v1.1 | 2026-07-28 | 首次创建:词库入库 + 后台 UI 任务说明书 | 宋献 |