Files
group_fqcd_jr/docs/evidence/20260918-t2f-c04-output-side.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

316 lines
12 KiB
JSON

{
"artifact": "t2f-c04-output-side",
"generated_at": "2026-09-18T12:34:39.933805+00:00",
"date_local": "2026-09-18",
"purpose": "按用户 2026-09-18 「按照你的建议继续」执行 C-04(输出侧补豁免线索 · 组 1 第 4 项会签范围)",
"scope": "app/core/compliance_context.py(底座)+ tests/unit/core/test_compliance_context.py",
"decisions_taken": {
"C-04-a": "「安全」在输出侧改为句式判定(与输入侧 C-02 对偶)—— 已做",
"C-04-b": "指标名白名单改为**句式判定**(承诺性线索负向表),不写固定白名单 —— 已做",
"C-04-c": "C-04 DoD ① 的 6 个短否定式全部补齐 —— 已做",
"C-04-d": "输入侧「不保本 / 非保本」暂不放行(保守)—— 未改输入侧"
},
"governing_principle": "输入侧放行了哪个概念词,输出侧就必须同口径放行 —— 否则 C-02 的收益被输出侧抹掉",
"implementation": {
"SHORT_NEGATION_CUES": [
"不保本",
"不保收益",
"非保本",
"并非保本",
"不确保",
"不担保"
],
"FACTUAL_TERMS": [
"安全",
"年化收益率"
],
"CLAIM_CUES": [
"保证",
"承诺",
"一定",
"绝对",
"肯定",
"百分百",
"万无一失",
"确保",
"可达",
"达到",
"可获",
"可获得",
"至少",
"不低于",
"保底",
"划算",
"最高",
"优于",
"领先",
"稳赚",
"包赚"
],
"NEGATION_CUES_added": [
"没有固定"
],
"new_helpers": [
"_short_negation_overlaps",
"_is_factual_term_mention"
],
"match_rule": "线索与命中词**相接或重叠**才算数(`不保本` 压住命中词、`不确保` 紧贴其前);中间有标点或别的字即不算",
"order": "短否定式 → 引号 → 否定线索 → 询问语境 → 元语言线索 → 指标名句式判定",
"deliberately_excluded": {
"预期收益率": "该词是明令禁用的营销表述,且输入侧并未放行它(不在含义题句式里)→ 输出侧保持命中即拦,收紧方向不失守",
"单字或两字的「没有」": "会在同一句里把后面的真实承诺一并豁免(实测反例:「这款产品没有风险,保本保收益」)"
},
"boundary_compliance": "未触碰零容忍集 11 条(业务层)、治理层硬模式 5 条(`governance.py`)、`CONTEXT_WINDOW` 与句子边界常量"
},
"probe": {
"cases": 22,
"mismatch_count": 0,
"mismatch": [],
"rows": [
{
"text": "本产品不保本",
"expected": null,
"actual": null,
"note": "短否定式 不保本",
"ok": true
},
{
"text": "该基金非保本浮动收益",
"expected": null,
"actual": null,
"note": "短否定式 非保本",
"ok": true
},
{
"text": "并非保本型产品",
"expected": null,
"actual": null,
"note": "短否定式 并非保本",
"ok": true
},
{
"text": "不确保安全",
"expected": null,
"actual": null,
"note": "短否定式 不确保(紧贴前缀)",
"ok": true
},
{
"text": "不担保安全",
"expected": null,
"actual": null,
"note": "短否定式 不担保(紧贴前缀)",
"ok": true
},
{
"text": "不保本的产品也很多,这只基金保本",
"expected": "保本",
"actual": "保本",
"note": "短否定式不得放过后文真实承诺",
"ok": true
},
{
"text": "保本",
"expected": "保本",
"actual": "保本",
"note": "红线词本体仍拦",
"ok": true
},
{
"text": "本产品保本",
"expected": "保本",
"actual": "保本",
"note": "真实承诺仍拦",
"ok": true
},
{
"text": "严禁承诺保本。但这只基金保本",
"expected": "保本",
"actual": "保本",
"note": "不得跨句豁免",
"ok": true
},
{
"text": "| 七日年化收益率 | 约1.85%-2.15% |",
"expected": null,
"actual": null,
"note": "指标名事实陈述",
"ok": true
},
{
"text": "七日年化收益率是货币基金过去七天每万份基金份额净收益折合成的年收益率",
"expected": null,
"actual": null,
"note": "指标名定义",
"ok": true
},
{
"text": "净值型产品是没有固定预期收益率、产品净值随投资运作波动的产品",
"expected": null,
"actual": null,
"note": "否定存在(没有固定)",
"ok": true
},
{
"text": "C1 保守型:无法承受任何本金损失,追求资产安全",
"expected": null,
"actual": null,
"note": "概念词事实陈述",
"ok": true
},
{
"text": "客户可在 APP「我的—安全中心」自助办理",
"expected": null,
"actual": null,
"note": "概念词在界面名里",
"ok": true
},
{
"text": "年化收益率 8%,非常划算",
"expected": "年化收益率",
"actual": "年化收益率",
"note": "指标名 + 推销口吻",
"ok": true
},
{
"text": "该产品预期收益率可达5%",
"expected": "预期收益率",
"actual": "预期收益率",
"note": "预期收益率仍拦(不可实现性断言)",
"ok": true
},
{
"text": "该产品预期收益率5%",
"expected": "预期收益率",
"actual": "预期收益率",
"note": "预期收益率命中即拦",
"ok": true
},
{
"text": "这只产品绝对安全,不用担心",
"expected": "安全",
"actual": "安全",
"note": "概念词 + 绝对化",
"ok": true
},
{
"text": "我希望本金绝对安全,即使收益很低",
"expected": "安全",
"actual": "安全",
"note": "概念词 + 绝对化(问卷选项)",
"ok": true
},
{
"text": "不得使用「安全」「保证」等误导性表述",
"expected": null,
"actual": null,
"note": "引用语境优先",
"ok": true
},
{
"text": "合规底线:严禁承诺保本保收益",
"expected": null,
"actual": null,
"note": "禁止语境",
"ok": true
},
{
"text": "请问该产品保证收益吗?",
"expected": null,
"actual": null,
"note": "询问语境",
"ok": true
}
]
},
"chunk_scan": {
"chunk_total": 628,
"union_blocked_before_c04": 22,
"union_blocked_after_c04": 6,
"per_word": [
{
"word": "保本",
"chunks_containing": 9,
"blocked_before_c04": null,
"blocked_after_c04": 5,
"samples_blocked": [
"### 第九条 问卷内容及评分标准 / / **Q1:您的年龄段是?**(满分10分) / / | 选项 | 分值 | / |------|------| / | A. 18-25周岁 | 8分 | / ",
"第九条 问卷内容及评分标准:A. 保本保息,资金安全最重要 2分",
"### 第十一条 产品风险等级划分 / / 公司销售的金融产品按风险由低到高划分为五个等级: / / | 风险等级 | 等级名称 | 典型产品 | 本金损失可能性 | / |----------|"
]
},
{
"word": "无风险",
"chunks_containing": 1,
"blocked_before_c04": null,
"blocked_after_c04": 0,
"samples_blocked": []
},
{
"word": "保证收益",
"chunks_containing": 2,
"blocked_before_c04": null,
"blocked_after_c04": 0,
"samples_blocked": []
},
{
"word": "预期收益率",
"chunks_containing": 1,
"blocked_before_c04": null,
"blocked_after_c04": 0,
"samples_blocked": []
},
{
"word": "年化收益率",
"chunks_containing": 4,
"blocked_before_c04": null,
"blocked_after_c04": 0,
"samples_blocked": []
},
{
"word": "安全",
"chunks_containing": 19,
"blocked_before_c04": null,
"blocked_after_c04": 2,
"samples_blocked": [
"### 第九条 问卷内容及评分标准 / / **Q1:您的年龄段是?**(满分10分) / / | 选项 | 分值 | / |------|------| / | A. 18-25周岁 | 8分 | / ",
"第九条 问卷内容及评分标准:A. \"我希望本金绝对安全,即使收益很低\" 2分"
]
},
{
"word": "零风险",
"chunks_containing": 1,
"blocked_before_c04": null,
"blocked_after_c04": 0,
"samples_blocked": []
}
],
"residual_samples": [
"### 第九条 问卷内容及评分标准 / / **Q1:您的年龄段是?**(满分10分) / / | 选项 | 分值 | / |------|------| / | A. 18-25周岁 | 8分 | / | B. 26-35周岁 | 10分 |",
"第九条 问卷内容及评分标准:A. 保本保息,资金安全最重要 2分",
"第九条 问卷内容及评分标准:A. \"我希望本金绝对安全,即使收益很低\" 2分",
"### 第十一条 产品风险等级划分 / / 公司销售的金融产品按风险由低到高划分为五个等级: / / | 风险等级 | 等级名称 | 典型产品 | 本金损失可能性 | / |----------|----------|---------",
"#### 8.2 信息披露禁止行为 / / 1. 不得预测产品投资收益或承诺保本保收益; / 2. 不得使用「安全」「保证」「承诺」「零风险」「无风险」等误导性表述; / 3. 不得片面夸大历史业绩,或以过往业绩暗示未来收益; / 4. ",
"禁止行为(负面清单):1 承诺保本保收益"
],
"residual_explanation": "残留全部是**保守方向**:① 「保本」类(红线词,含 `保本型银行理财` 品类名与政策清单片段);② 问卷片段里的「我希望本金绝对安全」(含绝对化线索,应拦)。两者都不是「把正确答案打成转人工」的误伤类型。"
},
"tests": {
"flipped": "test_red_line_word_stays_blocked_even_in_a_table → test_metric_name_in_a_fact_table_is_no_longer_blocked(旧口径「事实表格里也拦」与输入侧放行自相矛盾,已按 C-04 DoD ② 翻转并留痕理由)",
"added": [
"test_factual_term_mention_is_not_blocked",
"test_factual_term_still_blocks_when_claimed",
"test_short_negation_is_exempted",
"test_short_negation_does_not_release_a_later_promise"
],
"targeted": "4 文件 105 passed(含治理层与客服规则回归)"
},
"gate": {
"pytest": "2 failed / 1520 passed / 2 skipped(与 T0 基线同失败集;本轮新增 14 条用例)",
"pytest_flake_note": "首轮全量出现过 `test_http_accept_worker_commit_query_and_repeat[True]` 的第 3 个失败,复跑即消失、单跑通过 —— 该用例断言 `memory.extraction_requested` 事件为空,双 `runtime.execute` 并发下的既有抖动,与本轮改动无关(改动为纯字符串判定,且该用例消息不含任何规则词)",
"ruff": "22(改了的两文件 All checks passed,无新增)",
"mypy": "3(无新增)",
"docs": "50 documents, no number collision",
"schema": "89 business tables passed"
}
}