{ "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 两个出口未实现,能力上属缺口而非完成。" }