Files
group_xinghuo_jinrong/docs/项目框架设计/数据分析Agent-合并说明.md
T
zhanghongyu_0626 bcd6175d4e feat(analyst): Implement data analysis agent with authentication and query handling
- Introduced `analyst_auth_adapter.py` for managing authentication context and access control for the data analysis agent.
- Added new API endpoints in `analyst.py` for chat, dashboard, asset management, and metrics, utilizing the new authentication context.
- Created Pydantic models in `analyst_schemas.py` for request and response structures, ensuring consistent data handling.
- Updated SQL guard logic in `sql_guard.py` to enforce access restrictions based on user roles and contexts.
- Implemented migration scripts for new database tables related to the data analysis agent, enhancing data management capabilities.
- Removed legacy authentication code from `auth.py`, streamlining the authentication process.

This update significantly enhances the data analysis capabilities, providing a robust framework for querying and managing data securely.
2026-09-09 21:02:11 +08:00

19 KiB
Raw Blame History

数据分析 Agent · 从 data-analysis-agent-work 合并说明

日期:2026-09-09
远程分支:xinghuo/data-analysis-agent-work @ b19a241(zyi)
原则:只增不盖;与 merger 同路径冲突时 以 merger 为准(不覆盖 main.py / deps.py / chat.py / agent_service.py 宿主骨架)。
状态:接缝设计稿(未 merge、未接线)


0. 一句话定位

数据分析 Agent = NL2SQL 只读查数线:自然语言 → 安全 SQL → 表格 + 解读 + 留痕;与宿主 通用对话线(agent_service 轻提示词 Chat)是两条不同产物,接缝上 并行挂载,不替换 agent_service.py。


1. 合并什么(新增文件清单)

从 data-analysis-agent-work 整包迁入(无冲突或仅新增路径):

类别 路径 作用
路由 app/api/analyst.py /api/analyst/chat · /dashboard · /assets · /ops/metrics
编排 app/service/analyst_agent.py LangGraph StateGraph(input_guard → … → audit_persist)
安全 app/service/sql_guard.py guardrail.py 五层 SQL 白名单 + 数字护栏
支撑 analytics_repo.py dict_service.py cache_service.py schema_meta.py 留痕/口径/缓存/元数据
LLM app/service/llm.py DeepSeek 封装(分析线专用;与 merger embedding.py 不冲突)
模型 app/model/schemas/analyst.py 输出四件套 Pydantic(answer/table/sql/meta)
实体 app/model/entities/analytics.py(若远程有) analytics_* ORM 映射
工具 app/tool/sql_tool.py(若远程有) 只读执行 + 行数/超时
文档 数据分析Agent架构说明书.md 数据分析Agent开发清单.md 03-mysql-analyst专用.sql 架构 / 任务 / DDL
测试 见 §6 重命名后迁入,避免覆盖 merger 730 基线

不迁入(冲突 · 保留 merger):

