Files
group_xinghuo_jinrong/docs/项目框架设计/数据分析Agent-代码迭代.md
T
zhanghongyu_0626 21ced4d38f feat(report): Add battery report generation and update course documentation
- Introduced `battery_report.json` for local data analysis, excluding it from the database.
- Enhanced `AGENTS.md` to reflect updated test baseline with 795 passed tests.
- Added new metrics for trade flow in `dict_service.py`, improving transaction data analysis.
- Updated regex patterns in `guardrail.py` to better handle numeric extraction and prevent misinterpretation of tokens.
- Expanded course modules with new content on FR-8/9/10 capabilities and L3 role management.
- Improved concurrency handling in transaction processing to ensure accurate alert generation.

This update enhances data analysis capabilities and improves the overall structure and clarity of course materials.
2026-09-10 14:32:25 +08:00

9.2 KiB
Raw Blame History

数据分析 Agent · 代码迭代文档

演化记录:从空壳到可用的 NL2SQL Agent,含模块实现、测试基线、问题修复与待办。 关联:docs/memory/FRAMEWORK.md(技术选型 / 实现状态)、docs/需求拆解/01-数据分析Agent需求规格.md(需求 D-xx)、docs/项目框架设计/数据分析Agent架构说明书.md。

1. 定位与范围

数据分析 Agent(AnalystAgent)把自然语言问数翻译为一条只读 SELECT 并执行,面对 jinrong_core(模拟 Core 库,L0 事实)与部分 jinrong_agent 表,最终输出「人话解读 + 数据表格 + 元信息」。当前为 analyst 角色全量(full 域)可跑的实现。

约束(不可越界):仅 SELECT 只读 · 不带处置(不写预警)· 数字不可编造 · 留痕审计。

2. 代码演进时间线

日期 里程碑 Git 说明
2026-09-05 项目脚手架 + 需求/框架定稿 0374010 1ddd44a FastAPI 分层 / 双库 / LangGraph 选型;分析 Agent 仅空壳
2026-09-09 分析 Agent 全套落地 b19a241 api/service/schema/校验/护栏/缓存/字典/LLM + tests + 文档,41 文件 +3463 行
2026-09-10 三问查数 + 护栏 Decimal/标识误报修复 + 流水消歧 工作区 guardrail.py(Decimal/编号/日期时间/左边界)、dict_service(流水多义),degrade→success/clarify
2026-09-10 20 题实测 + 数字护栏误拦截修复 工作区 guardrail.py 两处修复,4 题 degrade → success

核心逻辑类:app/service/analyst_agent.py(AnalystAgent.run() 7 步编排,兼容 build_graph() LangGraph 适配)。

3. 模块实现清单

模块 文件 职责 状态 本轮变化
编排 service/analyst_agent.py 消歧→SQL→校验→执行→解读→护栏→留痕 已实现 –
路由 api/analyst.py /chat /dashboard /assets /ops/metrics 已实现 –
鉴权 utils/auth.py + api/deps.py JWT(HS256) + 角色→数据域 RBAC 已实现 –
数据访问 service/analytics_repo.py 只读执行 / 归属白名单 / 留痕 / 资产沉淀 / 空态三分类 已实现 –
SQL 校验 service/sql_guard.py 五层只读校验(关键字 / 表白名单 / 多语句 / 行级归属 / 粒度) 已实现 –
数字护栏 service/guardrail.py 解读数字与结果逐字校验(D-10) 已实现 本轮修复
指标口径 service/dict_service.py 指标字典 + 多义词消歧(N-01) 已实现 –
Schema 提示 service/schema_meta.py 注入表/列说明给 LLM 已实现 –
LLM service/llm.py DeepSeek 对话 / 提取 SQL / 成本估算 已实现 –
查询缓存 service/cache_service.py Redis→内存降级;权限指纹键;TTL 分层(D-06) 已实现 –
未接入 rag_service.py memory_service.py RAG 知识库 / L1-L3 业务记忆 空壳存根 –

请求流转(AnalystAgent.run())

auth 域判定 → 指标消歧(若多义→clarify) → 生成SQL →
SQL 五层校验(失败→deny) → 执行(缓存优先) → 空态三分类 →
LLM 解读 → 数字护栏(失败重试1次→降级) → 组装响应 → 留痕 double-write

4. 需求覆盖(对照需求规格)

需求 能力 落点
D-01/02 NL→SQL、只读查询 _generate_sql + validate
D-04 查询/审计留痕 log_query + log_audit
D-06 结果/模板缓存 cache_service
D-07 / N-01 口径字典 / 消歧 dict_service
D-10 数字护栏 guardrail(本轮加强)
D-11 资产沉淀 assets + insert_asset
D-12 / N-08 看数板 / 运营指标 dashboard / ops_metrics
RBAC 角色→数据域 auth.assert_analyst_access

5. 质量基线

单元测试: tests/test_*.py 覆盖 agent / api / cache / dict / guardrail(14) / sql_guard / llm / repo。改为本机确认 tests/test_guardrail.py OK。

实测基线(2026-09-10,analyst 全量域,20 题):

