标签 数据可视化 下的文章

目录

  1. 库的概览与核心价值
  2. 环境搭建与"Hello, World"
  3. 核心概念解析
  4. 实战演练:分析电影评分趋势
  5. 最佳实践与常见陷阱
  6. 进阶指引

1. 库的概览与核心价值

想象一下,你手头有一份包含一百万条销售数据的 Excel 表格,密密麻麻的数字堆叠在一起,让你头晕眼花。你需要找出旺季和淡季的趋势,对比不同产品的销售表现,但这些冰冷的数据就像沉默的密码,让你难以快速洞察其中的规律。这就是数据可视化的痛点——没有图形,数据就是一堆难以理解的数字。

Matplotlib 正是为解决这个核心问题而生的强大工具。它就像一位精通绘画的数据翻译官,能将枯燥的数据转化为直观、生动的图表,让你一眼看出数据背后的故事。在 Python 数据科学生态中,NumPy 负责数值计算,Pandas 处理结构化数据,而 Matplotlib 则承担着将数据"可视化呈现"的关键使命,三者共同构成了数据分析的三剑客。

那么,为什么需要专门的 Matplotlib,而不是直接用 Excel 或其他工具呢?关键在于它的三个独特优势

  • 无缝集成MatplotlibNumPyPandas 完美兼容,你可以直接读取 DataFrame 或数组进行绘图,无需繁琐的数据导出导入
  • 高度可定制:从坐标轴刻度、图例位置到颜色、字体、线型,每一个细节都可以精细控制,满足论文发表、专业汇报的苛刻要求
  • 生态基石:作为 Python 可视化的开山鼻祖,它不仅是独立工具,更是 SeabornPlotly 等高级库的基础,学会了它,后续学习会更轻松

一句话总结:Matplotlib 让数据"说话",让复杂的规律变得一目了然,是每位数据分析师必备的看家本领。

2. 环境搭建与"Hello, World"

安装说明

安装 Matplotlib 非常简单,推荐使用 pipconda

# 使用 pip 安装(推荐)
pip install matplotlib numpy

# 使用 conda 安装
conda install matplotlib numpy

注意Matplotlib 通常与 NumPy 配合使用,建议同时安装。如果安装过程中遇到权限问题,可以尝试使用 --user 参数(pip)或创建虚拟环境。

最简示例

让我们用最经典的"正弦曲线"作为入门案例,只需 5 行代码就能画出一张漂亮的图表:

import matplotlib.pyplot as plt
import numpy as np

# 1. 准备数据:x从0到2π,取100个点
x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)

# 2. 创建画布和绘图区域,并绘制曲线
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y)

# 3. 添加标题和标签
ax.set_title("正弦函数图像")
ax.set_xlabel("x值(弧度)")
ax.set_ylabel("sin(x)")

# 4. 显示图表
plt.show()

逐行解释

  • 第1-2行:导入 pyplot 子模块(简写为 plt)和 NumPypyplotMatplotlib 的高级接口,提供了类似 MATLAB 的绘图函数,是日常绘图最常用的模块。
  • 第4行np.linspace(0, 2*np.pi, 100) 生成从 0 到 2π 的 100 个等间距点,这是 NumPy 的核心函数,非常适合生成连续变化的 x 轴数据。
  • 第5行np.sin(x) 计算 x 数组中每个元素的正弦值,返回对应的 y 数组。NumPy 的数学运算会自动应用到数组的每个元素,无需循环。
  • 第8行plt.subplots(figsize=(8, 4)) 同时创建 Figure(画布)和 Axes(坐标轴)对象。figsize 参数设置画布大小为 8 英寸宽、4 英寸高。推荐使用 subplots() 而非单独创建,因为它更高效且符合面向对象风格。
  • 第9行ax.plot(x, y)Axes 对象上绘制折线图。这是最核心的绘图函数,将 x 和 y 数组连接成一条平滑的曲线。
  • 第12-14行set_title()set_xlabel()set_ylabel() 分别设置图表标题、x 轴标签和 y 轴标签。所有以 set_ 开头的方法都是在配置 Axes 的属性。
  • 第17行plt.show() 弹出窗口显示图表。在 Jupyter Notebook 中,可以省略这行代码直接在单元格中显示。

预期输出:运行后会弹出一个窗口,展示一条波浪状的正弦曲线,x 轴范围是 0 到 2π,y 轴范围是 -1 到 1,曲线从原点出发,先上升到 1(π/2 处),下降到 -1(3π/2 处),最后回到 0(2π 处)。

解决中文显示问题

Matplotlib 默认不支持中文,会导致中文显示为方块。需要在导入后添加以下配置:

import matplotlib.pyplot as plt
import matplotlib

# 设置中文字体(Windows 用 SimHei,Mac 用 Arial Unicode MS)
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决负号显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False

3. 核心概念解析

理解 Matplotlib 的核心概念是掌握它的关键。新手容易混淆的主要是以下四个对象,它们之间的关系就像画画工具的层级:

3.1 Figure(画布)

Figure 是整个图表的容器,相当于一张白纸或画框。一个 Figure 可以包含多个 Axes(子图),它负责管理整个图像的尺寸、背景色、边框等全局属性。你可以把 Figure 想象成一个画板,所有的图表元素都画在这个画板上。

fig = plt.figure(figsize=(10, 6), facecolor='lightgray')

3.2 Axes(坐标轴/子图)

Axes 是实际绘图的区域,每个 Axes 都包含独立的坐标系(x 轴、y 轴)、标题、标签、图例等元素。一个 Figure 可以有多个 Axes(比如 2×2 的子图布局),但每个 Axes 只能属于一个 Figure。你可以把 Axes 想象成画板上的一个画框,具体的线条、点、文字都画在这个画框里。

fig, ax = plt.subplots()  # 创建包含一个 Axes 的 Figure
fig, axs = plt.subplots(2, 2)  # 创建包含 2×2 个 Axes 的 Figure

3.3 Axis(坐标轴对象)

每个 Axes 包含两个(或 3D 图中的三个)Axis 对象,分别代表 x 轴和 y 轴。Axis 负责控制刻度(ticks)、刻度标签(tick labels)、坐标轴范围(limits)等。比如 x 轴的刻度位置是 0、π/2、π、3π/2、2π,刻度标签就是对应的数字。

ax.set_xlim(0, 10)  # 设置 x 轴范围
ax.set_xticks([0, 5, 10])  # 设置 x 轴刻度位置
ax.set_xticklabels(['起点', '中点', '终点'])  # 设置刻度标签

3.4 Artist(艺术家对象)

Artist 是所有可见元素的统称,包括线条(Line2D)、文本(Text)、矩形(Rectangle)、图例(Legend)等。FigureAxesAxis 本身也是 Artist。当调用 plt.show()plt.savefig() 时,所有 Artist 会被渲染到画布上。

line, = ax.plot([1, 2, 3], [4, 5, 6])  # line 是一个 Line2D Artist
title = ax.set_title("标题")  # title 是一个 Text Artist

核心概念关系图

以下 Mermaid 图表展示了这些核心对象之间的层次关系:

graph TD
    A[Figure<br/>画布容器] --> B[Axes<br/>绘图区域1]
    A --> C[Axes<br/>绘图区域2]
    A --> D[Axes<br/>绘图区域N]
    B --> E[Axis X<br/>X轴对象]
    B --> F[Axis Y<br/>Y轴对象]
    B --> G[Line2D<br/>线条]
    B --> H[Text<br/>标题/标签]
    B --> I[Legend<br/>图例]
    E --> J[刻度]
    E --> K[刻度标签]
    F --> L[刻度]
    F --> M[刻度标签]

这个图清晰地展示了:

  • Figure 是最顶层容器,可以包含多个 Axes
  • 每个 Axes 包含 Axis 对象和具体的 Artist 元素
  • Axis 负责刻度和标签管理
  • 所有的 Artist 最终渲染到 Figure

记住一句话:我们绘图时,先创建 Figure,再在 Figure 上添加 Axes,最后在 Axes 上调用绘图方法(如 plot()scatter()bar()),然后通过 set_xxx() 方法配置样式,最后用 plt.show()plt.savefig() 展示或保存图表。

4. 实战演练:分析电影评分趋势

需求分析

假设我们有一份电影数据集,包含电影类型、评分、上映年份等信息。我们需要分析不同类型电影的平均评分趋势,找出评分最高和最低的电影类型,并用可视化方式展示结果。这个任务涉及数据统计、多系列折线图绘制、图例和标签设置等核心技能。

方案设计

我们将按以下步骤实现:

  1. 生成模拟数据(包含电影类型、评分、年份)
  2. 按类型和年份分组计算平均评分
  3. 使用 Matplotlib 绘制多系列折线图,每种类型一条曲线
  4. 添加图例、标题、标签,美化图表样式
  5. 保存为高清图片

