做了这么多年数据开发,我最怕听到的不是“报表要改”,而是“这个数为什么不对”。“对不对”还能查,“为什么”往往要翻半天数据、写一堆临时 SQL,才能拼出一个大概结论。所以我从去年开始折腾 SwiftBoot AI 智能看板,刚把 v0.1.8 版本发出来。这个版本最大的变化,就是让数据不仅能被“看见”,还能直接“开口说话”——输入一句大白话,系统自己查数、画图、总结原因,甚至用语音把结论念出来。
SwiftBoot AI 智能看板,简单来说,就是一套把数据库里的表格变成“能对话、能解释、能预警”的分析系统。它把自然语言问答、指标语义层、SQL 自动生成、归因算法和可视化整合到一个闭环里。业务用户不用再等排期要数据,直接问“上周订单量为什么掉了”“哪个渠道转化率缩水最狠”,系统会给出查询结果、图表和归因说明。这篇文章适合正在做数据看板、BI 报表或者想给内部工具加上 AI 问答能力的朋友看,里面涉及的架构取舍、语义层设计、版本迭代思路和部署排障经验,都是我在实际折腾中踩过坑之后的总结。
v0.1.8 这个版本,我不想叫它“彻底重构”,更准确的描述是:它第一次把“听懂问题、算对数据、讲清原因、主动提醒”这四件事串成了一条稳定的链路。现在我就按项目从设计到落地的顺序,把这套系统的技术细节和实操经验完整拆开讲。
1. 为什么做 SwiftBoot:传统看板到底卡在哪
1.1 看板越来越多,问题并没有变少
传统看板这几年进化得很快,图表越来越精致,大屏越来越炫,点击下钻、联动筛选、移动端适配都已经很成熟。但业务方看完之后,通常只会说一句“我知道了”,然后继续来找你问“为什么”。原因其实很朴素:看板解决的是“呈现”问题,不是“解释”问题。指标下跌 30%,看板可以画出一条漂亮的下降曲线,但它不会告诉你这次下跌是东区某品类缺货导致的,还是某个渠道的投放预算被临时砍掉了。
我在这个项目早期做过一个内部调查,统计了业务同学日常提数的类型,结果超过一半的问题都是“为什么式”的问题,而不是“是多少式”的问题。比如“这个月退款率为什么涨了”“昨日的成交额为什么掉这么多”“哪个区域的用户流失最严重”。这些问题如果都要靠人肉写 SQL 去查,再手工汇总成因,一次至少半小时。更麻烦的是,不同人查出来的口径还不一样,最后开会时各说各话。正是这种真实场景的反复出现,让我决定不再把精力花在“做更多图表”上,而是去做一个能直接回答“为什么”的 AI 看板。
1.2 “让数据开口说话”到底是在说什么
很多朋友听到“让数据说话”,第一反应是加一个语音播报,把报表数字念出来。这理解太浅了。如果只是把“成交额 100 万”变成一段语音,那依然是一堆没有解释的数字。我理解的“开口说话”,至少包含三层能力。
第一层是能“听懂”,用户可以用日常语言提问,系统自动把口语转化成可以执行的查询。第二层是能“说清”,系统不仅要给数字,还要解释数字变化的原因,拆出是哪个品类、哪个渠道、哪个区域贡献了主要变化。第三层是能“提醒”,数据出现异常或趋势拐点的时候,系统主动推送消息,而不是等用户打开看板才发现。v0.1.8 的核心升级,就是把这三层串成了完整链路。尤其是第三层,这个版本加入了事件订阅和播报能力。你订阅“东区订单量”这个指标,系统监测到某天环比下降超过阈值,会自动生成一句“东区昨日订单量环比下降 11.2%,主要受 A 品类库存不足影响”,然后通过 IM 机器人或浏览器语音播报出来。这才是真正的“开口说话”。
这里我想特别强调一个观点:不具备可解释性的 AI 看板,本质上只是个花哨的报表插件。用户需要的是结论和依据,而不是一堆概率和“AI 猜的”。所以从 v0.1.0 开始,我就给自己的项目立了个规矩:AI 可以决定说什么,但不能决定数字本身。所有结论里的数字,必须来自可追溯的查询和计算。
1.3 版本号为什么停在 v0.1.x
不少朋友会问,项目都做到 v0.1.8 了,为什么还在 0.x 阶段?这个版本号是我刻意保持克制的。v0.1.x 意味着整体架构还在早期,很多模块会随时调整。前几个版本我一直在解决同一个问题:怎么让 AI 生成的查询结果可靠。没有可靠性,AI 再会说话也是“一本正经地胡说八道”。v0.1.8 虽然只是一个小版本,但它把对话能力、归因能力和播报能力首次稳定地组合在了一起,属于从“实验室原型”到“可内部使用工具”的分水岭。
我见过很多团队做类似项目,上来就规划了十几个模块,又是知识图谱又是强化学习,结果半年过去还是没有能用的东西。我的做法恰恰相反,每一个小版本只解决一个核心问题:v0.1.2 解决了数据源接入,v0.1.4 解决了指标语义配置,v0.1.6 解决了自然语言转 SQL 的基本链路,v0.1.7 加入了严格的数据权限过滤,到 v0.1.8 才把归因和播报接进来。这样每次发版都有明确的可验证目标,也不会因为功能太多而失控。
2. 架构设计:AI 看板不是把大模型直接接到数据库上
2.1 整体模块划分与选型逻辑
AI 看板最粗暴的做法,是把用户问题拼进 Prompt,扔给大模型,让它生成 SQL,然后直接执行。我在最早的 demo 阶段就是这么干的,结果很惨:字段经常拼错、表名张冠李戴、SQL 跑通但口径不对。后来我意识到,真正的瓶颈不是模型不会写 SQL,而是模型不知道你的数仓里有哪些表、字段代表什么含义、指标怎么算。所以 v0.1.8 的架构围绕“语义层 + 查询引擎 + AI 推理服务”三个核心来设计。
整体可以分成五个模块:
- 接入层:负责数据源连接、账号鉴权、连接池管理和基础权限过滤。
- 语义层:维护指标、维度的业务定义,包括字段别名、计算公式、数据权限和表关系。
- 查询引擎:把语义层的指标表达式翻译成具体数据库方言,执行查询,做缓存和结果校验。
- AI 推理服务:负责意图识别、SQL 生成、归因判断和摘要生成。
- 交互端:Web 看板、语音播报、IM 消息推送和反馈收集。
模块之间通过消息队列解耦。用户提了一个问题后,API 服务先把问题写入队列,Worker 异步处理完成后再回调结果。很多人不理解为什么不能同步处理,我可以给你一个真实数据:一个复杂分析问题的完整链路可能需要 8 到 15 秒,其中包括模型推理、SQL 执行、归因计算和摘要生成。如果搞同步 HTTP,网关和后端连接池都会被拖死。异步队列加上前端轮询或 WebSocket 推送,是这类产品比较稳的交互形态。
2.2 语义层是防幻觉的第一道保险
很多 AI 看板项目失败在“数据口径不受控”。业务方问“销售额”,有人认为是“支付金额”,有人认为是“订单金额”,模型如果自己去猜,一次一个口径,这个系统就废了。SwiftBoot 的语义层用一组 YAML 文件把指标定义固化下来。每定义一个指标,至少包含四个要素:指标代码、业务别名、计算公式、可用维度。
模型生成 SQL 之前,会先做“文本到语义映射”,把用户问题里的“成交额”映射到order_amount这个指标代码上。映射过程中只允许操作语义层给出的白名单字段,查询引擎生成 SQL 时也只会从expression对应的物理字段展开。这等于给模型画了一条边界:它可以在边界内发挥,但不能越界。
这个设计带来的直接收益是 SQL 生成正确率的提升。在内部测试集上,不做语义层约束时,正确率大概只有 75% 到 80%;加了语义层之后,稳定在 91% 左右。剩下的错误主要集中在复杂时间范围的表达上,比如“最近三个自然周”这种说法,模型偶尔会算错边界。这个方向会在后续版本继续优化。
2.3 查询执行回环:让模型自己纠错
大模型生成的 SQL 即使通过了语义层校验,也可能在语法、表名拼写或时间过滤条件上出错。v0.1.8 的查询引擎里做了一个“执行回环”,流程如下:
- 模型生成 SQL,附带预期返回字段。
- 引擎先做静态检查,比如字段是否在白名单里、是否存在明显的 SELECT * 写法。
- 执行 SQL,如果数据库报错,捕获错误信息。
- 把错误信息清理后返回给模型,让它根据错误修改 SQL,再执行。
- 如果执行成功但返回结果为空,或者字段数量不匹配,同样触发第二轮修正。
这个机制参考了 Agent 领域的自我纠错思路,但实现起来要克制。我最多允许模型重试 2 次,超过次数就返回“我暂时无法准确回答这个问题”,并把这句转给人工处理。为什么限制次数?因为无限制重试会让请求耗时膨胀,而且模型容易在同一个错误上反复横跳。实测中,一次错误重试能把 SQL 正确率从 82% 拉到 94%,第二次重试只能再提升 2% 左右,性价比已经很低。另外,所有重试消耗的 token 都要算成本,为了 2% 的准确率去翻倍 token 开销,不值得。
3. v0.1.8 新功能拆解:这一版到底升级了什么
3.1 自然语言问答不再只是“玩具”
v0.1.8 的自然语言问答界面做成了类似聊天的布局,用户可以连续输入“上季度退货率最高的三个区域”“分别列出这些区域的订单量和客单价”这类问题。系统会先识别意图,再生成查询,最后返回一张图加一段文字说明。这一版最关键的升级是“连续上下文”能力。用户问完第一个问题后,可以追加“为什么”“和上月比呢”这种省略句,系统会自动继承上一轮的指标、维度和时间范围。
实现的时候,我并没有把所有历史消息都塞进模型,而是只维护一个简洁的“上下文对象”。里面包含当前指标、维度、时间范围和上一轮 SQL 片段。这样既不会让模型被无关对话带偏,也能明显省 token。如果用户从头切换主题,只需要清除上下文对象即可。这个细节看起来简单,但对体验的提升非常明显。否则连续对话很容易变成“问着问着就忘了前面在算什么”。
下面是一次典型问答的结构化响应示例:
{ "question": "上周东区订单量为什么下降", "query": { "metric": "order_count", "dimensions": ["category", "channel"], "filters": {"region": "东区", "date_range": "last_week"} }, "sql": "SELECT category, channel, SUM(order_count) FROM demo_order WHERE region = '东区' AND order_date >= '2025-04-07' GROUP BY category, channel ORDER BY SUM(order_count) ASC LIMIT 10", "chart_type": "bar", "summary": "上周东区订单量环比下降 12.3%,主要来自 A 品类和自然渠道", "confidence": 0.84 }前端拿到这个 JSON 之后,按chart_type选择图表类型,把summary渲染成一段结论文本,再决定是否触发语音播报。模型在这里只负责生成 SQL 和摘要,图表选择完全由规则引擎决定,避免模型又去猜一个不合适的可视化方式。
3.2 智能归因分析:把“下跌”拆成人话
单纯的图表还是不够。v0.1.8 里做了一个轻量级归因引擎,用于回答“为什么”。归因的核心不复杂,就是对指标变化做维度拆解:变化贡献度 = 该维度下的变化量 ÷ 总变化量。假设订单量整体下降 1000 单,A 品类下降了 800 单,B 品类下降了 150 单,那么 A 品类的贡献度就是 80%。系统会把贡献度大于预设阈值(默认 15%)的维度挑出来,再结合变化率排序,生成一句人话:“订单量下降 12.3%,其中 A 品类贡献了 80% 的降幅,主要发生在自然渠道。”
为了避免模型乱解读,归因引擎只负责提供可解释的“事实片段”,语言组织交给模型,但结论中的数字和方向必须来自引擎。这个设计相当于让模型做“翻译官”,而不是“分析师”。真正需要深入研判的地方,系统会提示“当前数据不足以推断直接原因,建议查看库存或活动记录”,不做过度解读。
这里还有一个细节,归因计算要先做异常检测。如果指标只是小幅波动,系统不会强行解释,而是输出“本期指标总体稳定,未发现显著变化”。很多团队做归因分析时忽略了这个前置判断,结果就是把随机波动也当成重大变化,分析了个寂寞。异常检测我采用的是最朴素的办法:周期对比 + 同比环比 + 3σ 阈值。先用前 30 个自然日的数据算出均值和标准差,当变化幅度超过均值加三倍标准差时,才判定为“值得解释的异常”。
3.3 语音播报和自适应看板布局
标题里说“开口说话”,自然少不了语音。前端用的是浏览器自带的语音合成接口,后端只需要推送一个包含“标题 + 结论 + 数字”的文本,前端就会在图表加载完成后把结论读出来。这样做的好处是零成本接入,不需要额外依赖;坏处是不同浏览器的音色差异比较大。实际使用中,我会在设置页放一个“播报速度”和“音色选择”的下拉框,让用户自己调。语音播报适合的场景是监控大屏、晨会播报和驾驶舱页面,普通人日常看数据时多数还是会选择静音。所以这个功能被设计成默认关闭,用户按需开启。
自适应布局则是另一个实用升级。传统看板卡片是固定位置,v0.1.8 会根据返回结果的类型动态排布。如果结果是趋势,就放大折线图卡片;如果结果是排行,就优先展示表格;如果是归因结论,就把结论摘要置顶。本质上是一套规则引擎:分析引擎输出结果类型,然后选择模板,最后渲染卡片。它没有用复杂的强化学习,但很管用。做这类功能时,最忌讳一上来就上智能算法,先用规则把 80% 的场景覆盖住,剩下 20% 再靠反馈迭代。
3.4 其他升级与版本对比
为了给升级用户一个清晰参照,我把最近三个版本的核心差异整理成一张表:
| 特性 | v0.1.6 | v0.1.7 | v0.1.8 |
|---|---|---|---|
| 自然语言查询 | 单轮,只能简单取数 | 支持时间过滤 | 支持多轮上下文和省略指代 |
| SQL 生成正确率基线 | 约 75% | 约 83% | 约 91% |
| 归因分析 | 无 | 只输出贡献度 | 贡献度 + 事实摘要 + 置信度 |
| 语音播报 | 无 | 无 | 浏览器端语音合成 |
| 数据权限 | 接口级粗粒度 | 用户级白名单 | 语义层自动注入行级过滤 |
| 结果缓存 | 无 | 5 分钟 | 10 分钟,按问题指纹 |
表格里的正确率是内部回归测试集的结果,不代表通用场景。但它至少能说明一个问题:只要语义层和回环机制做到位,模型能力是能够被工程手段稳定兜住的。 v0.1.8 的缓存策略也很值得一提,我按“问题指纹”来做缓存,而不只是按 SQL 文本。所谓问题指纹,是对归一化后的问题文本、当前筛选条件和用户权限取哈希。这样同一个问题,不同权限用户会得到不同的缓存键,避免数据越权。
4. 实操:从零部署一套 SwiftBoot v0.1.8
4.1 部署环境与快速启动
部署采用 Docker Compose,这是目前最快的方式。整个系统其实只有三个核心进程:API 服务、Worker 服务和前端静态资源,再加 Redis 和 PostgreSQL。PostgreSQL 负责存元数据和查询历史,Redis 负责任务队列和结果缓存。为了方便本地调试,我通常会把模型服务配置成外部接口,通过环境变量连接。
下面是一份可用的 docker-compose 配置参考:
services: api: image: swiftboot/api:v0.1.8 ports: - "8080:8080" environment: DATABASE_URL: postgres://swiftboot:swiftboot@postgres:5432/swiftboot REDIS_URL: redis://redis:6379/0 LLM_BASE_URL: http://your-llm-service:8000/v1 LLM_API_KEY: ${LLM_API_KEY} LLM_MODEL: ${LLM_MODEL} SEMANTIC_DIR: /app/config/semantic depends_on: - postgres - redis worker: image: swiftboot/worker:v0.1.8 environment: DATABASE_URL: postgres://swiftboot:swiftboot@postgres:5432/swiftboot REDIS_URL: redis://redis:6379/0 LLM_BASE_URL: http://your-llm-service:8000/v1 LLM_API_KEY: ${LLM_API_KEY} LLM_MODEL: ${LLM_MODEL} depends_on: - api postgres: image: postgres:15 environment: POSTGRES_USER: swiftboot POSTGRES_PASSWORD: swiftboot POSTGRES_DB: swiftboot redis: image: redis:7-alpine启动命令很简单:
docker compose up -d启动后打开http://localhost:8080,第一次进入会要求初始化管理员账号,之后引导你配置数据源。整个部署过程建议控制在 20 分钟以内。如果超过这个时间,多半是模型服务的连通性或者数据源网络问题,可以参考后面的排障表。
4.2 配置数据源和指标语义层
登录后第一步是配置数据源。平台支持常见的关系型数据库和分析型数据库。配置时只需要填主机、端口、库名、用户名和密码。这里有一个非常重要的安全建议:给系统配置数据库账号时,务必使用只读账号,并且限制该账号只能访问固定的库表。虽然系统内部有行级权限过滤,但数据库账号本身仍然不应该有写权限。一旦 AI 生成 SQL 出错,最多是查询报错,不会造成数据污染。
第二步是配置语义层,这是整个部署中最关键的步骤。以demo_order表为例,在语义目录下新建一个 YAML 文件:
database: demo table: demo_order description: 模拟订单表,用于演示 dimensions: - name: order_date alias: [日期, 下单日期] type: date - name: region alias: [区域, 地区] type: string - name: category alias: [品类, 商品分类] type: string - name: channel alias: [渠道, 投放渠道] type: string metrics: - name: order_count alias: [订单量, 订单数] expression: "count(order_id)" default_dimensions: [region, order_date] - name: order_amount alias: [成交额, 销售额, GMV] expression: "sum(paid_amount)" default_dimensions: [region, order_date] - name: refund_rate alias: [退货率] expression: "sum(refund_amount) / sum(paid_amount)" default_dimensions: [region, channel]为什么要配置这些?因为模型不会自己知道“成交额”等于sum(paid_amount)。这一步把业务语言翻译成物理字段,AI 才有抓手。配置完成后,可以到“语义测试”页面输入测试问题,系统会展示映射到的指标和维度,确认无误后再开放给业务用户。我见过太多团队跳过这一步直接调 prompt,结果是模型换一个版本就“失忆”一次。语义层一旦配好,换模型、调 prompt 都不需要改口径。
4.3 接入模型服务并调优
v0.1.8 的推理服务通过一个兼容业界标准接口的模型网关来连接各类模型服务。在管理后台填入base_url、api_key和model_name即可。选模型主要看部署环境和成本:如果数据敏感、算力充足,就部署本地开源模型;如果追求效果且可以接受外部调用,就选商用模型接口。关键不是某一个模型有多强,而是要保持“自然语言到语义映射,再到 SQL 生成,最后归因摘要”的稳定链路,模型只是链路里的一个环节。
与模型交互时,系统会使用一套专用 Prompt。核心思想是让模型输出结构化 JSON,而不是自由文本。下面是我在配置里内置的 Prompt 摘要:
你是一名数据分析助手。请根据用户问题、语义层定义和可用字段,输出 JSON 结果。 JSON 结构必须如下: {"metric": "指标代码", "dimensions": ["维度1"], "filters": {"字段": "值"}, "time_range": "last_week", "sql": "生成的SQL"} 要求: 1. 只能使用语义层定义中出现的指标和维度,不得猜测字段。 2. 如果问题不明确,优先使用 default_dimensions。 3. 如果用户提到同比环比,请在 sql 中生成对应的对比逻辑。 4. 不要执行任何写操作。模型参数方面,我习惯把temperature调低到 0.1,max_tokens设置到 1000。低温度可以让输出更稳定,尤其对 SQL 这种确定性任务。归因摘要的生成可以单独调用一次模型,温度可以调到 0.3,让语言更自然一些。两次调用分开做,而不是一个 Prompt 同时生成 SQL 和摘要。因为模型一旦同时处理两件事,SQL 出错的概率会明显上升。
4.4 回归验证与上线检查
部署完成后,不要直接丢给业务方,建议先跑一遍回归问题集。我会准备一份约 30 条问题的测试集,覆盖“取数、趋势对比、排行、异常归因”四类问题,逐个记录 SQL 正确率和结论准确性。下面是一个简化的评分表:
| 问题类型 | 示例 | 考察点 | 通过标准 |
|---|---|---|---|
| 取数 | 上个月各区域成交额 | 指标、维度映射正确 | SQL 执行成功且结果与手工一致 |
| 趋势对比 | 本周订单量和上周比怎么样 | 时间范围正确,有环比 | 查询结果正确 |
| 排行 | 退货率最高的三个品类 | 排序逻辑正确 | 结果前三名与手工一致 |
| 归因 | 为什么整体成交额下降了 | 能拆出贡献度维度 | 贡献度数字来自引擎计算 |
回归过程中如果发现 20% 以上的问题失败,先检查语义层,而不是改 Prompt。大部分错误都出在字段别名没配上、时间口径不统一。上线前还要检查权限:用普通用户账号登录,尝试问一个越权问题,比如“其他部门的人均成本”,应该返回“无权限访问该指标”,而不是返回任何数据。这一步直接关系到数据安全,不能省。
5. 常见问题与排障实录
5.1 高频问题速查表
我把自己和试用用户在实际使用中遇到的典型问题整理成了一张速查表,方便你对照排查:
| 症状 | 可能原因 | 处理方式 |
|---|---|---|
| 模型生成了不存在的字段 | 语义层未命中,模型开始“自由发挥” | 检查指标别名和同义词映射,补充字段 |
| SQL 语法正确但查询特别慢 | 模型没有走适合的索引,扫描全表 | 在语义层配置默认时间范围,限制扫描区间 |
| 图表经常选成饼图 | 图表选择规则太简单 | 增加“趋势型指标优先折线,排行优先条形”规则 |
| 归因结论过度自信 | 模型直接生成了结论措辞 | 强制归因数字来自引擎,模型只做语言组织 |
| 同一个问题每次 SQL 不一样 | 生成参数温度过高 | 把 SQL 生成的温度调到 0.1,并开启缓存 |
| 普通用户访问到不该看的指标 | 行级权限未注入 | 在语义层配置权限组,自动注入数据过滤条件 |
| 语音播报没有声音 | 浏览器自动播放策略限制 | 用户点击页面后初始化音频上下文,再触发播报 |
这张表看起来简单,但每一条都是我实际踩过的坑。尤其是图表选择那条,早期版本模型经常把“订单量趋势”生成成饼图,原因就是模型觉得“饼图好看”。后来我在规则里写死:只要查询结果包含时间维,就优先折线图或面积图;只有维度枚举值小于等于 5 时才允许饼图。这样才把图表准确率拉回来。
5.2 三个让系统“少胡说”的调优细节
第一,Prompt 里不要同时给太多示例。很多朋友会在 Prompt 里塞十个八个小例子,结果模型反而被示例带偏。我的做法是只给 2 到 3 个“坏例子”,并且明确标注“错误”和“原因”。比如举例“用户问总利润,你生成了 sum(profit),但语义层没有 profit,错误”,这比堆正确示例更有约束力。模型知道不该做什么,通常比知道该做什么更重要。
第二,执行回环的报错信息要清理。数据库报错信息可能包含表名、字段名甚至部分数据,直接塞给模型会让模型抓住奇怪的特征。我会先把错误信息截断到 200 个字符,只保留“语法错误”“列不存在”“函数不存在”这类结构化信息。这样模型重写 SQL 时更聚焦,也不会因为看到敏感数据而产生意外输出。
第三,一定要记录“AI 拒答”场景。v0.1.8 里新增了一个反馈按钮,用户可以标记“回答错误”。后台会自动把该问题及其查询历史保存成负样本。积累几十条后,可以用它们做一轮补充校验。我试过用负样本反向检查语义层,发现不少之前没注意到的别名冲突。这个动作比单纯调模型划算得多,本质上是在用真实用户的提问方式修正系统的知识盲区。
5.3 一次线上事故给我的教训
有一次我在演示环境里开启了智能播报功能,没注意把播报阈值设得太低。结果指标稍微抖动一下,系统就不停地推送语音和 IM 消息,整个演示环境响了一整天。事后我把预警分成两级:超过阈值 10% 是“关注”,超过 20% 才是“预警”,而且同一指标在一个小时内最多推送一次。这个经验后来写进了 v0.1.8 的默认配置。
如果你也要做主动推送,请一定记住:加冷却时间,加聚合窗口,否则再聪明的 AI 也会变成噪音制造机。主动推送的核心不是“快”,而是“准”。宁可少推一条,也不要因为误报让用户把整个功能关掉。尤其是语音播报,一旦误报,打扰感极强,用户很可能直接取消授权。
6. 版本迭代的心得和下一步计划
6.1 从 v0.1.x 到 v0.1.8:我踩过的“版本坑”
SwiftBoot 从 v0.1.0 到 v0.1.8,并没有按功能清单一路加,而是反复在“模型能力”和“工程约束”之间做取舍。早期版本把很多逻辑写死在 Prompt 里,升级模型后表现很不稳定;后来逐步把口径、权限、图表类型这些确定性内容从 Prompt 里抽出来,放进语义层和规则引擎。
中间踩过最大的坑,是试图用一个大模型同时做“取数、归因、摘要、建议”四件事。单独看每个任务效果都不差,但组合起来一塌糊涂。原因是大模型多任务时注意力会被分散,尤其是归因和摘要都涉及数字,很容易把不同环节的数字搞混。v0.1.8 里把任务拆成了独立子任务,每个子任务只做一件事,再由编排层串起来。虽然多调了几次接口,但稳定性和可解释性都明显提升。
下一版的方向,我计划做三件事。一是多轮会话的上下文容量管理,不再只保留简单上下文对象,而是引入“查询意图树”,支持更复杂的嵌套提问。二是时序预测,在归因基础上给出未来几天的区间估计。三是把语义层变成可视化配置界面,让非开发者也能够自己维护指标定义。这些功能不会一次性堆进下一个版本,依然按小步快跑的方式验证。
6.2 一点个人实操体会
如果让我总结做 SwiftBoot AI 智能看板 v0.1.8 最值得分享的经验,我会说:先让数据把事实说清楚,再让模型把话说漂亮。现在很多 AI 产品一上来就追求“对话感”,结果模型把数字都编出来了还讲得头头是道。这个项目里,我反而花了大量时间在语义层、权限过滤、归因计算和缓存上,模型只是最后那层“翻译官”。回头看,真正让数据开口说话的,不是模型有多聪明,而是底座有多可靠。
如果你也在做类似的 AI 看板,建议从高频业务问题开始。先挑 20 个业务方最常问的问题,把这些问题对应的查询链路做扎实,再扩展长尾。版本迭代不用着急,稳定一个特性,再放开下一个。v0.1.8 对我来说是一次里程碑,但后面还有很多值得折腾的地方,希望这些经验能帮正在做同类事情的人少走几步弯路。