# 数据分析 Agent 架构说明书 > 版本:v1.1 · 状态:评审稿(开发期随落地细化) > 上游需求:《数据分析 Agent 需求规格(答辩版 v1.2)》`docs/需求拆解/01-数据分析Agent需求规格.md` > 对齐约束:`docs/memory/FRAMEWORK.md`(分层/选型)、`docs/项目框架设计/表设计/`(16 表 + Redis Key)、`docs/项目框架设计/技术选型和版本/02-JWT-RBAC鉴权手册.md`、`docs/项目框架设计/Core模拟底座/` > 范围声明:本文只描述**数据分析 Agent**;其余 Agent 仅作为「共用底座 / 数据供给方」出现,不在本文范围。 --- ## 0. 文档说明 ### 0.1 目的 把需求规格(D-01~D-12、N-01~N-08)翻译成**可实现的技术架构**:说清楚数据分析 Agent 由哪些模块组成、数据怎么流、权限怎么兜、SQL 怎么被约束、结果怎么被校验、资产怎么被沉淀,以及每一块落在仓库的哪个目录、哪张表、哪个 Key。 ### 0.2 读者 | 读者 | 关注章节 | |---|---| | 开发(Wave 1 分析组) | §4 核心链路、§5 模块划分、§6 LangGraph 编排、§7 数据与存储、§13 接口 | | 平台/底座组 | §8 权限与安全、§7.1 复用底座、§13 接口 | | 产品/项目经理 | §1 原则、§2 总体架构、§15 落地顺序、§16 验收对照 | | 合规/答辩 | §8 五层隔离、§10 数字护栏、§16 验收对照 | ### 0.3 需求 ID 对照速查 | 需求 | 含义 | 架构落点 | |---|---|---| | D-01~D-04 | 客户/产品/预警查数 + 留痕边界 | §4 主链路、§8 权限 | | D-05 | 复杂交叉问数 | §4 多表只读聚合 | | D-06 | 查询缓存 | §9 双层缓存 | | D-07 | 口径统一 | §7.2 口径字典、§4 元数据注入 | | D-08 | 兜底与拒答 | §4 失败分支、§6 节点 | | D-09 | 多轮追问 | §6 Constrained Edit、§9 短期记忆 | | D-10 | 数字护栏 | §10 | | D-11 | 养 Agent 闭环 | §11 | | D-12 | 智能看数板 | §12 | | N-01~N-08 | 消歧/空零/溯源/配额/复用/质量/转人工/可观测 | §4/§6/§7/§13 对应小节 | --- ## 1. 架构定位与设计原则 ### 1.1 定位(一句话) 数据分析 Agent = 把「会写 SQL 的人」的生产力变成**所有人都能自助调用的只读查数服务**:自然语言进、安全 SQL 出、人话解读回、全程可审计、好查询沉淀为资产。 ### 1.2 设计原则 | # | 原则 | 说明 | 对应需求 | |---|---|---|---| | P1 | **只读兜底** | 数据库只读账号 + AST 白名单双保险,任何写操作在生成与执行两层都被拦截 | D-04、§5 安全 | | P2 | **权限硬约束,不靠提示词自觉** | 归属注入是系统行为,模型产出的 SQL 必须再被 AST 二次校验 | §2.2 五层隔离 | | P3 | **数字不赌不猜** | 解读中的数字必须与 SQL 结果逐字比对,对不上就重生成或降级 | D-10 | | P4 | **一问一义** | 指标先经口径字典消歧,多义先反问再生成 | D-07、N-01 | | P5 | **全链路留痕** | `trace_id` 串联 问题→SQL→结果→判定,审计只 INSERT | D-04、F-02 | | P6 | **资产可沉淀可回滚** | 好查询 → 分析师确认 → 版本化发布 → 可灰度可回退 | D-11 | | P7 | **成本可控** | 双层缓存 + 配额限流,成本可计量 | D-06、N-04 | | P8 | **可降级** | LLM 超时/报错/校验失败 → 说明性拒答或转人工,不拖垮只读库 | N-07、§5 可用性 | --- ## 2. 总体架构 ### 2.1 分层图 ```text ┌─────────────────────────────────────────────────────────────────────┐ │ 客户端(内部工作台) │ │ 聊天窗 · 智能看数板卡片 · 资产沉淀台 · 运营指标面板 │ └──────────────────────────────┬──────────────────────────────────────┘ │ HTTPS + Bearer JWT │ X-Agent-Type: analyst · X-Trace-Id ┌──────────────────────────────▼──────────────────────────────────────┐ │ Agent Gateway / Auth SDK(共用底座) │ │ 验签 → 角色准入 → 注入 AuthContext → 越权 401/403 写审计 │ └──────────────────────────────┬──────────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ app/api/analyst.py(薄路由) │ │ /chat · /dashboard · /assets · /sample · /escalate · /ops │ └──────────────────────────────┬──────────────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ app/service/analyst_agent.py(LangGraph StateGraph) │ │ │ │ input_guard → scope_resolve → ambiguity_check → context_retrieve │ │ → sql_generate → sql_validate → execute → guardrail_check │ │ → answer_compose → audit_persist ──(analyst)──> asset_candidate │ │ │ │ 组件:sql_guard(五层) · guardrail(数字护栏) · dict_service(口径) │ │ cache_service(双层缓存) · analytics_repo(资产/留痕) │ └──────┬───────────────┬───────────────┬───────────────┬──────────────┘ ▼ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Core RO │ │ agent 库 │ │ Redis │ │ LLM │ │ 只读 Repository│ │ 只读/只增/资产│ │ 会话/缓存/限流│ │ DeepSeek │ │ (jinrong_core)│ │ (jinrong_agent)│ │ │ │ NL2SQL+解读 │ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ ``` ### 2.2 与四 Agent 共享底座的关系 数据分析 Agent **不建第二套账号/JWT/RBAC**,也不自建 Core 副本: - 身份/角色/归属 → 复用 Gateway + `customer_advisor_rel`(Core 同步)。 - 事实数据 → `CoreReadOnlyRepository` 只读 `jinrong_core`。 - 会话/消息/审计 → 复用 `agent_session` / `agent_message` / `agent_tool_call` / `audit_log` / `input_guard_log`。 - 画像/预警 → 只读 `customer_profile_l1/l2/l3`、`risk_alert`(做统计,不可处置)。 - 专属数据 → `analytics_query_log`(已定)+ §7.2 新增口径/示例/模板表。 --- ## 3. 技术栈(引用既有选型,不新增) | 层 | 选型 | 说明 | |---|---|---| | 服务 | Python 3.13 + FastAPI | 薄路由,不含业务 | | 编排 | **LangGraph 1.2.x** StateGraph + DeepSeek API | 状态机图,Tool 节点化 | | 关系库 | MySQL 8(`jinrong_agent` + `jinrong_core` 双库) | 权威落盘 + Core 只读 | | 缓存 | Redis 8 | 会话短期记忆 + 结果/模板缓存 + 限流 | | SQL 安全 | `sqlglot`(AST 解析白名单) + 只读账号 | 已确认新增,登记于技术选型文档 | | 图库/向量库 | Neo4j / Milvus(**一期分析 Agent 不依赖**) | 预留;关系与 RAG 归其他 Agent | > 一期数据分析 Agent 强依赖:MySQL 双库 + Redis + DeepSeek + `sqlglot`;Neo4j/Milvus 不阻塞。 --- ## 4. 核心链路:NL → SQL → 解读 ### 4.1 全流程(一次问答) ```text 用户提问(自然语言) │ ▼ ① 输入防护 guard:rate 限流 → 注入/超长拦截 → input_guard_log ▼ ② 权限上下文 解析 AuthContext;顾问/风控/运营的归属白名单/数据域 scope_resolve(顾问白名单实时取 core_customer_advisor active) ▼ ③ 指标消歧 命中口径字典的多义指标 → 反问候选口径(N-01) ambiguity_check (有歧义则暂停,本轮不生成 SQL) ▼ ④ 上下文组装 短期记忆(Redis 会话) + 口径字典条目 + schema 元数据 + few-shot context_retrieve ▼ ⑤ SQL 生成 LLM 生成只读 SELECT(多表只读聚合 D-05) sql_generate ▼ ⑥ SQL 校验 五层:白名单/归属注入/AST 越权/列级脱敏/粒度 → 不通过 403 sql_validate ▼ ⑦ 执行 查结果缓存(命中标 cache_hit)→ 未命中执行 → 写缓存 execute 行数上限 1000 / 超时 10s;空结果三态区分(N-02) ▼ ⑧ 数字护栏 四道校验:数字/单位/时间窗/抽样复核 → 重生成1次 → 降级(D-10) guardrail_check ▼ ⑨ 组装输出 answer + table + sql + meta(data_as_of/cost/cache_hit) + disclaimer answer_compose ▼ ⑩ 留痕 analytics_query_log + agent_tool_call + audit_log(同 trace_id) audit_persist ▼ ⑪ 资产候选 (仅 analyst)半自动提炼 few-shot/模板候选 → 分析师确认发布(D-11) asset_candidate ``` ### 4.2 失败与降级分支 | 场景 | 处理 | 留痕 | |---|---|---| | 越权(顾问查他人客户/运营下钻客户维度) | 403 + 说明性拒答 + 可查范围引导 | `analytics_query_log(blocked)` + `audit_log` | | SQL 生成失败 / LLM 超时 / 查不到表 | 说明性拒答 + 一键转人工(N-07) | `analytics_query_log(error)` + `audit_log` | | 数字护栏仍不一致(重试 1 次后) | 降级输出:只给表格 +「以数据为准」 | `result_summary` 标 `guardrail_failed` | | 空结果 | 区分 `zero` / `no_data` / `not_match`(N-02) | 写入解读 + `result_summary` | | 缓存命中 | 直接返回,标 `cache_hit=true` + `data_as_of` | `analytics_query_log` | --- ## 5. 模块划分(app/) > 遵守 FRAMEWORK §3 分层:`api → service → tool / repository / model / config`,api 不写业务,tool 不写流程。 ```text app/ ├─ api/ │ └─ analyst.py # 路由:/chat /dashboard /assets /sample /escalate /ops 【待实现】 ├─ service/ │ ├─ analyst_agent.py # LangGraph StateGraph 编排 + 各节点 【待实现】 │ ├─ sql_guard.py # 只读白名单 / AST 校验 / 归属注入 / 粒度 【待实现】 │ ├─ guardrail.py # 数字护栏四道校验 【待实现】 │ ├─ dict_service.py # 口径字典读写 + 消歧 【待实现】 │ ├─ cache_service.py # 结果缓存 / 模板缓存 / data_as_of 【待实现】 │ └─ analytics_repo.py # analytics_* 表读写(留痕/资产),不写 Core 【待实现】 ├─ tool/ │ ├─ core_ro_tool.py # 包装 CoreReadOnlyRepository 为 Tool 节点 【待实现】 │ └─ sql_tool.py # 只读执行 + 行数/超时控制 + 空态标记 【待实现】 ├─ repository/ │ └─ core_ro.py # Core 只读 SELECT(jinrong_core) 【已实现】 ├─ model/ │ ├─ schemas/analyst.py # 请求/响应/输出四件套 Pydantic 【占位】 │ └─ entities/analytics.py # analytics_* ORM 【占位】 ├─ config/ # settings / database(双库连接) 【settings 已实现】 └─ utils/ # response / exceptions / logger / trace 【占位】 ``` ### 5.1 关键模块职责边界 | 模块 | 做什么 | 不做什么 | |---|---|---| | `sql_guard` | SELECT 白名单、AST 越权、归属注入、粒度、脱敏列清单 | 不执行 SQL、不解析业务语义 | | `guardrail` | 解读数字与结果一致性校验 | 不生成 SQL | | `dict_service` | 指标定义/公式/适用表 + 消歧反问 | 不直接改口径(仅 analyst 经确认发布) | | `cache_service` | 键构造(含权限指纹)、TTL 分层、主动失效 | 不落 PII 明文 | | `analytics_repo` | `analytics_*` 增改查、版本/灰度状态 | 不写 `jinrong_core`,不改审计表 | --- ## 6. LangGraph 编排(StateGraph) ### 6.1 图结构 ```text ┌──────────────┐ │ input_guard │ └──────┬───────┘ │ passed ┌──────▼────────┐ │ scope_resolve │ └──────┬────────┘ │ ┌──────▼──────────┐ 歧义 │ ambiguity_check ├─────────► clarify(反问口径,写会话,结束本轮) └──────┬──────────┘ │ 无歧义 ┌──────▼──────────┐ │ context_retrieve│ └──────┬──────────┘ │ ┌──────▼──────────┐ │ sql_generate │ └──────┬──────────┘ │ ┌──────▼──────────┐ 拒绝(403) │ sql_validate ├─────────► deny(拒答+范围引导+留痕,结束) └──────┬──────────┘ │ 通过 ┌──────▼──────────┐ │ execute │ └──────┬──────────┘ │ ┌──────▼──────────┐ │ guardrail_check │──重试1次──► 回 sql_generate └──────┬──────────┘ │ 通过 / 降级 ┌──────▼──────────┐ │ answer_compose │ └──────┬──────────┘ │ ┌──────▼──────────┐ │ audit_persist │ └──────┬──────────┘ │ (analyst 角色) ┌──────▼──────────┐ │ asset_candidate │──► 半自动候选(仅提示,不自动生效) └─────────────────┘ ``` ### 6.2 State 概要(Pydantic) ```python class AnalystState(TypedDict): trace_id: str session_id: str auth: AuthContext # sub/roles/permissions/agent_type nl_question: str # 本轮问题(追问已带上下文) scope: ScopeContext # 角色数据域 + 归属白名单 customer_id 集合 ambiguity: Ambiguity | None # N-01 消歧候选 context: PromptContext # schema 元数据 + 口径条目 + few-shot sql: str # 生成/改写后的 SQL validation: ValidationResult # sql_guard 判定 result: QueryResult # rows/columns/空态/data_as_of/cache_hit guardrail: GuardrailResult # 四道校验结果 answer: AnalystResponse # 四件套 status: str # success/clarify/deny/degrade/error/escalate ``` ### 6.3 多轮追问(D-09)—— 与首轮的区别 追问**不走结果缓存命中**,而是: 1. 从短期记忆取出**上轮 SQL + 上轮口径四件套**(指标定义、时间窗、维度、脱敏级别)。 2. 对 SQL 做**受限改写(Constrained Edit)**:只允许追加/替换分组、过滤、排序,禁止更换事实表。 3. 改写失败 → 自动降级为**全新生成**,但必须携带同一口径四件套,保证「同一指标前后一个定义」。 4. 看板钻取(D-12)复用此链路。 --- ## 7. 数据与存储 ### 7.1 复用底座(11 表,只读/只增) | 表 | 用途 | 访问 | |---|---|---| | `agent_session` / `agent_message` / `agent_tool_call` | 会话与消息、Tool 调用 | 读 + 正常业务写 | | `audit_log` | 审计总账 | 只 INSERT | | `input_guard_log` | 输入防护 | 只 INSERT | | `customer_advisor_rel` | 顾问归属白名单(RBAC 权威) | 只读 | | `customer_profile_l1/l2/l3` | 画像(统计口径可选读) | 只读(脱敏/聚合) | | `risk_alert` | 预警台账 | 只读,不可处置 | | `risk_suitability_log` | 适当性 | 只读 | ### 7.2 专属表 **已有(`02-mysql-agent专用.sql` 已定义):** - `analytics_query_log`:NL→SQL→结果留痕,含 `sql_hash` / `exec_status` / `result_summary`。 **新增(已定稿 · 独立文件 `docs/项目框架设计/表设计/03-mysql-analyst专用.sql`):** ```sql -- 口径字典:指标名 → 定义/公式/适用表(D-07 / D-11) CREATE TABLE analytics_metric_dict ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, metric_key VARCHAR(128) NOT NULL COMMENT '唯一键,如 holding_scale', metric_name VARCHAR(128) NOT NULL COMMENT '持仓规模', aliases JSON NULL COMMENT '同义词:["规模","市值"]', definition TEXT NOT NULL COMMENT '口径定义', formula TEXT NULL COMMENT '计算公式', applicable_tables JSON NULL COMMENT '适用表清单', default_time_window VARCHAR(64) NULL COMMENT '默认时间窗', unit VARCHAR(32) NULL COMMENT '单位:元/万元/%', status ENUM('draft','published','rolled_back') NOT NULL DEFAULT 'draft', version INT UNSIGNED NOT NULL DEFAULT 1, gray_roles JSON NULL COMMENT '灰度:null=全量,["advisor"]=部分角色', created_by VARCHAR(64) NOT NULL, published_by VARCHAR(64) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), UNIQUE KEY uk_metric (metric_key, version), KEY idx_status (status, metric_key) ) ENGINE=InnoDB COMMENT='【分析专用】口径字典(D-07/D-11)'; -- few-shot 示例:问题 → 正确 SQL 对(D-11) CREATE TABLE analytics_few_shot ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, question TEXT NOT NULL, sql_text TEXT NOT NULL, tags JSON NULL, source_session_id VARCHAR(64) NULL COMMENT '溯源', status ENUM('draft','published','rolled_back') NOT NULL DEFAULT 'draft', version INT UNSIGNED NOT NULL DEFAULT 1, gray_roles JSON NULL, created_by VARCHAR(64) NOT NULL, published_by VARCHAR(64) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), KEY idx_status (status, id) ) ENGINE=InnoDB COMMENT='【分析专用】few-shot 示例(D-11)'; -- 快速模板:参数化 SQL(D-06 模板缓存 / D-11) CREATE TABLE analytics_query_template ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, template_key VARCHAR(128) NOT NULL, template_sql TEXT NOT NULL COMMENT '参数化 SQL,如 WHERE risk_code IN (:risk_codes)', params_schema JSON NULL COMMENT '参数定义', tags JSON NULL, source_session_id VARCHAR(64) NULL, status ENUM('draft','published','rolled_back') NOT NULL DEFAULT 'draft', version INT UNSIGNED NOT NULL DEFAULT 1, gray_roles JSON NULL, created_by VARCHAR(64) NOT NULL, published_by VARCHAR(64) NULL, created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), KEY idx_status (status, template_key) ) ENGINE=InnoDB COMMENT='【分析专用】快速模板(D-06/D-11)'; ``` > 三表分建(已定);灰度字段 `gray_roles` 用于「先灰度部分角色验证再全量」。建表 SQL 见 `docs/项目框架设计/表设计/03-mysql-analyst专用.sql`。 ### 7.3 Redis Key(分析 Agent 新增部分) 沿用 `{domain}:{agent}:{entity}:{id}` 规范: | Key | 类型 | TTL | 说明 | |---|---|---|---| | `sess:analyst:{session_id}:ctx` | Hash | 2h | 追问上下文 + 上轮 SQL + 口径四件套 | | `sess:analyst:{session_id}:msgs` | List | 2h | 最近 N 轮窗口 | | `cache:analyst:result:{perm_fp}:{sql_hash}` | String(JSON) | 分层 | 结果缓存(键含权限指纹) | | `cache:analyst:scope:{staff_id}` | String(JSON) | 5m | 顾问名下客户白名单(转岗/离职立即失效) | | `cache:analyst:top:{staff_id}` | String(JSON) | 24h | 中期记忆:常用查询 TOP + 偏好口径 | | `guard:rate:{actor_id}:analyst` | String INCR | 1m | 限流(复用 F-03) | **TTL 分层(D-06):** 交易类 5min / 台账类 1h / 基础信息类当日。 ### 7.4 缓存失效(data_as_of 与主动失效) - 响应 `meta.data_as_of` 标明数据截至时间(区分 T+1 / 准实时)。 - 交易/持仓/归属等**事实表变更时主动 DEL** 对应缓存键,不等 TTL。 - 一期模拟库:由 `scripts/sync/sync_advisor_rel.py`(归属)与 Core reset/更新流程广播失效;生产切换 CDC/binlog 订阅,Agent 层失效接口不变。 --- ## 8. 权限与安全:五层隔离实现 需求 §2.2 五层 → 实现组件映射: | 层 | 需求 | 实现组件 | 校验时机 | |---|---|---|---| | 1 身份 | Mock JWT(HS256,24h 续期) | Gateway / Auth SDK;payload 含 user_type/employee_role | 入口 | | 2 角色 | RBAC 数据域 | `RbacGuard.can(ctx, perm)`;analyst 角色 → `sql:execute:readonly` | 入口 + Tool | | 3 行级归属 | 归属强制注入 + 二次校验 | `scope_resolve` 取白名单 → `sql_guard` 在生成阶段注入 `WHERE customer_id IN (:scope)` → AST 校验超范围 403 | 生成 + 校验 | | 4 列级脱敏 | 存储层已脱敏 | 种子已存 mask;API/日志/归档同源;脱敏列清单由 `sql_guard` 维护 | 读取 | | 5 粒度控制 | 聚合 vs 明细 | `sql_guard` 检查是否含客户级下钻;ops 无客户维度 → 拒绝 + 说明 | 校验 | **越权处理:** 403 + 双留痕(`audit_log` 总账 + `analytics_query_log` 记录问题与拒绝原因),可演示「顾问 A 问顾问 B 的客户 → 被拒且留痕可查」。 **SQL 安全双保险(D-04 / §5 安全):** 1. 生成侧:`sql_guard` 用 `sqlglot` 解析 AST → 仅允许 SELECT(含 WITH/子查询白名单)→ 拦截多语句/写语句/DDL。 2. 执行侧:数据库连接使用**只读账号**(`jinrong_core` 只读;`jinrong_agent` 业务表按角色授权)。 3. 资源侧:`LIMIT 1000` / `10s` 超时。 --- ## 9. 缓存与记忆(D-06 / §9.1 定稿方案) ### 9.1 双层缓存 | 层 | 命中对象 | 机制 | |---|---|---| | 结果缓存 | 同形态**独立问题** | 键 = 权限指纹 + sql_hash;直接秒回;命中标 `cache_hit=true`;PII 不落或脱敏 | | 模板缓存 | 跨会话**同形态问题** | 命中参数化模板 → 填参执行;资产发布后自动入池(D-11 联动) | **追问变体**不走缓存命中,走上轮 SQL 受限改写(见 §6.3)。 ### 9.2 三层记忆 | 层 | 载体 | 内容 | 用途 | |---|---|---|---| | 短期 | Redis 会话级 30min | 追问上下文、上轮 SQL、口径四件套 | D-09 追问 / D-12 钻取 / D-10 重试 | | 中期 | Redis 用户级 24h | 常用查询 TOP + 偏好口径 | 调优缓存 TTL、看板排序 | | 长期 | MySQL 资产表 | few-shot / 字典 / 模板 | D-11 资产,喂养模板缓存 | --- ## 10. 数字护栏(D-10 · 亮点) `guardrail_check` 对解读执行四道校验,任一失败 → 重生成(默认 1 次)→ 仍失败 → **降级输出**(只给表格 +「解读校验未通过,以数据为准」): 1. **数字比对**:提取解读中全部数字/金额,与 SQL 结果逐项比对。 2. **单位/币种/百分比**:元 vs 万元、% vs bp。 3. **时间窗一致性**:「近 30 天」按自然日/交易日解析正确。 4. **抽样复核**:抽 1~2 行回源明细核对(与 N-03 共用链路)。 校验结果(通过/重试/降级)写入 `result_summary` + `audit_log`。 > 答辩台词:**「LLM 有幻觉,但我们不赌它不犯——我们校验它。」** --- ## 11. "养 Agent" 闭环(D-11 · 亮点) ```text 分析师问答 → 已执行 SQL → 半自动提炼候选(few-shot/模板/字典) │ ▼ 分析师确认 → 发布(版本化)→ 灰度(gray_roles)→ 生效 → 喂模板缓存 │ ▼ 出问题 → 一键回滚(status=rolled_back,回到上一版本) ``` - **仅 `analyst` 角色可写**;每次沉淀操作审计留痕。 - 资产三类:few-shot 示例 / 口径字典条目 / 快速模板。 - 版本化 + 可回滚 + 可灰度;系统从每次已执行 SQL 半自动提炼候选,分析师仅确认。 - 生效后同类问题命中新资产,`analytics_query_log.result_summary` 标 `source=沉淀资产`。 --- ## 12. 智能看数板(D-12 · 亮点) - 定位:**预聚合概览 + 钻取入口**,不是独立报表系统。 - 角色化卡片(后端返回结构化 JSON,前端下轮渲染): - analyst:客户总数 / 总持仓规模 / 今日交易笔数金额 / 待处理预警数 / 口径字典资产数 - advisor:名下客户数 / 名下资产规模 / 盈亏分布 / 风险等级分布(仅名下) - risk_officer:待处理预警数 / 按类型分布 / 近 7 天新增趋势 - ops:近 30 天申购赎回金额 / 各产品类型规模 TOP(仅聚合) - 卡片钻取 → 复用 D-09 追问链路,指标与对话打通。 - 边界:同样走只读层 + 角色权限;加载与钻取留痕;准实时/按需,不做实时推送。 --- ## 13. 接口设计(REST,`X-Agent-Type: analyst`) | 方法 | 路径 | 说明 | 需求 | |---|---|---|---| | POST | `/api/analyst/chat` | 主对话/追问(SSE 可选,首版 JSON) | D-01~D-05/D-09 | | GET | `/api/analyst/sessions/{id}/messages` | 会话消息回放 | D-04 | | GET | `/api/analyst/dashboard` | 看板数据(按角色) | D-12 | | GET | `/api/analyst/query/{trace_id}/sample` | 聚合结果抽样明细(脱敏) | N-03 | | POST | `/api/analyst/assets/{dict\|few_shot\|template}` | 沉淀资产(仅 analyst) | D-11 | | POST | `/api/analyst/assets/{kind}/{id}/publish` | 发布/灰度 | D-11 | | POST | `/api/analyst/assets/{kind}/{id}/rollback` | 回滚 | D-11 | | POST | `/api/analyst/query/{trace_id}/save` | 存为常用(P1) | N-05 | | POST | `/api/analyst/query/{trace_id}/share` | 分享(继承接收方权限,P1) | N-05 | | POST | `/api/analyst/query/{trace_id}/subscribe` | 订阅刷新(P1) | N-05 | | POST | `/api/analyst/escalate` | 一键转人工(写审计) | N-07 | | GET | `/api/analyst/ops/metrics` | 运营指标(P1) | N-08 | **统一输出四件套(§3 全局约定):** ```json { "answer": "人话解读…", "table": { "columns": ["risk_code","cnt"], "rows": [["C1",4]] }, "sql": "SELECT …", "meta": { "exec_ms":45, "row_count":5, "cache_hit":false, "data_as_of":"2026-09-04", "source":"jinrong_core", "cost_est":0.002 }, "disclaimer": "本内容仅为投资分析参考,不构成任何直接投资建议…" } ``` --- ## 14. 非功能需求落点 | 类别 | 需求 | 落点 | |---|---|---| | 安全 | 只读/注入拦截/越权拒绝/脱敏 | §8 sql_guard + 只读账号 | | 合规 | 免责声明/不处置/不推荐/不对客 | answer_compose 固定 disclaimer + D-02/D-03 边界 | | 性能 | 超时与行数上限 1000/10s + 缓存 | §4 execute、§9 缓存 | | 审计 | trace_id 全链路可还原 | §4 audit_persist | | 可运营 | 资产可维护、版本化回滚灰度 | §11 | | 数据新鲜度 | data_as_of + 主动失效 | §7.4 | | 成本 | 成本计量 + 配额限流 | `meta.cost_est` + `guard:rate` + N-04 | | 可观测 | 通过率/命中率/拒答率/成本/转人工率 | §13 /ops/metrics(N-08) | | 可用性 | 超时降级,不拖垮只读库 | §4.2 失败分支 + N-07 | --- ## 15. 落地顺序与实现状态 | 阶段 | 内容 | 状态 | |---|---|---| | Wave 0(平台) | JWT/RBAC(T-01)、审计贯通(T-02)、agent 库灌库(T-05) | 未做(复用,非分析组) | | Wave 1-A(P0 闭环) | `analytics_query_log` + `sql_guard` + `analyst_agent` 主链路 → D-01~D-04 闭环 | 未做 | | Wave 1-B(P0 增强) | 口径字典(D-07)、缓存+记忆(D-06)、追问改写(D-09)、数字护栏(D-10) | 未做 | | Wave 1-C(P0 亮点) | 养 Agent 资产沉淀(D-11)、智能看数板后端(D-12)、消歧(N-01)、空零(N-02)、溯源(N-03)、转人工(N-07) | **N-03/N-07 已做**;D-12 未做 | | Wave 2(P1) | 配额(N-04)、保存/分享/订阅(N-05)、质量提示(N-06)、运营面板(N-08) | 未做 | > 已有实现:`CoreReadOnlyRepository`(只读 SELECT)、`settings` 双库、Core 模拟库脚本、`customer_advisor_rel` 同步脚本。分析 Agent 业务层尚未实现。 --- ## 16. 验收对照(演示即验收) | 需求演示 | 架构断言 | |---|---| | 「按产品类型统计总持仓规模」 | sql_validate 通过 → execute → 四件套正确 | | 「查 CUST-1004(非名下)持仓」 | scope_resolve 白名单不含 → 403 + 双留痕 | | 「当前待处理大额预警占比」 | risk_alert 只读统计,处置意图被拒 | | 「近一月申购金额总额」(运营) | 粒度控制:仅聚合,无客户明细 | | 同形态问题重复问 | 结果缓存命中 `cache_hit=true` | | 「数字加起来是 123 万吗」 | guardrail 四道校验拦截或通过 | | 沉淀 few-shot 后问同类问题 | 命中沉淀资产,`source=沉淀资产` | | 点看板卡片钻取 | 复用 D-09 改写链路 | --- ## 17. 待定项 | # | 待定项 | 当前立场 | |---|---|---| | 1 | 口径字典/few-shot/模板三表是否合一 | 已定:三表分建,见 `03-mysql-analyst专用.sql` | | 2 | 新增依赖 `sqlglot`(AST 白名单) | 已确认,登记于技术选型文档与 requirements.txt | | 3 | D-12 钻取实现深度 | 已定做钻取,细节开发期细化 | | 4 | 看板刷新策略 | 准实时/按需,不做实时推送 | | 5 | 结果缓存失效通道(CDC vs 同步脚本) | 一期用同步脚本广播,生产切 CDC | --- ## 18. 决策记录 | 决策点 | 结论 | |---|---| | 编排 | LangGraph StateGraph,节点化 Tool | | SQL 安全 | `sqlglot` AST 白名单 + 只读账号双保险 | | 权限 | 五层隔离,行级归属系统注入 + 二次校验 | | 缓存 | 结果/模板双层 + 短期/中期/长期三层记忆 | | 数字护栏 | 四道校验,重试 1 次后降级 | | 资产 | 仅 analyst 可写,版本化/回滚/灰度(`gray_roles`) | | 专属表 | 口径字典/few-shot/模板三表分建,独立 `03-mysql-analyst专用.sql` | | 看数板 | 后端 JSON 接口先行,前端下轮渲染 | | 一期依赖 | 不依赖 Neo4j/Milvus | --- ## 变更记录 | 版本 | 日期 | 变更 | |---|---|---| | v1.0 | 2026-09 | 初版:基于需求规格 v1.2 生成,对齐 FRAMEWORK/表设计/JWT 手册/Core 模拟 | | v1.1 | 2026-09 | 确认新增 `sqlglot`;口径字典/few-shot/模板三表分建,DDL 独立为 `03-mysql-analyst专用.sql` |