这个案例将练习以下核心功能:DataFrame 分组统计、subplots 多图布局、plot 折线图、图例和标签设置、样式定制、图片保存。

完整代码实现

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# ===== 步骤1:生成模拟数据 =====
np.random.seed(42)  # 确保结果可复现

# 电影类型列表
genres = ['剧情', '动作', '喜剧', '科幻', '恐怖', '爱情']
n_movies = 1000  # 总电影数

# 生成随机数据
data = {
    'genre': np.random.choice(genres, n_movies),
    'year': np.random.randint(2010, 2024, n_movies),
    'rating': np.random.uniform(3.0, 9.0, n_movies)  # 评分3.0-9.0
}
df = pd.DataFrame(data)

# ===== 步骤2:数据统计 =====
# 按类型和年份分组,计算平均评分
grouped = df.groupby(['genre', 'year'])['rating'].mean().reset_index()

# 将数据转换为更适合绘图的格式:每种类型一个 Series
pivot_data = grouped.pivot(index='year', columns='genre', values='rating')

# ===== 步骤3:创建图表 =====
fig, ax = plt.subplots(figsize=(12, 6))

# 为每种类型绘制一条曲线,使用不同颜色和标记
colors = plt.cm.tab10(np.linspace(0, 1, len(genres)))
markers = ['o', 's', '^', 'D', 'v', 'p']

for i, genre in enumerate(genres):
    if genre in pivot_data.columns:
        ax.plot(pivot_data.index, pivot_data[genre],
                color=colors[i],
                marker=markers[i],
                markersize=6,
                linewidth=2,
                label=genre)

# ===== 步骤4:美化图表 =====
ax.set_title('2010-2023年各类型电影平均评分趋势',
             fontsize=16, pad=20)
ax.set_xlabel('年份', fontsize=12)
ax.set_ylabel('平均评分', fontsize=12)

# 设置 x 轴刻度为每年一个
ax.set_xticks(range(2010, 2024))
ax.set_xticklabels([str(year) for year in range(2010, 2024)],
                   rotation=45, ha='right')

# 设置 y 轴范围,突出差异
ax.set_ylim(3.0, 9.0)
ax.grid(True, linestyle='--', alpha=0.3)

# 添加图例
ax.legend(loc='upper left', fontsize=10, ncol=3)

# 添加参考线(平均分)
avg_rating = df['rating'].mean()
ax.axhline(y=avg_rating, color='red', linestyle=':',
           linewidth=1.5, label=f'总体平均分 ({avg_rating:.2f})')

# ===== 步骤5:保存和显示 =====
plt.tight_layout()  # 自动调整布局,避免标签被截断
plt.savefig('movie_rating_trend.png', dpi=300, bbox_inches='tight')
print("图表已保存为 movie_rating_trend.png")
plt.show()

运行说明

  1. 将上述代码保存为 movie_analysis.py 文件
  2. 确保已安装依赖:pip install matplotlib numpy pandas
  3. 运行命令:python movie_analysis.py
  4. 程序会弹出窗口显示图表,并在当前目录下生成 movie_rating_trend.png 高清图片

结果展示

生成的图表将展示:

  • 6条折线:每种电影类型一条曲线,用不同颜色和标记区分
  • x 轴:2010-2023 年,每年一个刻度,标签旋转 45 度避免重叠
  • y 轴:评分范围 3.0-9.0,突出评分差异
  • 红色虚线:总体平均分参考线,便于对比
  • 图例:显示所有类型和参考线,位于左上角,分 3 列排列
  • 网格线:浅灰色虚线,辅助读取数据

这个案例展示了 Matplotlib 的核心能力:数据处理与可视化的无缝结合、多系列图表绘制、样式精细控制、专业级图表输出。掌握了这些技能,你就能应对大多数数据可视化任务。

5. 最佳实践与常见陷阱

常见错误及规避方法

错误1:混淆 FigureAxes

问题描述:直接使用 plt.plot() 绘图,却不知道"画在哪个 Axes 上",导致多图布局混乱。

# ❌ 错误做法:使用 pyplot 状态机,难以控制
plt.plot(x, y1)  # 自动创建 fig1 和 ax1
plt.figure()     # 新建 fig2
plt.plot(x, y2)  # 画在 fig2 的 ax2 上,但 ax1 无法再修改
# ✅ 正确做法:手动创建 Axes,精准控制
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
ax1.plot(x, y1)
ax1.set_title('图表1')
ax2.plot(x, y2)
ax2.set_title('图表2')

原因plt 是便捷接口,会自动创建和管理对象,但复杂绘图时容易失控。面向对象风格更清晰、更可控。

错误2:保存图表的顺序错误

问题描述:先 plt.show()plt.savefig(),保存的是空白图片!

# ❌ 错误做法
plt.show()           # 弹出窗口并释放资源
plt.savefig('plot.png')  # 此时 Figure 已为空,保存空白
# ✅ 正确做法
plt.savefig('plot.png', dpi=300, bbox_inches='tight')  # 先保存
plt.show()            # 再显示

原因plt.show() 会弹出窗口并释放绘图资源,之后再调用 savefig()Figure 已为空。必须先保存再显示。

错误3:中文显示乱码

问题描述:图表中的中文显示为方块,无法识别。

# ❌ 错误做法:未配置字体
plt.title('电影评分趋势')  # 显示为方块
# ✅ 正确做法:配置中文字体
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['SimHei']  # Windows 用黑体
# plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']  # Mac 用这个
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示为方块
plt.title('电影评分趋势')  # 正确显示中文

原因Matplotlib 默认字体不支持中文,axes.unicode_minus 也需设置为 False 否则负号会乱码。

错误4:误解 figsize 的单位

问题描述:以为 figsize=(8, 4) 表示 8 像素×4 像素,结果图片太小。

# ❌ 错误理解
fig = plt.figure(figsize=(8, 4))  # 不是 8×4 像素!
# ✅ 正确理解
fig = plt.figure(figsize=(8, 4), dpi=100)  # 8英寸×4英寸,dpi=100,实际是 800×400 像素
# 想要 800×400 像素,要么设置 dpi=100,要么设置 figsize=(8, 4) 且 dpi=100

原因figsize 的单位是"英寸",而非像素。最终像素数 = figsize × dpi(默认 dpi=100)。

最佳实践建议

  1. 优先使用面向对象接口:虽然 plt.plot() 更简洁,但复杂场景(如多子图、自定义样式)必须用 fig, ax = plt.subplots() 面向对象风格。
  2. 统一配置字体和样式:在脚本开头一次性设置 rcParams,避免每个图表都重复配置。
  3. 养成使用 tight_layout() 的习惯:自动调整子图间距,避免标签被截断。
  4. 合理设置 dpi 参数:保存图片时 dpi=300 适合打印,dpi=150 适合屏幕显示,dpi=72 适合网页。
  5. 利用 colormaps 自动生成配色:不要手动指定颜色列表(如 ['red', 'blue', 'green']),用 plt.cm.tab10plt.cm.viridis 生成专业配色。
  6. 保存图片时使用 bbox_inches='tight':自动裁剪空白边距,让图片更紧凑。
  7. 多图布局时用 subplots_adjust 微调:当 tight_layout() 不能满足需求时,手动调整 left, right, top, bottom, wspace, hspace 参数。
  8. 避免使用过时的 API:如 plt.axes() 已被 plt.subplots() 替代,plt.hold() 已在新版本中移除。

6. 进阶指引

掌握了基础用法后,你可以继续探索 Matplotlib 的高级功能和生态系统:

高级功能

  • 多子图复杂布局:使用 plt.subplot_mosaic() 创建非网格状布局(如左大右小、上一下三等)
  • 3D 可视化:使用 mpl_toolkits.mplot3d 绘制三维曲面图、散点图
  • 动画制作:使用 matplotlib.animation 模块制作动态图表,展示数据变化过程
  • 交互式可视化:结合 ipywidgets 在 Jupyter Notebook 中实现滑块、下拉框等交互控件

生态扩展

  • Seaborn:基于 Matplotlib 的高级库,提供更简洁的 API 和更美观的默认样式,适合快速生成统计图表
  • Plotly:专注于交互式可视化,生成的图表支持缩放、拖拽、悬停查看数据,适合网页展示
  • Cartopy:地理数据可视化,支持地图投影、地理坐标转换等

学习资源

