Files
group_fqcd_jr/开发文档/D4.3-客服模块清除执行报告-2026-09-16.md
张胜宇 bc61d5c579 docs: 入库权威文档目录(客服agent/ 24 份 + 开发文档/ 50 份,替换旧命名的过期副本)
## 为什么做这一步

权威文档 74 份此前**只在本机**,评审者 clone 分支后看不到任何设计文档;而仓库里那两份同名目录
是 **2026-09-16 之前的过期副本,连文件名都是旧的**(无体系编号)。本次按「**权威覆盖过期**」入库。

## 入库内容

| 目录 | 文件数 | 体积 | 说明 |
|---|---|---|---|
| `客服agent/` | 24 | 0.77 MB | `D2.1`~`D2.6` 对外交付四件套 + 演示脚本/答辩报告 + `_build` 构建工具 |
| `开发文档/` | 50 | 2.16 MB | `D1.x` 索引与决策、`D3.x` 方案、`D4.x` 清除与重构留痕、`D5.x` 业务流程、`D6.x` 业务事实基座、`D7.x` 交付物、`D8.x` 规范 |

**旧的过期副本整体移除**(`客服Agent执行Todolist.md` → `D2.1-客服Agent执行Todolist.md` 之类
的改名 + 新增 `D2.5`/`D2.6`),入库后目录内容与权威副本**逐文件一致(零差异,已复核)**。

## 入库前的安全扫描(必须留痕)

- 扫描规则:`sk-` 类密钥 / `Bearer` 长串 / `password=`、`api_key=` 赋值 / 会话中出现过的两把明文 key 片段。
- 结论:**真实密钥只出现在 `.env`**(已被 `.gitignore` 命中,未入库);`.env.example` 与
  `config/risk.env.example` 只有**空占位**。
- 文档内唯一命中是 `D3.1` 里一处**截断的示例 JWT**(`Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`),
  末尾带省略号,是接口文档的示意值,**不是可用凭据**。
2026-09-20 15:03:15 +08:00

