feat(course): Add course assembly script and module structure for advisor training
- Introduced `build_all.py` script to automate the assembly of course modules into a single `index.html` file. - Created `index.html` for the main course overview, featuring a structured layout and navigation for various modules. - Developed `_base.html` and `_footer.html` templates for the advisor module, ensuring consistent styling and structure. - Added `build.sh` script for individual module assembly, enhancing modularity and ease of updates. - Implemented multiple module HTML files detailing specific training scenarios and functionalities for advisors, including interactive elements and quizzes. This update significantly enhances the course delivery framework, providing a comprehensive and interactive learning experience for advisors.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<section class="module" id="module-3">
|
||||
<div class="module-inner">
|
||||
<p class="eyebrow animate-in">模块 3 · 铁律与流式</p>
|
||||
<h1 class="module-title animate-in">两条铁律 +<br>prepare_customer_stream</h1>
|
||||
<p class="module-lead animate-in">
|
||||
客户线能跑通,靠文件头写死的两条
|
||||
<span class="term" data-definition="铁律 = 写进代码注释、测试会卡住的硬规则;违反会导致合规或数据错乱。">铁律</span>。
|
||||
流式 SSE 看起来是「边生成边推」,实现上是<strong>先跑完整张 LangGraph,再切块推送</strong>。
|
||||
</p>
|
||||
|
||||
<div class="screen animate-in">
|
||||
<h2>铁律(指挥 AI 改代码时别碰)</h2>
|
||||
<div class="pattern-cards">
|
||||
<div class="pattern-card">
|
||||
<h3>铁律 1 · 数值不经过 LLM 编造</h3>
|
||||
<p>持仓、流水、风评等查询结果 100% 来自 <code>core_ro_tool</code> 的 <code>fact_text</code>。LLM 在 <code>interpret</code> / <code>generate</code> 里只做解读与组织语言,不能自己算数。</p>
|
||||
</div>
|
||||
<div class="pattern-card">
|
||||
<h3>铁律 2 · customer_id 只来自 JWT</h3>
|
||||
<p><code>chat.py</code> 在进图之前已从令牌解析客户号并做归属校验。图内 <code>state["customer_id"]</code> 不信用户消息里的「帮我查 CUST-xxx」。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="callout callout-warning">
|
||||
<strong>和 advisor 线的差异:</strong> 理财师走 <code>agent_service</code> 的 tool→llm→guard;客户走独立 14 节点图。别混用 <code>run_tool</code> 关键词意图那套来改客户 RAG 分支。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screen animate-in">
|
||||
<h2>流式真相:图跑完再切块</h2>
|
||||
<p>方案 C 下 <code>prepare_customer_stream</code> 先调用 <code>run_customer_chat</code> 跑完整图,再用 <code>_chunk_reply_text</code> 切成 16 份左右推 SSE——Tool/RAG 仍是同步完成,不是 token 级流式。</p>
|
||||
|
||||
<div class="translation-block">
|
||||
<div class="translation-code">
|
||||
<span class="translation-label">CODE · prepare_customer_stream</span>
|
||||
<pre><code><span class="code-line"><span class="code-keyword">def</span> prepare_customer_stream(</span>
|
||||
<span class="code-line"> ctx, message, session_id, customer_id, end_session=<span class="code-keyword">False</span></span>
|
||||
<span class="code-line">) -> dict[str, Any]:</span>
|
||||
<span class="code-line"> reply, has_disclaimer, intent, transfer = run_customer_chat(</span>
|
||||
<span class="code-line"> ctx, message, session_id, customer_id, end_session</span>
|
||||
<span class="code-line"> )</span>
|
||||
<span class="code-line"> <span class="code-keyword">return</span> {</span>
|
||||
<span class="code-line"> <span class="code-string">"reply"</span>: reply,</span>
|
||||
<span class="code-line"> <span class="code-string">"has_disclaimer"</span>: has_disclaimer,</span>
|
||||
<span class="code-line"> <span class="code-string">"intent"</span>: intent,</span>
|
||||
<span class="code-line"> <span class="code-string">"transfer_to_human"</span>: transfer,</span>
|
||||
<span class="code-line"> <span class="code-string">"chunks"</span>: _chunk_reply_text(reply),</span>
|
||||
<span class="code-line"> }</span></code></pre>
|
||||
</div>
|
||||
<div class="translation-english">
|
||||
<span class="translation-label">白话</span>
|
||||
<div class="translation-lines">
|
||||
<p class="tl">入参里的 customer_id 是 chat.py 验完 JWT 后塞进来的,函数内部不再解析用户文本。</p>
|
||||
<p class="tl">先拿到完整 reply(含 intent、是否转人工、是否附免责),再切片给 SSE 层逐块写。</p>
|
||||
<p class="tl">改「真流式」要先动 LangGraph 执行模型,不是只改前端 ChatPanel。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="screen animate-in">
|
||||
<h2>相关文件(改流式 / 铁律时打开这些)</h2>
|
||||
<div class="file-tree animate-in">
|
||||
<div class="tree-item tree-folder">app/service/</div>
|
||||
<div class="tree-item tree-indent">customer_service.py — 14 节点图 + prepare_customer_stream</div>
|
||||
<div class="tree-item tree-indent">visitor_service.py — 游客 9 节点(无 Tool 查持仓)</div>
|
||||
<div class="tree-item tree-indent">rag_service.py — fin_faq / fin_product / fin_policy</div>
|
||||
<div class="tree-item tree-folder">app/api/</div>
|
||||
<div class="tree-item tree-indent">chat.py — customer 分支分流 + SSE 写帧</div>
|
||||
<div class="tree-item tree-indent">auth_adapter.py — host_auth_for_customer_service</div>
|
||||
<div class="tree-item tree-folder">app/tool/</div>
|
||||
<div class="tree-item tree-indent">core_ro_tool.py — query_holdings / query_trades 等</div>
|
||||
</div>
|
||||
|
||||
<div class="quiz-container" id="quiz-customer-m3">
|
||||
<div class="quiz-question-block"
|
||||
data-correct="option-c"
|
||||
data-explanation-right="对。prepare_customer_stream 先 run_customer_chat 整图 invoke,再 _chunk_reply_text 切块;不是 LLM token 级流。"
|
||||
data-explanation-wrong="客户 SSE 是「整图跑完再切块」,Tool/RAG 在推流前已同步完成。">
|
||||
<h3 class="quiz-question">客户 SSE 流式回复,LangGraph 什么时候跑完?</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>只跑 interpret,前面跳过</span>
|
||||
</button>
|
||||
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
||||
<div class="quiz-option-radio"></div><span>推流前整图 invoke 完成</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="quiz-feedback"></div>
|
||||
</div>
|
||||
<button class="quiz-check-btn" onclick="checkQuiz('quiz-customer-m3')">检查答案</button>
|
||||
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-customer-m3')">重做</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user