学习路径建议

  1. 第一阶段(1-2周):熟练掌握折线图、柱状图、散点图、饼图、直方图 5 种基础图表
  2. 第二阶段(2-3周):学会多子图布局、样式定制、图例标签设置
  3. 第三阶段(3-4周):尝试 3D 可视化、动画制作、交互式图表
  4. 第四阶段(持续):结合实际项目(如个人数据分析、Kaggle 比赛),在实战中积累经验

记住:Matplotlib 的核心是"多动手实践"。找一份真实数据(如公开数据集、个人消费记录),尝试用不同图表展示,逐步掌握参数调整和样式优化。从基础图表到专业可视化,Matplotlib 能伴随你从数据分析新手成长为可视化高手。

在企业数据分析场景中,专业的图表是传递数据洞察的核心载体。但传统表格工具的图表类型往往局限于基础柱状图、折线图,难以满足金融市场分析、财务利润拆解、业务趋势追踪等复杂场景的可视化需求。

SpreadJS V19.0 重磅升级数据图表功能,新增瀑布图、K 线图、OHLC 图表三大专业图表类型,并支持灵活组合展示,覆盖金融、财务、运营等多行业核心分析场景,让复杂数据的可视化呈现更直观、更专业。

一、核心新增图表:精准匹配专业分析需求

1. 瀑布图(Waterfall Chart):拆解数据变动的“可视化账本”

瀑布图的核心价值在于清晰展示一系列正负数值对累计总额的影响,让数据变动的来龙去脉一目了然。

在这里插入图片描述

  • 功能亮点:支持自定义配色方案、柱宽、图例样式,可通过连接线(颜色、宽度、虚线样式)强化数据关联;提供showTotal(显示总计)、totalLabel(总计标签)、orientation(布局方向)等属性,灵活控制图表呈现效果。
  • 应用场景:完美适配财务利润拆解(如营收-成本-费用-净利润的变动过程)、预算差异分析(实际值与预算值的偏差累计)、销售业绩追踪(各区域/产品对总业绩的贡献)、库存趋势分析(入库-出库-库存结余的动态变化)。

2. K 线图(Candlestick Chart):金融数据分析的“专业工具”

K 线图是金融市场的经典可视化工具,专为资产价格变动分析设计,每根 K 线都浓缩了特定时间单位的核心价格信息。
在这里插入图片描述

  • 功能亮点:每根 K 线包含开盘价(Open)、最高价(High)、最低价(Low)、收盘价(Close)四大核心数据;支持按日、周、月等不同时间单位展示,适配股票、期货、加密货币等各类金融资产的价格分析场景。
  • 应用场景:股票价格走势分析、期货合约波动监测、基金净值变动追踪、金融产品风险评估等专业金融场景,帮助分析师快速判断市场趋势与价格波动幅度。

3. OHLC 图表(Open-High-Low-Close Chart):金融数据的“极简可视化方案”

OHLC 图表与 K 线图功能互补,以简洁的柱状线形式展示资产价格变动,更侧重核心价格点的直观呈现。

在这里插入图片描述

  • 功能亮点:支持两种数据模式——四值模式(开盘价、最高价、最低价、收盘价)和三值模式(最高价、最低价、收盘价);可通过 API 灵活配置数据绑定与样式,适配不同精度的分析需求。
  • 应用场景:与 K 线图搭配使用,适合对价格数据进行轻量化展示的场景,如金融资讯平台的行情概览、移动端的简洁化数据展示、多资产价格对比分析等。

4. 组合图表:灵活搭配满足复合分析需求

除了新增单一专业图表,SpreadJS V19.0 还支持将新增图表与现有图表类型(如折线图、柱状图)组合展示。

在这里插入图片描述

  • 功能亮点:可在同一图表画布中绑定多组不同类型数据,通过分层展示实现复合分析(如 K 线图+均线图组合,同时呈现价格走势与趋势判断依据)。
  • 应用场景:金融市场的“价格+成交量”组合分析、财务报表的“实际值+预算值+偏差率”三重展示、运营数据的“业绩+增长率+目标线”综合呈现。

二、技术优势:低代码集成,高灵活自定义

SpreadJS V19.0 新增图表类型延续了产品“易用性+专业性”的核心优势,让开发者无需复杂开发即可快速落地:

  • 高兼容性:无缝适配 SpreadJS 现有表格生态,支持与公式计算、数据透视表、条件格式等功能联动,数据更新时图表实时同步。
  • 低代码配置:通过简洁的 API 即可完成图表初始化与参数配置,支持静态引用或 NPM 包导入两种集成方式,上手成本低。
  • 全场景适配:支持 Web 端、移动端等多终端展示,图表样式自动适配不同屏幕尺寸;兼容主流浏览器,无额外依赖。
  • 深度自定义:从数据绑定到样式细节(颜色、字体、线条)均可通过 API 灵活调整,满足企业个性化品牌视觉需求。

三、典型应用场景:覆盖多行业核心分析需求

  • 财务领域:用瀑布图拆解企业季度利润构成(营收→成本→税费→净利润),让管理层直观看到各环节对最终利润的影响。
  • 金融领域:用 K 线图+OHLC 图表组合展示股票日内价格波动,搭配成交量柱状图,帮助投资者判断市场情绪与价格趋势。
  • 运营领域:用瀑布图追踪月度 GMV 变动(新增用户贡献-流失用户影响-活动拉动-最终 GMV),快速定位业务增长或下滑的核心驱动因素。
  • 库存领域:用瀑布图展示月度库存变动(期初库存+入库量-出库量-损耗量=期末库存),优化库存管理决策。

结语

SpreadJS V19.0 新增的三大专业图表,填补了传统表格工具在复杂场景可视化上的空白,让开发者无需依赖第三方图表库,即可在表格内实现从数据录入、计算到专业可视化的全流程闭环。

无论是金融行业的价格分析、财务领域的利润拆解,还是运营场景的趋势追踪,这些专业图表都能帮助企业挖掘数据深层价值,让决策更有依据。SpreadJS V19.0 即将正式发布,欢迎持续关注,届时可通过官网 Demo 体验全新图表功能的强大能力!

扩展链接

可嵌入您系统的在线Excel

随着企业数字化转型的深入,报表不仅是数据的展示工具,更是业务逻辑的载体。在与众多开发者的交流中,我们发现了一个长期存在的痛点:“为什么我精心设计的报表导出到 Excel 后,动态的公式都变成了死板的数值?”

在即将发布的 SpreadJS V19.0 中,我们针对报表插件(ReportSheet)带来了一项重量级更新——“导出预览报表到 Excel 时保留公式”功能。今天,我就带大家深度解密这项特性,看它如何打破数据与逻辑之间的壁垒。

一、 痛点回顾:消失的“计算逻辑”

在过去,开发者在报表模板中定义的公式,在导出为 Excel 文件时,往往会被计算引擎处理并转化为静态值

这意味着,当终端用户拿到导出的 Excel 文件并试图修改其中的基础数据时,报表中的小计、总计等关键指标并不会随之更新。用户不得不手动重新输入 Excel 公式,这不仅降低了工作效率,也让报表失去了原本的动态交互灵魂。

二、 核心能力:让 Excel 报表“动”起来

SpreadJS V19.0 引入的“保留公式导出(Preserve Formula in Export)”功能,允许用户在将报表导出为 Excel 文件时,完整保留单元格中的计算逻辑

1. 核心价值总结

  • 逻辑无缝延续:导出后的 Excel 依然拥有动态计算能力,而非固定数值。
  • 自由编辑体验:终端用户修改 Excel 单元格内容后,相关公式会自动重算,保持与原始系统一致的交互体验。

在这里插入图片描述

三、 深度解析:它是如何实现的?

为了兼顾各种复杂的报表场景,我们针对不同的公式类型和布局制定了严密的导出策略。

1. 标准 Excel 函数处理

  • 连续区域引用:如果报表展开后的单元格区域是连续的,导出时将作为单一区域引用。
  • 不连续区域引用:对于 SUM、AVERAGE、MIN、MAX 等聚合函数,即使报表生成的区域不连续,SpreadJS 也会智能地将其导出为多个区域的组合引用。
    在这里插入图片描述

在这里插入图片描述

2. R.V(报表变量/视觉)公式的智能转换

R.V 公式是 SpreadJS 报表中的特色功能。在 V19.0 中:

  • 如果公式在预览模式下可解析,导出时会精准转换为 Excel 实际单元格引用
  • 对于表达式中部分可解析的情况,我们会使用 SJS.EMPTY_CELL(值为 0)进行占位,确保公式结构的完整性。
    在这里插入图片描述

在这里插入图片描述

3. 报表专用公式的保留

