一、客服 Agent 智能增强(正面回应"不智能、动不动就转人工")
- 决策链由 2 个出口扩到 5 个:E1 澄清 / E2 计算型 / E3 知识直返 / E4 证据约束生成 / E5 分级回退
- 转人工从"默认动作"降为最后一档 E5c,只保留 4 类白名单:
P0 反诈 / P1 账户与个人数据 / P2 写操作与争议 / 用户明确要求人工
- 46 条金标实测(修复前 → 修复后):
转人工率 43.5% → 10.9%;出口准确率 45.7% → 100%;事实正确率 69.6% → 100%
禁忌违反 1 → 0;档位越权 / 无出处数字 / 误拒 四项零容忍全 0
- 安全不变量 INV-1~INV-5;零容忍规则未删,改的是挂载点
(输出侧字面黑名单 → 检索层档位隔离 + 判定层合规词表 + 输出守护)
二、知识库:档位单点化与物理隔离
- 新增 app/core/knowledge_tier.py 作为档位规则唯一落点(G-03),
knowledge_contracts.py 原定义块改为显式再导出(X as X,非副本)
- 档位过滤由 bool 默认值(fail-open)改为 tiers 必填集合(缺参即 TypeError)
- Milvus 侧四集合按 visibility 分区键物理隔离;双 schema 收敛为一套
- 新增 app/core/actor.py:访客三元组与匿名判定的唯一构造/判定点(G-01/G-01b)
- 新增 app/core/fund_fee_rules.py:费率计算纯函数
三、前端入参边界对齐(本轮 W11 新修,4 处"校验宽于存储")
- message 加 max_length=8000(与浮窗 widget.js 的 maxlength 一致)
- session_id 加 1—64;idempotency_key 上限 128 → 64(对齐列宽 String(64))
- feedback_type 加 max_length=32(对齐列宽 String(32))
- 8 条路径参数补 min_length=1 + max_length=64 + 字符集正则
({session_id} / {run_id} / {handover_id})
- 改前超限值会落到 MySQL 才失败(500);改后一律 422 AGENT_INPUT_INVALID + 字段级定位
- 新增 tests/unit/api/test_frontend_boundaries.py(33 例),含"端点表 ↔ OpenAPI 全量对照"
四、投顾模块整体清除(D4.4 / D4.5)
- 删除投顾相关 controller / schema / model / repository / service 及门户页面
- tools/portal_api_check.py 同步作废 AD003/AD005/AD011/A047 四条用例与 advisor_t 登录
(端点与账号均已不存在,此前稳定报 3 条假红)
五、验证(提交前实测)
- pytest -q:1856 passed / 2 skipped / 0 failed
- ruff check app tools tests:19(= 基线);mypy app:2(= 基线)
- 前端接口契约体检 portal_api_check.py:38 项,通过 34,失败 0,跳过 4
- 全链路冒烟 e2e_smoke_test.py --read-only:31/31
- HTTP 全链路探针 http_probe.py:11/11 succeeded
- 跨文档一致性 _consistency.py:GATE PASS
- 真机边界复验 12 条:12/12 符合预期
六、纪律与文档
- 可改文件白名单 A-09(docs/46)与底座会签申请单 A-10(docs/47,组 1—组 4 全部受理)
- 零 DDL:未新增/修改任何表结构,89 张业务表与基线一致
- 证据留痕:docs/evidence/**(含 46 条金标 score、快照、清除与重建记录)
- 未提交(刻意排除,见提交说明):仓库内 客服agent/ 与 开发文档/ 是 2026-09-16 前的
过期副本(Todolist 440 行 vs 权威 D2.1 1167 行),权威正本在仓库外;
_chunks_report.txt 是 tools/build_knowledge_chunks.py 生成的本地产物
172 lines
7.1 KiB
JSON
172 lines
7.1 KiB
JSON
{
|
||
"artifact": "t2j-c07-legacy-routing-removal",
|
||
"generated_at": "2026-09-19T01:17:39.629532+00:00",
|
||
"date_local": "2026-09-19",
|
||
"purpose": "C-07 删除一期确定性路由 + 兼容桩:取证残留面、校验词表留痕完整性、补跑 §五 遗留门禁",
|
||
"user_instruction": "继续",
|
||
"residual_scan": {
|
||
"deleted_files_absent": {
|
||
"app/service/agent/customer_service_routing.py": true,
|
||
"app/service/agent/customer_service_agent.py": true
|
||
},
|
||
"CustomerServiceIntentRouter_hits": [],
|
||
"CustomerServiceRoute_hits": [],
|
||
"classify_callers": {
|
||
"hits": [
|
||
"tests\\unit\\service\\test_intent_config_runtime.py:48: return await classifier.classify(",
|
||
"tests\\unit\\service\\test_intent_classifier.py:19: result = await classifier.classify(",
|
||
"tests\\unit\\service\\test_intent_classifier.py:31: result = await classifier.classify(",
|
||
"tests\\unit\\service\\test_intent_classifier.py:40: await IntentClassifier(StubModel('{\"intent\":\"trade\",\"confidence\":1}')).classify(",
|
||
"tests\\unit\\service\\test_intent_classifier.py:44: await IntentClassifier(StubModel(\"not-json\")).classify(",
|
||
"app\\service\\agent\\base.py:205: self._classified_intent = await self._intent_classifier.classify("
|
||
],
|
||
"note": "全部为底座 IntentClassifier.classify(app/service/agent/base.py:205 + test_intent_classifier.py / test_intent_config_runtime.py),无一期 CustomerServiceIntentRouter.classify"
|
||
},
|
||
"legacy_constant_definitions": {
|
||
"note": "只应有『注释里的留痕引用』,不应有定义;下列命中均来自注释",
|
||
"hits": [
|
||
"app\\core\\customer_service_rules.py:168:# 提示词注入拦截(恢复自一期留痕 `_PROMPT_INJECTION_KEYWORDS`,8 条)",
|
||
"tests\\unit\\core\\test_customer_service_rules.py:23:#: 恢复自一期留痕 ``_PROMPT_INJECTION_KEYWORDS`` 的 8 条(重建前在生效路径上不存在)。",
|
||
"app\\core\\customer_service_rules.py:191:# 凭据披露拦截(恢复自一期留痕 `_SECURITY_DISCLOSURE_PHRASES`)"
|
||
]
|
||
},
|
||
"import_path": {
|
||
"bootstrap": [
|
||
"26:from app.service.agent.implementations.customer_service import CustomerServiceAgent"
|
||
],
|
||
"tests": [
|
||
"tests\\unit\\service\\test_customer_service_agent.py:16:from app.service.agent.implementations.customer_service import CustomerServiceAgent"
|
||
],
|
||
"chitchat_consumer": [
|
||
"app\\service\\agent_run_application_service.py:14:from app.core.customer_service_rules import chitchat_streak"
|
||
]
|
||
},
|
||
"verdict": "一期路由文件与兼容桩均已不存在;一期类名/路由返回类零引用;.classify( 仅剩底座 IntentClassifier;import 全部指向 app.service.agent.implementations.customer_service"
|
||
},
|
||
"trace_doc_completeness": {
|
||
"doc": "docs/customer-service-routing-legacy-keywords.md",
|
||
"method": "用 ast 取出两版历史文件的模块级/类级常量,逐字面比对是否出现在留痕文档",
|
||
"by_revision": {
|
||
"2026-09-10": [
|
||
{
|
||
"constant": "_ACCOUNT_KEYWORDS",
|
||
"literals": 7,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 7
|
||
},
|
||
{
|
||
"constant": "_CHITCHAT_PHRASES",
|
||
"literals": 5,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 5
|
||
},
|
||
{
|
||
"constant": "_COMPLIANCE_KEYWORDS",
|
||
"literals": 6,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 6
|
||
},
|
||
{
|
||
"constant": "_HUMAN_TRANSFER_KEYWORDS",
|
||
"literals": 6,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 6
|
||
},
|
||
{
|
||
"constant": "_POLICY_KEYWORDS",
|
||
"literals": 10,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 5
|
||
},
|
||
{
|
||
"constant": "_PRODUCT_KEYWORDS",
|
||
"literals": 8,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 3
|
||
},
|
||
{
|
||
"constant": "_SECURITY_KEYWORDS",
|
||
"literals": 5,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 4
|
||
}
|
||
],
|
||
"2026-09-11": [
|
||
{
|
||
"constant": "_ACCOUNT_KEYWORDS",
|
||
"literals": 7,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 7
|
||
},
|
||
{
|
||
"constant": "_CHITCHAT_PHRASES",
|
||
"literals": 5,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 5
|
||
},
|
||
{
|
||
"constant": "_COMPLIANCE_KEYWORDS",
|
||
"literals": 6,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 6
|
||
},
|
||
{
|
||
"constant": "_HUMAN_TRANSFER_KEYWORDS",
|
||
"literals": 6,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 6
|
||
},
|
||
{
|
||
"constant": "_POLICY_KEYWORDS",
|
||
"literals": 10,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 5
|
||
},
|
||
{
|
||
"constant": "_PRODUCT_KEYWORDS",
|
||
"literals": 8,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 3
|
||
},
|
||
{
|
||
"constant": "_PROMPT_INJECTION_KEYWORDS",
|
||
"literals": 8,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 8
|
||
},
|
||
{
|
||
"constant": "_REFERENCE_PHRASES",
|
||
"literals": 8,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 1
|
||
},
|
||
{
|
||
"constant": "_SECURITY_DISCLOSURE_PHRASES",
|
||
"literals": 5,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 5
|
||
},
|
||
{
|
||
"constant": "_SECURITY_KEYWORDS",
|
||
"literals": 5,
|
||
"missing_in_trace_doc": [],
|
||
"restored_in_rules_module": 4
|
||
}
|
||
]
|
||
},
|
||
"verdict": "两版历史文件的全部字面(含 2026-09-11 版新增的注入 8 条 / 凭据披露 5 条 / 指代 8 条)在留痕文档中缺失为 0",
|
||
"correction": "补记第 6 个路由取值 public_knowledge(此名此前只见于兼容桩 docstring 与 D4.6 基线文档的『预期路由』列)"
|
||
},
|
||
"gates": {
|
||
"pytest": "2 failed / 1577 passed / 2 skipped(失败集 = T0 基线同两项,与本步无关)",
|
||
"ruff": "22(= T0 基线)",
|
||
"mypy": "3(= T0 基线)",
|
||
"compileall": "app 全量 py_compile 通过(无悬空 import)",
|
||
"closes": "留痕文档 §五 遗留的『补齐依赖后补跑 pytest / ruff』本步已补跑"
|
||
},
|
||
"honest_notes": [
|
||
"C-07 的 ①(删 classify/路由类/词表)与 ②(删兼容桩)**不是本步执行的删除**:它们已由 2026-09-16「形态A 模块级清除」代删;本步做的是**取证、留痕补正与门禁收口**",
|
||
"留痕文档 docs/customer-service-routing-legacy-keywords.md 目前为 git untracked(本轮未提交,按纪律不代你 commit)",
|
||
"2 failed 为 T0 基线既有失败(test_profile_snapshot_current_invariant_mysql、test_worker_runtime_mysql[False]),不应记入 C-07 回归"
|
||
]
|
||
} |