Files
group_xinghuo_jinrong/docs/course/jinrong-module-analyst/modules/03-agent-api.html
T

100 lines
5.1 KiB
HTML
Raw Normal View History

<section class="module" id="module-3">
<div class="module-inner">
<p class="eyebrow animate-in">模块 3 · Agent 与页面</p>
<h1 class="module-title animate-in">AnalystAgent.run<br>+ 看板与资产 API</h1>
<p class="module-lead animate-in">
问数主脑是 <code>AnalystAgent.run</code>;页面侧 <code>AnalystQueryPage</code>(P2)
同时拉 <code>GET /dashboard</code> 卡片和 <code>POST /chat</code> 结果。
口径沉淀走 <code>POST /assets</code>(仅 analyst 角色可写)。
</p>
<div class="screen animate-in">
<h2>AnalystAgent.run 要点</h2>
<div class="pattern-cards">
<div class="pattern-card">
<h3>鉴权与域</h3>
<p><code>assert_analyst_query_access</code> → domain;<code>resolve_analyst_scope</code> → customer_id 白名单。</p>
</div>
<div class="pattern-card">
<h3>消歧与生成</h3>
<p><code>_detect_ambiguity</code> → clarify;否则 <strong>模板填参</strong> 或 <code>_generate_sql</code>。</p>
</div>
<div class="pattern-card">
<h3>执行与缓存</h3>
<p><code>validate</code> → <code>execute_readonly</code>;Redis <strong>权限指纹 + SQL + 表世代</strong>;写交易/预警/L3 后 bump。</p>
</div>
<div class="pattern-card">
<h3>解读与留痕</h3>
<p><code>_generate_verified_answer</code> + guardrail;<code>_persist</code> 写 analytics_query_log。</p>
</div>
</div>
<div class="callout callout-accent">
<strong>返回体 AnalystResponse:</strong> answer + table + sql + meta(exec_ms, <code>template_hit</code>, cache_hit, cost_est)+ disclaimer + status(success / degrade / clarify)。
</div>
</div>
<div class="screen animate-in">
<h2>dashboard / assets API</h2>
<div class="pattern-cards">
<div class="pattern-card">
<h3>GET /dashboard</h3>
<p>按角色返回 cards 文案 + metrics:analyst 全库统计、customer 本人持仓、advisor 名下 AUM 等。</p>
</div>
<div class="pattern-card">
<h3>POST /assets</h3>
<p>kind=dict/few_shot/template;仅 <code>analyst</code> 角色,写入口径资产表。</p>
</div>
<div class="pattern-card">
<h3>GET /ops/metrics</h3>
<p>运营侧查询总量与被拦截次数,与 dashboard 卡片分离。</p>
</div>
</div>
</div>
<div class="screen animate-in">
<div class="translation-block">
<div class="translation-code">
<span class="translation-label">CODE · AnalystQueryPage.tsx(P2)</span>
<pre><code><span class="code-line">useEffect(() => getAnalystDashboard(token))</span>
<span class="code-line">setDashMetrics(d.metrics)</span>
<span class="code-line">setDashCards(d.cards)</span>
<span class="code-line"><span class="code-comment">// 用户点查询</span></span>
<span class="code-line">const resp = await postAnalystChat(token, question)</span>
<span class="code-line">setResult(resp) <span class="code-comment">// Table + Collapse(SQL)</span></span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">白话</span>
<div class="translation-lines">
<p class="tl">进页面先拉看板 MetricCard,数字来自 /dashboard 不是 chat。</p>
<p class="tl">提问才走 AnalystAgent.run,结果区展示解读、表格、可折叠 SQL。</p>
<p class="tl">apiFetch 只带 token,与 risk.ts 的 X-Agent-Type 头无关。</p>
</div>
</div>
</div>
<div class="quiz-container" id="quiz-analyst-m3">
<div class="quiz-question-block"
data-correct="option-a"
data-explanation-right="POST /assets 在 问数 REST(analyst.py)硬校验 analyst 角色,advisor 或 customer 会 403。"
data-explanation-wrong="资产沉淀是分析员专属写操作,其他角色只能问数或看 dashboard。">
<h3 class="quiz-question">理财师 STAFF-10086 能调用 POST /api/analyst/assets 沉淀口径吗?</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>能,advisor 也有 assigned 域</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>能,只要带 Bearer 就行</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-analyst-m3')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-analyst-m3')">重做</button>
</div>
</div>
</div>
</section>