对于如 R.IndexR.RankR.YoY(同比)等 SpreadJS 专有的报表函数,导出时会保留其函数名和引用。虽然 Excel 原生不支持这些函数(会显示为 #NAME?),但这为二次开发或后续回导提供了珍贵的元数据信息。
在这里插入图片描述

四、 开发者友好:配置只需一个属性

在 SpreadJS V19.0 中,启用这项功能非常简单。

方式一:API 配置

在设置 StaticCell 类型的模板单元格时,只需指定 preserveFormulaInExport 属性:

// 代码示例
export type StaticCell = {
    type: 'Static',
    preserveFormulaInExport?: boolean; // 设为 true 即可开启
    // ... 其他属性
};

方式二:设计器直观操作

如果您使用的是 SpreadJS 设计器,完全无需编写代码。在“报表单元格”属性面板中,勾选“导出 Excel 时保留公式”选项即可一键开启。

在这里插入图片描述

五、 结语

“保留公式导出”特性的加入,标志着 SpreadJS 报表插件在“所见即所得”的基础上,进一步实现了“所获即所用”。它不仅是导出格式的改进,更是对数据生命周期的深度赋能。

SpreadJS V19.0 还有更多关于 AI 插件增强、协同插件正式版、WebWorker 增量计算等重磅特性蓄势待发。

道阻且长,行则将至。 让我们共同期待 V19.0 带来的生产力变革!

注:具体技术文档请以正式发布版本为准。

在生成式 AI 重构数据生产力的时代,BI 工具正从"被动响应"走向"主动洞察"。在 2025 年 4 月 InfoQ 举办的QCon 全球软件开发大会(北京站)上,阿里云智能集团瓴羊高级技术专家王璟尧分享了“从数据到决策:AI 驱动的 Quick BI 架构设计与实践”,他介绍了阿里云 Quick BI 如何通过技术架构跃迁、结合大模型的突破实现从传统 BI 到 AI 驱动的智能 BI 的跨越式进化。并重点解析领域大模型与 BI 引擎的协同设计、NL2SQL 算法调优与架构演进、AI + BI 在场景落地实践过程中的技术权衡,为行业提供可复用的技术范式。

预告:将于 4 月 16 - 18 召开的 QCon 北京站策划了「AI 重塑数据生产与消费」专题,将深入探讨如何系统化地运用大模型与智能体技术,重塑数据全链路的每一个环节。内容涵盖引擎与架构优化、数据治理、开发与运维提效、下一代 BI 与数据工具,以及智能的取数与分析等多个方向。如果你也有相关方向案例想要分享,欢迎提交

以下是演讲实录(经 InfoQ 进行不改变原意的编辑整理)。

BI 领域的技术演进及趋势

传统 BI VS 大模型驱动 BI

早期 BI 是在数据仓库和数据库不断发展演进后形成的需求场景:数据仓库会将各类数据融合到一起进行数据清洗和分析,随后业务人员对自助分析产生了一系列诉求,早期的 BI 工具便应运而生,像 90 年代的 Business Object 就是一个比较有代表性的例子,具有一定限度的自助式分析能力。当时其实还没有“商业智能”这一概念,随着自助分析能力要求的不断提高,可视化、自助式可交互的分析需求也越来越强烈,于是敏捷 BI 应运而生:基于可视化的自助式、可交互的分析,以 Tableau/Qlik 为代表,其最大特点是可通过拖拉拽、按钮点击等简单操作就能完成报表的搭建工作。

进入大模型时代,大模型强大的语言分析和生成能力以及更接近人类思维的推理方式,让 BI 领域进行了重新定位:即从一个单纯的工具到数字助手的进化,模型能力的突破让正在的商业“智能”可以从 DEMO 和实验室走向实际应用。Quick BI 也在各类大模型技术发展的时代洪流中逐步演进,不断成熟与发展,实践落地智能小 Q 系列,给用户带来全新的、端到端到产品体验。

传统数据分析存在局限性,它几乎主要聚焦于报表平台的工作流程:业务方提出需求,产研团队加工执行,然后制作简单的报表,以辅助管理仪表板。传统数据分析主要面向一线业务和老板,工具即使再敏捷,交付物本质上也是以固定式报表作为承载。尽管敏捷 BI 的诞生缓解了部分问题,但业务团队和数据团队之间难以融合贯通的问题依然无法避免。而在 AIGC 时代,大模型加持的对话式分析可以对自然语言灵活响应,简单、自动地完成需求,或许“人人都是数据消费者”及“数据民主化”不再仅仅是一句口号了。

大模型驱动的业务落地方向

基于用户的实际需求和大模型 Agent 技术发展,我们对大模型驱动的业务落地演进方向做了大致判断。从执行到思考,从智能到智慧,难度系数逐步增加。大模型刚出现的初期,大家都在做 Copilot(即搭建助手):用户通过 Copilot 用简单指令或描述就能辅助搭建报表,从而降低 BI 工具的使用门槛和成本。然后是 Chat BI,理论上它会改变整个分析流程,用户像和人类对话一样向系统提问,由系统即时理解并返回准确的分析结果,所有人都可以随时随地的获取数据,降低传统 BI 报表和仪表板出现的必要性。

再接着是洞察分析:基于数据、业务知识,利用机器学习算法、数据挖掘技术的融合,叠加上大模型的语言理解和推理能力,让使用传统算法的洞察分析脱胎换骨,实现更精准的总结、诊断、归因,能够自动发现数据中隐藏的价值。第四阶段可能还为时过早,很多厂商将其称为 DI(即决策智能 Decision Intelligence)。

随着数据量爆炸式增长和分析技术进步,如多模态、多元信息整合、多 Agent 技术等,我们可能不再满足于单个功能,产品形态会演变成分析平台主动在海量数据中发现价值,通过完整数据报告或主动 Feeds 流方式推送给我,不仅能给出“发生了什么”,还能进一步解释 “为什么会发生”、“未来会怎么样”,为用户提供更高阶的决策支持,这是也许是目前能看得到的数据分析领域的理想态。

基于对业务落地的判断,企业级智能 BI 分析离不开 BI 工具、大模型和企业私域知识这三者的有效融合。首先,BI 工具作为核心框架,凭借强大的数据分析和可视化能力,将规模庞大和复杂的数据转化为直观易懂的图文报表,为企业搭建洞察业务的桥梁。要最大化的发挥 BI 工具本身的作用,如高性能分析引擎、可视化、安全管控、开放集成能力、协调办公能力等。其次,BI 工具并非孤立的存在,大语言模型的加入为其注入了灵魂,通过大模型理解自然语言指令,精准理解用户意图,大大降低数据分析门槛。此外,随着多模态、multi-agent 等技术的成熟,大模型的记忆、推理、规划、反思、工具使用能力反过来推动大模型在各领域的丰富应用,包括数据分析产品。最后,绝大部分企业级的智能数据应用都离不开私域数据,作为大模型应用的根据,只有将企业数据、企业内部知识、行业知识深度整合,才能让 BI 分析更具针对性和业务价值。

大模型落地 QuickBl 全景

Quick BI 是阿里云上的一款 SaaS 的 BI 产品,连续 6 年入选 Gartner 的商业智能和数据分析魔力象限,也连续 6 年作为国内唯一入选榜单的国产 BI 产品,承载其智能化能力的产品叫智能小 Q。

大模型重塑整个 BI 分析流程

在大模型时代,有句话说得非常到位:所有产品都值得用大模型技术重做一遍,BI 产品也不例外。传统的 BI 产品,其分析流程在模式上相对比较固定,从数据到结果,基本要经历从数据连接、到数据建模、到数据分析、到数据可视化、再到数据协同和消费的整个流程。这个流程离不开业务人员的人工搭建操作,对用户的模型理解和配置技能有较高要求。而在大模型时代,这个流程的每一个环节都有可能被重塑。例如,在数据连接环节,我们可以对数据准备的 ETL 任务进行辅助开发,对连接的数据源进行数据探查和校验;在建模上,可以对字段质量进行评估,实现计算字段生成优化和 SQL 诊断;在数据分析阶段,对报表一键美化、洞察归因和自然语言生成报表;在消费端,有 Chat BI 智能问数;最终的消费态则可以有智能决策和数据解读报告这样的形态。当我们打开思维去尝试探索后会发现,这里面的发挥空间会非常大。

BI Copilot

BI Copilot 的具体形式就是智能搭建。分析师在原有搭建报表的流程时,用自然语言替代繁杂的功能寻找、拖拉拽按钮和配置,直接完成用户想要的操作。在这个领域,我们更多瞄准的是那些高频多步的、或者强依赖分析师经验的功能。例如:

  1. 金额大于 3000 的标红 - 就是个典型的条件格式场景;

  2. 帮我美化下这个报表

  3. ……

从技术流程图可以看出,我们将原本强耦合在底层产品内部的一些能力做了解耦和开放,在渲染引擎、搭建引擎和用户会话之间构建了一整套指令系统和前端 API 层。大模型作为稳定的“中介”,负责对接会话层和指令系统,将用户自然语言意图转换成底层引擎能识别的“API”指令。在这个部分,我们基于基座模型微调了适合 QBI 搭建的增强指令识别系统,即带有指令 CMD 和参数 Params 的 NL2API。初级 API 进过指令系统的复杂处理,如依赖检测、指令调度、执行等,最终会调用暴露出来的 API 层,最终在渲染引擎和搭建引擎的加持下,完成一整套动作。不过,在这层面上 NL2API 系统相对封闭,因为大模型本质上主要是为 Quick BI 或自身应用系统内部业务服务的。

BI copilot 的另一个重要应用是数据洞察。用户对洞察的期望通常是:看懂图表 ->补充信息 ->分析和解释数据现象 ->定位问题 ->支撑行动决策。这几个步骤里,任意一个步骤想要做好都需要天时地利人和的:算法够优秀、支撑数据够多、流程组织够清晰。

目前我们在洞察领域做了如下三方面的探索:

一是 内置洞察算法,这部分主要使用经典统计计算模型,毕竟智能化并不能完全等于大模型。例如,关注指标变动是否正常,若不正常,是哪些维度造成异常,本质上是参考历史数据、行业经验及其他关联数据,寻找对业务目标最具解释力的维度,这就是内置洞察算法。

二是 大模型的洞察解读,将报表数据和背后所在数据集的数据以及配置元数据等信息组合,利用通用模型在数据解读、语义理解等方面的优势,通过 Prompt 工程 +Multi-Agent 的方式完成的解读方式。

第三,QuickBI 具备外置 Agent 接入能力(如 Dify 或百炼等),让客户特定的工作流和业务逻辑对接到小 Q 对话流里。作为一款通用工具型产品,一定没法满足所有用户的个性化定开需求,这算是一种体验很好的曲线救国方式。

Chat BI

在当今的商业智能(BI)领域,Chat BI 这一概念正逐渐成为焦点。Quick BI 已经成功落地了智能问数这一场景,这在国内国际都引起了众多企业的浓厚兴趣。目前,众多厂商的 Chat BI 产品都在致力于实现类似的功能,技术路线也呈现出多样化,如 NL2DSL(自然语言到领域特定语言)、NL2Python、NL2SQL 等,可谓是百家争鸣。

以 QuickBI 的智能问数为例,一个智能问数的用户旅程大致如下:用户首先输入一个问题,系统在前置处理阶段会进行权限管控和流量管理等操作。随后,我们利用经过训练的大模型领域模型对问题意图进行判断。如果该任务需要多步才能完成,系统会将其拆分为多个子任务;若单步即可返回结果,则直接进入核心流程。通过一系列召回算法,我们将元数据、知识库等信息组合起来,输入到大模型中。最终,大模型以 DSL 和 SQL 的形式将结果传递给 BI 底层的查询引擎。查询引擎负责方言翻译、高级计算下推等复杂流程,并最终以图表形式呈现结果。这些图表在呈现过程中仍然可以进行交互和调整。整个流程的关键在于,我们能够清晰地梳理从上到下的所有字段血缘关系。

通用大模型与自研领域模型的混合流程设计

在通用大模型与自研领域模型的流程设计中,我们秉持着开放的态度。本质上,用户的自然语言通过大模型转换为代码,代码再通过我们工程内部的方式转化为技术逻辑,最终在产品中体现为具体的展现形式。BI Agent(在某些场合被称为 AI 中间层),它通过组织编排各种大模型的输出和流程代码,实现自然语言与代码的有效连接。BI Agent 会定义一些 API 和 DSL,为了让模型能够与应用系统有效交互,我们正在通过 MCP 的方式将其能力开放。

BI Agent 与中间层的控制中心配合,经过业务上下文处理、意图识别、任务拆分等步骤,使 BI 系统能够理解模型的返回结果,并据此进行进一步的操作。此外,在处理复杂任务时,我们还会按照正确的顺序执行编排的子任务,确保任务的成功完成。举个例子,需要获取“X 部门的经营分析报告”,LLM 本身是不会直接总结的,它需要调用取数工具先获取每个月的销量情况,再基于各种拆解数据做归纳分析,这里的“取数工具”就作为最原子化的 BI Agent 存在。

工程架构设计

在设计工程架构的最初阶段,我们在最初阶段经历了诸多纠结与讨论。我们曾反复思量,是要打造一个代码助手,还是 SQL 插件,又或是增强版的 BI 工具呢?无论最终选择何种形态,技术路径的抉择都必须着重考量几个关键问题。首先,该系统是否具备企业级的特性。这关乎到权限管理、租户隔离等诸多方面,以及它能否与现有的业务场景无缝兼容。其次,系统的前端界面是否交互便捷、易于使用,这至关重要。再者,系统是否拥有开放集成的能力,能否提供 API 接口,是否能够嵌入到自有系统,或是接入自有知识库和数据源。此外,多场景的适应性也不容忽视。在早期,我们发现许多开源的 Demo 项目,它们仅用几行代码就跑起来一个 Chat BI,虽在特定场景下效果显著,但难以在企业级的真实场景中落地应用。最后,系统的未来拓展性也是必须考量的因素之一。

智能小 Q 分层架构

下图展示了智能小 Q 的整体技术架构。从图中可以清晰地看到,智能小 Q 从上至下依次为应用层、AI 中间层、自研领域大模型和通用模型层,以及 BI 基座引擎层。AI 中间层处于上层应用与大模型之间,主要承担任务分发与协同的职责。我们通过构建 API 和 DSL,实现了 Agent 与算子的有效对接,让大模型应用更具确定性,避免以前通过自然语言输入的应用表达不稳定,使得在 BI 领域的大模型的应用编程变成确定性应用编程。作为支撑小 Q 的关键部分,基座的 BI 引擎确保了数据分析的强复用性。分析引擎涵盖了从数据连接建模到复杂分析的全方位能力,而渲染引擎则承载着图表可视化及交互的重任。整套系统都是在 Quick BI 已有的能力基座上进行开发的。

自研模型在 SQL 语义生成的可控性

在自研模型的 SQL 语义生成技术路线上,目前 主流的有两种方式:Text to SQL 和 Text to DSL。我们对这两种技术路线进行了长期且深入的对比分析。Text to SQL 是直接将文本转换为 SQL 语句,直接在物理数据源上进行查询;而 Text to DSL 则是先经过一层抽象的语法,再分发到数据源进行查询。从业务特性来看,Text to SQL 在门槛较低的情况下,能够充分利用大模型的泛化能力,简化数据分析过程。然而,它也存在一些局限性。由于缺乏数据模型的抽象定义,直接对标物理表,使得大模型生成 SQL 的过程变得异常复杂。

此外,大模型不可能被训练去了解市面上众多数据源的方言。以 Quick BI 为例,它支持四五十种方言,如果要对私域数据进行私有模型训练,成本将难以控制。而且,即使是同一数据源的不同版本,如 MySQL 5.7 和 8.0,它们支持的函数也有差异(如开窗函数),这对大模型来说并不友好。从技术限制角度而言,DSL 的灵活性相对较弱,其查询能力受限于 BI 引擎的能力边界。从适用场景来看,Text to SQL 更适合门槛较低、没有复杂业务分析要求的场景;而 Text to DSL 则更适合业务场景明确、面向大型团队和企业级应用的场景。对于 QuickBI 来说,技术路线从纯 Text to DSL 到 Text to SQL to DSL,再到混合模式,可谓是吸收各个路线的优势。

一个问数问题的工程链路

我们从工程链路的角度剖析一下问数。用户问了一个相对复杂的问题后,经过模型的复杂链路处理,包括 Agent 路由、各种实体召回,由自研 BI 大模型生成 DSL,经由工程端的查询参数构造后,发给查询引擎进行取数。查询分析引擎会处理复杂计算字段(如 LOD 函数、自定义抽象函数)、注入用户的行列权限等,最终翻译成物理 SQL 和内存计算进行取数处理。从下图的例子可以看到,相对抽象的 LOD 函数会被稳定转义成适配不同数据源方言的 JOIN, 大大降低了模型生成 SQL 的难度和稳定性。在这种工程架构下,可以解决传统 NL2SQL 面临的三大关键问题:1)保证可用,具备企业级的管控能力,如完备的权限能力、开放集成能力等;2)保证可信,BI 引擎的引入降低模型生成原生 SQL 的难度,对取数的每个链路都做到逻辑有迹可循,查询元数据血缘透出,提升结果的可信度;3)结果可交互,复用了 BI 丰富的可视化能力,在生成的图表后链路上可修改并进行二次查询。

