AI界面中的数据可视化设计

仪表盘、分析面板与智能洞察的可视化策略


1. AI 产品数据可视化的独特性

AI 产品中的数据可视化不同于传统 BI 仪表盘。它需要同时解决两类问题:展示 AI 系统自身的运行状态(模型性能、Token 消耗、推理延迟),以及呈现 AI 分析产出的业务洞察。

传统 BI 仪表盘:                AI 产品仪表盘:
+---------------------+       +---------------------+
|  业务数据展示         |       |  AI 运行监控         |
|  用户自主探索         |       |  模型性能/成本/质量   |
|  图表为主             |       +---------------------+
|  交互过滤             |       |  AI 洞察输出         |
+---------------------+       |  自然语言 + 图表     |
                               |  置信度 + 解释       |
                               +---------------------+
                               |  业务数据探索        |
                               |  AI 辅助分析         |
                               +---------------------+

1.1 设计原则

原则 说明 反模式
数据先于装饰 图表传达信息,不炫技 3D 饼图、彩虹配色
洞察先于数据 先展示结论,再展示证据 大量原始数据表格
上下文完整 提供比较基准和趋势 孤立的数字没有参照
可信度透明 AI 分析结果标注置信度 断言式结论无依据
渐进披露 摘要 -> 详情 -> 原始数据 信息一次性全部铺开

2. AI 监控仪表盘

2.1 核心指标卡片

+--------------------------------------------------+
|  AI 系统概览                                      |
+--------------------------------------------------+
|                                                   |
|  +--------+  +--------+  +--------+  +--------+  |
|  | 日调用  |  | 平均延迟|  | 成功率  |  | Token   |  |
|  | 12.5K  |  | 1.8s   |  | 99.2%  |  | 消耗    |  |
|  | +23%   |  | -0.3s  |  | +0.1%  |  | 2.3M   |  |
|  |  (上升) |  |  (改善) |  |  (稳定) |  | +15%   |  |
|  +--------+  +--------+  +--------+  +--------+  |
|                                                   |
+--------------------------------------------------+

KPI 卡片设计规范:

interface KPICardProps {
  label: string;           // "日调用量"
  value: string | number;  // "12.5K"
  trend: {
    direction: 'up' | 'down' | 'flat';
    percentage: number;    // 23
    isPositive: boolean;   // true = 上升是好事
  };
  sparkline?: number[];    // 7 天趋势迷你折线
  status?: 'normal' | 'warning' | 'critical';
}
/* KPI 卡片样式 */
.kpi-card {
  padding: 20px;
  border-radius: 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
}

.kpi-value {
  font-size: 32px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;  /* 数字等宽 */
  line-height: 1.2;
}

