一、客服 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 生成的本地产物
109 lines
7.0 KiB
JSON
109 lines
7.0 KiB
JSON
{
|
||
"round": "W8 / 2026-09-19",
|
||
"what": "P0 清单 1~5 一次性收口:演示数据分层/资产口径对齐 + risk_tags 自述事实持久化 + F-03/F-04 演示脚本与账号速查 + F-06 产品证据链(dry-run + 正式执行)+ A-05 演示前五项自检",
|
||
"user_instruction": "按照你的建议 全部一起做一起测试 我时间有限 我需要你认真严谨的去把这个模块全部完成,遇到错误就自己去推理然后选择最优解",
|
||
"scope_changed": {
|
||
"code": [
|
||
"tools/seed_profile_demo.py",
|
||
"tools/sync_nanfang_official_product_governance.py"
|
||
],
|
||
"tests": [
|
||
"tests/unit/tools/test_nanfang_official_product_governance.py"
|
||
],
|
||
"docs": [
|
||
"客服agent/D2.5-客服Agent演示脚本与账号速查-2026-09-19.md(新增)",
|
||
"开发文档/D1.1(索引登记 53→54 份)",
|
||
"开发文档/D1.6 §4.33",
|
||
"客服agent/D2.1 v6.20"
|
||
],
|
||
"app_code": "无(本轮未改 app\\ 任何一行,故线上 API 进程无需重启)"
|
||
},
|
||
"findings": [
|
||
{
|
||
"id": "D-15",
|
||
"title": "演示数据「分层档位 vs 总资产」5/6 行不在同一区间",
|
||
"root_cause": "种子把 tier 和 total_asset 各自手写,从未对过公开门槛(金卡 50 万+ / 白金 200 万+ / 钻石 600 万+ / 尊享 1000 万+)",
|
||
"fix": "6 行按档位区间重排 total_asset;9001 由 gold 改 normal(普通)——它的钱来自场内模拟账户 10 万,10 万 < 50 万,只能落普通档;新增 TIER_BANDS 自检,种子跑完逐行打印 OK/不一致并在不一致时断言失败",
|
||
"verified": "seed_profile_demo.py 输出 6 行「分层自洽检查 … OK」;真 HTTP「我够哪一档?」→ 客户分层:普通(与该客户账户看板『总资产约 10 万』同口径,见 docs/44 场景 2)",
|
||
"change": {
|
||
"9001": "gold→normal, 60000→100000",
|
||
"9101": "12800000→8600000",
|
||
"9102": "860000→2600000",
|
||
"9103": "420000→620000",
|
||
"9104": "150000→560000",
|
||
"9105": "880000→2400000"
|
||
}
|
||
},
|
||
{
|
||
"id": "D-16",
|
||
"title": "risk_tags「种了会被抹掉」,且种子初始标签与重建标签形状不同(两套值)",
|
||
"root_cause": "risk_tags 是 ProfileAssemblyService 的自述类字段:记忆重建时 values['risk_tags'] = tags 整体重算,无自述事实即清空;而种子写的是英文静态标签(conservative 等),与重建产出的『自述:<key>=<value>』并非同一形状",
|
||
"fix": "种子为 6 个客户各写一条 user_facts 自述事实 preference:risk_level(共 18 行事实,6×3);fin_customer_profile.risk_tags 写「重建后会得到的那一个值」(自述:preference:risk_level=<自述>),使种子里外一致",
|
||
"verified": "连库实测:6/6 客户 rebuild 前后 risk_tags 逐字相同(EQUAL: True),且列值与快照值一致;investor_type 仍只来自问卷(红线未动)"
|
||
},
|
||
{
|
||
"id": "D-17",
|
||
"title": "产品证据链同步被 1 只演示品拖垮(唯一硬阻断)",
|
||
"root_cause": "fin_product 里 510300 挂在南方基金名下,但它是华泰柏瑞的同指数参考产品(product-notes.js 已声明『非本公司发行』);官方接口对它恒定返回 ETS-5BA00008『找不到基金信息』,脚本把它当硬错误、整轮抛 ValueError ⇒ 19 只真实产品的证据一条都进不来",
|
||
"fix": "新增 OfficialSourceMissError 区分『官方没有这只』与『抓取失败』;collect_rows 逐只跳过并列出(与 sync_nav_history.py / sync_market_prices.py 同口径,口径保持两元组不变以免动底座调用点 product_governance_monitor_service._default_loader);『一只都没取到』仍硬失败",
|
||
"verified": "dry-run: validated: suitability=19 contracts=19(跳过 510300 并打印理由);正式执行后连库:advisor_product_suitability_reference 0→19 行、advisor_product_contract_snapshot 0→19 行,source_url 全部是 nffund.com 官方链接,含管理费/托管费/基金合同标题",
|
||
"db_before_after": {
|
||
"suitability_reference": "0 → 19",
|
||
"contract_snapshot": "0 → 19"
|
||
}
|
||
},
|
||
{
|
||
"id": "D-18",
|
||
"title": "演示行情已过期 7288 分钟(A-05 第 4 项不达标)",
|
||
"fix": "python tools/sync_market_prices.py(20 只全部刷新)",
|
||
"verified": "TIMESTAMPDIFF(MINUTE, MAX(source_updated_at), NOW()) = 0"
|
||
},
|
||
{
|
||
"id": "D-19",
|
||
"title": "工具口径问题:dependency_health_check.py 把 neo4j 当硬前置",
|
||
"detail": "neo4j(7687) 未起 → 脚本抛 ServiceUnavailable 退出,看不到 milvus 结论;而客服链路不需要 neo4j(DEC-19:长期记忆召回=关)",
|
||
"fix": "D2.5 §1 写明替代判据(MilvusClient 三集合计数);本轮不改该工具(改动属底座工具,须另立会签)"
|
||
},
|
||
{
|
||
"id": "D-20",
|
||
"title": "过期内容:docs/44 与 docs/40 仍列 advisor_t / abc12345",
|
||
"detail": "投顾模块已整体清除,该账号在 sys_user 里不存在;照文档念会当场翻车",
|
||
"fix": "D2.5 §2.1 加「不要念它」警示;正式回写属 F-05 范围"
|
||
}
|
||
],
|
||
"gates": {
|
||
"pytest": "1749 passed / 0 failed / 2 skipped(较上一步 1746 +3 条新用例)",
|
||
"ruff": "22(=基线)",
|
||
"mypy": "3(=基线)",
|
||
"_consistency.py": "GATE PASS",
|
||
"tools/e2e_smoke_test.py --read-only": "31/31",
|
||
"_eval_harness/http_probe.py": "11/11 succeeded"
|
||
},
|
||
"a05_self_check": {
|
||
"1_container_runtime": "milvus-standalone / milvus-etcd / milvus-minio Up(healthy);MySQL 3306 与 Redis 6379 为本机服务",
|
||
"2_vector_store": "fin_faq_collection=150 / fin_product_collection=191 / fin_policy_collection=288 / user_long_term_memory_v1=8(召回关)",
|
||
"3_worker": "python -m app.worker 在跑",
|
||
"4_quotes": "刷新后 age_min=0(刷新前 7288)",
|
||
"5_local_vector_switch": "MILVUS_LOCAL_URI 未设置 ⇒ milvus_local_uri='' ⇒ 实际 URI http://127.0.0.1:19530"
|
||
},
|
||
"accounts_verified": {
|
||
"cust_t": "200 roles=[customer]",
|
||
"risk_t": "200 roles=[risk_operator]",
|
||
"admin_t": "200 roles=[admin]",
|
||
"offsite_t": "200 roles=[operator]",
|
||
"review_t": "401(设计如此:账号存在但不绑角色、不设口令)",
|
||
"visitor": "201(sub 为数字串)"
|
||
},
|
||
"artifacts": {
|
||
"demo_doc": "客服agent/D2.5-客服Agent演示脚本与账号速查-2026-09-19.md",
|
||
"demo_lines_evidence": [
|
||
"docs/evidence/20260919-t8-demo-lines.json(17 条)",
|
||
"docs/evidence/20260919-t8-demo-lines2.json(5 条)"
|
||
]
|
||
},
|
||
"honest_notes": [
|
||
"本轮用户已授权自主决策;上述 3 处修复均为『按最优解自行裁定』,未逐项回问。",
|
||
"F-06 的 DoD 第 4 条『演示相应步骤候选数 > 0』已随投顾模块清除而失去对象(消费方已删除);本轮据实只交付『证据链非空 + 官方来源』,不作候选人数的结论。",
|
||
"dependency_health_check.py 与本轮无关的 22 个 ruff / 3 个 mypy 基线问题均未修(超出本轮范围)。"
|
||
]
|
||
} |