维度 结果
成功返回可用结果 18 / 20(90%)
澄清后继续(多义) 1(「规模」持仓/产品多义,属预期)
白名单误杀 deny 1(Q17 触发 create 危险词误判)
数字护栏误拦截(修复前) 4(Q1/Q9/Q19/Q20)→ 修复后可全过
内容正确性 17 / 18 数字无误写;1 题口径跑题(Q7)

6. 本轮迭代详情(2026-09-10)

背景

用户问「用户持仓前三? 申购前三? 交易流水前三?」验证 NL2SQL 查数。端到端跑通后暴露两个问题:数字护栏把正确回答误判为降级,「交易流水前三」语义漂移。

问题 1:数字护栏误拦截(三类根因)

  • Decimal 不被识别:pymysql 对 DECIMAL/SUM(...) 返回 Decimal,_to_float 只认 int/float/str,金额被当 None 丢弃,result_numbers() 只剩 {0.0, 行数},导致「315.00万元」这类正确解读被判失败,三次查询全部 degrade。
  • ID/名称/日期里的数字误报:extract_numbers 把 CUST-3001 拆成 -3001、把「沪深300指数」拆出 300、把「9月3日10:00」拆出 9,从而误判「说错数字」。
  • 其中「中文后直接接编号」(客户CUST-3001、产品PROD-510300)会使 \b 边界失效(中文也属 \w)。

修复 1(app/service/guardrail.py)

  1. _to_float 新增 Decimal 分支。
  2. extract_numbers 先屏蔽编号 token(CUST-/TRD-/PROD-/STAFF-,不加 \b)与日期/时间 token(YYYY-MM-DD、M月D日、HH:MM),再匹配。
  3. NUMBER_RE 加左边界 (?<![\w]),挡掉「沪深300」「中证500」等名称内数字。

问题 2:「交易流水前三」语义漂移

同一问题多次运行,LLM 分别给出「按时间取最新 3 笔」「按交易笔数排序」「按金额排序」三种口径,非确定性(「流水」无口径定义,_detect_ambiguity 拦不住)。

修复 2(app/service/dict_service.py,N-01 / B2)

新增 交易流水金额 与 交易流水笔数 两个口径,别名均含「交易流水/流水」,「流水」成为多义词 → resolve() 返回 Ambiguity,Agent 反问「按金额还是按笔数」;「流水金额/流水笔数」仍各指向唯一口径。

验证

  • 单测:test_guardrail.py 14 项(新增 7 项回归)、test_dict_service.py 7 项(新增 4 项)全 OK;sql_guard/cache_service/agent 编排无回归(合计 42 项)。
  • 端到端(进程内 + HTTP 8002):用户持仓前三、申购前三 由 degrade → success,数字逐一正确;交易流水前三 由漂移 → clarify(反问金额/笔数)。

踩坑备注:① 8000 端口跑的是 customer-service-agent 分支(auth/chat),非数据分析 Agent,勿按端口混淆分支;② 旧服务由 node 守护进程自动重启,非管理员 shell 杀 python 无效。

7. 上一轮迭代详情(2026-09-10)

问题:数字护栏误拦截(4 题 degrade)

  • Q1/Q20 根因:结果列是比率(0.1515),解读写百分比(15.15%),护栏未做「比率 ×100」换算即判错。
  • Q19 根因:解读「近 30 天」的时间窗数字 30 被正则当成数据数字,与结果 0 比对失败。
  • 附带:Q9 依赖 LLM 措辞(是否用「万」)存在波动,与护栏策略耦合。

修复(app/service/guardrail.py)

  1. 新增 _WINDOW_TOKEN:数字提取前遮挡「近30天/近 30 月」等时间窗口径,防窗口数字污染。
  2. check_numbers():当结果集合含 0~1 的比率时,追加 0.01 比对刻度(识别 n×0.01 ≈ 结果,即百分比=比率×100)。

验证

  • 离线确定性用例:Q1/Q19/Q20 通过;编造数字负例(999999.99)仍被拦截(护栏未削弱)。
  • 既有 14 项 guardrail 单测均 OK,无回归。
  • 端到端真实接口(重启后端加载新码后):Q1/Q9/Q19/Q20 全部 degrade → success,数字逐一核对正确。

踩坑备注:后端 --reload 对已改模块未实时生效,须重启进程验证代码变更。

8. 已知问题与下一步

# 问题 影响 建议
1 Q17:SQL 白名单把 create 当危险词,字段/列名命中即 deny 一次误拦 create 仅拦截语句级(CREATE TABLE),字段/列名放行
2 Q7:库无「城市」字段时,Agent 静默改按「职业」统计而非澄清/拒绝 答非所问 NL2SQL 对库结构不匹配加「澄清/拒绝」兜底
3 数字护栏对"聚合比率/多位小数"依赖 LLM 措辞 flaky 可考虑允许集合追加百分比别名校验以进一步收敛
4 guardrail 修复尚无回归用例 防复发缺口 将 4 题误报场景补入 tests/test_guardrail.py
5 RAG / 业务记忆仍为空壳 能力边界 待后续迭代按架构说明书接入

9. 验证方式

运行:uvicorn app.main:app --reload → POST /api/analyst/chat(Bearer 开发 token)
探活:GET /health
单测:tests/(guardrail、sql_guard、agent、api 等)
实测:scripts/dev/run_query_battery.py(20 题基线)
配置:.env(DEEPSEEK_API_KEY 必填;缺失则 LLM 报错)