.kpi-trend {
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.kpi-trend--positive { color: var(--color-success); }
.kpi-trend--negative { color: var(--color-error); }
.kpi-trend--neutral  { color: var(--color-muted); }

2.2 模型性能对比

模型性能对比表:
+-----------+--------+-------+---------+--------+
| 模型       | 质量   | 延迟  | Token/$ | 推荐   |
+-----------+--------+-------+---------+--------+
| Opus 4    | 95/100 | 3.2s  | 12K/$1  |        |
| Sonnet 4  | 89/100 | 1.1s  | 40K/$1  | *推荐* |
| Haiku 3.5 | 78/100 | 0.4s  | 200K/$1 |        |
| GPT-4o    | 87/100 | 1.5s  | 30K/$1  |        |
| Gemini Pro| 86/100 | 1.3s  | 50K/$1  |        |
+-----------+--------+-------+---------+--------+

可视化方案:

// 雷达图对比多维度性能
const radarOption = {
  radar: {
    indicator: [
      { name: '质量', max: 100 },
      { name: '速度', max: 100 },    // 1/延迟 归一化
      { name: '性价比', max: 100 },
      { name: '稳定性', max: 100 },
      { name: '多模态', max: 100 },
    ]
  },
  series: [{
    type: 'radar',
    data: [
      { value: [95, 40, 30, 92, 85], name: 'Claude Opus' },
      { value: [89, 75, 70, 95, 80], name: 'Claude Sonnet' },
    ]
  }]
};

2.3 成本分析

Token 消耗趋势 (按模型/按功能):

Token (万)
   |
40 |          ___
   |         /   \
30 |    ____/     \___
   |   /              \___
20 |  /                   \____
   | /
10 |/
   +---+---+---+---+---+---+---> 日期
   1/1  1/5  1/10 1/15 1/20 1/25

[==] 代码生成  [//] 对话  [..] 分析  [##] 其他

3. AI 洞察可视化

3.1 洞察卡片设计

AI 分析产出的洞察,需要同时呈现结论、证据和置信度:

+-----------------------------------------------+
| [洞察] 用户流失风险预警               置信度: 87% |
+-----------------------------------------------+
|                                               |
| 过去 7 天,高价值用户群体的活跃度下降了 23%,   |
| 主要集中在以下特征:                             |
|                                               |
| [柱状图: 按用户特征的活跃度变化]                |
|                                               |
| 建议操作:                                      |
| [按钮: 查看详细分析]  [按钮: 发送预警邮件]      |
|                                               |
| 数据来源: 用户行为日志 (2026-02-21 ~ 02-28)    |
| AI 模型: Claude Sonnet | 分析时间: 3.2s        |
+-----------------------------------------------+
interface InsightCard {
  title: string;
  confidence: number;           // 0-1
  summary: string;              // 自然语言摘要
  evidence: {
    chart?: ChartConfig;        // 支撑图表
    metrics?: MetricItem[];     // 关键指标
    dataRange?: DateRange;      // 数据时间范围
  };
  actions?: Action[];           // 建议操作
  metadata: {
    model: string;
    analysisTime: number;
    dataSource: string;
  };
}

3.2 置信度可视化

置信度展示层级:

高 (>= 85%):
  [========] 92%   "高置信度 - 数据充分"
  颜色: 成功绿

中 (60-84%):
  [======..] 73%   "中置信度 - 建议验证"
  颜色: 警告黄

低 (< 60%):
  [===.....] 38%   "低置信度 - 需人工核实"
  颜色: 错误红 + 警告图标
.confidence-bar {
  width: 120px;
  height: 6px;
  border-radius: 3px;
  background: var(--color-border);
  overflow: hidden;
}

.confidence-bar__fill {
  height: 100%;
  border-radius: 3px;
  transition: width 0.6s ease-out;
}

.confidence--high .confidence-bar__fill {
  background: var(--color-success);
}
.confidence--medium .confidence-bar__fill {
  background: var(--color-warning);
}
.confidence--low .confidence-bar__fill {
  background: var(--color-error);
}

4. 图表设计规范

4.1 配色系统

// AI 产品图表配色
const chartPalette = {
  // 主序列色
  primary: [
    '#3B82F6',  // 蓝
    '#8B5CF6',  // 紫
    '#06B6D4',  // 青
    '#F59E0B',  // 琥珀
    '#EF4444',  // 红
    '#22C55E',  // 绿
  ],

  // 语义色
  semantic: {
    positive: '#22C55E',
    negative: '#EF4444',
    neutral: '#94A3B8',
    highlight: '#3B82F6',
    baseline: '#E2E8F0',
  },

  // 渐变色(用于面积图/热力图)
  gradient: {
    blue: ['#DBEAFE', '#3B82F6'],
    purple: ['#EDE9FE', '#8B5CF6'],
    heat: ['#FEF3C7', '#F59E0B', '#EF4444'],
  },

  // 对比色(AB 测试/前后对比)
  comparison: {
    before: '#94A3B8',
    after: '#3B82F6',
  }
};

4.2 图表排版规则

元素 字号 字重 颜色
图表标题 16px 600 #1E293B
坐标轴标签 12px 400 #64748B
数据标签 11px 500 #374151
图例文字 12px 400 #64748B
单位标注 11px 400 #94A3B8

4.3 网格与刻度

// AI 产品图表的极简化网格
const gridConfig = {
  xAxis: {
    axisLine: { show: true, lineStyle: { color: '#E2E8F0' } },
    axisTick: { show: false },
    splitLine: { show: false },          // 不显示竖网格线
  },
  yAxis: {
    axisLine: { show: false },           // 不显示 Y 轴线
    axisTick: { show: false },
    splitLine: {
      show: true,
      lineStyle: { color: '#F1F5F9', type: 'dashed' }
    },
    splitNumber: 4,                       // 最多 4 条网格线
  }
};

5. 交互设计

5.1 Tooltip 规范

悬停 Tooltip:
+---------------------------+
| 2026年1月15日              |
| ● 调用量: 15,234          |
| ● 成功率: 99.3%           |
| ● 平均延迟: 1.6s          |
+---------------------------+

规则:
- 背景: 深色半透明(rgba(0,0,0,0.85))
- 圆角: 8px
- 内边距: 12px 16px
- 阴影: 0 4px 12px rgba(0,0,0,0.15)
- 最大宽度: 280px
- 跟随鼠标,不遮挡数据点

5.2 缩放与过滤

时间范围选择器:
[1H] [6H] [24H] [7D] [30D] [自定义]

维度过滤器:
模型: [全部 v]  功能: [全部 v]  状态: [全部 v]

刷选缩放:
在图表上拖动选择区域 -> 放大到选中范围 -> [重置缩放] 按钮

5.3 钻取交互

概览图表
  |
  +---> 点击某日数据点
         |
         v
       详情面板(右侧滑出)
         |
         +---> 按小时分布
         +---> 按模型分布
         +---> 错误日志列表
         +---> [跳转到完整分析页]

6. 实时数据可视化

6.1 实时更新策略

策略 更新频率 适用场景 实现方式
轮询 5-30s KPI 卡片 setInterval + fetch
SSE 实时 日志流、监控 EventSource
WebSocket 实时 实时图表 Socket.io
增量更新 1-5s 折线图追加 只推新数据点
// 增量更新折线图
function appendDataPoint(chart, newPoint) {
  const series = chart.getOption().series[0];
  const data = series.data;

  // 追加新点
  data.push([newPoint.timestamp, newPoint.value]);

  // 保持窗口大小(最多显示 100 个点)
  if (data.length > 100) {
    data.shift();
  }

  // 平滑更新
  chart.setOption({
    series: [{ data }],
    xAxis: {
      min: data[0][0],
      max: data[data.length - 1][0]
    }
  });
}

6.2 大数据量优化

数据量 优化方案 说明
< 1,000 点 直接渲染 无需优化
1K-10K 点 降采样 (LTTB) 保留视觉特征
10K-100K 点 Canvas 渲染 替代 SVG
> 100K 点 WebGL + 降采样 ECharts GL / deck.gl
// LTTB 降采样算法(Largest Triangle Three Buckets)
function lttbDownsample(data, threshold) {
  if (data.length <= threshold) return data;

  const sampled = [data[0]];  // 保留首点
  const bucketSize = (data.length - 2) / (threshold - 2);

  let a = 0;  // 上一个选中点的索引

  for (let i = 0; i < threshold - 2; i++) {
    const bucketStart = Math.floor((i + 1) * bucketSize) + 1;
    const bucketEnd = Math.min(
      Math.floor((i + 2) * bucketSize) + 1,
      data.length - 1
    );

    // 计算下一个桶的平均值
    const nextBucketStart = Math.floor((i + 2) * bucketSize) + 1;
    const nextBucketEnd = Math.min(
      Math.floor((i + 3) * bucketSize) + 1,
      data.length - 1
    );
    let avgX = 0, avgY = 0, count = 0;
    for (let j = nextBucketStart; j < nextBucketEnd; j++) {
      avgX += data[j][0];
      avgY += data[j][1];
      count++;
    }
    avgX /= count;
    avgY /= count;

    // 在当前桶中选择面积最大的三角形
    let maxArea = -1;
    let maxIndex = bucketStart;
    for (let j = bucketStart; j < bucketEnd; j++) {
      const area = Math.abs(
        (data[a][0] - avgX) * (data[j][1] - data[a][1]) -
        (data[a][0] - data[j][0]) * (avgY - data[a][1])
      );
      if (area > maxArea) {
        maxArea = area;
        maxIndex = j;
      }
    }

    sampled.push(data[maxIndex]);
    a = maxIndex;
  }

  sampled.push(data[data.length - 1]);  // 保留尾点
  return sampled;
}

7. 空状态与错误状态

7.1 空状态设计

无数据状态:
+-----------------------------------+
|                                   |
|     [插图: 数据收集中]            |
|                                   |
|     暂无数据                      |
|     AI 模型尚未产生分析结果       |
|                                   |
|     [开始分析]                    |
|                                   |
+-----------------------------------+

加载状态:
+-----------------------------------+
|                                   |
|     [骨架屏: 图表形状]           |
|     ====  ====  ====  ====       |
|     ||||  ||||  ||||  ||||       |
|     ====  ====  ====  ====       |
|                                   |
+-----------------------------------+

7.2 错误状态

数据加载失败:
+-----------------------------------+
|                                   |
|     [插图: 连接中断]             |
|                                   |
|     数据加载失败                  |
|     请检查网络连接后重试          |
|                                   |
|     [重试]  [查看离线数据]        |
|                                   |
+-----------------------------------+

部分数据缺失:
+-----------------------------------+
|  [图表正常显示]                   |
|  ===  ===  ???  ===  ===         |
|                                   |
|  NOTE: 1月15日数据缺失,         |
|  图表中已跳过该日期。             |
+-----------------------------------+

8. 响应式图表

8.1 断点适配

function getChartConfig(containerWidth: number): Partial<EChartsOption> {
  if (containerWidth < 400) {
    // 手机: 极简
    return {
      grid: { left: 40, right: 10, top: 20, bottom: 30 },
      legend: { show: false },
      xAxis: { axisLabel: { rotate: 45, fontSize: 10 } },
      yAxis: { axisLabel: { fontSize: 10 } },
    };
  }

  if (containerWidth < 768) {
    // 平板: 简化
    return {
      grid: { left: 50, right: 20, top: 30, bottom: 40 },
      legend: { bottom: 0, type: 'scroll' },
      xAxis: { axisLabel: { fontSize: 11 } },
    };
  }

  // 桌面: 完整
  return {
    grid: { left: 60, right: 30, top: 40, bottom: 50 },
    legend: { right: 20, top: 10 },
    xAxis: { axisLabel: { fontSize: 12 } },
  };
}

8.2 ResizeObserver 自适应

function useResponsiveChart(containerRef: RefObject<HTMLDivElement>) {
  useEffect(() => {
    const observer = new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        const chart = echarts.getInstanceByDom(entry.target);
        if (chart) {
          chart.resize({ width, height });
          chart.setOption(getChartConfig(width));
        }
      }
    });

    if (containerRef.current) {
      observer.observe(containerRef.current);
    }

    return () => observer.disconnect();
  }, []);
}

9. 可访问性

要求 实现方式
图表描述 aria-label 包含数据摘要
色盲安全 颜色 + 图案/线型区分
键盘导航 Tab 可聚焦图表,箭头键切换数据点
高对比度 支持 prefers-contrast: more
数据表替代 提供数据表格作为图表的无障碍替代

10. 工具选型

需求 推荐 备选 原因
常规图表 ECharts Recharts SSR 支持,中文文档好
定制化图表 D3.js Visx 完全可控
表格 TanStack Table AG Grid 轻量 + 虚拟滚动
地图 ECharts Map Mapbox GL 中国地图数据内置
实时监控 Grafana 嵌入 自建 成熟的告警体系
仪表盘框架 React Grid Layout Gridstack 拖拽编排

Maurice | maurice_wen@proton.me