Files
group_xinghuo_jinrong/docs/superpowers/specs/2026-09-12-analyst-query-visualization-design.md
zhanghongyu_0626 a0f550646e feat(analyst): Add analyze endpoint and chart specification validation
- Introduced a new `/analyze` endpoint in the analyst API to process analysis requests, allowing users to receive textual interpretations and chart specifications based on provided prompts.
- Enhanced `analyst_schemas.py` with `AnalyzeRequest` and `ChartSpec` models to structure analysis requests and validate chart specifications.
- Implemented chart validation logic in a new `analyst_chart.py` service, ensuring that chart types and fields are correctly specified and conform to allowed values.
- Updated `AnalystAgent` to handle analysis requests, integrating the new logic for generating responses based on user prompts and data availability.
- Added unit tests to verify the functionality of the new endpoint and validation mechanisms, ensuring robustness and reliability.

This update significantly enhances the analytical capabilities of the application, providing users with improved tools for data interpretation and visualization.
2026-09-12 12:33:37 +08:00

9.6 KiB
Raw Permalink Blame History

问数结果 · 分析助手(文字 + 可选图表)设计

日期: 2026-09-12
状态: 已实现(2026-09-12)
关联需求: D-12 子集(问数页可视化)· 不实现 D-09 多轮 · NL2SQL 路径不变


1. 目标与边界

1.1 用户故事

分析员在问数工作台先 NL 问数得到表格;再打开分析助手对话框,用自然语言说明要什么——可能只要文字解读、只要可视化、或两者都要。大模型根据当前表格结构 + 用户分析提示词决定输出形态与图表类型(如时间序列 → 折线图),前端渲染可简单互动的图表。

1.2 必须覆盖的三类意图(分析阶段)

用户意图 问数阶段 分析对话框提交后
只要表 点「问数」即可 不打开分析助手;无额外 LLM
只要分析(文字) 先有表 answer 有内容,chart=null
只要图 先有表 chart 有 spec,answer 可为空或一句说明
要表 + 分析(文+图) 先有表 answer + chart 同时存在

「表」指问数 SQL 执行结果表格,始终在问数成功后展示;分析助手不再执行 SQL。

1.3 明确不做(本期)

  • D-09 多轮追问 / Redis 会话上下文
  • 在主问数输入框里混合「画图」语句(避免误走 NL2SQL)
  • 把 chart spec 沉淀为 D-11 资产
  • D-12 看板卡片钻取进对话
  • 替换行情详情页 ProductNavChartPanel(Chart.js)

2. 交互设计

2.1 问数工作台(AnalystQueryPage.tsx)

  1. 主输入 +「问数」:行为不变,POST /api/analyst/chat,interpret=false。
  2. 成功/降级且有行时展示结果表格、SQL、溯源/转人工等现有能力。
  3. 原「分析该数据」单按钮 → 「分析助手…」,打开 Modal(或小 Drawer):
    • 说明:基于本轮问数问题 + 下方表格,不会重新查库。
    • 分析提示词(必填):多行输入。
    • Placeholder 示例轮换:
      • 「用三句话总结这张表的关键结论」
      • 「把各产品按日期的净值趋势画成可悬停折线图」
      • 「总结要点并画一张适合这张表的图」
    • 主按钮:「生成分析」(loading 态)。
  4. 提交后在表格下方新增区域(可与原「数据解读」Card 合并):
    • 有 answer → 文字 Card + disclaimer
    • 有 chart → ChartCard + AnalystResultChartPanel
  5. 新开一轮问数时清空分析结果(与现清空 interpret 一致)。
  6. 门禁:status ∈ {success, degrade} 且 table.rows.length > 0 才可打开对话框;否则 Tooltip 提示先问数。

2.2 与「只要表」的关系

用户若仅需表格:问数后不点分析助手即可。无需新开关;顶栏 Alert 可补一句「需要解读或图表时点分析助手」。


3. API 契约

3.1 新增:POST /api/analyst/analyze

项 说明
鉴权 与 /api/analyst/chat 相同(deps + analyst RBAC)
请求 扩展问数快照 + 分析提示词
{
  "question": "上轮 NL 问数原问题",
  "analysis_prompt": "用户在对画框里输入的内容",
  "status": "success",
  "answer": "",
  "table": { "columns": [], "rows": [] },
  "sql": "...",
  "trace_id": "trace-...",
  "meta": { "row_count": 0, "...": "..." }
}
字段 约束
question 上轮问数问题(审计关联)
analysis_prompt 1~2000 字,trim 后非空
其余 与现有 InterpretRequest 一致,客户端提交当前页快照

3.2 响应:扩展 AnalystResponse

新增字段:

type ChartType = 'line' | 'bar' | 'column' | 'pie' | 'none'

type ChartSpec = {
  chart_type: ChartType
  title: string
  reason?: string          // 模型简述为何选此图型(展示在 subtitle)
  x_field: string | null   // pie 可为 null
  y_fields: string[]       // 一个或多个度量列
  series_field?: string | null  // 多系列折线/柱:系列维度列
}

// AnalystResponse 增:
analysis_kind: 'text' | 'chart' | 'both' | 'none'
chart: ChartSpec | null
analysis_kind 条件
text 有 answer,无有效 chart
chart 有 chart,answer 可选短说明
both 同时有
none 失败/空(应极少;降级时用 degrade + message)

table / sql / meta:原样回传客户端快照(便于前端不丢上下文);不因分析而改表数据。

