Files
group_fqcd_jr/app/static/portal/employee-risk/dashboard/index.html
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

162 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>风险工作台 · 南方基金</title>
<link rel="stylesheet" href="/static/portal/common/base.css">
<link rel="stylesheet" href="/static/portal/employee-risk/dashboard/dashboard.css?v=20260913-11">
</head>
<body>
<main id="main-content" class="page-shell operations-shell">
<section class="operations-hero fade-in">
<div class="operations-hero__content">
<p class="operations-kicker">场内基金模拟交易风险监测</p>
<h1 class="operations-hero__title">风险事件研判与处置工作台</h1>
<p class="operations-hero__copy">聚合规则扫描、预警证据、人工处置与通知结果,所有状态变化均由服务端鉴权并留存审计。</p><div class="operations-hero__signals" aria-label="风险工作台能力"><span>预警队列</span><span>证据查询</span><span>通知留痕</span></div>
</div>
<div class="operations-hero__meta">
<div class="operations-hero__identity">
<strong data-staff-name>当前操作员</strong>
<button class="risk-notice-button" type="button" data-system-tips aria-haspopup="dialog" aria-label="站内提醒">
<svg class="risk-notice-button__icon" viewBox="0 0 24 24" aria-hidden="true">
<path d="M10.268 21a2 2 0 0 0 3.464 0"></path>
<path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"></path>
</svg>
<span>站内提醒</span>
<span class="risk-notice-button__count" data-system-tip-count hidden>0</span>
</button>
</div>
<span data-data-scope>数据范围加载中</span>
</div>
</section>
<section class="metric-grid" data-risk-metrics aria-label="风险概览"></section>
<section class="operations-layout">
<article class="panel panel--flush risk-main-panel">
<div class="operations-tabs" role="tablist" aria-label="风险功能">
<button class="operations-tab" type="button" role="tab" aria-selected="true" data-tab="alerts">预警队列</button>
<button class="operations-tab" type="button" role="tab" aria-selected="false" data-tab="evidence">证据查询</button>
<button class="operations-tab" type="button" role="tab" aria-selected="false" data-tab="notifications">通知记录</button>
<button class="operations-tab" type="button" role="tab" aria-selected="false" data-tab="assistant">风控助手</button>
</div>
<section class="operations-view" data-view="alerts">
<form class="risk-filter operations-toolbar" data-alert-filter>
<label class="form-field"><span class="form-field__label">关键词</span><input class="form-field__input" name="keyword" maxlength="128" placeholder="预警、客户或产品"></label>
<label class="form-field"><span class="form-field__label">客户编号</span><input class="form-field__input" name="customer_no" maxlength="32" placeholder="业务客户编号"></label>
<label class="form-field"><span class="form-field__label">产品代码</span><input class="form-field__input" name="product_code" maxlength="32" placeholder="场内基金代码"></label>
<label class="form-field"><span class="form-field__label">风险等级</span><select class="form-field__input" name="risk_level"><option value="">全部等级</option><option value="高">高风险</option><option value="中">中风险</option><option value="低">低风险</option></select></label>
<label class="form-field"><span class="form-field__label">规则编号</span><input class="form-field__input" name="rule_code" pattern="RW-[0-9]{3}" placeholder="RW-007"></label>
<div class="operations-toolbar__actions"><button class="button" type="submit">查询</button><button class="button button--primary" type="button" data-scan data-permission-required="risk:alert:scan">手动扫描</button></div>
</form>
<div data-alert-table></div>
<div class="operations-pagination"><span class="pagination-summary" data-alert-summary></span><div class="pagination-actions"><button class="button table-action" type="button" data-alert-prev disabled>上一页</button><button class="button table-action" type="button" data-alert-next disabled>下一页</button></div></div>
</section>
<section class="operations-view" data-view="evidence" hidden>
<form class="risk-filter operations-toolbar" data-evidence-filter>
<label class="form-field"><span class="form-field__label">证据类型</span><select class="form-field__input" name="source"><option value="customers">客户</option><option value="products">产品</option><option value="transactions">交易</option><option value="capital_flows">资金流水</option><option value="holdings">持仓</option><option value="login_records">登录记录</option><option value="alerts">风险预警</option><option value="notifications">通知</option></select></label>
<label class="form-field"><span class="form-field__label">关键词</span><input class="form-field__input" name="keyword" maxlength="128" placeholder="按当前证据字段检索"></label>
<label class="form-field" data-behavior-filter><span class="form-field__label">行为关注度</span><select class="form-field__input" name="behavior_level"><option value="">全部</option><option value="normal">正常</option><option value="slight">轻微</option><option value="attention">关注</option><option value="high">高关注</option><option value="immediate">立即处理</option></select></label>
<div class="operations-toolbar__actions"><button class="button" type="submit">查询证据</button></div>
</form>
<div data-evidence-table></div>
<div class="operations-pagination"><span class="pagination-summary" data-evidence-summary></span><div class="pagination-actions"><button class="button table-action" type="button" data-evidence-prev disabled>上一页</button><button class="button table-action" type="button" data-evidence-next disabled>下一页</button></div></div>
</section>
<section class="operations-view" data-view="notifications" hidden>
<form class="risk-filter operations-toolbar" data-notification-filter>
<label class="form-field"><span class="form-field__label">关键词</span><input class="form-field__input" name="keyword" maxlength="128" placeholder="通知或预警编号"></label>
<label class="form-field"><span class="form-field__label">发送状态</span><select class="form-field__input" name="send_status"><option value="">全部状态</option><option>待发送</option><option>已发送</option><option>发送失败</option><option>未启用</option></select></label>
<div class="operations-toolbar__actions"><button class="button" type="submit">查询通知</button></div>
</form>
<div data-notification-table></div>
<div class="operations-pagination"><span class="pagination-summary" data-notification-summary></span><div class="pagination-actions"><button class="button table-action" type="button" data-notification-prev disabled>上一页</button><button class="button table-action" type="button" data-notification-next disabled>下一页</button></div></div>
</section>
<section class="operations-view risk-assistant" data-view="assistant" hidden>
<div class="risk-assistant__intro"><div><h2>南方基金风控助手</h2><p>用于查询风险概览、预警和证据,结论仅作为人工研判草案。</p></div><span class="tag tag--neutral">只读分析</span></div>
<div class="risk-context-bar">
<span>当前会话:<strong data-chat-context>通用风险问答</strong></span>
<button class="button table-action" type="button" data-clear-chat-context hidden>退出预警上下文</button>
</div>
<form class="risk-alert-context-form" data-alert-context-form>
<label class="form-field"><span class="form-field__label">预警编号</span><input class="form-field__input" name="alert_no" maxlength="64" pattern="[A-Za-z0-9_-]+" placeholder="输入预警编号后绑定上下文"></label>
<button class="button" type="submit">绑定预警</button>
<div class="form-alert" data-alert-context-error></div>
</form>
<details class="agent-boundary">
<summary>能力边界</summary>
<p>仅支持风险概览、预警列表和指定预警证据的只读查询与研判草案,不执行确认、调查、关闭、升级或数据修改。</p>
</details>
<div class="risk-chat" data-chat-log aria-live="polite"></div>
<div class="risk-prompts" data-general-prompts><button type="button" data-prompt="查看当前风险概览">当前风险概览</button><button type="button" data-prompt="查询高风险预警">高风险预警</button><button type="button" data-prompt="说明风控助手的能力边界">能力边界</button></div>
<div class="risk-prompts risk-prompts--alert" data-alert-prompts hidden>
<button type="button" data-alert-prompt="请基于当前预警证据生成风险研判,说明命中规则、核心证据、风险判断和人工复核建议。">生成研判</button>
<button type="button" data-alert-prompt="请基于当前预警生成客户回访话术,保持中性审慎,不预设客户违规。">生成话术</button>
<button type="button" data-alert-prompt="请基于当前预警生成内部工单摘要,包含工单标题、命中规则、关键证据、建议动作和处理时限。">工单摘要</button>
</div>
<form class="risk-composer" data-agent-form><label class="sr-only" for="risk-message">风控问题</label><input id="risk-message" class="form-field__input" name="message" maxlength="2000" placeholder="输入风险查询问题" required><button class="button button--primary" type="submit" data-permission-required="agent:run">发送</button></form>
<p class="risk-disclaimer">智能助手生成内容仅供风险研判参考,不构成最终合规结论或处置决定,请以业务数据和人工复核结果为准。</p>
</section>
</article>
<aside class="operations-stack">
<article class="panel"><div class="panel__header"><h2 class="panel__title">重点预警</h2><span class="tag tag--accent">高风险优先</span></div><div class="panel__body" data-high-priority></div></article>
<article class="panel"><div class="panel__header"><h2 class="panel__title">风险日报</h2></div><div class="panel__body risk-report-entry"><p>日报统计、处置结果与规则效果均来自服务端生成结果。</p><button class="button button--primary" type="button" data-open-report>生成日报</button></div></article>
<article class="panel"><div class="panel__header"><h2 class="panel__title">政策解读</h2><span class="tag tag--neutral">预留</span></div><div class="panel__body risk-report-entry"><p>政策解读入口已预留,本期暂不开放具体内容。</p><button class="button" type="button" data-policy-tips>查看说明</button></div></article>
</aside>
</section>
</main>
<dialog class="operations-dialog" data-alert-dialog>
<div class="operations-dialog__header"><h2>预警详情</h2><button class="button icon-button" type="button" data-close-alert aria-label="关闭">×</button></div>
<div class="operations-dialog__body" data-alert-detail></div>
<div class="operations-dialog__footer" data-alert-actions></div>
</dialog>
<dialog class="operations-dialog action-dialog" data-action-dialog>
<form data-action-form>
<div class="operations-dialog__header"><h2 data-action-title>确认操作</h2><button class="button icon-button" type="button" data-close-action aria-label="关闭">×</button></div>
<div class="operations-dialog__body"><p class="action-dialog__copy" data-action-copy></p><label class="form-field" data-action-field hidden><span class="form-field__label" data-action-label>处理说明</span><textarea class="form-field__input action-dialog__textarea" name="reason" maxlength="500"></textarea></label><div class="form-alert" data-action-alert></div></div>
<div class="operations-dialog__footer"><button class="button" type="button" data-close-action>取消</button><button class="button button--primary" type="submit">确认提交</button></div>
</form>
</dialog>
<dialog class="operations-dialog" data-report-dialog>
<form data-report-form>
<div class="operations-dialog__header"><h2>风险日报</h2><button class="button icon-button" type="button" data-close-report aria-label="关闭">×</button></div>
<div class="operations-dialog__body">
<div class="risk-report-controls"><label class="form-field"><span class="form-field__label">报告日期</span><input class="form-field__input" type="date" name="report_date"></label><button class="button" type="button" data-generate-report>流式生成</button></div>
<p class="risk-report-status" data-report-status>选择日期后生成日报。</p>
<details class="risk-report-preview" data-report-preview-wrap hidden>
<summary>结构化摘要</summary>
<div class="risk-report-preview__content" data-report-preview></div>
</details>
<label class="form-field"><span class="form-field__label">日报内容</span><textarea class="form-field__input risk-report-content" name="content" maxlength="20000" required></textarea></label>
<label class="form-field"><span class="form-field__label">邮件主题</span><input class="form-field__input" name="subject" maxlength="128" value="南方基金风控日报" required></label>
<label class="form-field"><span class="form-field__label">收件邮箱</span><input class="form-field__input" name="recipients" placeholder="多个邮箱用逗号分隔" required></label>
<div class="form-alert" data-report-alert></div>
</div>
<div class="operations-dialog__footer"><button class="button" type="button" data-close-report>关闭</button><button class="button button--primary" type="submit" data-permission-required="risk:report:mail">发送日报邮件</button></div>
</form>
</dialog>
<dialog class="operations-dialog utility-dialog" data-system-tips-dialog>
<div class="operations-dialog__header"><h2>站内提醒</h2><button class="button icon-button" type="button" data-close-system-tips aria-label="关闭">×</button></div>
<div class="operations-dialog__body"><div data-system-tips-list></div></div>
<div class="operations-dialog__footer"><button class="button" type="button" data-open-notification-records>查看全部通知记录</button><button class="button" type="button" data-close-system-tips>关闭</button></div>
</dialog>
<dialog class="operations-dialog utility-dialog" data-policy-dialog>
<div class="operations-dialog__header"><h2>政策解读</h2><button class="button icon-button" type="button" data-close-policy aria-label="关闭">×</button></div>
<div class="operations-dialog__body"><p class="action-dialog__copy">政策解读入口为预留功能,本期暂未接入具体内容。后续确定政策数据来源和更新流程后再开放。</p></div>
<div class="operations-dialog__footer"><button class="button" type="button" data-close-policy>关闭</button></div>
</dialog>
<script type="module" src="/static/portal/employee-risk/dashboard/dashboard.js?v=20260913-11"></script>
</body>
</html>