159 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 客服 Agent 模块清除执行报告(形态A:模块级全清)
> **体系编号**:`D4.3` · 域:四、清除与重建留痕 · 编号体系见 `D1.1` §4.0
> **编号**:CS-PURGE-2026-008
> **日期**:2026-09-16
> **依据**:`开发文档/D4.2-客服模块清除影响面清单.md`(CS-PURGE-2026-007)§4 「形态A」+ 用户指令「按你的建议在本地项目进行删除或修改操作,先删客服模块」
> **范围**:`group_fqcd_jr/`(分支 `qyqy_develop`)
> **结论**:**删除 34 个客服专属文件 + 修改 17 个共享文件引用;610 个 .py 语法零错误、悬空 import 零条。**
---
## 一、为什么是形态A(一句话)
`svc_handover_ticket` 工单表、员工端工单队列 7 个端点、访客端「转人工」链路、Portal 外壳、
`sanitize_customer_service_message` 隐私函数**都是跨模块共享资产**。字面全清会把投顾/风控/员工端
一起打挂,且直接违反 `AGENTS.md` 规则 1/4/7 与 Todolist A-09「既有接口路径与签名不可改」。
形态A = 清掉客服**专属**资产,摘掉共享文件里的客服引用,**保留共享表与共享链路**。
---
## 二、已删除(34 个文件,可回退)
| 类别 | 数量 | 文件 |
|---|---|---|
| 后端核心实现 | 4 | `app/service/agent/implementations/customer_service.py`(748 行主逻辑)、`app/service/agent/customer_service_routing.py`(一期路由)、`app/core/customer_service_rules.py`(二期安全路由)、`app/service/customer_service_session_memory_service.py`(Redis 短期记忆) |
| 前端挂件 | 3 | `app/static/portal/common/customer-service-widget/widget.js`、`widget.css`、`app/static/index.html`(客服测试页) |
| 运维/发布脚本 | 8 | `tools/ask_customer_service.py`、`customer_service_check.py`、`grant_customer_service_phase2_permissions.py`、`publish_customer_service_config.py`、`publish_customer_service_knowledge.py`、`verify_customer_service_phase1.py`、`publish_chitchat_prompt.py`、`publish_profile_tool_whitelist.py` |
| 测试 | 9 | `tests/unit/api/test_customer_service_test_page.py`、`tests/unit/core/test_customer_service_rules.py`、`tests/unit/service/test_customer_service_{agent,chitchat_metadata,search_query,session_memory_service,suitability,topic_matrix}.py`、`tests/unit/tools/test_publish_customer_service_knowledge.py` |
| 文档 | 10 | `docs/24-客服Agent阶段性总结与下阶段计划.md`、`docs/41-客服Agent前端开发约束_v1.md`、`docs/客服Agent二期_画像投影协议_v1.md`、`docs/客服Agent接入底座扩展说明_v1.md`、`docs/客服Agent一期远程整合测试手册.md`、`docs/superpowers/specs/2026-09-10-customer-service-agent-design.md`、`docs/superpowers/plans/2026-09-10-客服Agent与RAG实施计划-qyqy版.md`、`docs/superpowers/handoff/2026-09-11-{工作报告,交接文档}-客服Agent与RAG收尾.md`、`docs/evidence/20260910-customer-service-knowledge-preflight.json` |
| 过期字节码 | 6 | `tools/__pycache__/` 下 5 个已删脚本 + 其余已删模块的 `.pyc`(源码已不存在者一律清除) |
完整路径清单:`_cs_delete_list.txt`(工作区根)。**回退副本:`_cs_purge_backup/`(34/34 个文件,已核对)**。
---
## 三、已修改(17 个共享文件,逐处说明)
| # | 文件 | 改了什么 | 为什么必须改 |
|---|---|---|---|
| 1 | `app/main.py` | 删掉 `/customer-service-test` 静态挂载 | 挂载目录已删,留着 = 启动即 404/异常 |
| 2 | `app/service/agent/bootstrap.py` | 删 `CustomerServiceAgent` import + `factory.register(...)` | 不删 = **整个 Agent 注册入口 import 失败**,全部 7 个 Agent 一起挂 |
| 3 | `app/service/agent_run_application_service.py` | 删 5 处客服 import、`CustomerServicePriorContext`、`_read_customer_service_short_context`/`_load_mysql_prior_context`/`_load_customer_service_prior_context`、`session_memory` 构造参数;`accept()` 改为直接用 `request.message`;`build_outbox_metadata()` 退化为纯序列化 | 客服专属方法寄居在**全 Agent 共用**的受理链路里 |
| 4 | `app/worker/runtime.py` | 删客服 session_memory import/字段/构造参数、`should_request_memory_extraction` 的客服短路、`should_request_profile_candidate` 的 `agent_type != "customer_service"`、`_append_customer_service_session_memory()`;新增 `PROFILE_CANDIDATE_AGENT_TYPES`(见 §六) | Worker 分发全部 Agent |
| 5 | `app/static/portal/common/layout/app-shell.js` | 删 widget import + 挂载/样式注入块 | `app-shell.js` 是全 Portal 外壳 → 不删 = **所有页面 import 报错白屏** |
| 6 | `app/static/portal/common/visitor-token.js` | 更新注释(不再指向已删的 widget 路径) | 悬空路径引用 |
| 7 | `app/service/agent/governance.py` | 2 处注释:热线同步说明改写;`CUSTOMER_FACING_AGENT_TYPES` 加「客服仍在名单内」的理由 | 原文引用已删模块 `customer_service_rules.CONTACT_PHONE` |
| 8 | `app/service/auth_service.py` | docstring 里 `CustomerServiceAgent` → 「面向客户的 Agent」 | 引用已删类名 |
| 9 | `tools/check_rbac_seed_consistency.py` | `GRANT_SCRIPTS` 移除客服二期条目 | 该条目指向已删脚本 → 一致性校验脚本会 `RuntimeError` |
| 10 | `tools/seed_demo_data.py` | `STEPS` 移除「客服配置白名单」「客服闲聊提示词」两步 | 两步指向已删脚本 |
| 11 | `tools/api_console.py` | 移除 `/customer-service-test` 路径分组项 | 与 #1 同因 |
| 12 | `tests/unit/service/test_knowledge_granularity.py` | 删 import + 4 条 `CustomerServiceAgent._prefer_section` 用例 | import 已删模块 |
| 13 | `tests/unit/service/test_agent_governance.py` | 删 import + `test_authenticated_customer_service_does_not_recall_customer_memory` | 同上 |
| 14 | `tests/unit/service/test_knowledge_keyword_recall.py` | `test_gate_value_matches_agent_high_score` 改为锁定 `VECTOR_CONFIDENT_SCORE == 0.75` | 原用例比较的 `HIGH_SCORE` 只存在于已删模块 |
| 15 | `tests/unit/worker/test_runtime_worker_dispatch.py` | 删 `CustomerServiceSessionTurn` import + 3 条客服用例;2 条访客用例的 `agent_type` 改为存活 Agent | 已删模块 import / 已删方法调用 |
| 16 | `tests/unit/tools/test_foundation_migration_preflight.py` | 替身 Git 输出里的 `customer-service-rag` / `customer_service_agent.py` 改为中性路径 | 纯命名残留 |
| 17 | `docs/customer-service-routing-legacy-keywords.md` | 顶部加「已被形态A推翻」告示块 | 该文档原写「`chitchat_streak()` 保留未删」,现整个文件已删除 |
---
## 四、有意保留(**不是漏删**,逐条给理由)
| 保留项 | 理由 |
|---|---|
| `app/api/controllers/admin.py` 的 7 个 `/api/v1/admin/customer-service/handover-tickets*` 端点 | **员工端工单队列**。删除即改变既有接口面(违反 A-09),且 `svc_handover_ticket` 是平台核心表 |
| `app/service/customer_service_handover_{context,action,admin}_service.py` | 同上;`customer_service_handover_context` 还被**共享的** `agent_persistence_service.py:15` 导入 |
| `svc_handover_ticket` / `agent_run` / `request_idempotency` / `domain_event_outbox` / `outbox_delivery` / `agent_negative_word` | 平台核心表,服务全部 Agent |
| `app/core/conversation_privacy.py::sanitize_customer_service_message` | **公共**隐私函数,还被 `memory_extraction_worker` + 2 个画像投影 + `public_platform_service` 使用 |
| `app/service/public_platform_service.py` 的访客转人工写单 | 公共平台链路(访客入口),非客服模块私有 |
| `app/service/customer_profile_candidate_service.py` 的 `customer_service_preferences` 快照键 | 画像快照**已落库字段名**,改名 = 数据迁移 |
| `app/service/agent/governance.py::CUSTOMER_FACING_AGENT_TYPES` 中的 `"customer_service"` | **合规门禁 F5**(面向客户输出必须附免责声明)。留着 → 重建后自动继承;摘掉 → 重建后出现合规缺口 |
| `docs/客服Agent一期_合规红队与业务评测集_v1.md`、`docs/customer-service-routing-legacy-keywords.md` | 重建的**验收基线 / 词表唯一副本**(见 §六) |
---
## 五、验证结果(本机可做的上限)
| 项 | 结果 |
|---|---|
| `py_compile` 全量语法校验 | **610 个 .py,0 错误** |
| AST 静态扫描:指向不存在文件的 import | **0 条** |
| `__pycache__` 过期字节码 | 已清(仅保留源码仍在的 570 个) |
| 文本残留 | 68 个 .py / 215 处(全部为**数据值、共享表名、保留模块名、历史注释**,见下) |
| pytest / ruff / mypy / 集成测试 | ❌ **跑不了**:本机无项目依赖(pytest/fastapi/sqlalchemy/pydantic/redis/pymilvus/alembic 全部 ModuleNotFoundError),仓库内无 venv |
验证脚本:`_purge_verify.py`;原始报告:`_purge_verify_out.json`。
(`alembic.*` 是第三方包,首轮扫描把它误判成悬空 import,已在脚本里修正口径。)
**残留分类(68 个文件)**:
- `app/`(15 个):全部为**有意保留**项(handover 三件套 + 工单端点 + 公共隐私函数 + 核心表名 + 历史注释)。
- `tests/`(28 个):`agent_type="customer_service"` / `customer_service:faq` 等**测试夹具与配置键的字符串值**;`acceptance_registry` 夹具自己注册替身 Agent,故这些用例仍然自洽。
- `tools/`(11 个):见 §六.3。
- `alembic/`(1 个):基线迁移里的表注释。
---
## 六、需要你拍板 / 重建时必须补齐(6 项)
### 6.1 已随模块消失的安全能力(**最重要**)
删除的不只是"客服话术",还包括三套拦截能力,现在**在生效路径上不存在**:
| 能力 | 原位置 | 现状 |
|---|---|---|
| 提示词注入拦截(8 条词) | 先期迁入 `customer_service_rules.py` | 随模块删除 → **红队 RT-009/010 必然失败** |
| 凭据披露拦截(`_SECURITY_DISCLOSURE_PHRASES`) | 同上 | 同上 |
| 安全关键词路由 + 零容忍词(11 条,与库内 `agent_negative_word` 镜像) | `route_message()` / `ZERO_TOLERANCE_WORDS` | 同上 |
**词表唯一副本已存于** `docs/customer-service-routing-legacy-keywords.md`(我已在该文档顶部加了告示块)。
重建时按它的迁移对照表恢复,否则这批词会**彻底丢失**。
### 6.2 `PROFILE_CANDIDATE_AGENT_TYPES` 目前为空集合(需确认)
`app/worker/runtime.py` 新增该常量,`frozenset()`。**行为与删除前完全等价**(此前也只有客服命中)。
我**故意没有**把它改成"任何非访客 Agent 都可产出候选"——因为候选里含 `preference:risk_level`,
放开会让投顾对话也能产出风险等级候选,**触碰 MVP 红线①「风险等级唯一来源是问卷测评」**。
重建客服 Agent 后,把它的 `agent_type` 填回该集合即可接通候选链路。
### 6.3 11 个开发脚本仍指向已注销的 `agent_type="customer_service"`
`tools/`:`smoke_check.py`(7)、`e2e_smoke_test.py`(4)、`acceptance_check.py`(3)、`portal.py`(3)、
`portal_api_check.py`(2)、`memory_demo_chain.py`(2)、`chat_console.py`(1)、`drop_table_header_vectors.py`(1)、
`publish_risk_agent_config.py`(1)、`seed_compliance_baseline.py`(1)、`seed_knowledge_r1r5_faq.py`(1)。
这些脚本**不是构建依赖**(`app/` 不 import 它们),但连上服务后会因为 Agent 未注册而失败。
**替换成哪个存活 Agent(`advisor`?`fund_query_demo`?)会改变脚本演示的语义,我不替你做这个决定。**
请给一个口径,我一次改完。
### 6.4 文档层残留(约 30 处,在 `docs/` 站内)
分两类,处理方式不同:
- **历史记录**(交付说明、评审回复、合并记录、验收报告等):按其写作日期引用当时的文件,**建议原文不动**(改历史=伪造记录)。
- **在用运行手册**(`AGENTS.md:163`、`docs/05-接口文档.md`(10)、`docs/09-底座使用文档.md`(9)、`docs/32-平台侧交接与联调准备.md`(3)、`docs/11/14/15-接入说明书`):命令/脚本已不存在,**建议回写**。要我做就说一声。
### 6.5 Advisory:`AGENTS.md:163` 引用了已删的发布脚本
`AGENTS.md` 是项目的规则文件(Rule Priority 载体)。它把「同 key 继承项必须被覆盖」这条教训
挂在 `tools/publish_customer_service_config.py` 上,而该脚本已删 → 教训的载体消失。
**我没有擅自改 `AGENTS.md`**(规范性文件),请你决定是改引用还是换载体。
### 6.6 重建时必须带回的测试(我已在原位留注释)
- `tests/unit/service/test_agent_governance.py`:客服不得触发通用长期/画像记忆读取。
- `tests/unit/service/test_knowledge_granularity.py`:整节块 vs 行级子块的取舍(`_prefer_section`)。
- `tests/unit/service/test_knowledge_keyword_recall.py`:检索层门槛与客服高置信门槛的**跨模块对齐**。
---
## 七、回退方式
```bash
# git 写入被本机沙箱拦截(git branch 返回 0 但分支未创建),故用文件级备份:
# D:\桌面\金融\_cs_purge_backup\ 34/34 个被删文件的副本(保持原目录结构)
# 恢复:按原相对路径复制回 group_fqcd_jr\ 即可;
# 17 个被改文件请用 git diff 逐处回退(改动都是"删引用",无逻辑重写)。
```