工程架构设计

NL2SQL 算法的挑战

与通用模型处理的其他类型问题相比,NL2SQL 算法领域面临的挑战主要集中在以下三个部分:

  1. 语义的模糊到精确:自然语言天然是非精确的,同样一个意图可以有多种不同方式的表达,而 SQL 代码及执行是精确的,用户对结果的正确性的容忍度非常低。因此 NL2SQL 天然属于模糊到精确的多对多映射问题。

  2. 语言结构化:SQL 是“结构化查询语言”,而对比与 Python/C++ 等其他编程语言是过程化的语言。这里有什么区别呢?过程化语言可以做片段化的逻辑生成,对模型推理的要求偏低,但结构化语言需要结构和逻辑整体正确,难度相对大些。

  3. 在问数任务的绝大部分场景下,用户的问题只提供了信息的局部,只是回答信息必须上下文的很少一部分。有更多信息以企业内部约定俗称、表元数据的简称、数据的具体内容形式存在。这点相信在这个领域的各位应该也有比较深刻的体会。事实上,有大量的 Query 之外的“隐藏信息”需要补全,而这又无形中对系统的配套设施提出了更高要求。

我们在训练模型前,对要达到的效果做了定义和预演。即什么样的数据分析助手是“好”的助手?

首先在风格和调性上来说,主要有以下几点:

  1. 有效性,模型必须保证准确和稳定,即单位 token 的有效信息密度高,不啰嗦;

  2. 准确性,在最小可用的数据和关联拓展之间做一个平衡。用户问数往往是看一系列数据,不是单个数据,我们会在某些场景下主动给一些关联数据,实践下来带来会给用户一些“小惊喜”;

  3. 在复杂任务上的表现,过程中逐步规划、反馈,通过多个简单任务组合解决复杂任务。当然,这里如何拆分子任务、子任务的粒度也是另外一个较大的话题了(过于原子化和过于抽象都是有问题的)。

