- Introduced `pending_trade` handling in the chat API to manage trade requests more effectively. - Updated the `submit_trade_api` to allow advisors to access customer trades based on assigned roles. - Added new methods in `GatewayRepository` for managing core holdings during trade subscriptions and redemptions. - Implemented context-aware trade dialogue management in the customer service layer to improve user experience during multi-turn interactions. - Enhanced the tool service to support trade actions and suitability checks, ensuring accurate processing of user requests. This update significantly improves the trade interaction flow, providing a more robust and user-friendly experience for customers engaging in trading activities.
803 lines
48 KiB
HTML
803 lines
48 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>JinRong 项目现状 · 交互导览</title>
|
||
|
||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400;12..96,600;12..96,700;12..96,800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400;1,9..40,500&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
||
|
||
<link rel="stylesheet" href="styles.css">
|
||
|
||
<style>
|
||
:root {
|
||
--color-accent: #2A7B9B;
|
||
--color-accent-hover: #1F6280;
|
||
--color-accent-light: #E4F2F7;
|
||
--color-accent-muted: #5A9DB8;
|
||
}
|
||
</style>
|
||
|
||
<script src="main.js" defer></script>
|
||
</head>
|
||
<body>
|
||
|
||
<nav class="nav" id="nav">
|
||
<div class="progress-bar" id="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||
<div class="nav-inner">
|
||
<span class="nav-title">JinRong 项目现状</span>
|
||
<div class="nav-dots" id="nav-dots" role="tablist">
|
||
<button class="nav-dot" data-target="module-1" data-tooltip="这是什么" role="tab" aria-label="模块 1: 这是什么"></button>
|
||
<button class="nav-dot" data-target="module-2" data-tooltip="四个角色" role="tab" aria-label="模块 2: 四个角色"></button>
|
||
<button class="nav-dot" data-target="module-3" data-tooltip="进门钥匙" role="tab" aria-label="模块 3: 进门钥匙"></button>
|
||
<button class="nav-dot" data-target="module-4" data-tooltip="数据从哪来" role="tab" aria-label="模块 4: 数据从哪来"></button>
|
||
<button class="nav-dot" data-target="module-5" data-tooltip="现在做到哪" role="tab" aria-label="模块 5: 现在做到哪"></button>
|
||
<button class="nav-dot" data-target="module-6" data-tooltip="硬阀门" role="tab" aria-label="模块 6: 硬阀门"></button>
|
||
<button class="nav-dot" data-target="module-7" data-tooltip="未实现对照" role="tab" aria-label="模块 7: 未实现对照"></button>
|
||
<button class="nav-dot" data-target="module-8" data-tooltip="答辩动线" role="tab" aria-label="模块 8: 答辩动线"></button>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<main id="main">
|
||
<section class="module" id="module-1">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 1 · 从用户视角出发</p>
|
||
<h1 class="module-title animate-in">JinRong 是什么?<br>一次「问 AI」背后发生了什么</h1>
|
||
<p class="module-lead animate-in">
|
||
这是一个<strong>金融智能管家 Demo</strong>:四类人用四个不同的 AI 助手(客户 / 理财师 / 分析员 / 风控),
|
||
共用同一套数据和合规规则。没有真实银行 Core,用本地模拟库代替。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>你已经在用的能力</h2>
|
||
<ul>
|
||
<li>登录后看<strong>持仓、流水、产品行情</strong>(平台只读 API)</li>
|
||
<li>和 AI <strong>对话</strong>(同步或流式 SSE)</li>
|
||
<li>分析员<strong>问数</strong>(自然语言 → SQL → 表格)</li>
|
||
<li>风控看<strong>预警台账</strong>、做<strong>模拟交易</strong>造演示数据</li>
|
||
</ul>
|
||
<div class="callout callout-accent">
|
||
<strong>为什么要懂这些?</strong> 你指挥 AI 改功能时,得知道「这是对话线还是平台 API」「要不要带 X-Agent-Type」——否则改完浏览器 401,AI 也会绕圈。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>想象:客户打开「客户助手」发一句话</h2>
|
||
<p>下面是一次真实链路的简化版(2026-09 现状:客户线已走<span class="term" data-definition="SSE = Server-Sent Events,服务器像打字一样一段段把 AI 回复推给浏览器,不用等整段话生成完。">SSE 流式</span>)。</p>
|
||
|
||
<div class="flow-animation" data-steps='[
|
||
{"highlight":"flow-actor-1","label":"浏览器:登录拿到 JWT,打开 ChatPanel"},
|
||
{"highlight":"flow-actor-2","label":"POST /api/chat/stream + X-Agent-Type: customer","packet":true,"from":"1","to":"2"},
|
||
{"highlight":"flow-actor-3","label":"四 Agent 对话 HTTP 入口(chat.py)分流 → 登录客户 14 节点编排(customer_service.py)跑完 LangGraph","packet":true,"from":"2","to":"3"},
|
||
{"highlight":"flow-actor-4","label":"查 Core 模拟库 / Milvus 知识库,再拼回复","packet":true,"from":"3","to":"4"},
|
||
{"highlight":"flow-actor-1","label":"SSE 分块返回 + MySQL 落会话历史","packet":true,"from":"4","to":"1"}
|
||
]'>
|
||
<div class="flow-actors">
|
||
<div class="flow-actor" id="flow-actor-1"><span class="flow-actor-icon">🖥</span><span>浏览器 web/</span></div>
|
||
<div class="flow-actor" id="flow-actor-2"><span class="flow-actor-icon">🚪</span><span>四 Agent 对话 HTTP 入口(chat.py)四 Agent 对话 HTTP 入口</span></div>
|
||
<div class="flow-actor" id="flow-actor-3"><span class="flow-actor-icon">🤖</span><span>登录客户 14 节点编排(customer_service.py)登录客户 14 节点编排</span></div>
|
||
<div class="flow-actor" id="flow-actor-4"><span class="flow-actor-icon">🗄</span><span>Core + Milvus</span></div>
|
||
</div>
|
||
<p class="flow-step-label">点击「下一步」看数据怎么流</p>
|
||
<div class="flow-controls">
|
||
<button class="btn flow-next-btn">下一步</button>
|
||
<button class="btn flow-reset-btn">重来</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<div class="translation-block">
|
||
<div class="translation-code">
|
||
<span class="translation-label">入口</span>
|
||
<pre><code><span class="code-line"><span class="code-comment"># web/src/api/chat.ts</span></span>
|
||
<span class="code-line"><span class="code-string">'X-Agent-Type'</span>: agentType, <span class="code-comment">// customer | risk | …</span></span>
|
||
<span class="code-line">Authorization: <span class="code-string">`Bearer ${token}`</span></span></code></pre>
|
||
</div>
|
||
<div class="translation-english">
|
||
<span class="translation-label">白话</span>
|
||
<div class="translation-lines">
|
||
<p class="tl">前端每次调「对话 API」都要带两样东西:登录令牌 + 你正在用哪条 Agent 线。</p>
|
||
<p class="tl">后端据此决定走客服 LangGraph 还是通用 顾问通用 tool→llm→guard 编排(agent_service.py),以及能不能过门禁。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="quiz-container" id="quiz-module1">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-b"
|
||
data-explanation-right="对。问数走 /api/analyst/*,用平台鉴权,不要 X-Agent-Type。"
|
||
data-explanation-wrong="对话线才要 X-Agent-Type。问数和读客户档案一样,只带 JWT 即可。">
|
||
<h3 class="quiz-question">分析员「问数工作台」调 API 时,要不要带 X-Agent-Type?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>要,填 analyst</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>不要,只带 Bearer JWT</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>看心情,可有可无</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module1')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module1')">重做</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-2">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 2 · 认识主要角色</p>
|
||
<h1 class="module-title animate-in">四个 Agent,<br>各干各的活</h1>
|
||
<p class="module-lead animate-in">
|
||
它们<strong>不互相打电话</strong>(不调彼此的 LLM)。要共享信息,走数据库里的画像层、预警表、平台 API。
|
||
像一栋楼里的四个窗口,共用同一套档案室。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>四个窗口分别是谁</h2>
|
||
<div class="pattern-cards">
|
||
<div class="pattern-card">
|
||
<h3>客户财富 Agent</h3>
|
||
<p>服务登录客户本人:查持仓/流水、产品规则 RAG、合规话术。代码:登录客户 14 节点编排(<code>customer_service.py</code>)登录客户 14 节点编排</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>代理人助手</h3>
|
||
<p>服务理财师:聊名下客户、公开知识库。代码:顾问通用 tool→llm→guard 编排(<code>agent_service.py</code>)顾问通用 tool→llm→guard 编排 + advisor 分支</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>数据分析 Agent</h3>
|
||
<p>NL→SQL 问数、看板 metrics、口径资产。独立路由 <code>/api/analyst/*</code></p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>风控监测 Agent</h3>
|
||
<p>预警台账、适当性、AML、模拟交易触发规则。代码:<code>app/service/risk/*</code></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>群聊:一次请求里谁跟谁说话</h2>
|
||
<p>理财师问「客户 CUST-9527 持仓如何」——简化对话:</p>
|
||
|
||
<div class="chat-window" id="chat-module2">
|
||
<div class="chat-messages">
|
||
<div class="chat-message" data-msg="0" data-sender="browser" style="display:none">
|
||
<div class="chat-avatar" style="background:#2A7B9B">前</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#2A7B9B">浏览器</span>
|
||
<p>POST /api/chat/stream · X-Agent-Type: advisor</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="1" data-sender="chat" style="display:none">
|
||
<div class="chat-avatar" style="background:#5A9DB8">API</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#5A9DB8">四 Agent 对话 HTTP 入口(chat.py)</span>
|
||
<p>验 JWT + 矩阵准入 → 建/续 session</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="2" data-sender="tool" style="display:none">
|
||
<div class="chat-avatar" style="background:#1F6280">Tool</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#1F6280">对话 Tool 编排(tool_service.py)</span>
|
||
<p>关键词命中「持仓」→ query_holdings → 查 core_ro</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="3" data-sender="llm" style="display:none">
|
||
<div class="chat-avatar" style="background:#D4A843">AI</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#D4A843">DeepSeek</span>
|
||
<p>把 Tool 结果组织成自然语言,SSE 推回前端</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="chat-typing" id="chat-module2-typing" style="display:none">
|
||
<div class="chat-avatar" id="chat-module2-typing-avatar">…</div>
|
||
<div class="chat-typing-dots"><span class="typing-dot"></span><span class="typing-dot"></span><span class="typing-dot"></span></div>
|
||
</div>
|
||
<div class="chat-controls">
|
||
<button class="btn chat-next-btn">下一条</button>
|
||
<button class="btn chat-all-btn">全部播放</button>
|
||
<button class="btn chat-reset-btn">重播</button>
|
||
<span class="chat-progress"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>代码地图(改功能前先找门)</h2>
|
||
<div class="file-tree animate-in">
|
||
<div class="tree-item tree-folder">app/</div>
|
||
<div class="tree-item tree-indent">FastAPI 应用入口(main.py)FastAPI 应用入口 — 挂载所有路由</div>
|
||
<div class="tree-item tree-indent">四 Agent 对话 HTTP 入口(chat.py)四 Agent 对话 HTTP 入口 — app/api/chat.py</div>
|
||
<div class="tree-item tree-indent">问数 REST 路由(analyst.py)问数 REST 路由 — app/api/analyst.py</div>
|
||
<div class="tree-item tree-indent">风控 REST(risk.py)风控 REST — app/api/risk.py · 模拟交易 HTTP 入口(simulate.py)模拟交易 HTTP 入口 — app/api/simulate.py</div>
|
||
<div class="tree-item tree-indent">登录客户 14 节点编排(customer_service.py)登录客户 14 节点编排 — app/service/customer_service.py</div>
|
||
<div class="tree-item tree-indent">顾问通用 tool→llm→guard 编排(agent_service.py)顾问通用 tool→llm→guard 编排 — app/service/agent_service.py</div>
|
||
<div class="tree-item tree-folder">web/</div>
|
||
<div class="tree-item tree-indent">src/pages/* — 四角色页面</div>
|
||
<div class="tree-item tree-indent">src/api/*.ts — 调后端(注意鉴权头差异)</div>
|
||
</div>
|
||
|
||
<div class="quiz-container" id="quiz-module2">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-c"
|
||
data-explanation-right="客户线已独立:同步 POST /api/chat 和 SSE stream 都走 登录客户 14 节点编排(customer_service.py),不是 顾问通用 tool→llm→guard 编排(agent_service.py)那条通用图。"
|
||
data-explanation-wrong="customer 在 四 Agent 对话 HTTP 入口(chat.py)里有专门 if 分支,不会和 advisor 共用同一张 LangGraph。">
|
||
<h3 class="quiz-question">客户打开「客户助手」时,编排跑在哪?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>顾问通用 tool→llm→guard 编排(agent_service.py)通用图</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>analyst_agent 问数</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>登录客户 14 节点编排(customer_service.py)LangGraph</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module2')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module2')">重做</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-3">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 3 · 进门钥匙</p>
|
||
<h1 class="module-title animate-in">JWT 与 X-Agent-Type:<br>两套门禁别混</h1>
|
||
<p class="module-lead animate-in">
|
||
<span class="term" data-definition="JWT 像一张带防伪的工牌:服务器验签后知道你是谁(客户还是员工)、有什么角色。">JWT</span>
|
||
证明「你是谁」;<span class="term" data-definition="HTTP 请求头里的一行额外信息,告诉后端这次请求走哪条 Agent 业务线。">X-Agent-Type</span>
|
||
证明「你正在敲哪扇窗」。本项目里<strong>有两套验法</strong>,混用会 401。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>两条通道(背下来能少踩一半坑)</h2>
|
||
<table style="width:100%; border-collapse:collapse; margin: 1.5rem 0; font-size: 0.95rem;">
|
||
<thead><tr><th>场景</th><th>鉴权函数</th><th>X-Agent-Type</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>对话 / 风控 REST</td><td><code>get_auth_context</code></td><td><strong>必须</strong>(customer/advisor/risk/analyst)</td></tr>
|
||
<tr><td>平台只读 / 问数</td><td><code>get_platform_auth_context</code></td><td><strong>不要</strong></td></tr>
|
||
<tr><td>模拟交易</td><td><code>get_auth_context</code></td><td>要;且角色需 risk_demo 或客户本人</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="callout callout-warning">
|
||
<strong>真实 bug 已修:</strong> 风控台账 <code>risk.ts</code> 曾缺 <code>X-Agent-Type: risk</code>,JWT 正确也会 401。指挥 AI 接新 REST 时记得对照这条表。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<div class="translation-block">
|
||
<div class="translation-code">
|
||
<span class="translation-label">CODE · 模块鉴权工厂(deps.py)模块鉴权工厂</span>
|
||
<pre><code><span class="code-line">agent_type = request.headers.get(<span class="code-string">"X-Agent-Type"</span>)</span>
|
||
<span class="code-line"><span class="code-keyword">if not</span> agent_type:</span>
|
||
<span class="code-line"> raise ApiError(<span class="code-number">401</span>, <span class="code-string">"AUTH_401_MISSING_AGENT_TYPE"</span>)</span>
|
||
<span class="code-line">assert_agent_access(auth, agent_type, ...)</span></code></pre>
|
||
</div>
|
||
<div class="translation-english">
|
||
<span class="translation-label">白话</span>
|
||
<div class="translation-lines">
|
||
<p class="tl">读请求头:你声明自己是 customer 还是 risk?</p>
|
||
<p class="tl">没声明 → 直接 401,连业务代码都进不去。</p>
|
||
<p class="tl">再查矩阵:STAFF-30001 能不能走 risk 线?客户 token 能不能走 advisor 线?</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>Demo 账号(本地登录页一键用)</h2>
|
||
<div class="badge-list">
|
||
<div class="badge-item"><span class="badge-code">CUST-9527</span><span class="badge-desc">客户</span></div>
|
||
<div class="badge-item"><span class="badge-code">STAFF-10086</span><span class="badge-desc">理财师</span></div>
|
||
<div class="badge-item"><span class="badge-code">STAFF-20001</span><span class="badge-desc">分析员</span></div>
|
||
<div class="badge-item"><span class="badge-code">STAFF-30001</span><span class="badge-desc">风控 + risk_demo</span></div>
|
||
</div>
|
||
<p>改 宿主 JWT 签发/验签(<code>jwt_service.py</code>)宿主 JWT 签发/验签 里角色后,<strong>必须重新登录</strong> 才会拿到新 JWT。</p>
|
||
|
||
<div class="quiz-container" id="quiz-module3">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-a"
|
||
data-explanation-right="GET /api/customers/... 走 platform 鉴权,前端 apiFetch 只带 Bearer。"
|
||
data-explanation-wrong="平台读 API 故意不要 X-Agent-Type,和 chat 线不同。">
|
||
<h3 class="quiz-question">客户「我的持仓」页调 /api/customers/.../holdings,要带 X-Agent-Type 吗?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>不要</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>要,填 customer</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module3')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module3')">重做</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-4">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 4 · 数据从哪来</p>
|
||
<h1 class="module-title animate-in">双 MySQL、Redis、<br>模拟 Core 与风控引擎</h1>
|
||
<p class="module-lead animate-in">
|
||
没有真实银行 Core。L0 事实(客户、持仓、流水)在 <code>jinrong_core</code> 模拟库;
|
||
Agent 会话、预警、审计在 <code>jinrong_agent</code>。像<strong>前台展示用的假金库 + 后台自己的笔记本</strong>。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>分层速记</h2>
|
||
<ul>
|
||
<li><strong>L0</strong> — <code>jinrong_core</code> 只读(Tool / 问数 SQL _guard 白名单)</li>
|
||
<li><strong>L1/L2/L3 画像</strong> — agent 库 MySQL 表(客户/顾问/风控 enrich)</li>
|
||
<li><strong>会话窗口</strong> — Redis(TTL 2h,挂了会降级回 MySQL)</li>
|
||
<li><strong>RAG</strong> — Milvus 向量库 + <code>data/kb/</code> 产品手册</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>风控演示:模拟交易 → 出预警</h2>
|
||
<div class="flow-animation" data-steps='[
|
||
{"highlight":"flow-actor-1","label":"风控 Demo 提交 POST /api/simulate/trade"},
|
||
{"highlight":"flow-actor-2","label":"trade_gateway 写 core_trade(唯一允许 INSERT Core 的路径)","packet":true,"from":"1","to":"2"},
|
||
{"highlight":"flow-actor-3","label":"risk 规则引擎扫描 → 聚合写入 risk_alert","packet":true,"from":"2","to":"3"},
|
||
{"highlight":"flow-actor-4","label":"Redis Pub/Sub 可选推送;台账页 GET /api/risk/alerts 可见","packet":true,"from":"3","to":"4"}
|
||
]'>
|
||
<div class="flow-actors">
|
||
<div class="flow-actor" id="flow-actor-1"><span class="flow-actor-icon">🧪</span><span>模拟交易 UI</span></div>
|
||
<div class="flow-actor" id="flow-actor-2"><span class="flow-actor-icon">⚙</span><span>trade_gateway</span></div>
|
||
<div class="flow-actor" id="flow-actor-3"><span class="flow-actor-icon">🛡</span><span>risk_engine</span></div>
|
||
<div class="flow-actor" id="flow-actor-4"><span class="flow-actor-icon">📋</span><span>risk_alert 表</span></div>
|
||
</div>
|
||
<p class="flow-step-label">A-3 预设:CUST-3001 · 50 万 · 大额预警</p>
|
||
<div class="flow-controls">
|
||
<button class="btn flow-next-btn">下一步</button>
|
||
<button class="btn flow-reset-btn">重来</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="translation-block">
|
||
<div class="translation-code">
|
||
<span class="translation-label">问数 · sql_guard</span>
|
||
<pre><code><span class="code-line"><span class="code-comment"># 分析 Agent 只读 SELECT,customer 域强制 self</span></span>
|
||
<span class="code-line">assert_analyst_query_access(auth)</span>
|
||
<span class="code-line"><span class="code-comment"># 客户问数:仅趋势/统计,尾部「AI 分析有风险」</span></span></code></pre>
|
||
</div>
|
||
<div class="translation-english">
|
||
<span class="translation-label">白话</span>
|
||
<div class="translation-lines">
|
||
<p class="tl">问数不是随便跑 SQL:先过权限域,再过只读与白名单。</p>
|
||
<p class="tl">客户角色不能查别人的数据,也不能给投资建议(产品规则写死在 guardrail)。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<div class="quiz-container" id="quiz-module4">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-b"
|
||
data-explanation-right="Core 正式账 C1~C5 禁止被 Agent 画像覆盖;只有 gateway 模拟 INSERT 交易。"
|
||
data-explanation-wrong="画像写 L1/L2/L3 可以,但不能动 Core 里的正式客户等级等 C 类字段。">
|
||
<h3 class="quiz-question">项目硬规则:Agent 能不能直接改 Core 里客户的「正式风险等级」?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>可以,方便演示</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>不可以,Core 只读(模拟交易除外)</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module4')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module4')">重做</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-5">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 5 · 现状与下一步</p>
|
||
<h1 class="module-title animate-in">现在做到哪?<br>怎么本地跑起来</h1>
|
||
<p class="module-lead animate-in">
|
||
分支 <code>merger</code> · 测试基线 <strong>825 pytest</strong> · 前端 <strong>22 Vitest</strong> · Redis Docker <strong>6380</strong>。
|
||
文档入口:<code>docs/memory/MEMORY.md</code> §0 · 答辩提纲 <code>docs/答辩/答辩知识点清单.md</code> · 滚动版见<strong>模块 8</strong>。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>已完成(2026-09-10 快照)</h2>
|
||
<div class="pattern-cards">
|
||
<div class="pattern-card"><h3>✓ 平台 API v0.1</h3><p>客户/产品/顾问/合规只读 REST</p></div>
|
||
<div class="pattern-card"><h3>✓ 四 Agent 对话 + SSE</h3><p>客服 Wave3 · 游客 1B · customer 14 节点</p></div>
|
||
<div class="pattern-card"><h3>✓ 问数 S3 + D-06</h3><p>模板填参 · 结果缓存 + 写侧 bump · 问数 UI 标签</p></div>
|
||
<div class="pattern-card"><h3>✓ 风控 + 前端 P0</h3><p>台账/模拟/AML 页 · <code>prepare_all.ps1</code> 灌库</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>仍开放(指挥 AI 前先心里有数)</h2>
|
||
<ul>
|
||
<li>接口契约发群(稿在 <code>docs/项目管理/接口契约发群-2026-09-09.md</code>)</li>
|
||
<li>风控演示种子 / cron 脚本(运维向,见 TODO)</li>
|
||
<li>画像 Redis L1/L2 热缓存未全接</li>
|
||
<li>口径字典种子 SQL 需本机执行一次</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>本地启动(最小路径)</h2>
|
||
<div class="step-cards">
|
||
<div class="step-card"><span class="step-num">1</span><p><code>pip install -r requirements.txt</code></p></div>
|
||
<div class="step-card"><span class="step-num">2</span><p><code>.\scripts\demo\prepare_all.ps1</code> 或 <code>.\scripts\core\reset.ps1</code></p></div>
|
||
<div class="step-card"><span class="step-num">3</span><p><code>.\scripts\dev\start-redis.ps1</code> → 6380</p></div>
|
||
<div class="step-card"><span class="step-num">4</span><p><code>uvicorn app.main:app --reload</code> :8000</p></div>
|
||
<div class="step-card"><span class="step-num">5</span><p><code>cd web && npm run dev</code> → :5173 代理 API</p></div>
|
||
<div class="step-card"><span class="step-num">6</span><p><code>python -m pytest</code> 验收 825 绿</p></div>
|
||
</div>
|
||
<div class="callout callout-accent">
|
||
<strong>改后端后:</strong> 若浏览器问数 404,多半是 :8000 的 uvicorn 没重启,OpenAPI 里还缺新路由。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>情景题:AI 说「问数和 Chat 用同一套鉴权」</h2>
|
||
<div class="quiz-container" id="quiz-module5">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-c"
|
||
data-explanation-right="应纠正 AI:问数走 get_platform_auth_context,Chat 走 get_auth_context + X-Agent-Type。两套不能混。"
|
||
data-explanation-wrong="这是本项目的核心接缝设计,写错会导致 401 或越权。">
|
||
<h3 class="quiz-question">你怎么回复?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>好的,都加 X-Agent-Type: analyst</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>都去掉 JWT,用 debug 头</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>不对,对照 MEMORY/发群稿里两套鉴权表</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-module5')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-module5')">重做</button>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>想继续深入?</strong> 模块 8 有<strong>答辩 5~8 分钟动线</strong>;或打开 <a href="../index.html" style="color:var(--accent)">课程中心</a> 按角色深潜。
|
||
</div>
|
||
|
||
<p class="module-footer-note">课程更新 2026-09-10 · 对照 <code>docs/memory/MEMORY.md</code> 与 <code>docs/答辩/答辩知识点清单.md</code></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-6">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 6 · 硬阀门</p>
|
||
<h1 class="module-title animate-in">改代码前先念五条<br>踩了就是合规事故</h1>
|
||
<p class="module-lead animate-in">
|
||
四 Agent 可以各自演进,但有几条是<strong>全项目硬阀门</strong>——不是「最好遵守」,是写进合规文档、测试也会卡住的规则。
|
||
指挥 AI 加功能前,先用这张表判断「能不能做」。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>五条硬阀门(2026-09 快照)</h2>
|
||
<div class="pattern-cards">
|
||
<div class="pattern-card">
|
||
<h3>① Core 正式 C1~C5 不可被画像覆盖</h3>
|
||
<p>L0 风评在 <code>jinrong_core</code> 是权威;L1 画像 enrich 只能辅助,不能改正式等级。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>② 审计表只 INSERT</h3>
|
||
<p><code>audit_log</code> / <code>input_guard_log</code> 等只追加、不 UPDATE/DELETE——留痕不可篡改。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>③ 仅 R-02 可阻断交易</h3>
|
||
<p>适当性不匹配可在网关拦单;R-01/R-03 只生成预警,<strong>不自动冻户</strong>。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>④ 代理人草稿不外发</h3>
|
||
<p>顾问 Agent 产出是草稿;没有「一键发给客户」API,须人工复核后才能外用。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>⑤ 四 Agent 不互调 LLM</h3>
|
||
<p>跨角色协作走 L1/L2/L3 画像表与 <code>risk_alert</code>,禁止 A 调 B 的 LangGraph。</p>
|
||
</div>
|
||
</div>
|
||
<div class="callout callout-warning">
|
||
<strong>还有技术硬阀门:</strong> Core 模拟库除模拟交易网关外<strong>只读</strong>;Streamlit 禁止引入(MEMORY 第 3 节)。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>数据流:谁有权改什么</h2>
|
||
<div class="flow-animation" data-steps='[
|
||
{"highlight":"flow-h-1","label":"客户问持仓 → Core 只读 Tool(core_ro_tool.py)只读 SELECT"},
|
||
{"highlight":"flow-h-2","label":"模拟下单 → 仅 gateway_repository 可 INSERT core_trade","packet":true,"from":"1","to":"2"},
|
||
{"highlight":"flow-h-3","label":"风控预警 → risk_alert 待人工 pending_review,不自动改账户状态","packet":true,"from":"2","to":"3"},
|
||
{"highlight":"flow-h-4","label":"audit_log → 只 INSERT,任何 UPDATE 都是违规","packet":true,"from":"3","to":"4"}
|
||
]'>
|
||
<div class="flow-actors">
|
||
<div class="flow-actor" id="flow-h-1"><span class="flow-actor-icon">📖</span><span>Core 只读</span></div>
|
||
<div class="flow-actor" id="flow-h-2"><span class="flow-actor-icon">💳</span><span>模拟网关</span></div>
|
||
<div class="flow-actor" id="flow-h-3"><span class="flow-actor-icon">⚠</span><span>预警台账</span></div>
|
||
<div class="flow-actor" id="flow-h-4"><span class="flow-actor-icon">📋</span><span>审计总账</span></div>
|
||
</div>
|
||
<p class="flow-step-label">点击「下一步」看写入边界</p>
|
||
<div class="flow-controls">
|
||
<button class="btn flow-next-btn">下一步</button>
|
||
<button class="btn flow-reset-btn">重来</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<div class="quiz-container" id="quiz-overview-m6">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-b"
|
||
data-explanation-right="对。R-01 大额等只生成 pending_review 预警,冻户必须风控专员人工处置,Agent 不能自动冻。"
|
||
data-explanation-wrong="只有 R-02 适当性可在交易网关阻断;其他预警不自动冻户。">
|
||
<h3 class="quiz-question">AI 建议「大额预警命中就自动冻结账户」,你怎么回复?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>好,在 risk_engine 里加 freeze 分支</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>不行,只生成预警单,处置走 POST /api/risk/alerts/{id}/handle</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>可以,让客服 Agent 调风控 LLM 冻户</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-overview-m6')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-overview-m6')">重做</button>
|
||
</div>
|
||
<p class="module-footer-note">深潜各模块的硬阀门细节见对应课程 · 下一模块:未实现对照表</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-7">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 7 · 未实现对照</p>
|
||
<h1 class="module-title animate-in">文档写了 ≠ 代码有<br>2026-09 快照表</h1>
|
||
<p class="module-lead animate-in">
|
||
指挥 AI 时最容易把「需求规格里的 P0」当成「仓库已经做完」。
|
||
下表是<strong>课程专用快照</strong>(不写入项目记忆文件),对照 <code>merger</code> 分支实际代码。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>已实现(别重复造轮子)</h2>
|
||
<div class="badge-list">
|
||
<div class="badge-item"><span class="badge-code">✓</span><span class="badge-desc">平台 API v0.1 · 四 Agent 对话 + customer SSE</span></div>
|
||
<div class="badge-item"><span class="badge-code">✓</span><span class="badge-desc">问数 S3 + D-06 模板/结果缓存 · 风控台账 + 模拟交易 + 前端四页</span></div>
|
||
<div class="badge-item"><span class="badge-code">✓</span><span class="badge-desc">客服 14 节点 + 游客 9 节点 · R-02 网关阻断</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>未实现 / 演示停在某层(指挥 AI 前先查)</h2>
|
||
<div class="pattern-cards">
|
||
<div class="pattern-card">
|
||
<h3>空壳 API</h3>
|
||
<p>知识库空壳 API(<code>knowledge.py</code>)· 管理空壳 API(<code>admin.py</code>)空壳 API — T-21 拍板一期只做脚本入库,无上传/重建端点。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>T-20 顾问工作台</h3>
|
||
<p>A-03 话术草稿复核 · A-05 合规巡检台 · A-06 跟进草稿入库 — prompt 有约束,无前端/表流程。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>前端仍简版</h3>
|
||
<p>风控 P1 已接(筛选/适当性/AML)· 看板<strong>无钻取</strong> · 分析 Chat 仍占位 · 平台适当性按钮部分未接。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>运维 cron 无 UI</h3>
|
||
<p>FR-9 超期升级 cron(<code>escalation_scan.py</code>)FR-9 cron · FR-10 行为扫描 cron(<code>agent_behavior_scan.py</code>)FR-10 cron — 引擎在,须手动跑脚本。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>演示边界</h3>
|
||
<p>转人工 = API 字段 + 橙色 Tag · debug 头仅 dev · 脱敏默认关 · 无真呼叫中心排队。</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>画像热缓存</h3>
|
||
<p>L1 Redis 全量热缓存 · L2 Repository — 客服线部分已接,宿主/顾问未全接。</p>
|
||
</div>
|
||
</div>
|
||
<div class="callout callout-accent">
|
||
<strong>注意:</strong> <code>REQUIREMENTS.md</code> 部分 Wave 条目仍标「未做」,与代码不同步——以本表 + 各模块深潜课为准。
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>鉴权三线速查(跨课总表)</h2>
|
||
<div class="translation-block">
|
||
<div class="translation-code">
|
||
<span class="translation-label">三条入口</span>
|
||
<pre><code><span class="code-line">对话 Chat → get_auth_context + X-Agent-Type</span>
|
||
<span class="code-line">问数/平台 → get_platform_auth_context(无 Agent 头)</span>
|
||
<span class="code-line">风控 REST → get_auth_context + X-Agent-Type: risk</span></code></pre>
|
||
</div>
|
||
<div class="translation-english">
|
||
<span class="translation-label">白话</span>
|
||
<div class="translation-lines">
|
||
<p class="tl">401 <code>MISSING_AGENT_TYPE</code>:Chat 忘了带头,不是 JWT 坏了。</p>
|
||
<p class="tl">问数页加 <code>X-Agent-Type: analyst</code> 是<strong>错方向</strong>——会走错鉴权栈。</p>
|
||
<p class="tl">持仓页用平台鉴权,不要 Agent 头——和 Chat 不是一套。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="quiz-container" id="quiz-overview-m7">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-c"
|
||
data-explanation-right="对。T-21 一期知识库走 知识库脚本入库(scripts/kb/build_kb.py)脚本入库,空壳 knowledge API 是刻意的。"
|
||
data-explanation-wrong="知识库空壳 API(knowledge.py)空壳是拍板结果,不是「忘了做」——别指挥 AI 直接补上传 API 而不对契约。">
|
||
<h3 class="quiz-question">AI 说「补全 knowledge 上传 API 就能用 RAG」,你怎么回?</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>好,在 知识库空壳 API(knowledge.py)加 POST /upload</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>好,让前端直连 Milvus</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>先查 T-21 拍板:一期脚本入库,上传端点不做</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-overview-m7')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-overview-m7')">重做</button>
|
||
</div>
|
||
|
||
<p class="module-footer-note">快照日期 2026-09-10 · 仅用于交互课程 · 深潜见 <a href="../index.html" style="color:var(--accent)">课程中心</a></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<section class="module" id="module-8">
|
||
<div class="module-inner">
|
||
<p class="eyebrow animate-in">模块 8 · 答辩动线</p>
|
||
<h1 class="module-title animate-in">5~8 分钟 Demo<br>+ 必背铁律</h1>
|
||
<p class="module-lead animate-in">
|
||
对照 <code>docs/答辩/答辩稿.md</code> 与 <code>DEMO-SOP-答辩全流程.md</code>:先讲清<strong>四角色不互调 LLM</strong>与合规铁律,再按动线<strong>展示业务</strong>,收口讲<strong>四角色价值</strong>(不口播缺陷与测试数)。
|
||
手册 <code>docs/答辩/README.md</code> · 幻灯片 · 答辩稿 · 功能测试(内部)。
|
||
</p>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>30 秒总架构(开口即说)</h2>
|
||
<div class="pattern-cards">
|
||
<div class="pattern-card">
|
||
<h3>分层</h3>
|
||
<p>浏览器 → FastAPI → 编排 service → tool/repository → 双库 MySQL + Redis + Milvus</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>四条入口</h3>
|
||
<p>Chat · 客服 14 节点 · 问数 + analyze · <strong>/api/advisor-agent</strong> 顾问 REST(2026-09-12 合入)</p>
|
||
</div>
|
||
<div class="pattern-card">
|
||
<h3>铁律</h3>
|
||
<p>L0 画像不可覆盖 · 仅 R-02 可阻断交易 · 风控不自动冻户 · 审计只 INSERT</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>推荐演示顺序(动画)</h2>
|
||
<div class="flow-animation" data-steps='[
|
||
{"highlight":"flow-actor-1","label":"① 登录 → Dashboard(平台只读 API 从 Core 来)"},
|
||
{"highlight":"flow-actor-2","label":"② 客户:持仓 / Chat SSE 或阈值提醒(Core + 1B sanitize)","packet":true,"from":"1","to":"2"},
|
||
{"highlight":"flow-actor-3","label":"③ 风控:模拟交易 → 台账 pending → 人工处置(事件线闭环)","packet":true,"from":"2","to":"3"},
|
||
{"highlight":"flow-actor-4","label":"④ 问数:「客户总数」→ 看模板命中标签 + SQL 折叠(D-06 + 护栏)","packet":true,"from":"3","to":"4"},
|
||
{"highlight":"flow-actor-1","label":"⑤ 可选:风控 Chat 只读查预警(强调不能改状态)","packet":true,"from":"4","to":"1"}
|
||
]'>
|
||
<div class="flow-actors">
|
||
<div class="flow-actor" id="flow-actor-1"><span class="flow-actor-icon">🖥</span><span>登录/Dashboard</span></div>
|
||
<div class="flow-actor" id="flow-actor-2"><span class="flow-actor-icon">💬</span><span>客户线</span></div>
|
||
<div class="flow-actor" id="flow-actor-3"><span class="flow-actor-icon">🛡</span><span>风控线</span></div>
|
||
<div class="flow-actor" id="flow-actor-4"><span class="flow-actor-icon">📊</span><span>问数线</span></div>
|
||
</div>
|
||
<p class="flow-step-label">灌库:<code>prepare_all.ps1</code> + <code>seed_advisor_agent.ps1</code> · SOP + 幻灯片见 <code>docs/答辩/</code></p>
|
||
<div class="flow-controls">
|
||
<button class="btn flow-next-btn">下一步</button>
|
||
<button class="btn flow-reset-btn">重来</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>群聊:评委问「四个 Agent 为什么不互相打电话?」</h2>
|
||
<div class="chat-window" id="chat-defense-m8">
|
||
<div class="chat-messages">
|
||
<div class="chat-message" data-msg="0" data-sender="j" style="display:none">
|
||
<div class="chat-avatar" style="background:#2A7B9B">评委</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#2A7B9B">评委</span>
|
||
<p>风控 Agent 能不能直接让客服 Agent 去安抚客户?</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="1" data-sender="you" style="display:none">
|
||
<div class="chat-avatar" style="background:#5A9DB8">你</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#5A9DB8">答辩口径</span>
|
||
<p>不互调 LLM。跨线靠<strong>表</strong>(如 <code>risk_alert</code>)和平台只读 API;审计按 Agent 边界留痕,避免一条链路里混处置权限。</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="2" data-sender="j" style="display:none">
|
||
<div class="chat-avatar" style="background:#2A7B9B">评委</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#2A7B9B">评委</span>
|
||
<p>那数据怎么同步?</p>
|
||
</div>
|
||
</div>
|
||
<div class="chat-message" data-msg="3" data-sender="you" style="display:none">
|
||
<div class="chat-avatar" style="background:#5A9DB8">你</div>
|
||
<div class="chat-bubble">
|
||
<span class="chat-sender" style="color:#5A9DB8">答辩口径</span>
|
||
<p>交易写 Core → 风控引擎出单进 agent 库;客服查持仓走 Core RO Tool,不读风控写侧。问数只统计,<strong>不能</strong>调处置 API。</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn chat-play-btn" data-chat="chat-defense-m8">播放对话</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="screen animate-in">
|
||
<h2>诚实边界(主动说加分)</h2>
|
||
<ul>
|
||
<li><strong>客户交易 2026-09-13</strong>:选购清单 · Modal · holding 同步(工作区未 commit)</li>
|
||
<li><strong>顾问 REST 已合入</strong> · T-20 / KYC D2 / D3 open</li>
|
||
<li>L0 是模拟 Core,不是真银行托管库</li>
|
||
<li>问数与 Chat 已拆分 · D-09 多轮 · D-12 钻取 open</li>
|
||
<li>看板无钻取 · 行情 Phase B 草案未接</li>
|
||
<li>知识库 T-21 脚本入库,上传 API 一期不做</li>
|
||
</ul>
|
||
|
||
<div class="quiz-container" id="quiz-defense-m8">
|
||
<div class="quiz-question-block"
|
||
data-correct="option-b"
|
||
data-explanation-right="对。StrictMode 开发态双 mount 会让两个并发请求竞态,旧响应覆盖新响应会「先闪错再正常」——已用 useAsyncSequence 按序号丢弃过期结果。"
|
||
data-explanation-wrong="这不是后端 500,多半是前端并发竞态;答辩可指向 web 课模块 4 与清单 §九。">
|
||
<h3 class="quiz-question">评委:「刷新 Dashboard 会先红一下再正常,是不是没做错误处理?」</h3>
|
||
<div class="quiz-options">
|
||
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>是,axios 没 catch</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>否,React StrictMode 双请求竞态,已用 useAsyncSequence</span>
|
||
</button>
|
||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||
<div class="quiz-option-radio"></div><span>是,JWT 过期</span>
|
||
</button>
|
||
</div>
|
||
<div class="quiz-feedback"></div>
|
||
</div>
|
||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-defense-m8')">检查答案</button>
|
||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-defense-m8')">重做</button>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<strong>全文提纲:</strong> 仓库内 <code>docs/答辩/答辩知识点清单.md</code> · 深潜按角色打开 <a href="../index.html" style="color:var(--accent)">课程中心</a>。
|
||
</div>
|
||
<p class="module-footer-note">模块 8 · 2026-09-10 · 与答辩清单同步</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
</body>
|
||
</html>
|