文件 原因
app/main.py AL-09 全量宿主入口;仅 追加 include_router(analyst_router)
app/api/deps.py merger 完整 JWT + 归属 + 矩阵(382 行);远程版被砍成 22 行 stub
app/api/chat.py app/service/agent_service.py 四 Agent 通用对话线已集成
app/config/settings.py merger 含 risk/customer/visitor/JWT 全量;追加 analyst_* 字段
app/model/schemas.py 保留单文件;分析专用模型放 schemas/analyst.py 子模块(见 §3.3)
app/repository/core_ro.py merger 版含 check_suitability 等平台能力;分析线只 调用 不覆盖
app/utils/auth.py 远程第二套鉴权(subject_id);废弃,改 deps 适配(§4)
docs/memory/*、前端 web/、风控/平台 API 全部保留 merger

2. 数据库(需手工执行)

2.1 已有(merger canonical)

docs/项目框架设计/表设计/02-mysql-agent专用.sql 已含 analytics_query_log(NL2SQL 留痕)。merger entities.py 已有 ORM。无需重复建表(若本机已跑过 02 迁移)。

2.2 新增(分析资产三表 · D-07 / D-11)

远程 03-mysql-analyst专用.sql → 独立迁移脚本(不修改 canonical 02 文件):

scripts/agent/migrate-analyst-d07-d11.sql
  → analytics_metric_dict      口径字典
  → analytics_few_shot         问题→SQL 示例
  → analytics_query_template   参数化模板

执行时机:merge 代码后、跑分析线单测/E2E 前;库 jinrong_agent,前置 01/02 共用底座已存在。

2.3 Redis

复用 merger Docker Redis(:6380)。分析线 cache_service 使用独立 key 前缀(对齐 02-redis-keys.md 分析段);与客服/游客/风控 key 命名空间隔离,同实例不冲突。


3. S3 接缝设计(推荐方案 · 待你确认 §8)

3.1 入口策略:并行双轨(推荐)

入口 行为 前端页面
POST /api/analyst/chat AnalystAgent.run() → JSON 四件套(table/sql/meta/disclaimer) /app/analytics/query 问数工作台(主链路)
GET /api/analyst/dashboard D-12 智能看数卡片 /app/analyst/home 可接 metrics
POST /api/analyst/assets D-11 资产沉淀 问数页「沉淀」按钮(P1 后做)
GET /api/analyst/ops/metrics N-08 运营指标 分析员运维面板(P1 后做)
POST /api/chat + X-Agent-Type: analyst 仍走 agent_service(轻量对话 stub,无 NL2SQL) /app/analytics/chat 分析对话(可选保留)

为何不把 analyst 并入 chat.py 分流?

  • 问数响应含 结构化 table + sql + meta,与 Chat 的 {reply, has_disclaimer} 形状不同;硬塞进 SSE 需额外 adapter 层,收益低。
  • 架构说明书 §13 已定义独立 /api/analyst/*;与客服 S2「customer 分流」场景不同(customer 仍是 Chat 形态)。

main.py 改动(唯一宿主挂载点):

from app.api.analyst import router as analyst_router
app.include_router(analyst_router)  # prefix 已在 analyst.py 内:/api/analyst

3.2 鉴权接缝:deps 为准 + 薄适配

远程代码混用 deps.get_auth_context 与 utils.auth.AuthContext(字段 subject_id vs actor_id)。合并后:

  1. 删除迁入后的 app/utils/auth.py(或保留空 shim 仅 re-export,最终删除)。
  2. 新增 app/api/analyst_auth_adapter.py(或扩展现有 auth_adapter.py):
def analyst_auth_from_deps(ctx: deps.AuthContext) -> AnalystAuthView:
    """deps.AuthContext → 分析线内部视图(仅字段映射,不做权限判定)。"""
    return AnalystAuthView(
        subject_id=ctx.actor_id,   # 分析 repo 写 staff_id 用
        roles=ctx.roles,
        permissions=ctx.permissions,
        token_type=ctx.token_type,
        trace_id=current_trace() or "",
        agent_type="analyst",
    )
  1. analyst.py 路由层:auth = Depends(get_auth_context) → 适配后传入 AnalystAgent.run()。
  2. 远程 assert_analyst_access(auth) 逻辑 迁入 deps.py 或 app/utils/authz.py(与 assert_customer_access 并列),使用 actor_id 命名。
  3. X-Agent-Type:/api/analyst/* 不要求该头(路由即 analyst);JWT 矩阵仍校验 token 角色含 analyst/compliance/advisor/risk_officer/ops(按远程 assert_analyst_access 域划分)。

3.3 Schemas:单文件 + 子模块共存

merger 当前 app/model/schemas.py 为单文件。合并策略:

  • 新增 app/model/schemas/analyst.py(仅分析请求/响应)。
  • 不把 schemas.py 改成包(避免大面积 import 破坏);analyst.py 路由 from app.model.schemas.analyst import ... 直引子路径。
  • 若 Python 包解析与 schemas.py 文件冲突:将子模块改为 app/model/analyst_schemas.py(备选,merge 时二选一)。

3.4 settings 追加字段(合并冲突手工解)

在 merger settings.py 追加(取自远程,命名对齐架构说明书):

字段 用途
analyst_llm_model / analyst_llm_timeout DeepSeek NL2SQL
analyst_sql_row_limit / analyst_sql_timeout_sec 只读执行上限
analyst_cache_ttl_sec 结果缓存
analyst_rate_limit_per_min 问数限流

.env.example 同步追加;不覆盖 merger 已有 jwt_* / risk_* / customer_*。

3.5 requirements

merger 已有 langgraph;追加 sqlglot>=25.0.0(远程新增,SQL AST 白名单硬依赖)。

3.6 core_ro / llm 边界

模块 策略
core_ro.py 保留 merger;analytics_repo.execute_readonly 走 agent 库只读账号 或现有 Core RO 连接,不 duplicate
llm.py 迁入分析线专用;AnalystAgent 只 import 此模块
input_guard 分析线复用 merger app/service/input_guard.py(限流/注入),不保留远程 duplicate utils/input_guard.py

4. 前端接缝(merger 现状 → 目标)

4.1 现状

路由 现状
/app/analytics/query PlaceholderPage(待 NL2SQL)
/app/analytics/chat ChatPanel + agentType="analyst" → POST /api/chat/stream(无 table/sql)

4.2 推荐(与 §3.1 双轨一致)

页面 API UI
问数工作台 /app/analytics/query POST /api/analyst/chat 新问题组件:AnalystQueryPanel(问题框 + 解读 + Ant Design Table + SQL 折叠 + disclaimer)
分析对话 /app/analytics/chat 暂保留 ChatPanel SSE 页顶 Banner 提示:「复杂查数请用问数工作台」;P2 可下线或改跳转

新增 web/src/api/analyst.ts:

export interface AnalystChatResponse {
  answer: string
  table: { columns: string[]; rows: unknown[][] }
  sql: string
  meta: { exec_ms: number; row_count: number; cache_hit: boolean; data_as_of?: string }
  disclaimer: string
  status: string
  trace_id?: string
}

不强行让 ChatPanel 解析四件套(职责分离)。

4.3 首页看板

AnalystMarketDashboard QuickAction「问数工作台」已指向 /app/analytics/query;merge 后可接 GET /api/analyst/dashboard 填充 metrics 卡片(P1)。


5. 需求 ID 对齐

需求 合并后落点 阶段
D-01~D-04 analyst_agent + sql_guard + analytics_query_log merge 后冒烟
D-05 多表只读聚合(sql_generate 节点) 同上
D-06 cache_service 双层缓存 同上
D-07 dict_service + analytics_metric_dict 需跑 migrate-analyst
D-08~D-10 拒答分支 + guardrail 同上
D-11 /assets + 三资产表 migrate + 前端 P1
D-12 /dashboard 首页 P1
N-01~N-08 见架构说明书 §4/§6 单测覆盖

6. 测试策略

6.1 远程测试文件 → 迁入命名

远程 迁入后 说明
tests/test_agent.py tests/test_wave6_analyst_agent.py 改 import:utils.auth → analyst_auth_adapter
tests/test_sql_guard.py tests/test_wave6_sql_guard.py 无冲突,直迁
tests/test_guardrail.py tests/test_wave6_guardrail.py 若 merger 已有同名则合并 case
tests/test_dict_service.py tests/test_wave6_dict_service.py
tests/test_cache_service.py tests/test_wave6_cache_service.py merger 已有 test_cache_service.py → 合并或 rename 远程
tests/test_llm.py tests/test_wave6_analyst_llm.py 避免与 merger LLM 测试混淆

6.2 基线要求

  • merge + 适配完成后:python -m pytest → 730 + N passed(N = 新增 wave6 条数)。
  • 禁止恢复远程对 deps.py / conftest.py 的删减。

6.3 冒烟清单(Scope B · merge 后)

  1. POST /api/analyst/chat + analyst JWT → 200 + 四件套 JSON
  2. 顾问 token 查他人客户 → 403 + analytics_query_log(blocked)
  3. GET /api/analyst/dashboard → 200 + cards
  4. 前端 /app/analytics/query 真跑一条问数
  5. POST /api/chat/stream + analyst → 仍 200(stub 未回归)

7. Merge 操作顺序(执行 SOP · 尚未做)

1. git worktree add ../JinRong-analyst-merge data-analysis-agent-work   # 可选隔离
2. git merge data-analysis-agent-work --no-commit                          # 或 cherry-pick 新增文件
3. 冲突文件按 §1「不迁入」表逐项保留 merger 版
4. 手工:analyst_auth_adapter · main.py include_router · settings 追加 · requirements sqlglot
5. 删除 utils/auth.py · 改 analyst.py / analyst_agent.py import
6. 执行 scripts/agent/migrate-analyst-d07-d11.sql
7. pytest 全绿 → 前端 AnalystQueryPanel → Scope B 冒烟
8. 更新 docs/memory/TODO.md · FRAMEWORK 实现状态表

8. 已确认决策(2026-09-09)

# 决策 结论
Q1 问数主入口 A · 独立 POST /api/analyst/chat;各角色在权限范围内自助查数(见 §9)
Q2 /app/analytics/chat A · 保留 ChatPanel stub + Banner 引导问数工作台
Q3 schemas 路径 A · app/model/schemas/analyst.py(merge 时若与 schemas.py 包冲突再改 analyst_schemas.py)
Q4 merge 方式 A · git merge + 手工解冲突(默认,未单独拍板则按此执行)

9. 鉴权接缝 · 角色矩阵与缺口(merge 前必须补)

9.1 目标口径(产品确认)

每个 Demo 账户角色都能调用数据分析模块,只看其权限范围内的数据。

前端已把「数据分析」放进 客户 / 理财师 / 风控 的 sharedPlatform 菜单(/app/analytics/query);后端远程实现 尚未覆盖 customer,且与 merger deps 矩阵不一致,需在 S3 接缝一并补齐。

9.2 目标角色 × 数据域(接缝后应达到)

Demo 仅四角色:customer · advisor · analyst · risk_officer(无 compliance / risk_manager 独立账号;问数线不单独开域)。

角色 token 数据域 key 可见范围 sql_guard 要点
customer customer self(待实现) 仅本人可读数据(持仓/流水/风评/净值趋势等) 禁止其他 CUST-*;强制 customer_id = auth.customer_id;见 §9.6 产品约束
advisor staff assigned 名下客户(core_customer_advisor active) 远程已有;inject_ownership + 白名单
analyst staff full 全量 + 敏感列策略 远程已有
risk_officer staff risk 预警台账全量 + 客户/持仓/交易只读(脱敏列) 远程已有;表域评估见 §9.7
ops staff aggregate 无客户维度,仅聚合 远程已有(非 Demo 角色,预留)

9.6 客户问数 · 产品约束(2026-09-09 确认)

客户走 self 域,能力边界如下(merge 时在 analyst_agent 解读阶段 + prompt 硬约束):

项 口径
允许 基于本人可读数据的趋势总结、分布描述、数量统计(如持仓结构、近 N 日交易笔数、盈亏区间描述)
禁止 投资建议、收益承诺、买卖时点、产品推荐;命中则拒答或降级为「仅展示表格」
尾部声明 在标准 disclaimer 之外,客户域回复追加:「AI 分析有风险,仅供参考。」
留痕 analytics_query_log.actor_id = customer_id,actor_role = customer

实现落点(merge 时):

  • scope_resolve:token_type=customer → domain=self,scope=[auth.customer_id]
  • sql_guard.validate(domain=self):同 advisor 归属逻辑,但 scope 固定单人
  • _generate_sql / ANSWER_SYSTEM:注入「仅描述数据、不给建议」
  • answer_compose:domain=self 时 append 客户专用尾注

9.7 风控专员 · 表域是否够用(2026-09-09 评估)

结论:够用。 风控 Agent 自动监督触发的结果(规则引擎出单、AML 命中、适当性拦截、集中度/代理人行为链等)权威落点都在现有白名单内;风控专员问数线是只读查台账与关联上下文,不通过 NL2SQL 触发处置或扫名单。

监督链路(风控 Agent / 引擎) 落库/可读表 已在 sql_guard 白名单
RISK-001~006 交易/持仓规则 risk_alert(alert_type + payload/triggered_rules) ✅
RISK-006 集中度 risk_alert(pattern + payload.alert_subtype=concentration)+ core_holding ✅
RISK-008 代理人行为链 risk_alert(pattern + payload.alert_subtype=agent_behavior) ✅
AML 命中 risk_alert(alert_type=aml)+ customer_profile_l3 标记 ✅
适当性拦截 risk_alert(alert_type=suitability) ✅
客户监测画像 customer_profile_l1/l2/l3 ✅
关联上下文(客户/持仓/交易/产品) core_* 系列 ✅

刻意不进白名单(安全/职责分离):

表 原因
risk_aml_list 反洗钱名单本体;命中结果已在 risk_alert,不应 NL2SQL 直查名单库
audit_log 审计明细走 HTTP/专用 Tool;问数以 risk_alert 聚合即可

可选 P2(非阻塞 merge): 若后续要问「适当性判定历史通过率/明细」,可把 risk_suitability_log 加入白名单并在 risk 域只读;当前 Demo 问数(待处理预警数、按类型分布、客户监测分布)不依赖该表。

域规则: 维持远程 domain=risk(台账全量 + 白名单内客户只读),不新增 compliance/manager 域;与现网风控 Demo(STAFF-30001 · risk_officer)一致即可。

9.3 远程 vs merger 缺口清单

缺口 远程现状 merger 现状 接缝动作(记入 TODO)
G1 customer 不可用 assert_analyst_access 要求 token_type=staff 平台 G-01 支持 customer 本人 新增域 self;/api/analyst/* 入口允许 customer token
G2 sql_guard 无 self 域 仅 full/assigned/risk/aggregate — validate() + inject_ownership() 支持 self + 强制 customer_id = auth.customer_id
G3 双套 AuthContext subject_id + utils/auth.py actor_id + deps.py §3.2 适配器;废弃 remote auth
G4 入口矩阵分裂 /api/analyst/* 用 ANALYST_ROLES 四角色 AGENT_ACCESS_MATRIX["analyst"] 仅 analyst+compliance(对话线) 问数路由 不走 chat 矩阵;assert_analyst_query_access() 覆盖 customer/advisor/analyst/risk_officer
G5 — — 已关闭:无 compliance/risk_manager Demo 角色,不单独开域
G6 留痕 actor staff_id=subject_id customer 无 staff_id analytics_query_log 写 actor_id + actor_role;customer 写 customer_id
G7 前端 PermissionGate — 问数页仍 Placeholder 403 展示可查范围引导(对齐 AnalystResponse.suggestions)
G8 客户解读约束 远程无 customer 域 — §9.6:趋势总结 · 禁建议 · 尾部「AI 分析有风险」

9.4 推荐实现落点(merge 时)

app/utils/authz.py          # 新增 assert_analyst_query_access(auth) → domain
app/service/sql_guard.py    # 扩展 domain=self(§9.6 客户约束)
app/api/analyst.py          # Depends(get_auth_context) → assert_analyst_query_access → adapter → agent.run
app/api/analyst_auth_adapter.py   # actor_id ↔ 分析线内部视图(可选 NamedTuple)

/api/chat analyst stub 仍走现有 AGENT_ACCESS_MATRIX(analyst/compliance 轻聊,Demo 无 compliance 账号);与问数线 刻意分离。


10. 修订记录

日期 说明
2026-09-09 初稿:远程 b19a241 审阅 + merger 730 基线对照;未 merge
2026-09-09 Q1=A Q2=A;§9 鉴权缺口与角色矩阵(含 customer self 域待实现)
2026-09-09 产品拍板:§9.6 客户趋势总结/禁建议/AI 风险尾注;§9.7 risk 表域够用;关闭 G5