其次对于大模型能力,主要有以下几点:

  1. 基础能力稳定性高:在问数基础、高频场景下需要稳定且高准确度的表现,避免过多的过程性解释;

  2. 在数据分析场景下的专业性:模型训练能够对数据分析师、业务常用的分析思路有理解,能给出专业的数据建议。比如用户问单个指标的时候,同时看一下指标趋势也没有坏处;

  3. 规划、矫正能力:具备将复杂任务拆解为用户易于理解。易于干预的子任务,能根据不同的上下文、用户提示,矫正复杂任务的执行规划。

一个问数问题的大模型旅程

从算法的视角来重新看问数的链路:大模型在生成抽象 SQL/DSL 的过程中,经历了元数据选取、上下文添加、问题改写、完整 Prompt 构建、输出、转译等步骤。。这其中最重要的一步就是领域模型的训练,领域模型训练需要足够的信息来进行正确推理,这些信息主要包括任务描述和通识能力,例如大模型不知道今天是哪天,我们需要将当前时间戳加入其中。其次是表和字段信息,这是非常关键的,如果没有表的字段信息和维度枚举值,对于 NL2SQL 来说将是一场灾难。再者是私域知识库,相关的知识条目以及是否做强制改写等,都会给大模型提供启发。另外,参考样例也很重要,什么是好、什么是坏的,我们在产品上通过点赞、点踩等方式给大模型提供真实的 few-shot 示例。经过各种选表问题改写 SQL 等流程后,最终生成的 Prompt 会交给领域模型完成推理。

基于 BI 引擎的 NL2SQL 算法演进

前面有讲到,最初我们定义了特定的查询语言 DSL, 用于表达对于不同查询参数的描述,由大模型直接学习并生成 DSL,再通过中间层将抽象的 DSL 在元数据和知识库的召回后实例化,转换成实际 QBI 的查询参数执行真实的取数;这里的几个好处,比如 SQL 方言屏蔽、高级计算能力复用等等。但随着支持的问数能力越来越多,问数的意图千变万化,要准备这套 DSL 语义的样本成本在逐渐增大,毕竟 DSL 是我们自定义的,通用模型训练并不含这部分内容。同时,各类通用基座模型本身对意图转简单 SQL 确是有大量积累的。于是我们在单表查询的标准 SQL 基础上拓展了抽象函数和高级计算符,变成增强 SQL 语言,以训练基座模型对于增强 SQL 的生成来提升对复杂意图的理解准确度,然后通过自研语法解析器来改写成 DSL 映射。也就是说,增强 SQL 和 DSL 是可以稳定转换的。这样既能巧妙利用通用模型的能力,又能大大降低训练样本的准备成本。至此,复杂查询意图到取数流程就被串联起来了。

Text2DSL:丰富的算子和函数

对于上述架构的最终选择,有两个重要因素支撑才能成立。第一个是丰富的算子和函数,得益于 Quick BI 内置大量逻辑函数,如聚合数值处理、文本处理,以及 LOD 函数、时间算子等。例如,计算环比对于 SQL 来说可能很复杂,我们会将大量复杂分析场景定义封装在这些算子和函数里,大模型在生成增强 SQL 时不需要感知这些复杂内容,它只需要知道如何使用这些算子和函数即可,这有点像现在流行的 Agent 方式。第二个是完善的数据模型,我们作为 BI 系统本身就支持很多关联模型,包括自定义 SQL 模型,如单表星形、雪花星系等经典 BI OLAP 模型。实际上,我们会将复杂的多表关联合并和嵌套查询下推到数据建模层,这些信息对大模型来说是透明的。大模型不需要感知这些,因为 Chat BI 不仅仅是 NL2SQL 算法的炫技,更重要的是解决实际客户的问题。有时我们会将复杂建模放在前面,对于整个大模型来说,它只是一个单表的、带有各种复杂函数的 SQL 生成逻辑。

另一个重要的计算逻辑是多步计算。多步计算是为了解决一些纯 NL2SQL 无法处理的问题,转而通过 NL2Python,或者说 NL2Python Agent 的方式来解决。举个简单例子,询问销售金额日环比超过 40% 的用户有哪些?我们可能只能算日环比,超过 40% 对于人来说很简单,但实际上这是一个多步计算的解决方案。在这个流程中,大模型会进行多次推理,这里的 Python Agent 会触发大模型在当前输入上进行二次推理。通过合理的任务拆解,可以降低整个复杂问题的解决难度。

此外,关于领域模型的训练,我们这边的训练主要分为三个部分:继续预训练、微调和 GRPO。简单来说,在预训练阶段,我们会把 Query 质量不高但有大量抽象 SQL 的东西作为预训练的一部分。在微调阶段,我们会把高质量的 query 和 SQL 对应关系放到微调中进行训练。最终通过强化学习 GRPO 的方式把整个模型训练好。

大模型与好数据:训练数据准备

大模型是离不开好数据的,只有大量 + 优质的训练数据加持,模型才有可能突破。下图是我们数据准备的一个数据飞轮:

一方面我们依赖了人工构造,我们有一只专门的数据团队去构造、收集复杂的训练数据。其次,利用模版、AI 去生成,各类大小模型的结合提升训练数据的质量和覆盖。然后是数据蒸馏,对一些复杂问题,我们会通过大模型训练小模型的方式。与此同时,我们还会在数据准备过程中利用若模型生成一些有价值的错误,这些样本随后可以在执行引擎的协助下执行验证并进行错误归纳,相当于反例的标注,这对于训练非常有必要。我们实践下来发现,有价值的错误在整个训练过程中是非常有必要的。

业务价值与展望

智能小 Q 客户实践场景

以零售品牌为例,它们直接利用我们的 SaaS 产品来推进功能演进。还有快消品客户,更是将我们的小 Q 直接嵌入到他们的业务系统中。实际上,在客户那里,我们进行了一些实践和调优工作。作为一个通用的 BI 工具,无需任何配置的前提下想要直接达到 90% 以上的准确率是不现实的。事实上,脱离具体应用场景谈准确率,多少有些不切实际。这里有一个案例,一开始我们完全没有介入时,准确率仅为 65%。通过交付过程中的介入,引导用户如何使用、如何提问,以及让用户通过点赞、点踩的方式参与,我们的模型可以自动进行 SFT。在这种场景下,最终将模型强化后的问数准确率提升到了 92%。主要提升点在于指标维度的扩充、指标覆盖等,让用户尽可能多地提供信息,针对复杂问题进行自动拆解。很多时候,客户的问题并非单纯的问数问题,比如他们可能会让你去分析一下某个情况,这就需要进行问题拆解。此外针对无法回答的问题,提供用户提示,即拒识方面的引导优化也是非常有必要的。

Bl 未来发展

