一、客服 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 生成的本地产物
25 KiB
前端验收清单(正式门户)
被测对象:正式前端
app/static/portal/,由app/main.py挂载在/portal/入口:http://127.0.0.1:8000/portal/(/与/portal/都会 307 跳到/portal/guest/home/) 时点:2026-09-13(第三次更新:补入投顾/运营两套页面、访客客服浮窗、Worker 前置) 🔴 状态更正(2026-09-19):本文档写于 2026-09-13。此后客服 Agent 已整体重构 (五出口E1—E5c+ 转人工白名单 4 类),投顾模块已整体清除(D4.4/D4.5), 客服浮窗已于 2026-09-19 重建恢复(乙-15)。因此:§6「投顾」整节与账号表的advisor_t行 已作废;§9-1 的转人工口径已被H-04白名单取代(见各行 🔁 标记)。 现行验收入口见客服agent\D2.5-客服Agent演示脚本与账号速查-2026-09-19.md。
证据口径 ✅实测 = 我用真实 HTTP 请求打过,数字是那次响应的真实值; ⚠️待点验 = 只能从代码与接口推断的页面交互,需要你在浏览器里点一遍。
交付方自述的路由与数据源见
app/static/portal/README.md。
0. 启动与前置 ⚠️ 这一节最容易踩
| # | 项 | 命令 / 检查 | 预期 |
|---|---|---|---|
| 0-1 | 依赖服务 | MySQL、Redis 可用;Milvus 需要 Docker Desktop 在运行 | 平台能起,无 500 |
| 0-2 | RBAC 种子 | python tools/seed_test_rbac.py |
五个演示账号可登录 ✅实测 |
| 0-3 | 演示口令 | python tools/set_user_password.py |
口令生效(非幂等,重跑等于改密)✅实测 |
| 0-4 | 虚拟资金账户 | python -m tools.seed_sim_account_demo |
客户 9001 开 10 万初始资金 + 2 只持仓。 不跑这步, /customer/dashboard/ 与 /customer/cash-ledger/ 必然打不开(404「客户未开户」)✅实测 |
| 0-5 | 风控 Agent 配置 | python tools/publish_risk_agent_config.py |
risk_overview/risk_search/risk_evidence 三个工具生效 ✅实测 |
| 0-6 | Agent Worker(必开!) | python -m app.worker |
不启动它,所有客服对话都会"超时" —— 见下方说明 |
⚠️ 0-6 为什么是"必开"而不是"必停"
Agent 请求是三段式:API 受理(返回 202)→ Worker 领单执行 → 落结果。
没有 Worker 时,agent_run 会一直停在 status='queued'、worker_id 为空,
前端轮询到底只会显示"客服繁忙/超时" —— 看起来像链路慢,实际是没人处理。
(2026-09-13 的访客浮窗"回答超时"就是这么来的。)
docs/20里写的是"跑验收脚本前先停 Worker"(免得抢队列)—— 两件事不矛盾: 要跟 Agent 对话就必须开着;要跑验收脚本就关掉。
排查第一步永远是:查 agent_run 最新那行的 status 是不是 queued。
# 一次性把前置跑齐(两个终端)
python tools/seed_test_rbac.py
python tools/set_user_password.py
python -m tools.seed_sim_account_demo
python tools/publish_risk_agent_config.py
# 终端 1:API
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000
# 终端 2:Worker(客服对话依赖它)
python -m app.worker
模块级变量是
app,不是application。
1. 页面路由与静态资源 ✅实测
18 个路径全部 200(/ 与 /portal/ 记的是跟随重定向后的最终 200):
| 分组 | 路径 | 实测 |
|---|---|---|
| 跳转 | / → /portal/guest/home//portal/ → 同上 |
✅ |
| 访客 | /portal/guest/home/(5740 B)、products/(2153 B)、product-detail/(2317 B) |
✅ |
| 客户 | customer/login/、dashboard/、holdings/、orders/、transactions/、profit-loss/、cash-ledger/、risk-questionnaire/ |
✅ 8/8 |
| 员工 | employee-console/login/、employee-console/workspace/ |
✅ |
| 风控 | employee-risk/dashboard/(11872 B) |
✅ |
| 投顾 | employee-advisor/dashboard/(2449 B) |
✅ 本轮新增 |
| 运营 | employee-operations/dashboard/(1968 B) |
✅ 本轮新增 |
13 个关键静态资源全部 200:api-client.js / auth.js / login-controller.js / permission-guard.js /
layout/app-shell.js / visitor-token.js / product-notes.js / customer-service-widget/widget.js / widget.css /
base.css / tokens.css / operations.css / auth-layout.css ✅
(common/mock-data.js 已于 2026-09-13 随公开产品接口接入删除,实测返回 404 ✅)
2. 访客(未登录)
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 2-1 | 打开 /portal/guest/home/ |
首屏含品牌与产品摘要 | ⚠️待点验(推荐位取接口返回的前 3 只) |
| 2-2 | 看页面的数据来源提示条 | 产品列表页与详情页顶部都有浅色提示条,写明数据来自平台产品库与行情源同步结果 | ✅ 三个页面都写 [data-source-notice];接口侧由 tests/integration/test_public_products_endpoint_mysql.py 守着⚠️ 渲染位置待点验 |
| 2-3 | 进产品列表 / 详情 | 列表显示产品库全部 20 只(不再是 8 只);能筛选、能按 ?view=ranking 排序 |
✅ 接口实测 count=20;?view=ranking 按 change_pct 排序、缺数据的排最后⚠️ 渲染待点验 |
| 2-4 | 点登录入口 | 进 /portal/customer/login/ |
⚠️待点验 |
公开产品数据已接真实接口(2026-09-13):
GET /api/v1/products(编号 P001,见docs/05§19), 产品与净值取自fin_product、行情取自fin_market_price。 此前三页读的是common/mock-data.js—— 那份数据只有 8 只,且其中 6 只根本不在产品库里 (如把海富通的511360标成"南方短融ETF"),净值也是编的。该文件已删除。两条不能想当然的口径(改前端前先读):
change_pct可能是null(该行由净值降级路径写入、源没给涨跌幅,或行情未同步)。 页面必须显示"暂无"——formatPercent收到null会渲染成+0.00%, 那等于告诉客户"今天平盘"。 2026-09-13 起已正常有值:行情源(腾讯)直接返回涨跌幅,由20260913_market_price_change_pct迁移新增的fin_market_price.change_pct存下, 同步脚本写入;接口优先用它,历史行才回退到"今日收盘 vs 昨收"现算。- 历史净值走势图:
fin_nav_history由tools/sync_nav_history.py同步 (东财净值接口,近 120 个交易日,实测 20 只 / 2513 行)。 表为空时不画曲线、显式显示"尚未接入",绝不回退到编造点位 —— 走势图最容易被当成真实业绩。
2.5 访客智能客服浮窗 ⭐ 本轮重点
公开首页、产品列表页、产品详情页右下角都有客服浮窗。
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 2-5 | 点浮窗,问一个知识库里有的问题 | 约 4 秒内给出答案 | ✅实测端到端 4.11s 问「基金定投是什么」→ score 0.8203 → 直接答 |
| 2-6 | 问一个知识库里没有的问题 | 🔁 2026-09-19 更正:走 E5b 部分答 + 引导(给出能找到的公开资料 + 邀请改写问法),不再直接引导拨热线 |
现行口径见 D2.5 §1 台词表 |
| 2-7 | 问个人账户相关问题(如"我的风险等级是多少") | 提示"该服务需要登录后才能查询您的个人信息" | ⚠️待点验(代码路径已确认:_guide_to_login) |
| 2-8 | 浮窗里点"登录后查询账户" | 跳客户登录页 | ⚠️待点验 |
访客令牌机制:POST /api/v1/visitor-tokens(无鉴权)
→ 返回短期令牌,身份是 roles=("visitor",)、permissions=("agent:run","knowledge:query") ✅实测
⚠️ 访客与客户走的是不同的检索工具名:访客走
query_knowledge(要knowledge:query), 登录客户走search_knowledge(要knowledge:reference:read)。两者必须同时在发布配置agent_tools/customer_service:<intent>的白名单里 —— 缺哪一条,对应人群就一问即失败。 2026-09-13 修过一次:当时白名单只有search_knowledge,访客一问就抛ForbiddenAgentError。
3. 客户(cust_t / 123456)
3.1 登录与账户域
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 3-1 | 登录(A034) | 200,拿到令牌,跳 dashboard | ✅ 200,user_id=9001,expires_in=1800 |
| 3-2 | dashboard(T001) | 总资产 / 可用资金 / 持仓市值 | ✅ 200(修前置前是 404「客户未开户」) |
| 3-3 | 持仓(T006) | 持仓表 | ✅ 200 |
| 3-4 | 交易流水(T007) | 流水表 | ✅ 200 |
| 3-5 | 资金流水(T009) | 资金明细 | ✅ 200 |
| 3-6 | 订单列表(T003) | 空列表不报错 | ✅ 200 |
| 3-7 | 下单(T002) | 报文 {product_code, order_side, quantity},order_side ∈ {buy, sell} |
⚠️待点验 需真实 product_code(7002 是 product_id 不是 code) |
| 3-8 | 盈亏(T001) | 收益曲线 | ⚠️待点验 |
| 3-9 | 风险测评(ONB001) | 返回问卷定义 | ✅ 200 |
| 3-10 | 提交问卷(ONB002) | 提交后状态变更 | ⚠️待点验 |
3.2 客户客服浮窗
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 3-11 | 在客户工作台用浮窗提问 | 与访客同一浮窗,但身份是登录客户 | ⚠️待点验(需 Worker 在跑) |
| 3-12 | 点"转人工客服" | POST /conversations/{sid}/handover-requests → 202,工单进管理员队列 |
✅ 实测 202(前提:先由 C001 真实创建会话) |
转人工的实现口径(🔁 2026-09-19 更新,
H-04):转人工收敛为 4 类白名单 ——客户显式要求人工 /P0反诈 /P1账户数据 /P2写操作与争议;"答不上来"不再转人工(改走E5b部分答 + 引导,不建工单)。 上面 3-12 是客户主动点"转人工"按钮才建工单,两者不是一回事。
4. 员工 / 管理员(admin_t / 88888888)
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 4-1 | 员工入口登录 | 进 workspace | ✅ 200 |
| 4-2 | 配置发布列表(A002) | 版本列表 | ✅ 200 |
| 4-3 | 模型端点(A012) | 端点列表 | ✅ 200(deepseek-flash、qwen-embedding) |
| 4-4 | 审计查询(A033) | 时间/动作/操作者/结果 | ✅ 200 |
| 4-5 | 角色 / 权限 / 用户身份(A035–A038) | 角色与权限明细 | ✅ 200(customer 26 项、advisor 28 项、admin 59 项、operator 2 项、risk_operator 10 项) |
| 4-6 | 画像候选审核(A039) | 候选列表 | ✅ 200 |
| 4-7 | 客服转人工工单(ADMIN_HANDOVERS) | 工单队列,不返回客户标识与原始正文 | ✅ 200 |
| 4-8 | 配置发布四态(A004/A005/A006) | 校验→审核→激活,必须带 Idempotency-Key |
⚠️待点验(写操作) |
平台只提供 RBAC 只读查询:没有改权限的写接口,权限变更走
config_release发布。这是设计。
5. 风控(risk_t / 666666)—— 对齐 docs/风控业务演示文档/17-*.md
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 5-1 | 风险概览(RK001) | 总量/等级/待处理/超时/重点预警 | ✅ 200(total=2 pending=1 overdue=2 levels{高风险:2}) |
| 5-2 | 预警队列(RK002) | 每页 5 条、筛选、分页 | ✅ 200(2 条:ALDEMO0002、ALDEMO0001)⚠️ limit 上限就是 5,传 20 会 422 且表格渲染不出来 |
| 5-3 | 队列筛选 | 关键词/客户号/风险等级/规则码/产品/时间 | ✅ rule_code=RW-015 → ALDEMO0002、customer_no=T-CUST → 2 条⚠️ 风险等级填「高/中/低」:预警对象用「高」,概览 levels 用「高风险」 |
| 5-4 | 预警详情(RK003) | 编号/状态/规则/证据/回执/客户 | ✅ 200(alert 23 字段 + customer 13 字段) |
| 5-5 | 八类证据(RK004) | customers/products/transactions/capital_flows/holdings/login_records/alerts/notifications |
✅ 8/8 全 200 ⚠️ 是 holdings,写 positions 会被 422 |
| 5-6 | 通知记录(RK005) | 预警编号/类型/发送状态 | ✅ 200 |
| 5-7 | 手动扫描(RK006) | 200 code=0,要带 Idempotency-Key |
✅ 200 |
| 5-8 | 确认接收(RK007) | 二次确认;状态不符返回 409 | ✅ 409「只有待处理的预警才能确认解决」 |
| 5-9 | 进入调查(RK008)/ 关闭误报(RK009) | 误报必须填理由 | ⚠️待点验(写操作) |
| 5-10 | 结案(RK010)/ 升级(RK011) | 结案填 resolution、升级填 reason;需先确认接收 |
⚠️待点验(顺序:确认 → 调查/误报/升级/结案) |
| 5-11 | 证据上传(RK012) | multipart/form-data |
⚠️待点验 |
| 5-12 | 日报(RK013/RK014/RK015) | 生成 / SSE 流式 / 多邮箱发送 | ✅ RK013 200;SSE 事件类型实测 start/progress/replace |
6. 投顾(advisor_t / abc12345)⭐ 本轮新增页面〔🔴 2026-09-19 起整节作废:投顾模块已整体清除,不要按本节验收〕
登录入口同样是员工登录页 /portal/employee-console/login/,登录后自动落到投顾工作台。
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 6-1 | 用 advisor_t 登录 |
跳 /portal/employee-advisor/dashboard/ |
✅ 实测守卫生效(此前会静默弹回登录页,已修) |
| 6-2 | 工作台列表 | 显示"投资目标方案书 · 客户 9001"卡片 + 发布时间 + 方案内容 | ✅ 接口实测返回 1 条(content_id=1、customer_id=9001、type=investment_goal_book、published_at=2026-09-13T10:50:17) |
| 6-3 | 点"刷新" | 重新拉取 ADVISOR_PUBLISHED |
⚠️待点验 |
| 6-4 | 用别的角色访问该页 | risk_operator 会被弹回风控页;operator 弹回运营页 |
✅ 实测守卫矩阵 |
数据口径(ProductRecommendationService.published):
按「本人 + sys_customer_assignment 里名下归属客户」过滤,且覆盖两类内容 ——
investment_goal_book(方案书,发布后 review_status='published')与
advisor_recommendation_plan(推荐方案,审核后 'approved')。
不用
data_scope的原因:投顾持有promotion:*这类 all 级权限,IdentityService会把整个身份的 scope 抬到all,按它判定会放开到全部客户。 归属关系来自sys_customer_assignment(逐条授权 + 时间窗校验),比 scope 更窄。本机归属数据:
sys_customer_assignment只有一行(customer_id=9001, employee_id=9020, advisor)。 所以投顾现在能看到客户 9001 的交付物;换环境这条数据不跟着走,页面会是空态。
6.5 方案书的审核与发布必须由管理员做
客户确认目标 → 管理员审核方案书 → 管理员发布方案书
review_book 与 publish_book 都带 admin=True(investment_goal_service.py:174/216)——
投顾虽然有 investment-goal:review 权限码也做不了。这是有意的复核环节,不是缺陷。
实测:投顾调用审核 → 403;管理员调用 → 200 ✅
7. 运营(offsite_t / offsite123)⭐ 本轮新增页面
| # | 操作 | 预期 | 证据 |
|---|---|---|---|
| 7-1 | 用 offsite_t 登录 |
跳 /portal/employee-operations/dashboard/ |
✅ 实测守卫生效(此前同样静默弹回) |
| 7-2 | 场外邮件列表(OFFSITE_MAILS) |
分页列表:主题/发件人/时间/状态 | ✅ 200 data=dict{items,page,page_size,total} |
| 7-3 | 收件箱状态(OFFSITE_MAILBOX) |
邮箱 / 游标状态 / 阻塞标记 | ✅ 200 data=dict{mailbox,status,blocked,last_uid,…} |
| 7-4 | 用客户/风控访问这两个接口 | 被拦 | ✅ 客户 code=403 当前角色不能操作场外基金流程;风控 code=403 缺少场外基金操作权限 |
场外线按角色收口(
operator/risk_operator/admin/super_admin),不是按权限码。
8. 通用预期(跨页面)
| # | 情形 | 预期 |
|---|---|---|
| 8-1 | 业务失败也返回 HTTP 200 | 平台把业务错误放在 body.code(如生成失败 HTTP 200 + code=422),前端按 error-codes.js 解析 ✅实测 |
| 8-2 | 403 | "没有当前操作权限";按钮可见性应与服务端权限一致 ✅实测 |
| 8-3 | 404 | SESSION_NOT_FOUND 被三个异常类共用(会话不存在 / 客户不可访问 / 知识文档不存在),只能看 message ✅实测 |
| 8-4 | 幂等 | 写请求必须带唯一 Idempotency-Key(api-client.js 用 idempotent: true 标记)✅实测 |
| 8-5 | 多标签 | 各页面独立。注意:auth.js 现在以 cookie 为权威(跨标签同步),所以同一浏览器两个账号不能并存 ✅实测代码逻辑 |
| 8-6 | 排版 | 文字不重叠、内容不溢出、表格行高稳定 ⚠️待点验 |
| 8-7 | 缓存 | 产品列表/详情页的 CSS/JS 已带 ?v=20260913-4;若改了资源仍看不到效果,请硬刷新 ⚠️待点验 |
9. ⚠️ 看起来像 bug、其实是设计(测试时最容易被误判的三件事)
9-1 "客服答不上来,总是引导转人工" —— 🔁 本节已于 2026-09-19 重写(旧结论已作废)
客服命中知识后要过两道阈值(customer_service.py:148-150):
HIGH_SCORE = 0.75 # ≥ 0.75 直接答
MID_SCORE = 0.55 # 0.55~0.75 之间,必须同时满足 MIN_GAP
MIN_GAP = 0.07 # top1 领先次优的最小间隙
实测三条,逐条对上:
| 提问 | top1 分数 | 次优 | 间隙 | 判定 |
|---|---|---|---|---|
| 基金定投是什么 | 0.8203 | 0.5886 | 0.2317 | ≥0.75 → 直接答 ✅ |
| 南方沪深300ETF的起投金额是多少 | 0.6818 | 0.6784 | 0.0034 | 间隙 < 0.07 → E5b 部分答 + 引导(旧实现是"转人工";知识库至今仍无场内条目) |
| 购买基金需要什么条件 | 0.5221 | 0.5162 | 0.0059 | 分数 < 0.55 → 澄清(E1)/ E5b 引导(不再直接转人工) |
第二问如果硬答,会答成"南方结构性存款(挂钩型):起投金额 20 万元" —— 那是另一个产品,
而且客户问的是场内 ETF。"不硬答"在这里仍然是正确行为;但按 🔁 2026-09-19 的新口径,它现在落到 E5b 部分答 + 引导(给出能查到的公开资料 + 邀请换个问法),只有 4 类白名单才转人工。
真正要改的是知识库内容,不是代码:检索命中的是一套"南方科技有限公司 个人理财产品手册" 的素材(
PROD-*/FAQ-*/POL-*),里面没有本项目的场内 ETF 条目,所以问 ETF 注定分数上不去。
9-2 "客户能读投顾的接口" —— 不是越权
GET /api/v1/advisor/recommendations/published 客户调用返回 200,但 SQL 里按
customer_id IN (本人 + 归属客户) 过滤,读的是自己的。风控返回 403 是因为没有
product-recommendation:read:self 权限码。用"能访问"判断越权会误判。
9-3 "投顾发布不了方案书" —— 是有意的复核环节
见 6.5。审核与发布都要求 admin=True。
10. 我做了什么验证(可复现)
| 项 | 方式 | 结果 |
|---|---|---|
| 18 个页面路径 + 12 个静态资源 | 逐个 GET | 全部 200 |
| 五个角色登录 | POST /api/v1/auth/tokens × 5 |
全部 200 |
| 各角色登录后落点与越权矩阵 | 真实执行 auth.js 的守卫函数(node + DOM 桩) |
advisor→投顾页、operator→运营页、risk→风控页、admin→工作台;交叉误入能弹回自己家 |
| 访客客服问答端到端 | 与浮窗同链路(V001 → R001 → 轮询 R002) | 4.11s / 4.09s / 4.82s,三条全部 succeeded |
| 投顾页数据 | 走完整业务流(客户确认→管理员审核→管理员发布)后复查 | 投顾读到归属客户 9001 的方案书;客户只读到自己的;风控 403 |
| 平台门禁 | ruff / mypy / pytest / 表审计 / 文档检查 | ruff 干净 · mypy 249 文件 0 错 · 单元+契约 1376 passed 2 skipped · 集成 104 passed · 89 张业务表 · 文档 55 份无编号冲突 |
| 前端 JS 语法 | 7 个文件按 ESM 解析检查 | 全部通过 |
联调中发现并已修的问题:
T001/T009恒 404「客户未开户」 ——tools/seed_test_rbac.py把fund_account_status硬编码成'closed',与create_test_user.py的{customer: 已开户, employee: closed}不一致。 已改为按user_type取;配合seed_sim_account_demo后 T001/T006/T007/T009 全部 200。rule_code筛选恒为空 ——risk_repository.py用.contains([code]),SQLAlchemy 编译成LIKE, 而trigger_rule_codes是 JSON 数组。已改为func.json_contains(...),扫描去重处同一写法一并修。- 误提交的
.agents/skills(15 个文件) —— AI 助手配置,与本项目无关,已移除并加入.gitignore。 - 投顾/运营登录后静默弹回登录页 ——
staffHomeForRoles缺这两个角色的落点, 进 workspace 后被requireAdmin弹回且不带任何提示,看起来像"登录没反应"。 已补两个落点与requireAdvisor/requireOperator守卫。 - 访客客服浮窗一问即失败 —— 客服代码让访客走
query_knowledge,但发布配置的三个知识意图 只发了search_knowledge,工具白名单直接抛ForbiddenAgentError。已补发query_knowledge(保留search_knowledge给登录客户)。 - 访客页的"演示数据"声明被删掉、但假数据还在渲染 —— 已恢复
MOCK_SOURCE_NOTICE、 两个页面的提示条与样式,并给link/script加版本参数(此前会被浏览器缓存)。 2026-09-13 已彻底解决:公开产品接口(P001)落地后common/mock-data.js整体删除, 页面改读真实数据 —— 只要数据是假的就总有人想删那条声明,接口接上才是根治。 - 发布脚本会静默丢提示词 ——
publish_customer_service_config.py只继承platform_config_item,把customer_service_chitchat提示词漏在了旧版本里。 已改用effective_snapshot()读全三张受管表、补提示词搬运与条数硬校验;丢失的提示词已按原文恢复。
11. 已知问题(未修)
| 项 | 说明 |
|---|---|
| 知识库没有场内 ETF 内容 | 检索命中的是旧理财手册素材,问 ETF 类问题分数不足。属知识内容工作,需业务提供素材后灌库(🔁 2026-09-19:此类问题现已走 E5b 部分答 + 引导,不再转人工) |
fin_knowledge_meta 表为空 |
Milvus 里有知识(FAQ-*/PROD-*/POL-* 都能检索到),但 MySQL 元数据表 0 行 ⇒ 管理端列表(GET /api/v1/knowledge/list)看不到内容、也无从删除。元数据与向量不一致 |
400-889-8899 + 官网 nffund.com,不是「南方财富」;本条记述的当日决定已被 D1.4 §2.1—§2.4 的替换矩阵取代〕 |
已按当时口径统一为「南方财富」:customer_service_rules.py 的防诈骗/转人工话术、risk_agent.py 与 risk_analysis_service.py 的风控助手名、customer_service.COMPANY 常量、app/static/index.html 旧联调页、风控页助手标题,以及闲聊提示词(已重发为 release 308 / v5)。⚠️ 仍是旧品牌的地方:Milvus 里的知识素材( RAG-*/NF-* 写"奶龙基金"、PROD-* 写"南方科技")—— 属知识数据,需重灌才能统一。⚠️ 不能改: fin_product.fund_manager = "南方基金",它被 market_quote_sync_service / product_history_sync_service 当过滤条件用 |
| 知识库缺场内基金条目 | 已产出草稿 docs/42-场内基金知识条目草稿.md(含 20 只产品,数据取自 fin_product),待审核后入库。草稿里费率等缺失字段一律标"以交易页面为准",未编造数字 |
ADVISOR_GOAL / ADVISOR_ANALYSIS 声明未用 |
投顾页只调了 ADVISOR_PUBLISHED;且 portfolio-analysis 的 body 必须是 {}(空模型 + extra="forbid") |
widget.js 里的 portal:auth-changed 监听 |
是死代码 —— auth.js 从不派发该事件(它用 BroadcastChannel) |
| 同一浏览器不能并存两个账号 | 见 8-5,是跨标签同步的代价,若不符合预期需要改回 |
附:演示账号
| 角色 | 用户名 | 密码 | user_id | 入口 |
|---|---|---|---|---|
| 客户 | cust_t |
123456 |
9001 | /portal/customer/login/ |
| 风控专员 | risk_t |
666666 |
9002 | /portal/employee-console/login/ |
| 管理员 | admin_t |
88888888 |
9003 | 同上 |
| 运营 | offsite_t |
offsite123 |
9006 | 同上(→ 运营工作台) |
advisor_t |
abc12345 |
该角色与账号库里已不存在,不要念 |
⚠️
tools/set_user_password.py的内置演示规则只写了 9001/9002/9003; 9006 与 9020 的口令是建号时单独设的,换环境重建时会没有密码,需要用python tools/set_user_password.py --user 9006 --password <口令>补设。 另:9004review_t、9005offsite_worker是占位符,登不了。