Article body
正文
引言
用户愿意用 ChatBI,第一道门槛不是「准不准」,而是「快不快」。一句问话发出去,如果转了五六秒才出图,多数人就失去了耐心,回到「还是我自己写 SQL 吧」的老习惯。
但 ChatBI 的延迟来源极其复杂——它不像传统 BI 那样「发一条 SQL、等数据库返回」那么单纯。它要先做语义理解(调一次大模型)、再生成查询计划、再执行查询、再做结果解读(再调一次大模型)、最后渲染图表。任何一环慢,用户就感知到卡。
衡石 ChatBI 构建了一套覆盖「理解加速 → 查询加速 → 生成加速 → 渲染加速」全链路的性能优化体系,并引入流式响应让「等待感」大幅降低。 本文将拆解这套让自然语言问数做到秒级甚至亚秒级体验的技术。
一、ChatBI 的延迟到底花在哪
1.1 端到端耗时拆解
一次典型的 ChatBI 问数,时间花在四个阶段:
- 理解阶段:大模型解析自然语言、做实体识别和意图消歧,通常占 30%-40% 耗时。
- 查询阶段:生成 SQL、优化、下发数据库执行并返回,占 30%-45%,取决于数据量和索引。
- 生成阶段:大模型把数据组织成自然语言答案和图表配置,占 20%-30%。
- 渲染阶段:前端绘制图表,通常 < 200ms,不是瓶颈。
1.2 两个认知误区
误区一:「慢是模型的问题,没法优化」。模型推理确实占大头,但衡石通过缓存、并行、流式等手段,把「模型耗时」对用户的体感影响降到最低——你不等模型全部想完,就能先看到它「想出来」的部分。
误区二:「查询慢就只能加机器」。很多查询慢是因为没有走预聚合、没有分区裁剪、没有命中缓存。工程优化带来的提升,往往比堆硬件更显著。
二、理解加速:让大模型「想得快」
2.1 语义层短路
在之前的语义理解文章中我们讲到,衡石 ChatBI 基于语义层做「选择题」而非「生成题」。这个设计的性能收益常被忽视:当问题能直接命中语义层的明确映射时,大模型不需要「自由发挥」去猜数据库结构,推理路径更短、输出更稳定、耗时更低。
对于高频、标准的问法(如「今日销售额」),衡石甚至能跳过完整推理,直接从意图模板映射出查询计划,把理解阶段从「调模型」降级为「查表」,延迟从几百毫秒降到几十毫秒。
2.2 提示词精简与结构化
大模型耗时与输入 token 强相关。衡石对每次推理的提示词做严格裁剪:
- 只注入与当前问题相关的语义层子集(相关指标、维度),而非全量元数据。
- 用结构化格式(而非冗长自然语言)描述可用工具,减少模型解析负担。
- 历史上下文经压缩(见多轮对话文章),避免无谓的长 prompt。
2.3 模型路由降本提速
在 LLMOps 文章中我们介绍过多模型路由。性能维度上,路由同样关键:简单问法走轻量小模型(快、便宜),复杂多步分析才调用强模型。把「杀鸡用牛刀」变成「该快则快、该准则准」,整体 P95 延迟显著下降。
三、查询加速:让数据「回得快」
3.1 预聚合与物化视图
企业最常问的,是那批「固定口径的常规指标」(日销、月活、区域对比)。衡石在语义层配置预聚合表(物化视图),把这些高频查询的结果提前算好。当用户问「本月销售额」,直接读预聚合结果,跳过对原始明细的扫描,响应从秒级降到毫秒级。
预聚合不是万能的——它适合维度组合有限的常规分析。对于高度自由的探索式问数,则需要下一层的优化。
3.2 分区裁剪与索引下推
生成的 SQL 在执行前经过优化器处理:
- 分区裁剪:根据时间过滤条件,只扫描相关分区,避免全表扫描。一个按天分区的表,查「上月」只扫 30 个分区而非全年。
- 索引下推:把过滤条件下推到存储引擎,在扫描阶段就过滤掉不符合条件的行,减少数据搬运。
- 列裁剪:只读取查询涉及的列,不拉全行。
3.3 查询缓存
对于「完全相同或语义等价」的问法,衡石做结果缓存。判断「语义等价」不是简单比字符串,而是比「查询计划是否一致」——「上月华东销量」和「华东上个月销量多少」生成的是同一份计划,命中同一份缓存。缓存 TTL 结合数据新鲜度配置,确保缓存结果不会返回过期数据。
3.4 并行与异步
复杂分析常需多次查询(如先取今年、再取去年做同比)。衡石对无依赖的多个子查询做并行执行,把串行等待变成并发汇总。对于超大数据量的探索,走异步模式——先返回「正在计算」状态,算完再推送结果,避免前端长时间阻塞。
四、生成加速:让答案「写得快」
4.1 图表配置的确定性生成
传统做法是用大模型「描述」要画什么图,再解析成图表配置,慢且不稳。衡石的改进是:图表类型由意图分类确定性决定(趋势→折线、排名→柱状、占比→饼图),不依赖大模型「即兴发挥」。大模型只负责写那段自然语言结论,图表配置由模板生成。这一步把生成阶段最不稳定的部分变成了最快的部分。
4.2 结果与解读解耦
大模型解读数据需要先「看到」数据。衡石在查询返回后,只把聚合后的精简结果(而非原始明细)喂给模型做总结,减少输入 token,加快生成。对于「只需给数字、不需长篇解读」的简单问法,甚至跳过生成阶段,直接上图。
五、流式响应:把「等待」变成「进行中」
5.1 为什么流式体验这么重要
心理学上,「有反馈的等待」远好于「无反馈的等待」。即使总耗时相同,如果用户能看到「正在理解…正在查询…正在生成…」的进度,焦虑感会大幅下降,主观体验更快。
5.2 衡石的流式实现
衡石 ChatBI 采用流式输出:
- 阶段进度流:理解、查询、生成各阶段开始/结束时,向前端推送状态事件,用户看到实时进度条和阶段提示。
- 答案流式生成:最终的自然语言答案,采用逐字流式输出(类似打字机效果),用户边看边理解,不必等全文生成完。
- 图表渐进渲染:图表先出骨架、再填充数据,而非白屏转圈到最后一次性蹦出。
5.3 流式与正确性的平衡
流式输出有个风险:模型可能「边说边改主意」。衡石的应对是:阶段进度流是确定性的(基于真实执行状态推送),答案流式是生成阶段内的 token 流(已生成的结论基于已确定的数据)。一旦数据或计划变更,前端会基于最终状态校正,不会出现「先说 A 后偷偷改成 B」的割裂感。
六、并发与资源调度
6.1 多用户并发
企业里多个用户同时问数是常态。衡石的查询网关做连接池管理和队列调度:
- 高频轻查询走快队列,优先返回。
- 重量查询(大数据量扫描)走慢队列,限流保护,避免拖垮集群。
- 大模型推理按租户配额调度,防止某个租户的突发流量挤占他人。
6.2 大模型推理池
大模型 API 是稀缺资源。衡石维护推理请求池,做批处理(把多个小推理合并发送)和优先级调度,在吞吐和延迟间平衡。对于内部私有化部署的模型,做 GPU 显存管理和请求排队,最大化利用率。
七、可观测的性能指标
性能优化离不开度量。衡石为 ChatBI 定义了关键性能指标并纳入监控:
- P50/P95/P99 端到端延迟:分位数比平均值更能反映「慢请求」体验。
- 各阶段耗时占比:定位瓶颈在理解、查询还是生成。
- 缓存命中率:衡量预聚合和查询缓存效果。
- 流式首字时间(TTFT):用户感知到的「它开始响应了」的时间,是体验核心指标。
这些指标与 Agent 可观测性体系打通,运维人员能清晰看到「哪类问法慢、慢在哪、怎么优化」。
八、技术对比
| 优化手段 | 典型收益 | 适用场景 |
|---|---|---|
| 语义层短路 | 理解阶段降 70%+ | 高频标准问法 |
| 预聚合/物化视图 | 查询降 1-2 个数量级 | 常规固定口径 |
| 分区/索引下推 | 查询降 5-10 倍 | 大表探索 |
| 查询缓存 | 命中即毫秒级 | 重复/等价问法 |
| 并行/异步 | 多步分析降 30-50% | 复杂对比分析 |
| 流式响应 | 主观体验提升显著 | 全部场景 |
九、FAQ
Q1:私有化部署的小模型会不会比云上大模型慢很多?
取决于模型大小和硬件。衡石支持按场景选模型——轻量问法用小模型本地跑(快且数据不出域),复杂分析用强模型。通过路由和缓存,私有化也能做到良好体验。
Q2:流式输出会不会影响准确性?
不会。流式是「呈现方式」,底层的数据和计划是确定后再生成的。用户看到的是已确定结论的逐字展示,不存在边生成边推翻。
Q3:预聚合表太多会不会占用大量存储?
会,所以有策略:只对高频、维度组合有限的指标建预聚合,配合 TTL 自动过期。存储成本和查询提速之间是权衡,衡石提供配置建议而非一刀切。
十、总结
ChatBI 的「快」,不是靠某一个魔法,而是全链路每一环都抠出来的工程累积:用语义层让理解变短、用预聚合和缓存让查询变快、用确定性图表让生成变稳、用流式让等待变轻。
核心认知是:用户体验的延迟 ≠ 系统真实耗时。 通过把「模型思考」对用户透明化、把「结果返回」渐进化,衡石让自然语言问数在体感上达到了「随问随答」的流畅度——这正是 ChatBI 从尝鲜走向日常依赖的关键一环。