目前大模型擅长的包括:语义理解、代码生成、分析思路、文本生成、任务编排… 我认为大模型在以下几个方面会有长足进步,具体进步包括:

  1. 动态推理能力:包括任务拆分、逻辑推演、冲突解决;

  2. 多模态感知能力:未来可能会整合跨平台的报表数据、根据截图、报告来挖掘出更有意义的数据科学部分;

  3. 模型能力本身的持续进化、自我反思机制的增强:在整体水位线上能让智能来的更加真切;

  4. 自主决策能力:非预设路径的行动生成和决策。在更高的角度来看,随着大模型这些能力的持续进化,我相信将会推动智能 BI 从任务执行者向决策主体跨越,进而让整个领域在交互模式和能力边界上都有相应的变化。

嘉宾介绍

王璟尧,毕业于浙江大学信电系,10 年数据产品建设和技术架构经验。现任阿里云智能集团高级技术专家,Quick BI 数据智能研发负责人,负责 BI 平台架构、新一代智能 BI 建设等工作,在元数据管理、BI + AI、大模型应用等领域上有丰富经验。

会议推荐

从基础设施、推理与知识体系,到研发与交付流程,再到前端、客户端与应用体验——AI 正在以更工程化的方式进入软件生产。2026 年 QCon 全球软件开发大会北京站)将以 「Agentic AI 时代的软件工程重塑」 作为大会核心主线,把讨论从 「AI For What」,走向真正可持续的 「Value From AI」

我开发过一款开源的数据可视化编辑器,在编辑完成后他会产生一个 json 格式的项目数据结构。这两年 AI 识图的效果快速发展。我就在想,如果我随手丢一个可视化面板的效果图,AI 就可以识别这个效果图中的元素,并且按照我项目的数据格式要求生成最终的 JSON 文件。这样一来岂不就完成了 AI 直接生成可视化面板的效果吗?

摸索了一两天之后有一条可实践的路径,大概流程为

  1. 让 AI 识别图片中的可视化元素。
  2. 根据识别的元素选择我编辑器中可以使用的组件
  3. 结合上面两点让 AI 输出一个简化版的数据结构,其中包括使用的组件类型、组件的尺寸、组件的位置等信息
  4. 然后再自己编写一套逻辑解析上面的简化版数据结构,确保生成的最终数据结构是编辑器可以识别的

上面的流程确实能够走通,但是生成的效果图实在惨不忍睹(如下图)。

cbb8df8e-8f0b-4f2f-b322-a7289ceeb5b0.png

最根本的原因在于不管提示词写得多么详细,AI 反馈过来的简化的数据结构始终都是非常潦草的。比如我从肉眼上看这个设计稿可能至少需要一百个可视化元素,但实际上它返回给我的结果可能就包含十几二十个元素。我以为是 AI 上下文大小限制的问题。但我切换过高级模型 200K 的上下文长度完全是足够的。但是 AI 输出结果依然没有提升多少。
想问问各位 V 友。这个想法是现阶段可以实现的吗? AI 识图的能力有没有到可以支撑这个想法的地步?

前言

在数字化运维与业务监控的实践中,仪表板(Dashboard)与汽车的仪表盘同等重要,它不仅是数据可视化的载体,更是团队快速定位问题、洞察数据趋势的核心工具。观测云在平台中内置了大量通用组件、云服务的仪表板模板。但如果你希望从零开始构建个性化的仪表板,又或者对自己绘制的仪表板不够满意,那么这篇文章将教授你几个小技巧,帮助你有效提升仪表板的质量。

观测云简介

观测云是一个统一实时监测平台,它提供全面的系统可观测性解决方案,帮助用户快速实现对云平台、云原生、应用及业务的监控需求。观测云的核心功能包括:基础设施监测,日志采集和分析,用户访问监测(RUM),应用性能监测(APM),服务可用性监测(拨测),安全监测,智能监控等等。这款产品能够帮助工程师全面了解端到端的用户体验追踪,了解应用服务的每一次调用,以及全面监控云时代的基础设施。此外,观测云还具备快速发现系统安全风险的能力,为数字化时代提供安全保障。更多信息可以访问观测云官网:https://www.guance.com

基础仪表板的绘制

让我们进入到观测云,创建一个属于您自己的仪表板。首先,你需要找到仪表板的入口「场景」-「仪表板」,点击「新建仪表板」-「新建空白仪表板」。

图片

其次,可以从侧滑窗口中选择适合展示数据的图表类型,拖拽到左边的空白画布中。

图片

以常用的「时序图」为例,拖动到画布中即可打开「新建图表」弹窗,此时通过数据筛选控件来选择需要展示的指标。

图片

如图所示,我们已经展示了一条指标曲线,它代表的含义为:指标集为 cpu,指标名为 usage_total,按照 host 进行分组并统计 Avg 平均值,只显示 host=DESKTOP-F9E75IG 的值(过滤条件),点击右下角的保存即可。

图片

此时你已经完成了第一张图表的制作,通过一张张图表的叠加,你很快能得到一个完整的仪表板,不过它看上去有些简陋,我们需要更多技巧对仪表板的美观程度和易读性进行优化。

图片

仪表板的优化

新增标题和描述

恰当的标题能让用户第一时间知道图表展示的指标及其含义,而图表的描述能够起到有效补充说明。我个人的习惯是将图表名设置为指标的英文名,然后在「描述」中补充该指标的中文含义。如下所示:

图片

保存生效的效果如下,图表左上角将展示标题,而鼠标 hover 到帮助按钮上则会悬浮显示描述。

图片

数据单位

一部分指标在采集到观测云后没有单位,因此在绘制仪表板时需要注意补充单位。

图片

别名

图表的曲线会显示对象的名称,并且对象名称会随着分组条件的增多而变得复杂。例如下图,由于添加了 namespace,pod_name 等多个分组条件,对象名称显得很长,很不直观。好在我们可以通过配置「别名」来简化对象名称的显示。

图片

在图表配置的「别名」处,我们选择对应的指标序列,并用 {{}} 将分组条件包起来作为变量,例如下图中的分组条件 pod_name 就写为 {{pod_name}} ,效果如下所示。

图片

我们也支持用多个变量作为别名,写法为 {{分组条件1}}-{{分组条件2}} ,例如 {{namespace}}--{{pod_name}} ,效果如下图所示:

图片

现在,曲线上显示的对象名称已经比原始的名称简洁、清晰了很多。

图例

图表默认没有带上图例,除非将鼠标 hover 上去,否则无法看到什么颜色的曲线代表哪一个对象,如下图的左侧所示。而「图例」则可以将对象的名称和统计值显示到图表中,如下图的右侧所示。

图片

添加图例的方式如下,可选择将图例放置在图表的底部或者右侧,并显示单个或者统计值,将 Avg、Max、Last 一起显示出来是个不错的选择。

图片

分组

当仪表板中需要展示很多张图表时,使用「分组」来将不同含义的图表分门别类地归类就十分有必要了,这会让仪表板的显示更具有条理,用户能通过分组快速找到自己关注的图表,如下图所示。

图片

给仪表板添加分组时,只需要在侧滑菜单中找到「分组」这个图表类型,拖动到左侧画布即可。

图片

取一个有意义的分组名称,选择一个与众不同的颜色,保存即可。

图片

下图即为新创建的分组,后续添加的图表即可拖动到该分组下。

图片

锁定时间

如果你希望每次进入到仪表板,都查看到固定时间区间(例如最近1天)的数据,应该如何实现呢?

我们很容易注意到仪表板的时间控件,可以在这里固定整个仪表板的时间。

图片

如果需要将单个图表的时间进行固定,而其他图表的时间则跟随仪表板的时间控件,也很好实现。我们进入单个图表的编辑窗口,打开「高级配置」,将时间锁定为指定区间即可。

图片

配置完成后,这个图表的右上角会出现你锁定的时间区间,该时间不受仪表板整体的时间区间控制,如下图所示。

图片

视图变量

视图变量允许用户通过下拉菜单来选择特定对象的监控数据,从而根据自身需求动态筛选和分析数据。如下图所示,该仪表板包括了 Cluster、Namespace 和 Node 三个视图变量,用户可以进行自由筛选。

图片

我们首先添加一个简单的视图变量,需求是通过选择 host_ip 来过滤单台主机的数据。在仪表板中点击「添加视图变量」。

图片

图片

host_ip 是 cpu 相关指标数据的一个标签,因此我们从指标类型- CPU指标集里面选择 host_ip 作为视图变量的来源,然后将「变量名」和「显示名」都与之保持一致,保存窗口即可。

图片

此时返回仪表板,就会看到刚才添加的 host_ip 视图变量,从下拉菜单中可以筛选主机 IP。如下图所示:

图片

