feat(analyst): Implement audit logging for query denial and clarification
- Enhanced the `AnalystAgent` class to include an `_audit_terminal` method for logging query denials, clarifications, and errors, ensuring compliance and traceability. - Updated error handling paths to call the new audit method, capturing relevant details such as question, user authentication, and SQL context. - Introduced new validation checks in `sql_guard.py` to enforce ownership filters for sensitive queries, improving security measures. - Added unit tests to verify the correct logging behavior and ownership filter enforcement, ensuring robust functionality. This update significantly strengthens the auditing capabilities of the analyst agent, enhancing security and compliance in query handling.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# 答辩 Demo · 问数工作台 SOP
|
||||
|
||||
> **套餐 ① 答辩稳**(2026-09-11)· 基线 **813 pytest** · 问数/解读拆分已落地
|
||||
|
||||
## 1. 环境(答辩前 30 分钟)
|
||||
|
||||
```powershell
|
||||
cd "d:\项目\JinRong"
|
||||
docker compose up -d redis # 或 .\scripts\dev\start-redis.ps1
|
||||
# .env: REDIS_URL=redis://127.0.0.1:6380/0 · DEEPSEEK_API_KEY 已填
|
||||
|
||||
mysql -u root -p jinrong_agent < scripts/agent/seed-analyst-metric-dict.sql
|
||||
mysql -u root -p jinrong_agent < scripts/agent/seed-analyst-query-templates.sql
|
||||
|
||||
python -m uvicorn app.main:app --reload --port 8000
|
||||
cd web && npm run dev
|
||||
```
|
||||
|
||||
**无 DeepSeek Key:** 问数仍可出 **模板 SQL + 表**;点「分析该数据」解读会降级或失败——答辩建议带 Key。
|
||||
|
||||
## 2. 推荐口述动线(3~5 分钟 · 分析员账号)
|
||||
|
||||
| 步骤 | 操作 | 答辩句 |
|
||||
| --- | --- | --- |
|
||||
| 1 | 打开 **问数工作台** | 「查数和解读拆开:先 NL2SQL 可审计,再按需看图说话」 |
|
||||
| 2 | 问:**客户总数是多少** | 指 **蓝色「模板命中 · customer_total_count」** → D-06 模板跳过 LLM 写 SQL |
|
||||
| 3 | 再问同一题 | 指 **绿色「结果缓存」** → 权限指纹 + SQL + 表世代 |
|
||||
| 4 | 点 **分析该数据** | 「上下文只有本轮问题和表格,不接 Chat 历史;数字走 D-10 护栏」 |
|
||||
| 5 | 问:**近30天申购金额**(或含「近30天」「申购」「金额」) | 模板 `subscribe_amount_recent_days` |
|
||||
| 6 | 问:**近30天交易流水是多少** | **clarify** → N-01 多义,不猜口径 |
|
||||
| 7 | 可选 deny | 理财师问非名下客户 → 权限与问数 **同一 answer**,解读按钮不调 LLM |
|
||||
|
||||
## 3. 客户角色(平台服务 · 数据分析)
|
||||
|
||||
- 登录 **客户** Demo → **平台服务 · 数据分析**
|
||||
- 问:**我近30天有多少笔交易** → 模板 `customer_self_trade_count_recent`(需种子)
|
||||
- 按钮文案:**解读我的数据** · 尾注含「AI 分析有风险」
|
||||
|
||||
## 4. 20 题 battery(答辩后自测,报告不入库)
|
||||
|
||||
```powershell
|
||||
python scripts/dev/run_query_battery.py
|
||||
# 本地生成 scripts/dev/battery_report.json(.gitignore)
|
||||
```
|
||||
|
||||
验收:**A1 Q17**(`created_at` 列不误杀)· **A5** 流水 clarify · 模板题稳定命中。
|
||||
|
||||
## 5. 诚实边界(主动一句)
|
||||
|
||||
- **D-09 多轮追问**、**D-12 看板钻取**、**N-03 溯源** 未做
|
||||
- `/app/analytics/chat` **重定向**到问数页,避免双入口
|
||||
- 分析占位 **agent_service** 仍存在于 API,菜单已收
|
||||
+14
-12
@@ -1,6 +1,6 @@
|
||||
# 金融四 Agent 答辩知识点清单
|
||||
|
||||
> 用途:按模块讲清**数据怎么流、怎么跑、为什么这样选、亮点在哪**;答辩时可当提纲。基线:**804 pytest** · **19 Vitest** · 分支 **`merger`**。
|
||||
> 用途:按模块讲清**数据怎么流、怎么跑、为什么这样选、亮点在哪**;答辩时可当提纲。基线:**816 pytest** · **22 Vitest** · 分支 **`merger`**。
|
||||
|
||||
---
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
| --- | --- |
|
||||
| **业务定位** | 代销场景四角色(客户 / 理财师 / 分析 / 风控)共用 **L0 事实 + 合规底座**;**四 Agent 不互调 LLM**,跨线靠画像表、预警表、平台 API |
|
||||
| **分层** | 浏览器 → FastAPI(`api/`)→ 编排(`service/`)→ 工具/仓储(`tool/` · `repository/`)→ MySQL 双库 / Redis / Milvus / Neo4j / Core 模拟 |
|
||||
| **两条对话主线** | ① **通用 Chat**:`POST /api/chat` 或 `/stream` + `X-Agent-Type` → `agent_service`(advisor/risk/分析占位)② **客服专用**:`customer` → `customer_service` 14 节点 ③ **问数独立**:`POST /api/analyst/chat` → `analyst_agent`(非同一 StateGraph) |
|
||||
| **两条对话主线** | ① **通用 Chat**:`POST /api/chat` 或 `/stream` + `X-Agent-Type` → `agent_service`(advisor/risk)② **客服专用**:`customer` → `customer_service` 14 节点 ③ **问数独立**:`POST /api/analyst/chat` + **`POST /api/analyst/interpret` 按需解读**(非 Chat 历史) |
|
||||
| **可审计** | `trace_id` / `request_id` 贯通 · `audit_log` / `http_access` / `agent_tool_call` / `analytics_query_log` **只 INSERT** |
|
||||
|
||||
**铁律(必背):** Core 正式 C1~C5 画像不可覆盖 · 仅 **R-02 适当性** 可阻断交易 · 风控 **不自动冻户** · 审计 **只增不改**。
|
||||
@@ -71,14 +71,14 @@
|
||||
|
||||
| 项 | 内容 |
|
||||
| --- | --- |
|
||||
| **入口** | `POST /api/analyst/chat`(**无** `X-Agent-Type`)· `GET /dashboard` · `POST /assets` |
|
||||
| **编排** | `analyst_agent.run()`:**消歧 → 模板或 LLM 生成 SQL → 五层 sql_guard → 执行 → 解读 → 数字护栏 → 留痕** |
|
||||
| **入口** | `POST /api/analyst/chat`(默认仅表)· **`POST /api/analyst/interpret`** · `GET /dashboard` · `POST /assets` |
|
||||
| **编排** | `analyst_agent.run(interpret=false)`:**消歧 → 模板或 LLM SQL → 五层 sql_guard → 执行 → 留痕**;解读 **`interpret()`** → D-10 护栏 |
|
||||
| **数据流** | 只读 `jinrong_core` + 白名单 agent 表(如 `risk_alert`)→ `analytics_query_log` + `audit_log` |
|
||||
| **D-06 缓存** | ① **结果缓存**:权限指纹 + SQL + **表世代**(写交易/预警/L3 后 bump,不等 TTL)② **模板缓存**:published 模板 **填参**,跳过 LLM 写 SQL(`template_hit`) |
|
||||
| **D-10 护栏** | 解读数字与结果 **逐字比对** · 失败重试 1 次 → **degrade 只出表** |
|
||||
| **N-01** | 「流水」等多义 → **clarify**,不猜口径 |
|
||||
| **聪明做法** | 问数与 **Chat 分离**(分析对话页仍是轻量 LLM,真 NL2SQL 在问数工作台)· 客户域 **self** + 固定 AI 风险尾注 |
|
||||
| **诚实缺口** | D-09 多轮追问 · N-03 溯源 API · N-07 转人工 — 未做 |
|
||||
| **聪明做法** | 问数与 Chat **分离** · 各角色问数页 **「分析该数据 / 解读我的数据」** 仅带本轮快照 · 客户 **self** 域 + AI 风险尾注 · **Q17** 列名 `created_at` 不误杀 `create` |
|
||||
| **诚实缺口** | D-09 **多轮** · N-03 溯源 · N-07 转人工 — 未做 · **分析对话菜单已收**(URL 重定向问数) |
|
||||
|
||||
### 4.4 风控 Agent
|
||||
|
||||
@@ -105,8 +105,8 @@
|
||||
| --- | --- |
|
||||
| **运行** | React 19 + Vite 8 · HashRouter · Demo 账号登录 → JWT → 四角色菜单 |
|
||||
| **数据流** | `apiFetch` 统一 Bearer · Dashboard hooks 聚合 Core+净值 · ChatPanel SSE/sync |
|
||||
| **聪明做法** | **`useAsyncSequence`** 防 StrictMode 双请求竞态(先闪错再刷新的问题)· 问数页展示 **模板命中 / 结果缓存** 标签 |
|
||||
| **诚实** | 分析对话 **占位** · 看板 **无钻取** |
|
||||
| **聪明做法** | **`useAsyncSequence`** 防 StrictMode 双请求 · 问数页 **模板/缓存/未命中** 四 Tag · **解读按钮** 分角色文案 |
|
||||
| **诚实** | 看板 **无钻取** · 进页仍全量拉平台 API(见 MEMORY Redis≠Dashboard) |
|
||||
|
||||
---
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
| **Tool 归属纵深** | Tool 层 blocked 留痕 + API 层 403 · 风控 officer 可无 customer_id 查全量待审(C2) |
|
||||
| **RAG 溯源** | `source_refs` / effective_date 过滤 · 禁止 LLM 编造未检索内容 |
|
||||
| **风控评审闭环** | B1~B9b、C4~C6 独立 AI 评审 · 挂账 #1~#9 核对 |
|
||||
| **测试** | **804** 后端 · Wave 分模块 · 风控/问数/客服 单测+集成 · 前端 19 Vitest |
|
||||
| **测试** | **816** 后端 · Wave 分模块 · 问数 interpret 拆分 + sql_guard Q17 · 前端 **22** Vitest |
|
||||
| **文档** | `docs/memory/*` Agent 交接 · `docs/course/` 交互深潜课 · 演示 SOP |
|
||||
| **问数 battery** | `run_query_battery.py` 本地跑分 · **报告不入库** |
|
||||
| **输入与输出双护栏** | 输入:注入/限流 · 输出:客服 sanitize + 问数 guardrail |
|
||||
@@ -146,8 +146,9 @@
|
||||
1. **登录** → 四角色之一 Dashboard(平台只读数据从哪来)
|
||||
2. **客户** → 持仓/Chat SSE 或阈值提醒(Core + 1B)
|
||||
3. **风控** → 模拟交易 A-1 → 台账 pending → 处置(事件线 + 人工闭环)
|
||||
4. **分析** → 问数「客户总数」「近7天申购金额」→ 看 **模板命中** + SQL 折叠(D-06 + 护栏)
|
||||
5. **可选** → 风控 Chat 只读查预警(强调 **不能** 让 Agent 改状态)
|
||||
4. **分析** → 问数「客户总数」→ 模板 + 缓存 Tag → **分析该数据** → 解读卡片(D-06 + D-10 + interpret 拆分)
|
||||
5. **可选** → 问「交易流水」→ **clarify**(N-01)
|
||||
6. **可选** → 风控 Chat 只读查预警(强调 **不能** 让 Agent 改状态)
|
||||
|
||||
---
|
||||
|
||||
@@ -156,7 +157,7 @@
|
||||
| 项 | 说法 |
|
||||
| --- | --- |
|
||||
| 无真实 Core | L0 为 **模拟库**,生产接托管 Core 只读账号 |
|
||||
| 分析对话 vs 问数 | 多轮 NL2SQL **未合并**;规格 D-09 待做 |
|
||||
| 分析对话 vs 问数 | **已拆分**:默认只出表 · 按钮调 `/interpret` · 旧 **分析对话** 路由重定向问数 · D-09 **多轮**仍 open |
|
||||
| 客服 L1/L2 Redis | 热读方案已定,**风控不做 L1/L2** |
|
||||
| C-04 push | 仅持仓查询 **内联提醒**,无定时 push |
|
||||
| 行情 Phase B | v0.2 草案,未接 sync |
|
||||
@@ -192,6 +193,7 @@
|
||||
| 前端验收 | `docs/frontend/FRONTEND-HANDOFF.md` |
|
||||
| 交互课导览 | `docs/course/index.html` |
|
||||
| 答辩滚动课(浏览器) | `docs/course/jinrong-overview/index.html` 模块 8 |
|
||||
| 问数 Demo SOP | `docs/答辩/DEMO-SOP-问数.md` |
|
||||
| 问数 D-06 深潜 | `docs/course/jinrong-module-analyst/index.html` 模块 5 |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user