101 lines
5.2 KiB
Python
101 lines
5.2 KiB
Python
"""客服 Agent 的**出口码注册表**(`W27` 新增,`D3.9` §3.1 / §6.2)。
|
||||
|
|
|
|||
|
|
## 为什么要有这个模块
|
|||
|
|
|
|||
|
|
`D3.7` §3 记着一条老口径:「旧实现**没有** `E1`—`E5` 出口码」,评测探针只能靠"包装终止型
|
|||
|
|
方法"给每条打标。那套包装法有两个代价:
|
|||
|
|
|
|||
|
|
1. **它测的是探针的包装,不是产品声明** —— 出口改名/换位置,标就变了,而 `D3.7` 的
|
|||
|
|
验收结论是拿这些标算出来的;
|
|||
|
|
2. 有些**行为正确但没出口方法**的分支(例如 `E8` 风险等级代办拦截)会被记成
|
|||
|
|
「没有任何出口」,于是**做对的安全行为被判未达标**(`D3.9` §2 的度量失真)。
|
|||
|
|
|
|||
|
|
因此 `W27` 起改为:`CoreResult.exit_code` 由**出口自己声明**,读侧不反解文本。
|
|||
|
|
第一个(也是目前唯一)消费方是门禁 `F5` 的**免责声明分档**(`DEC-W27-10`):
|
|||
|
|
业务出口附完整投资免责话术,非业务出口只附轻量提示。
|
|||
|
|
|
|||
|
|
## 与 `D3.6` / `D3.7` 的编号关系
|
|||
|
|
|
|||
|
|
本模块的编号**直接沿用** `D3.6` §3 的出口码(`E1` 澄清 / `E2a`—`E2e` / `E3` / `E4` /
|
|||
|
|
`E5a`—`E5c`),并补三个 `D3.6` 未给码的出口:
|
|||
|
|
|
|||
|
|
- `E0`:`L0` 表层判定层本身(`D3.9` §3.1)。它是**路由层**不是终态出口,因此
|
|||
|
|
**不写入 `CoreResult.exit_code`**,只作为日志/审计的分组名;
|
|||
|
|
- `E6`:行情出口(`D3.9` §4);
|
|||
|
|
- `E8`:风险等级代办拦截(`D3.7` 的 `E-08` 红线 1 ④);
|
|||
|
|
- 安全出口沿用 `SafetyRoute.priority`(`P0` / `P1` / `P2` / `COMPLIANCE` /
|
|||
|
|
`PROMPT_INJECTION` / `ADVICE_BOUNDARY`),`D3.7` §3 已按这个口径给安全出口打标;
|
|||
|
|
- `LOGIN` 沿用 `D3.7` 金标里已经在用的写法(`H-03` 的期望出口并列里就有它);
|
|||
|
|
- `CHAT` / `CONTACT` 是本轮新增:闲聊与"问渠道联系方式"没有历史编号,但
|
|||
|
|
`D3.9` §6.2 明确把它们列入**非业务档**,所以必须有一个可声明的码。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
# ---- `L0` 表层判定层(路由分组名,不写入 `CoreResult.exit_code`) ----
|
|||
|
|
EXIT_SURFACE = "E0"
|
|||
|
|
|
|||
|
|
# ---- 出口 `E1` / `E2` 族:澄清与计算型 ----
|
|||
|
|
#: `E1`:澄清。**非业务档**(`D3.9` §6.2)—— 「请问您想了解哪一只」不该挂投资风险提示。
|
|||
|
|
EXIT_CLARIFY = "E1"
|
|||
|
|
#: `E2a`:类别费率试算(给算法 + 区间,不给单一结论金额)。
|
|||
|
|
EXIT_CALC_CATEGORY_FEE = "E2a"
|
|||
|
|
#: `E2b`:单只产品赎回费递进。
|
|||
|
|
EXIT_CALC_REDEMPTION = "E2b"
|
|||
|
|
#: `E2c`:`C—R` 通用匹配规则(矩阵一格)。
|
|||
|
|
EXIT_SUITABILITY_RULE = "E2c"
|
|||
|
|
#: `E2d`:适当性裁决(产品风险等级 × 客户档案等级)。
|
|||
|
|
EXIT_SUITABILITY_VERDICT = "E2d"
|
|||
|
|
#: `E2c-my`(`W21` 新增):**以本人等级为对象**的可购买范围清单。
|
|||
|
|
#: 与 `E2c` 的分工是"问句里有没有自带参数":`E2c` 收 `C1 能买 R3 吗` 这类自带 C/R
|
|||
|
|
#: 的规则题,本码收 `我能买什么等级的产品` 这类**只问范围**、等级从画像里取的问法。
|
|||
|
|
EXIT_ELIGIBLE = "E2c-my"
|
|||
|
|
#: `E2e`:本人画像 / 客户分层作答(`query_customer_profile`)。
|
|||
|
|
EXIT_PROFILE = "E2e"
|
|||
|
|
|
|||
|
|
# ---- 出口 `E3` / `E4`:知识直返与证据约束生成 ----
|
|||
|
|
EXIT_KNOWLEDGE_DIRECT = "E3"
|
|||
|
|
EXIT_EVIDENCE = "E4"
|
|||
|
|
|
|||
|
|
# ---- 出口 `E5` 族:分级回退 ----
|
|||
|
|
#: `E5a`:知识侧的澄清(候选来自当前可见档位)。**非业务档**。
|
|||
|
|
EXIT_CLARIFY_KB = "E5a"
|
|||
|
|
#: `E5b`:部分答 + 引导。**业务档**—— 即使正文为空,客户拿到的也是"业务上答不上来",
|
|||
|
|
#: 该给的投资风险提示一个字都不能少(这正是分档判据必须用出口码的原因)。
|
|||
|
|
EXIT_PARTIAL = "E5b"
|
|||
|
|
#: `E5c`:转人工。**业务档**(安全与责任披露最不能省的一档)。
|
|||
|
|
EXIT_TRANSFER = "E5c"
|
|||
|
|
|
|||
|
|
# ---- 出口 `E6` / `E8` ----
|
|||
|
|
#: `E6`:行情出口(净值序列 / 区间涨跌)。数字来自受控数据源,**业务档**。
|
|||
|
|
EXIT_QUOTE = "E6"
|
|||
|
|
#: `E8`:风险等级代办拦截(`D3.7` `E-08` 红线 1 ④)。业务档。
|
|||
|
|
EXIT_RISK_LEVEL_GUARD = "E8"
|
|||
|
|
|
|||
|
|
# ---- 无编号出口:沿用既有语义名 ----
|
|||
|
|
#: 闲聊。非业务档。
|
|||
|
|
EXIT_CHITCHAT = "CHAT"
|
|||
|
|
#: 引导登录(访客请求超出公开服务范围)。非业务档;`D3.7` 金标已用 `LOGIN` 这个名字。
|
|||
|
|
EXIT_LOGIN = "LOGIN"
|
|||
|
|
#: 问渠道联系方式(公开信息,不是提交投诉)。非业务档 —— 「电话是多少」后面跟一句
|
|||
|
|
#: 投资风险提示属于挂错话术(`D3.9` §6.2 的例证之一)。
|
|||
|
|
EXIT_CONTACT = "CONTACT"
|
|||
|
|
|
|||
|
|
#: **非业务档**出口集合:门禁 `F5` 只对这些出口追加**轻量提示**,其余一律追加完整
|
|||
|
|
#: 投资免责话术。集合取"白名单式"是刻意的 —— 新增出口若忘记登记,默认落到**业务档**
|
|||
|
|
#: (多一句披露),失败方向与 `INV-5`(收敛)一致。
|
|||
|
|
NON_BUSINESS_EXIT_CODES = frozenset({
|
|||
|
|
EXIT_CLARIFY,
|
|||
|
|
EXIT_CLARIFY_KB,
|
|||
|
|
EXIT_CHITCHAT,
|
|||
|
|
EXIT_LOGIN,
|
|||
|
|
EXIT_CONTACT,
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
#: 安全出口的优先级标签(与 `app/core/customer_service_rules.py` 的
|
|||
|
|
#: `SafetyRoute.priority` 同源)。列在这里是为了让"哪些 priority 是安全出口"可被
|
|||
|
|
#: 静态检查与测试引用,而不是散落在注释里。
|
|||
|
|
SAFETY_PRIORITIES = frozenset({
|
|||
|
|
"P0", "P1", "P2", "COMPLIANCE", "PROMPT_INJECTION", "ADVICE_BOUNDARY",
|
|||
|
|
})
|