一、客服 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 生成的本地产物
140 lines
7.0 KiB
JSON
140 lines
7.0 KiB
JSON
{
|
||
"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 两个出口未实现,能力上属缺口而非完成。"
|
||
} |