Files
group_fqcd_jr/docs/evidence/20260918-t2-customer-service-skeleton.json
T
张胜宇 5d0becb67d 客服 Agent 重构收口:五出口决策链 + 知识库档位隔离 + 前端入参边界(答辩演示版本)
一、客服 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 生成的本地产物
2026-09-20 14:33:30 +08:00

140 lines
7.0 KiB
JSON
Raw 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.
{
"artifact": "t2-customer-service-skeleton",
"generated_at": "2026-09-18T10:23:00.905825Z",
"date_local": "2026-09-18",
"purpose": "D2.1 T2 第一步:重建客服 Agent 本体(含安全词表恢复)+ 用 E5 分级回退替换一刀切转人工",
"premise_correction": {
"finding": "客服 Agent 本体在 2026-09-16 随客服业务层整体清除,未在 AgentFactory 注册",
"before": "POST /api/v1/conversations {agent_type: customer_service} -> 404 AGENT_TYPE_NOT_FOUND;注册表只有 6 个 Agent",
"after": "已注册,注册表 7 个 Agent:customer_service / financial_nl2sql / fund_query_demo / offsite_fund / platform_probe / promotion_material / risk",
"source_of_truth": "docs/customer-service-routing-legacy-keywords.md(清除时留下的词表留痕,明确要求重建时逐条恢复)"
},
"deliverables": [
{
"file": "app/core/customer_service_rules.py",
"action": "新建(重建)",
"detail": [
"零容忍词表 11 条原样恢复(名字与内容均未改动,唯一消费方是输入侧判定)",
"提示词注入 8 条恢复(清除前在生效路径上不存在,红队 RT-009/010 因此必然失败)",
"凭据披露短语 5 条恢复",
"P0 补 非本人交易;P2 补 替我交易 / 纠纷(按留痕文档 §三 迁移对照表)",
"品牌统一:南方基金 / 400-889-8899 / 每日 7:00—22:00 / www.nffund.com",
"transfer_reason 改为枚举码(safety_risk / account_data / write_or_dispute / explicit_request),不再写中文自由文本",
"拦截顺序固定 P0 -> 提示词注入 -> 合规 -> P1 -> P2"
]
},
{
"file": "app/service/agent/implementations/customer_service.py",
"action": "恢复 + 改造为五出口",
"detail": [
"E1 安全出口(route_message 确定性拦截)",
"E3 知识直答(高置信原文直返,不经模型)",
"E5a 澄清 / E5b 部分答 + 引导 / E5c 转人工(白名单四类)",
"删除 _guide_to_human:原先 10 处调用(未命中 / 置信度不足 / 检索降级 / 画像失败 / 适当性无结论 / 闲聊模型不可用)全部改为 E5a 或 E5b,且不建单",
"transfer_required=True 只保留 1 处(_exit_transfer),越出白名单即抛 ValueError",
"E2 计算型(H-02)与 E4 证据约束生成(H-03)本次未实现,已在模块 docstring 中标注"
]
},
{
"file": "app/service/agent/bootstrap.py",
"action": "注册 CustomerServiceAgent",
"detail": [
"工厂注册表 6 -> 7;import 与 register 各一处"
]
},
{
"file": "tests/unit/core/test_customer_service_rules.py",
"action": "新建单测",
"detail": [
"零容忍词/注入词/披露短语原样守卫、话术自绊守卫、官方电话守卫、拦截顺序守卫"
]
},
{
"file": "tests/unit/service/test_customer_service_agent.py",
"action": "新建单测",
"detail": [
"转人工白名单(越界即抛错)、E5b 不置 transfer_required、E5a 澄清下限与去重"
]
}
],
"gates": {
"pytest": "7 failed, 1482 passed, 2 skipped(基线 T0:8 failed, 1440 passed, 2 skipped)",
"pytest_no_new_failures": true,
"pytest_fixed_since_baseline": [
"tests/unit/tools/test_rbac_seed_consistency.py::test_permission_ids_are_consistent_between_seed_and_grant_scripts"
],
"ruff": "Found 22 errors(与基线 T0 逐项相同:bootstrap.py 4 / promotion_renderer.py 9 / 其余 9)",
"ruff_new_files": "All checks passed(新增与恢复的 4 个文件 0 错)",
"mypy": "Success: no issues found in 3 source files(本次改动的 3 个源文件 0 错)",
"check_authoritative_docs": "checked 50 documents, no number collision",
"audit_schema": "schema audit passed: 89 business tables, no missing or unexpected tables"
},
"config_probe": {
"note": "发布配置仍在库中(随代码清除未被删除),客服 Agent 的工具白名单无需重发即可生效",
"active_release_id": 58,
"agent_tools": {
"customer_service:faq": [
"search_knowledge",
"query_knowledge",
"query_customer_profile"
],
"customer_service:product_inquiry": [
"search_knowledge",
"query_knowledge"
],
"customer_service:policy_explain": [
"search_knowledge",
"query_knowledge"
],
"customer_service:suitability_check": [
"search_knowledge",
"check_suitability"
]
},
"agent_intent_config_active": {
"customer_service": [
"suitability_check"
],
"risk": [
"general",
"risk_evidence",
"risk_overview",
"risk_search"
]
}
},
"known_gaps": [
{
"id": "T2-2 / 受理服务脱敏缺失",
"severity": "高(隐私)",
"detail": "app/service/agent_run_application_service.py 随模块清除被剥掉 4 项能力:① 受理时 sanitize_customer_service_message(HEAD 第 149 行)—— 现状是原始凭据明文落 conversation_message;② chitchat_streak 服务端覆写;③ clarification_round 服务端覆写(E5a 澄清轮次上限依赖它);④ session_context 短期上下文(Redis + MySQL 回退)",
"evidence": "tests/integration/test_agent_run_acceptance.py::test_customer_service_accept_redacts_sensitive_message_before_persistence 仍失败,断言 '123456' not in message.content 不成立",
"note": "属底座(受理服务)改动,D2.1 组 1 第 6 项,须会签 + 逐项留痕;与 F-01(MySQL 回退主体隔离)同处一文件"
},
{
"id": "C-05 / C-06 合规种子未跑",
"severity": "中",
"detail": "agent_negative_word active = 0、agent_reply_template active = 0;4 项 test_compliance_seed_mysql 失败的直接原因",
"note": "与基线 T0 一致,未变化"
},
{
"id": "品牌残留:闲聊提示词仍是旧品牌",
"severity": "中(评审可见)",
"detail": "prompt_template_version.customer_service_chitchat 的 system_prompt 仍写「南方财富」",
"note": "属配置层数据修正,不是代码改动"
},
{
"id": "P0 裸词覆盖过宽",
"severity": "中(影响转人工率)",
"detail": "P0_KEYWORDS 含裸词「密码」「验证码」,会把「忘记登录密码怎么办」这类公开 FAQ 打成反诈分支(transfer_required=True)",
"note": "本次按留痕文档原样恢复以保持可验证;是否收窄为限定式(如「我的密码」「验证码是」)属 C-03 决策"
},
{
"id": "admin / advisor / operator 档位",
"severity": "低",
"detail": "不在 TIERS_BY_SUBJECT 表内,收敛为 {public},员工侧看不到 registered 内容",
"note": "待用户裁定"
}
],
"honesty": "本次如实记录:pytest 7 项失败全部是基线 T0 已有失败的子集,无新增;E2/E4 两个出口未实现,能力上属缺口而非完成。"
}