44e77dcb0e
**重构前**(旧编号 02-11): - docs/02-产品需求/ → 00 产品规划/PRD - docs/03-技术架构/ → 01-05 子目录散落 - docs/04-原型设计/ → 01-02 产品设计(HTML 原型) - docs/05-原型设计/ → screens/ - docs/06-测试素材/ → 02-E2E / 03-功能 / 04-版本测试 - docs/07-项目管理/ → 任务说明书/日报/计划 - docs/08-安全审计/ → 审计报告 - docs/09-堡垒运维/ → toolbox / deploy - docs/10-项目管理/ → 任务说明书(重复) - docs/11-历史归档/ → deploy-nas-archived **重构后**(新编号 00-07,语义化): - docs/00-产品开发流程与文档管理规范.md - docs/00-版本迭代总览.md - docs/01-产品文档/ (PRD/原型/认证/会话/AI 服务/坐席/集成) - docs/02-技术文档/ (技术方案/架构图/重构记录/前端改造/实现配置) - docs/03-测试文档/ (E2E/功能用例/版本报告/缺陷单) - docs/04-运维文档/ (部署运维/运维指南) - docs/05-运营文档/ (品牌推广/用户手册) - docs/06-安全审计/ (审计报告) - docs/07-项目管理/ (任务说明书/日报/计划/看板) **净收益**: - 目录编号与产品文档管理规范对齐(按文档阶段 01-07 编号) - 消除 02-产品需求 与 10-项目管理 的编号重叠 - 子目录按文档类型分组(如 01-产品文档/00-产品规划、01-产品文档/01-认证与登录) - 把运维/安全/项目管理从 0X 散落改为 04/06/07 合计 494 文件 + 78495 行 / - 14076 行
277 lines
12 KiB
Markdown
277 lines
12 KiB
Markdown
# PRD - 敏感词检测
|
||
|
||
> **需求编号**: REQ-通用-004
|
||
> **版本**: v1.0
|
||
> **状态**: [已上线/部分达标]
|
||
> **作者**: 宋献
|
||
> **日期**: 2026-07-28
|
||
> **关联任务**: 项目主文档 #81(v0.7.1 已上线)
|
||
> **关联文档**:
|
||
> - 技术方案:`02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.md`
|
||
> - 测试用例:`03-测试文档/03-功能测试用例/TC-通用-004-敏感词检测.md`
|
||
> - 看板验真测试报告(历史基线):`03-测试文档/04-版本测试报告/看板验真-测试报告-20260707.md`
|
||
> - 内容审核服务源码:`src/backend/app/services/content_moderation_service.py`
|
||
> - 内容审核测试源码:`src/backend/tests/test_content_moderation.py`
|
||
|
||
---
|
||
|
||
## 1. 需求描述
|
||
|
||
### 1.1 背景
|
||
|
||
IT 智能服务台坐席在工作过程中会发送大量文字消息(回复员工、推送通知、催办等),存在两类内容风险:
|
||
|
||
| 风险类别 | 典型场景 | 后果 |
|
||
|----------|----------|------|
|
||
| **服务态度风险** | 坐席使用轻视/推诿/反问式语气("你爱找谁找谁"、"自己不会百度吗") | 员工投诉,IT 服务台品牌受损 |
|
||
| **隐私泄露风险** | 坐席误发员工手机号、身份证号、银行卡号、个人邮箱 | 公司合规风险,员工个人隐私暴露 |
|
||
|
||
历史经验表明,**人工巡检难以 100% 覆盖**。需要在坐席发送消息**前**做一次内容审核,给出风险提示。
|
||
|
||
### 1.2 目标
|
||
|
||
建立坐席发送消息的**内容审核机制**,做到:
|
||
|
||
1. **覆盖风险面**:敏感服务用语(脏话/不当推诿/反问)+ 隐私字段(手机/身份证/银行卡/个人邮箱)
|
||
2. **低干扰**:命中后**仅警告不阻断**(WARN 策略,2026-07-08 决策),保留坐席自主权
|
||
3. **可扩展**:词库/规则**可运营**(理论上可由管理后台维护,当前 v1.0 为写死基线)
|
||
|
||
### 1.3 范围
|
||
|
||
| 范围项 | v1.0 状态 | 说明 |
|
||
|--------|----------|------|
|
||
| 敏感服务用语检测 | ✅ 已实现 | wordfilter 库 + 自定义词库(写死 4 条) |
|
||
| 隐私字段检测 | ✅ 已实现 | 正则匹配手机/身份证/银行卡/邮箱 |
|
||
| 命中动作 | ✅ 维持 WARN | 不阻断发送,仅提示 |
|
||
| 修改建议 | ✅ 已实现 | 按分类返回固定建议文案 |
|
||
| 词库运营管理 | ❌ 未实现 | 当前写死,PRD §6 数据需求中已规划 |
|
||
| 后台配置 UI | ❌ 未实现 | 运营需改代码发布 |
|
||
| 命中动作可配置 | ❌ 未实现 | 当前固定 WARN,无法升级为 BLOCK |
|
||
|
||
### 1.4 Non-goals
|
||
|
||
| 不做 | 原因 |
|
||
|------|------|
|
||
| 图像/附件内容审核 | 仅做文本审核;图片走企微原生反垃圾 |
|
||
| AI 实时生成建议 | 当前为固定文案模板;AI 改写后续再评估 |
|
||
| 阻断(BLOCK)动作 | 2026-07-08 决策:维持 WARN,避免误伤业务 |
|
||
| 员工端(H5)输入审核 | 员工端走企微原生反垃圾 + AI Wingman |
|
||
|
||
---
|
||
|
||
## 2. 用户故事
|
||
|
||
### 2.1 坐席
|
||
|
||
| 优先级 | 用户故事 |
|
||
|--------|----------|
|
||
| P0 | 作为坐席,我希望发送"自己不会百度吗"前收到警告,知道这不合适 |
|
||
| P0 | 作为坐席,我希望看到具体哪些词被命中(matched_words) |
|
||
| P0 | 作为坐席,我希望能继续发送(不被强制阻断),由我自己判断 |
|
||
| P1 | 作为坐席,我希望看到修改建议(suggestion),学习如何更专业 |
|
||
| P1 | 作为坐席,我希望知道为什么被警告(category:脏话/隐私/...) |
|
||
|
||
### 2.2 运营人员
|
||
|
||
| 优先级 | 用户故事 |
|
||
|--------|----------|
|
||
| P1 | 作为运营,我希望能调整词库(添加/删除敏感词),无需改代码 |
|
||
| P2 | 作为运营,我希望能调整隐私正则(如新增"军官证号"),支持业务扩展 |
|
||
| P2 | 作为运营,我希望能查看词库命中统计(高频误判词/低频词) |
|
||
|
||
### 2.3 管理员
|
||
|
||
| 优先级 | 用户故事 |
|
||
|--------|----------|
|
||
| P1 | 作为管理员,我希望命中动作可配置(WARN/BLOCK),应对合规升级 |
|
||
| P2 | 作为管理员,我希望审核日志可追溯(谁发了什么被警告) |
|
||
|
||
---
|
||
|
||
## 3. 功能需求
|
||
|
||
### 3.1 敏感词检测(写死词库)
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 检测范围 | 坐席发送的所有文本消息(员工消息不审) |
|
||
| 词库来源 | `content_moderation_service.py::ContentModerationService.__init__` 写死 4 条 |
|
||
| 词库当前值 | `["投诉我", "你爱找谁找谁", "自己不会百度吗", "这点小事"]` |
|
||
| 匹配算法 | `wordfilter` 库(基于 DFA 的 Aho-Corasick 变体) |
|
||
| 分类 | 当前仅支持 profanity(脏话),其它分类保留扩展位 |
|
||
| 命中动作 | `ModerationAction.WARN`(固定) |
|
||
|
||
### 3.2 隐私字段检测
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 检测项 | phone / id_card / bank_card / personal_email |
|
||
| 手机号正则 | `(?<!\d)1[3-9]\d{9}(?!\d)`(**已修复**:用数字边界替代 `\b`,修复 Python3 re 中文失效) |
|
||
| 身份证正则 | `(?<!\d)\d{17}[\dXx](?!\d)` |
|
||
| 银行卡正则 | `(?<!\d)\d{16,19}(?!\d)` |
|
||
| 个人邮箱正则 | 排除 `servyou-it.com` 和 `servyou.com.cn` 后缀 |
|
||
| 返回值 | 命中的字段描述列表(如 `["phone", "id_card"]`) |
|
||
| 命中动作 | `ModerationAction.WARN`(隐私检测暂未接入 moderate 主流程,仅提供独立方法) |
|
||
|
||
### 3.3 提示与建议
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 提示形式 | 坐席端发送按钮上方黄色提示条 |
|
||
| 提示内容 | "⚠️ 检测到敏感词:[xxx] 建议修改为:xxx" |
|
||
| 阻断行为 | 无(坐席可继续发送) |
|
||
| 审计日志 | 当前未写审计日志(v1.0 限制) |
|
||
|
||
### 3.4 词库管理(v1.0 留接口,未实现 UI)
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 数据存储 | 计划存 `system_config` 表(key=sensitive_words, value=JSON 数组) |
|
||
| 加载时机 | 服务启动时一次性加载到内存(`Wordfilter.addWords`) |
|
||
| 热更新 | 未实现(v1.0 限制;改词库需重启后端) |
|
||
| 增删 API | `service.add_custom_word(word)` / `service.remove_custom_word(word)` 已有,未挂载到路由 |
|
||
| 后台 UI | ❌ 未实现(PRD §6 数据需求规划) |
|
||
|
||
### 3.5 命中动作分级(v1.0 限制)
|
||
|
||
| 分类 | v1.0 动作 | 后续规划 |
|
||
|------|----------|----------|
|
||
| profanity | WARN | 可配置为 BLOCK |
|
||
| politics | WARN(理论) | 应升级为 BLOCK |
|
||
| porn | WARN(理论) | 应升级为 BLOCK |
|
||
| ad | WARN(理论) | 可配置 |
|
||
| privacy | WARN(理论) | 应升级为 BLOCK |
|
||
| other | WARN(理论) | 可配置 |
|
||
|
||
> **决策记录**:2026-07-08 项目评审决定 v1.0 维持 WARN,不升级 BLOCK。理由:避免误伤业务(WARN 已经能让坐席知道问题,且坐席有最终决策权)。
|
||
|
||
---
|
||
|
||
## 4. 非功能需求
|
||
|
||
| 维度 | 要求 |
|
||
|------|------|
|
||
| 性能 | 单次审核 < 5ms(wordfilter DFA 算法,已实测) |
|
||
| 可用性 | 不阻塞主流程:审核失败不阻断消息发送(v1.0 异常吞掉) |
|
||
| 可维护性 | 词库/正则集中在一个 service,修改影响范围可控 |
|
||
| 可测试性 | 13 个单元测试用例,覆盖率 ≥ 85% |
|
||
| 兼容性 | Python 3.11+ / FastAPI / PostgreSQL / Redis(与现有架构一致) |
|
||
| 国际化 | 当前仅中文(敏感词库和提示文案) |
|
||
|
||
---
|
||
|
||
## 5. 接口需求
|
||
|
||
### 5.1 服务层 API(已实现)
|
||
|
||
| 方法 | 签名 | 返回 |
|
||
|------|------|------|
|
||
| `moderate(text)` | `str -> ModerationResult` | 审核结果(action/category/matched_words/suggestion) |
|
||
| `check_privacy_leak(text)` | `str -> List[str]` | 命中的隐私字段名 |
|
||
| `add_custom_word(word)` | `str -> None` | 动态加词(v1.0 未挂路由) |
|
||
| `remove_custom_word(word)` | `str -> None` | 动态删词(v1.0 未挂路由) |
|
||
|
||
### 5.2 路由层 API(计划中)
|
||
|
||
| 接口 | 方法 | 说明 | 状态 |
|
||
|------|------|------|------|
|
||
| `/api/admin/sensitive-words` | GET | 词库列表 | ❌ 未实现 |
|
||
| `/api/admin/sensitive-words` | POST | 添加词 | ❌ 未实现 |
|
||
| `/api/admin/sensitive-words/{id}` | DELETE | 删除词 | ❌ 未实现 |
|
||
| `/api/admin/sensitive-words/test` | POST | 测试输入文本(不入库) | ❌ 未实现 |
|
||
| `/api/admin/privacy-patterns` | GET/POST | 隐私正则管理 | ❌ 未实现 |
|
||
| `/api/admin/moderation-config` | GET/PUT | 命中动作配置(WARN/BLOCK) | ❌ 未实现 |
|
||
|
||
> **现状**:v1.0 仅服务层可用,无 HTTP API 暴露。
|
||
|
||
---
|
||
|
||
## 6. 数据需求
|
||
|
||
### 6.1 词库存储(v1.0 写死,v1.1 计划入库)
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 表名 | `sensitive_words`(v1.1 计划新建) |
|
||
| 字段 | id / word / category / severity / is_active / created_at / updated_at |
|
||
| severity | 1=低(仅 WARN)/ 2=中(WARN+审计)/ 3=高(BLOCK) |
|
||
| 初始化 | 通过 Alembic 迁移 + init SQL 导入基础词库 |
|
||
| 缓存 | 服务启动时全量加载到 `Wordfilter` 实例 |
|
||
|
||
### 6.2 隐私正则存储(同上)
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 表名 | `privacy_patterns`(v1.1 计划新建) |
|
||
| 字段 | id / name / pattern / description / is_active / created_at |
|
||
| 名称示例 | phone / id_card / bank_card / personal_email |
|
||
| 初始化 | 同上,Alembic + init SQL |
|
||
|
||
### 6.3 命中审计日志(v1.1 计划)
|
||
|
||
| 字段 | 规格 |
|
||
|------|------|
|
||
| 表名 | `moderation_logs` |
|
||
| 字段 | id / message_id / agent_id / matched_words / category / action / created_at |
|
||
| 用途 | 追溯谁发了什么被警告 |
|
||
|
||
---
|
||
|
||
## 7. 风险与约束
|
||
|
||
| 风险 | 等级 | 缓解措施 |
|
||
|------|------|----------|
|
||
| 命中仅 WARN,违规坐席可忽略 | 🟡 中 | PRD §3.5 已记录决策;后续可配置 |
|
||
| 词库写死,运营无法调整 | 🟡 中 | v1.1 计划入库(PRD §6) |
|
||
| 隐私正则覆盖有限(未含军官证/护照/车牌) | 🟢 低 | v1.1 计划扩展正则集合 |
|
||
| 误报(正常消息触发 WARN) | 🟡 中 | 词库极小(4 条),v1.1 后由运营调整 |
|
||
| 漏报(新敏感词未及时入库) | 🟡 中 | 依赖运营定期 review |
|
||
| 后台 UI 缺失 | 🟡 中 | v1.1 计划开发(参考通用-002 快速回复规则后台管理) |
|
||
|
||
---
|
||
|
||
## 8. 验收标准
|
||
|
||
### 8.1 必达项(v1.0 已实现)
|
||
|
||
- [x] `moderate("你爱找谁找谁")` 返回 WARN,matched_words 含该词
|
||
- [x] `moderate("您好,电脑无法开机")` 返回 PASS
|
||
- [x] `check_privacy_leak("电话13800138000")` 返回 `["phone"]`
|
||
- [x] `check_privacy_leak("身份证11010119900307123X")` 返回 `["id_card"]`
|
||
- [x] 命中动作固定为 WARN,不 BLOCK
|
||
- [x] 自定义词库包含 4 条基础词
|
||
- [x] 隐私正则使用数字边界(修复 Python3 中文失效)
|
||
|
||
### 8.2 已知不达标项(v1.0 接受,v1.1 解决)
|
||
|
||
- [ ] 命中动作可配置(v1.0 固定 WARN)
|
||
- [ ] 词库可数据库化(v1.0 写死)
|
||
- [ ] 后台管理 UI(v1.0 无)
|
||
- [ ] 命中审计日志(v1.0 无)
|
||
- [ ] 隐私正则可扩展(v1.0 仅 4 类)
|
||
|
||
---
|
||
|
||
## 9. 关联文档
|
||
|
||
| 文档 | 位置 | 关联点 |
|
||
|------|------|--------|
|
||
| 看板验真测试报告 | `03-测试文档/04-版本测试报告/看板验真-测试报告-20260707.md` | 历史基线测试(11/13 通过) |
|
||
| 项目状态看板 #81 | `07-项目管理/任务说明书/IT智能服务台-项目管理主文档.md` | v0.7.1 已上线 |
|
||
| 快速回复规则后台管理 PRD | `01-产品文档/00-产品规划/PRD-REQ-通用-002-快速回复规则后台管理-v1.2.md` | 同类功能(运营后台词库管理),可复用架构 |
|
||
| 知识库迭代技术方案 §4 代答排除规则 | `02-技术文档/技术架构/技术方案-REQ-知识-001-知识库迭代-v1.0.md` | 关键词匹配机制可参考 |
|
||
| 内容审核服务源码 | `src/backend/app/services/content_moderation_service.py` | 当前实现 |
|
||
| 内容审核测试源码 | `src/backend/tests/test_content_moderation.py` | 13 用例基线 |
|
||
|
||
---
|
||
|
||
## 10. 变更日志
|
||
|
||
| 版本 | 日期 | 变更 | 变更人 |
|
||
|------|------|------|--------|
|
||
| v1.0 | 2026-07-28 | 首次整理:v0.7.1 上线内容回溯为正式 PRD | 宋献 |
|
||
|
||
---
|
||
|
||
> **备注**:本文档是对 v0.7.1 已上线功能的**回溯性 PRD 化**,用于补全项目文档体系。功能本身已在生产稳定运行(命中即 WARN 是已接受的产品决策)。
|