2026-09-09 23:22:59 +08:00
|
|
|
|
<section class="module" id="module-2">
|
|
|
|
|
|
<div class="module-inner">
|
|
|
|
|
|
<p class="eyebrow animate-in">模块 2 · 模拟交易链路</p>
|
|
|
|
|
|
<h1 class="module-title animate-in">一笔演示交易<br>怎么长出预警单?</h1>
|
|
|
|
|
|
<p class="module-lead animate-in">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<code>RiskSimulatePage</code> 提交表单 → 模拟交易入口(<code>simulate.py</code>)验权 → 模拟写 Core 网关(<code>trade_gateway.py</code>)写库 →
|
|
|
|
|
|
规则引擎(<code>risk_engine.py</code>)扫规则 → 聚合进 <code>risk_alert</code>。
|
2026-09-09 23:22:59 +08:00
|
|
|
|
像演示用的「假收银台」:钱是假的,但风控流程是真的。
|
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>四段链路(动画)</h2>
|
|
|
|
|
|
<div class="flow-animation" data-steps='[
|
|
|
|
|
|
{"highlight":"flow-actor-1","label":"RiskSimulatePage:submitSimulateTrade(token, \"risk\", body)"},
|
2026-09-10 10:57:40 +08:00
|
|
|
|
{"highlight":"flow-actor-2","label":"模拟交易入口(simulate.py):POST /api/simulate/trade → 鉴权 risk_demo 或客户本人","packet":true,"from":"1","to":"2"},
|
|
|
|
|
|
{"highlight":"flow-actor-3","label":"模拟写 Core 网关(trade_gateway.py):R-02 适当性 → INSERT core_trade(唯一写 Core 路径)","packet":true,"from":"2","to":"3"},
|
|
|
|
|
|
{"highlight":"flow-actor-4","label":"规则引擎(risk_engine.py)扫描 → 写 risk_alert(大额/集中度等)","packet":true,"from":"3","to":"4"},
|
2026-09-09 23:22:59 +08:00
|
|
|
|
{"highlight":"flow-actor-1","label":"台账 GET /api/risk/alerts 可见 + 固定 disclaimer","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>模拟交易 UI</span></div>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<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>模拟写 Core 网关</span></div>
|
|
|
|
|
|
<div class="flow-actor" id="flow-actor-4"><span class="flow-actor-icon">🛡</span><span>规则引擎</span></div>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<p class="flow-step-label">Preset A-3:CUST-3001 · 50 万 → 大额预警 · Preset A-1:适当性阻断</p>
|
|
|
|
|
|
<div class="flow-controls">
|
|
|
|
|
|
<button class="btn flow-next-btn">下一步</button>
|
|
|
|
|
|
<button class="btn flow-reset-btn">重来</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-09-10 14:32:25 +08:00
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>R-02 阻断 vs R-01 大额待审(同网关、不同结果)</h2>
|
|
|
|
|
|
<p>模拟写 Core 网关(<code>trade_gateway.py</code>)里<strong>先</strong>跑适当性:不过 → 交易写不进去(R-02);过了 → 写入 <code>core_trade</code> → 规则引擎再扫 R-01 大额等 → 出 <code>pending_review</code> 预警。</p>
|
|
|
|
|
|
<div class="pattern-cards">
|
|
|
|
|
|
<div class="pattern-card">
|
|
|
|
|
|
<h3>A-1 · R-02 阻断</h3>
|
|
|
|
|
|
<p>CUST-1001 + PROD-161725 · 风评与产品 R 档不匹配 → 网关拒绝 · 可有 suitability 类预警 · <strong>无成交</strong></p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="pattern-card">
|
|
|
|
|
|
<h3>A-3 · R-01 大额待审</h3>
|
|
|
|
|
|
<p>CUST-3001 · 50 万申购 → 成交写入 Core → 引擎出大额类 <code>pending_review</code> · 台账可见</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="callout callout-warning">
|
|
|
|
|
|
<strong>指挥 AI 时:</strong> 别把「阻断交易」和「出预警待审」混成一个状态——前者在网关,后者在引擎聚合。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>代码地图</h2>
|
|
|
|
|
|
<div class="file-tree animate-in">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="tree-item tree-folder">模拟交易入口(app/api/simulate.py)</div>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<div class="tree-item tree-indent">薄路由:鉴权 + 调 submit_trade</div>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="tree-item tree-folder">模拟写 Core 网关(app/gateway/trade_gateway.py)</div>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<div class="tree-item tree-indent">适当性 → 写 core_trade → 调 risk 引擎</div>
|
|
|
|
|
|
<div class="tree-item tree-folder">app/service/risk/</div>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="tree-item tree-indent">规则引擎(risk_engine.py) · alert_service.py · 规则聚合</div>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<div class="tree-item tree-folder">web/src/pages/risk/RiskSimulatePage.tsx</div>
|
|
|
|
|
|
<div class="tree-item tree-indent">预设 A-1 / A-3 一键填表</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<div class="translation-block">
|
|
|
|
|
|
<div class="translation-code">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<span class="translation-label">CODE · 模拟交易入口(simulate.py)</span>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
<pre><code><span class="code-line"><span class="code-keyword">if not</span> (auth.has_role(<span class="code-string">"risk_demo"</span>)</span>
|
|
|
|
|
|
<span class="code-line"> <span class="code-keyword">or</span> (auth.is_customer() <span class="code-keyword">and</span></span>
|
|
|
|
|
|
<span class="code-line"> auth.customer_id == req.customer_id)):</span>
|
|
|
|
|
|
<span class="code-line"> deny(auth, <span class="code-string">"AUTH_403_ROLE"</span>, ...)</span>
|
|
|
|
|
|
<span class="code-line"><span class="code-keyword">return</span> submit_trade(req.model_dump(), ...)</span></code></pre>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="translation-english">
|
|
|
|
|
|
<span class="translation-label">白话</span>
|
|
|
|
|
|
<div class="translation-lines">
|
|
|
|
|
|
<p class="tl">能点「提交模拟交易」的只有两类人:带 risk_demo 的风控演示号,或客户本人买自己的单。</p>
|
|
|
|
|
|
<p class="tl">STAFF-30001 在 jwt_service 里配了 risk_demo,所以能造 A-3 大额演示数据。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="quiz-container" id="quiz-risk-m2">
|
|
|
|
|
|
<div class="quiz-question-block"
|
|
|
|
|
|
data-correct="option-c"
|
2026-09-10 10:57:40 +08:00
|
|
|
|
data-explanation-right="模拟写 Core 网关(trade_gateway.py)是唯一允许向 jinrong_core 写 INSERT 的路径(模拟成交);Agent 画像不能直接改 Core 正式字段。"
|
2026-09-09 23:22:59 +08:00
|
|
|
|
data-explanation-wrong="问数和其他 Agent 对 Core 是只读;只有网关模拟交易可写 core_trade。">
|
|
|
|
|
|
<h3 class="quiz-question">Demo 里谁可以把新成交写进 core_trade?</h3>
|
|
|
|
|
|
<div class="quiz-options">
|
|
|
|
|
|
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="quiz-option-radio"></div><span>NL→SQL 编排(analyst_agent.py)问数 SQL</span>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>风控对话 Tool</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="quiz-option-radio"></div><span>模拟写 Core 网关(trade_gateway.py,经 simulate/trade)</span>
|
2026-09-09 23:22:59 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quiz-feedback"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button class="quiz-check-btn" onclick="checkQuiz('quiz-risk-m2')">检查答案</button>
|
|
|
|
|
|
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-risk-m2')">重做</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|