你可能会发现筛选结果之后,对下方的图表没有任何作用,因为我们还需要在图表中的过滤条件配置变量,使仪表板的额视图变量与图表的过滤条件进行联动。再次进入图表编辑界面,添加一个过滤条件,字段选择为 host_ip,值选择「视图变量」,如下图所示。

图片

返回仪表板,这时仪表板的视图变量 host_ip 就可以与图表中的监控对象 host_ip 进行联动了。我们可以通过下拉菜单来筛选不同的主机,从而观察不同主机的监控指标。

图片

如果是有多个视图变量,且视图变量之间有依赖关系,例如我们针对 Pod 的监控是首先选择 namespace,再选 Pod,那我们又应该如何配置呢?这就要用到「级联」的写法,让我们来再来回顾一下刚才本章开头的那张图片。选择 Cluster 后,Namespace 的值随 Cluster 的取值而联动,Node 的值又随 Namespace 的取值而联动。

图片

我们研究一下这组视图变量的写法,不难发现规律是在 show_tag_value 函数的后面跟随了一个 {key=value} 的过滤条件,其固定写法为 {key='#{value}'} ,key 和 value 都取自上一级的变量名,表示该变量随上一级变量的值而联动。如下图所示,当用户在界面上选择了 cluster_name_k8s 的值后,该值就会传入 namespace 作为过滤条件,从而实现变量联动。

图片

图片

小结

通过上面的几个小技巧,相信你已经跃跃欲试将自己的仪表板更上一层楼了。在得到令自己满意的仪表板后,你可以选择将仪表板开放给团队、配置为定时报告、投放到大屏幕、关联到日志或链路查看器中,又或者在接收到告警时一键查看这张仪表板。我们非常期待你通过仪表板来向你的团队/客户呈现数据的价值。

佬们好,vibe 了一个简洁美观的串口调试工具 PortaX


项目地址

Portax:一款简单、美观且便捷的串行调试工具
开箱即用: Portax

亮点

  • ui 简洁美观:深浅主题
  • 关键词高亮:支持自定义关键词高亮及颜色配置
  • 快捷指令:可自定义、持久化保存的快捷指令组,支持快速点击发送
  • 历史回溯:支持通过键盘 / 键回溯发送历史
  • 数据过滤:支持实时日志搜索与过滤
  • RX/TX 监控:底部状态栏集成动态呼吸灯,实时反馈数据收发状态
  • 支持生成折线图:这个功能目前还没优化好,效果如图三,且可以截图与导出图片到 pdf


演示图

图一

图二

图三

图四

开发计划

  • 优化曲线部分
  • windows 客户端
  • 其他协议

欢迎佬们提建议,帮助我完善优化,使 PortaX 成为更好的工具


📌 转载信息
原作者:
HaxIOX
转载时间:
2026/1/14 18:20:45

前言

最近在优化网站访问链路的过程中,部署了一套 WAF 防火墙,它大部分功能都做的挺好,美中不足的地方就是针对于网站访客的相关功能需要付费( 3600 元/年)才能用。

付费是不可能付费的,找了一圈 nginx 日志分析的开源项目,大部分都做的挺简陋的,要么就是做的很重,需要部署其他服务。

既然找不到合适的,那就自己动手写一个吧!

如果看不到图片的话,直接访问我个人网站上发布的。https://www.kaisir.cn/post/186

实现效果

做了 4 个模块对日志数据进行分析。

  • 访问概况
  • 数据日报
  • 实时访问
  • 访问明细

image-20260108124900609

访问概况

概况模块中,做了 8 个维度的数据分析。

核心指标

在这个维度中,针对 http 状态码、浏览量、访客数、会话数做了更细致的划分。

image-20260108125517344

每一个划分中,在详情面板里,都可以看到这个访客在什么时间做了什么事情。

image-20260108125954027

image-20260108130323366

image-20260108130405011

image-20260108130452437

趋势分析 & 新老访客

这一部分可以看到每天的访问趋势以及当天与前一天的新老访客占比。

image-20260108130725966

来路、受访页、入口页

这部分可以看到访客的来源,以及每个路径的访问次数。

image-20260108131048943

地域 & 终端设备

这部分可以看到每个省份的访问情况以及访问设备的分布情况。

image-20260108131213706

数据日报

在这个模块中,可以看到每天的浏览量、访客数、平均访问时长等信息。

image-20260108134815067

image-20260108140538356

实时访问

在这个模块里,可以查看最近 5/15/30 分钟内的访问情况

image-20260108141207205

访问明细

这个模块就以表格的形式展示每一条日志。

image-20260108141436301

如何使用

为了方便使用,我已经将这个项目打包成镜像发布到 dockerhub 上了,镜像名为magiccoders/nginxpulse,可以通过 docker 的形式使用,也可以通过 docker compose 的形式使用。

需要传入的参数:

  • WEBSITES 它的值是个数组,一个对象就是一个网站,需要传入网站名、日志路径、网址(或者内网 ip ,主要用于站内/站外的区分)
  • ports 端口映射,容器内暴露出来的端口是 8088
  • volumes 文件挂载,这里需要挂载:日志文件、容器内产生的数据文件、时区

此处我以 docker compose 的形式举例:

version: "3"
services:
  nginxpulse:
    image: magiccoders/nginxpulse:latest
    container_name: local_nginxpulse
    ports:
      - "9200:8088"
    environment:
      WEBSITES: '[{"name":"神奇的程序员","logPath":"/var/log/nginx/access.log","domains":["kaisir.cn","www.kaisir.cn"]}]' #domains 用于“来源( referer )统计”的站内/站外分类
      PV_EXCLUDE_IPS: '["127.0.0.1", "::1", "10.10.0.1", "192.168.30.21"]' #pv 统计时需要排除的 ip
    volumes:
      - ./nginx_data/logs/all/access.log:/var/log/nginx/access.log
      - ./nginxpulse_data:/app/nginxpulse_data
      - /etc/localtime:/etc/localtime
    restart: unless-stopped

写在最后

至此,文章就分享完毕了。

我是神奇的程序员,一位前端开发工程师。

如果你对我感兴趣,请移步我的个人网站,进一步了解。

把城市名替换成你所在的城市,或者你想去的城市,期待看到你们的作品

第一弹

Present a clear, side miniature 3D cartoon view of [YOUR CITY] tallest buildings. Use minimal textures with realistic materials and soft, lifelike lighting and shadows. Use a clean, minimalistic composition showing exactly the three tallest buildings in Sopot, arranged from LEFT to RIGHT in STRICT descending height order. The tallest must appear visibly tallest, the second must be clearly shorter than the first, and the third must be clearly shorter than the second.
All buildings must follow accurate relative proportions: if a building is taller in real life, it MUST be taller in the image by the same approximate ratio. No building may be visually stretched or compressed.
Each building should stand separately on a thin, simple ceramic base. Below each base, centered text should display:
Height in meters — semibold sans-serif, medium size
Year built — lighter-weight sans-serif, smaller size, directly beneath the height text
Provide consistent padding, spacing, leading, and kerning. Write "YOUR CITY NAME" centered above the buildings, using a medium

第二弹

Create a high-detail 3D isometric diorama of the entire China, where each state is represented as its own miniature platform. Inside each state, place a stylized, small-scale 3D model of that state's most iconic landmark. Use the same visual style as a cute, polished 3D city diorama: soft pastel colors, clean materials, smooth rounded forms, gentle shadows, and subtle reflections. Each landmark should look like a miniature model, charming, simplified, but clearly recognizable. Arrange the states in accurate geographical layout, with consistent lighting and perspective. Include state labels and landmark labels in a clean, modern font, floating above or near each model.

在 cherry studio 的助手配置里面加上自定义参数,关闭流式输出开关,cs 版本升级到最新

{"aspectRatio": "16:9", "imageSize": "4K"} 

4K 高清大图,17M,放在了 cf 的存储桶里

https://img.0rzz.ggff.net/china.png 20M


📌 转载信息
原作者:
Triceratops2017
转载时间:
2026/1/6 12:18:47

CLIProxyAPI 是一个非常优秀 cli2api 工具,不过作者明确提过,不会提供对目前保存在内存中的使用数据持久化支持。(每次更新或重启都会丢失使用数据)

咱又刚好对自己的用量比较感兴趣,就试着搓了一个仪表盘。

纯 Vercel + Postgres 部署,无需拥有服务器。

每天定时持久化上游使用数据,每次打开看板也都会更新一次。
(该策略未经压测,个人使用应该不会有性能问题)

预览图如下,算是把毕生统计所学都用上了:


希望这个项目能对各位有所帮助,也欢迎任何建议。

祝元旦快乐!


📌 转载信息
转载时间:
2026/1/2 12:34:46