3.3 保留 /api/analyst/interpret

  • 一期实现 /analyze 后前端改走 analyze;/interpret 保留兼容旧客户端,内部可委托 analyze(analysis_prompt 默认「请解读下表」)或标记 deprecated(文档说明即可)。

4. 后端逻辑(analyst_agent.py)

4.1 新入口 analyze(req, auth) -> AnalystResponse

  1. 权限:assert_analyst_query_access(与 interpret 相同)。
  2. 终态 clarify/deny/error/escalate:echo 快照,不调用 LLM。
  3. 空表:返回 degrade,answer 说明无数据可分析。
  4. 行数上限:500 行(可配置 ANALYST_CHART_MAX_ROWS);超出 → degrade,提示缩小问数范围或加条件。
  5. 构造 LLM 消息:
    • System:角色 + JSON schema + 图表类型选择规则 + 禁止编造未出现在表中的数值。
    • User:question、analysis_prompt、列名、行数、data_as_of、SQL 一行、表格 前 30 行 TSV(超 30 行注明「仅展示样本」)。
  6. LLM 输出 单 JSON 对象(temperature=0);解析失败 → 重试 1 次 → 仍失败 escalate / INTERPRET_ERROR。
  7. validate_chart_spec(spec, columns, row_count)(新模块或 analyst_chart.py):
    • chart_type 枚举内;none 表示不要图。
    • 所有 field 名 ∈ columns(大小写按列名精确匹配)。
    • y_fields 非空(当 chart 非 none);pie 时 y_fields.length === 1 且需 series_field 或 x 为分类。
    • 可选:检测 x 列是否日期型(≥80% 可 parse)→ 建议 line + time,但 最终 chart_type 以模型为准,校验只拦非法映射。
  8. 文字解读:若用户 prompt 明显要文字或 both,生成/保留 answer;若仅要图,answer 可为 reason 一句。
  9. 数字护栏:若 answer 含数字,复用现有 _generate_verified_answer / guard 逻辑(与 interpret 同路径);纯 chart 无 prose 数字可跳过 guard。
  10. 审计:log_audit(event_type=analyst_analyze, input_summary={question, analysis_prompt, analysis_kind, chart_type}, trace_id)。

4.2 LLM 图表选择规则(写入 system prompt 摘要)

  • 日期/时间 + 数值 → 优先 line
  • 分类 + 单指标比较 → bar / column
  • 占比、少量分类 → pie(分类 ≤ 12)
  • 无法安全绑列 → chart_type: none + answer 解释需要什么列
  • 用户明确说「不要图」→ none
  • 用户明确图型时优先遵从,若与数据结构严重不符则在 reason 说明并选最接近合法类型

4.3 NL2SQL

不修改 run() 的模板/LLM SQL 生成、sql_guard、execute 路径。


5. 前端实现

5.1 API 层(web/src/api/analyst.ts)

  • postAnalystAnalyze(token, payload) → AnalystChatResponse & { analysis_kind, chart }
  • 类型 ChartSpec 与后端一致

5.2 组件

中文职责 路径
分析助手 Modal + 结果区编排 AnalystQueryPage.tsx
ChartSpec + table → @ant-design/charts AnalystResultChartPanel.tsx
列类型推断、长表 series pivot web/src/utils/analystChartSpec.ts

5.3 图表库

  • 使用 @ant-design/charts(与 Dashboard 一致)。
  • 互动:tooltip、legend 切换;折线支持 smooth optional。
  • x 为日期字符串时:parse 为 Date,axis formatter MM-DD / 自动。

5.4 布局规则

analysis_kind UI
text 仅文字 Card
chart 仅 ChartCard(title + reason)
both 文字在上或左,图在下(移动端纵向堆叠)

6. 错误与降级

场景 status 用户可见
chart spec 校验失败 degrade 文字说明 + 仍展示原表
LLM JSON 无效 escalate 与现 interpret 失败一致
行数 > 500 degrade 提示缩小问数
客户角色 self 域 同 interpret disclaimer + AI 风险提示

7. 测试计划

7.1 pytest

  • validate_chart_spec:合法 line / 非法列名 / pie 多 y / 空 y
  • analyze() mock LLM:返回 text-only、chart-only、both;guard 误杀 degrade
  • API route 401/403 与 chat 一致

7.2 Vitest

  • analystChartSpec.ts:宽表 pivot、日期 x、多 series
  • 可选:Panel smoke render with fixture table

7.3 手工 Demo

  1. 问数:「各产品最近 30 天每日净值」→ 表有 nav_date + nav + product_name
  2. 分析助手:「画趋势折线,按产品分系列」→ 多系列折线 + tooltip
  3. 「三句话总结」→ 仅文字
  4. 「总结并画图」→ both
  5. 问数后不点助手 → 仅表

8. 文档与 memory(实现后)

  • MEMORY.md / FRAMEWORK.md:问数页增 analyze + chart
  • docs/答辩/DEMO-SOP-问数.md:加 30 秒可视化演示步骤
  • REQUIREMENTS:可挂 D-12 子能力脚注(非完整看板钻取)

9. Spec 自检(2026-09-12)

  • 无 TBD 占位
  • 「只要表」= 不问 analyze,与「只要图/文/both」不矛盾
  • NL2SQL 与 analyze 边界清晰
  • 单迭代可交付(API + agent + 页 + 校验 + 测试)

请评审本文件。 确认或修改后回复,将进入 writing-plans 生成实现任务清单(仍不自动 commit,除非你要求)。