feat(chat): Enhance session management with new API endpoints and filtering options

- Added `status` query parameter to `list_sessions_api` for filtering sessions by their status (active/closed).
- Introduced `close_all_sessions_api` endpoint to allow users to close all active sessions for the current actor.
- Updated `SessionRepository` to support status filtering in session listing and implemented logic for closing active sessions.
- Improved Redis connection settings for better performance and reliability.

This update enhances the chat functionality by providing more control over session management, improving user experience and system efficiency.
This commit is contained in:
2026-09-10 22:30:07 +08:00
parent 48355cee8e
commit 9d4d4aaa6d
59 changed files with 2261 additions and 265 deletions
+118 -5
View File
@@ -33,6 +33,7 @@
<button class="nav-dot" data-target="module-2" data-tooltip="NL→SQL" role="tab" aria-label="模块 2: NL→SQL"></button>
<button class="nav-dot" data-target="module-3" data-tooltip="Agent 与页面" role="tab" aria-label="模块 3: Agent 与页面"></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="D-06 缓存" role="tab" aria-label="模块 5: D-06 缓存"></button>
</div>
</div>
</nav>
@@ -194,9 +195,10 @@
<div class="flow-animation" data-steps='[
{"highlight":"flow-actor-1","label":"① 消歧:口径字典命中多义指标 → 返回 suggestions 让用户选"},
{"highlight":"flow-actor-2","label":"② 生成 SQL:DeepSeek + SCHEMA_PROMPT + 权限域提示","packet":true,"from":"1","to":"2"},
{"highlight":"flow-actor-2","label":"② 模板匹配:published 模板填参 → 可跳过 LLM","packet":true,"from":"1","to":"2"},
{"highlight":"flow-actor-2","label":"②b 未命中 → DeepSeek + SCHEMA_PROMPT 生成 SQL","packet":true,"from":"1","to":"2"},
{"highlight":"flow-actor-3","label":"③ SQL 安全校验(sql_guard.py)五层校验:只读 / 表白名单 / 行级归属…","packet":true,"from":"2","to":"3"},
{"highlight":"flow-actor-4","label":"④ 执行:AnalyticsRepo 只读查询(Redis 缓存可命中)","packet":true,"from":"3","to":"4"},
{"highlight":"flow-actor-4","label":"④ 执行:AnalyticsRepo + Redis 结果缓存(表世代键)","packet":true,"from":"3","to":"4"},
{"highlight":"flow-actor-5","label":"⑤ guardrail:解读数字必须与表格一致,不过则降级","packet":true,"from":"4","to":"5"},
{"highlight":"flow-actor-1","label":"⑥ 留痕:analytics_query_log 写入 SQL/耗时/护栏结果","packet":true,"from":"5","to":"1"}
]'>
@@ -303,11 +305,11 @@
</div>
<div class="pattern-card">
<h3>消歧与生成</h3>
<p><code>_detect_ambiguity</code> 命中则 <code>_clarify</code> 返回 suggestions;否则 <code>_generate_sql</code>。</p>
<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 按权限指纹 + SQL hash 缓存结果。</p>
<p><code>validate</code> → <code>execute_readonly</code>;Redis <strong>权限指纹 + SQL + 表世代</strong>;写交易/预警/L3 后 bump。</p>
</div>
<div class="pattern-card">
<h3>解读与留痕</h3>
@@ -315,7 +317,7 @@
</div>
</div>
<div class="callout callout-accent">
<strong>返回体 AnalystResponse:</strong> answer + table + sql + meta(exec_ms, cache_hit, cost_est)+ disclaimer + status(success / degrade / clarify)。
<strong>返回体 AnalystResponse:</strong> answer + table + sql + meta(exec_ms, <code>template_hit</code>, cache_hit, cost_est)+ disclaimer + status(success / degrade / clarify)。
</div>
</div>
@@ -460,6 +462,117 @@
<p class="module-footer-note">相关:NL→SQL 编排(<code>app/service/analyst_agent.py</code>) · SQL 安全校验(<code>app/service/analyst/sql_guard.py</code>)</p>
</div>
</div>
</section>
<section class="module" id="module-5">
<div class="module-inner">
<p class="eyebrow animate-in">模块 5 · D-06</p>
<h1 class="module-title animate-in">模板填参 + 结果缓存<br>写侧 bump 失效</h1>
<p class="module-lead animate-in">
问数两层「快路径」:① <strong>同形态问题</strong>命中 published 模板,跳过 LLM 写 SQL(<code>template_service.py</code>)
② 执行结果进 Redis,键里带<strong>表世代</strong>——交易/预警/L3 写后 bump,不等 TTL 过期。
</p>
<div class="screen animate-in">
<h2>两层 D-06 各管什么</h2>
<table style="width:100%; border-collapse:collapse; margin:1.5rem 0; font-size:0.95rem;">
<thead>
<tr><th style="text-align:left;padding:0.5rem;">层</th><th style="text-align:left;padding:0.5rem;">入口</th><th style="text-align:left;padding:0.5rem;">答辩句</th></tr>
</thead>
<tbody>
<tr>
<td style="padding:0.5rem;">模板缓存</td>
<td style="padding:0.5rem;"><code>match_template</code> → 填 <code>:days</code> 等</td>
<td style="padding:0.5rem;">「客户+总数」→ <code>template_hit: true</code>,省 LLM 写 SQL</td>
</tr>
<tr>
<td style="padding:0.5rem;">结果缓存</td>
<td style="padding:0.5rem;"><code>cache_service.py</code> 权限指纹 + SQL hash + 世代</td>
<td style="padding:0.5rem;">「同 SQL 同权限」秒回;写侧 bump 后旧键自然 miss</td>
</tr>
<tr>
<td style="padding:0.5rem;">写侧失效</td>
<td style="padding:0.5rem;"><code>analyst_cache_invalidate</code> 交易/预警/L3 后</td>
<td style="padding:0.5rem;">「演示里刚模拟交易,问数不会还显示旧汇总」</td>
</tr>
</tbody>
</table>
<div class="callout callout-accent">
前端问数页会展示 <strong>模板命中</strong> / <strong>结果缓存</strong> 标签(读 <code>meta.template_hit</code> · <code>cache_hit</code>)。
</div>
</div>
<div class="screen animate-in">
<div class="translation-block">
<div class="translation-code">
<span class="translation-label">analyst_agent 决策顺序(简化)</span>
<pre><code><span class="code-line">clarify? → return suggestions</span>
<span class="code-line">template match? → fill SQL → validate → execute</span>
<span class="code-line">else LLM generate_sql → validate → execute (cache?)</span>
<span class="code-line">guardrail → persist analytics_query_log</span></code></pre>
</div>
<div class="translation-english">
<span class="translation-label">白话</span>
<div class="translation-lines">
<p class="tl">像<strong>预制菜 + 冰箱贴保质期</strong>:常问题型直接拿模板填天数;跑完的结果贴冰箱,但 Core 有新交易就撕掉旧标签(bump)。</p>
<p class="tl">种子:<code>scripts/agent/seed-analyst-query-templates.sql</code> · 一键演示:<code>prepare_all.ps1</code>。</p>
</div>
</div>
</div>
</div>
<div class="screen animate-in">
<h2>群聊:模板 vs LLM vs 缓存</h2>
<div class="chat-window" id="chat-analyst-m5">
<div class="chat-messages">
<div class="chat-message" data-msg="0" data-sender="page" style="display:none">
<div class="chat-avatar" style="background:#2A7B9B">问数页</div>
<div class="chat-bubble">
<span class="chat-sender" style="color:#2A7B9B">AnalystQueryPage</span>
<p>POST「近7天申购金额」</p>
</div>
</div>
<div class="chat-message" data-msg="1" data-sender="tpl" style="display:none">
<div class="chat-avatar" style="background:#6B5B95">template</div>
<div class="chat-bubble">
<span class="chat-sender" style="color:#6B5B95">template_service</span>
<p>关键词 + schema 命中 → 填 <code>:days=7</code> → 跳过 LLM</p>
</div>
</div>
<div class="chat-message" data-msg="2" data-sender="cache" style="display:none">
<div class="chat-avatar" style="background:#5A9DB8">cache</div>
<div class="chat-bubble">
<span class="chat-sender" style="color:#5A9DB8">cache_service</span>
<p>世代未变 → <code>cache_hit</code>;刚 bump → 重算再写 Redis</p>
</div>
</div>
</div>
<button class="btn chat-play-btn" data-chat="chat-analyst-m5">播放对话</button>
</div>
<div class="quiz-container" id="quiz-analyst-m5">
<div class="quiz-question-block"
data-correct="option-c"
data-explanation-right="对。模板是「同形态填参」省 LLM;结果缓存是「同 SQL 同权限」省 DB。两层独立,meta 可同时看 template_hit 与 cache_hit。"
data-explanation-wrong="D-06 是两层:不要混成「只有 Redis 缓存」。">
<h3 class="quiz-question">AI 说「问数缓存就是 Redis TTL 10 分钟」,你怎么纠正?</h3>
<div class="quiz-options">
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>对,只靠 TTL</span>
</button>
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>模板和缓存是一回事</span>
</button>
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
<div class="quiz-option-radio"></div><span>还有表世代 bump + 模板填参两层</span>
</button>
</div>
<div class="quiz-feedback"></div>
</div>
<button class="quiz-check-btn" onclick="checkQuiz('quiz-analyst-m5')">检查答案</button>
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-analyst-m5')">重做</button>
</div>
</div>
</div>
</section>
</main>