小程序 AI 流式输出的难点不在调用模型,而在三层约束同时生效:传输层没有浏览器那套可读流,渲染层每写一次数据都要过一次原生桥,能力层又按基础库版本灰度下发。下面按这三层拆开,最后给一套从报错到卡顿的排查顺序。
一、传输层:只有分块和切帧
浏览器接大模型的标准姿势,是拿到可读流逐块消费。小程序发起请求时没有对应的流式响应类型,工程上能做的是分块传输加自己切帧:打开分块开关,在回调里拿到二进制缓冲,再按流式协议的帧边界把字节流重新拼成数据段。
跨端框架下也没有统一解法:小程序端只能走请求分块,网页端和客户端才有原生的流式读取,同一套业务代码落到不同端,跑的是两套传输实现。跨端项目要把这层差异单独测一遍,H5 上的流畅度不能直接当小程序的结论。
如果项目本来就在微信云开发里,还有更省事的一条:平台内置的 AI 能力可以直接拿到文本增量的异步迭代器,协议解析交给平台。代价是模型网关、密钥和调用配额一起绑在平台上。
| 路线 | 流式协议谁解析 | 前端改动量 | 断流可控性 | 适合 |
|---|---|---|---|---|
| 平台内置流式 | 平台内部 | 最小,直接取增量 | 中,依赖平台长连接 | 已在云开发里、要快速上线 |
| 前端自行分块 | 自己按帧切缓冲 | 最大,要处理缓冲与重连 | 高,超时与重试自己定 | 已有后端网关、要求可控降级 |
| 长连接自建 | 服务端推送 | 中,需鉴权与心跳 | 高,连接维护成本高 | 多轮长会话、需服务端主动中断 |
三条路线在各项目约束下怎么取舍,站内另一篇小程序集成 AI 能力的落地场景与架构选型给过按场景比较的口径,可以先对齐再动手。

二、渲染层:观感由提交频率决定
官方接入文档把这件事写成了明确警告:「不要在每次循环里都 setData,小程序的 setData 走 native 桥,几十毫秒一次时 UI 就会卡。上面用 80ms 节流够大多数场景了」。这句话基本定死了实现方式:分块到达不是渲染单位,提交频率才是。
做法可以拆成四步,全部围绕「减少跨层调用」:
- 收到的增量先拼进内存字符串,不直接触发渲染;
- 用一个固定间隔的定时器做批量提交,定时器在途时不重复创建;
- 提交时只写当前这条消息的文本字段路径,不替换整个消息数组;
- 提交完立刻清空缓冲,避免同一段文字被渲染两次。
80 毫秒大约等于每秒十余次文本刷新,肉眼看已经是连续打字效果,而写数据的调用次数被压到分块数的一个零头。想更跟手可以降到 50 毫秒,但必须重新真机测一遍,开发者工具里的流畅度不能作准。
另一项容易被忽略的浪费是滚动定位。不要每次到达都去改滚动锚点,只在新增一条消息时设置一次,否则长回答过程中列表会被反复拉到底部,回看上文很费劲。
三、版本层:基础库不到 3.15.1 就是一行报错
门槛写在接入文档上:基础库低于 3.15.1 时不支持 createModel("cloudbase") 统一平台调用,线上表现是一句「不是函数」的类型报错。这类问题不会在构建期暴露,只在低版本机型上出现。
版本号也不能当字符串直接比:按字符串比较,「3.9.0」会被判成大于「3.15.1」,判断分支就整体走反。要按点切成数字逐段比较,这个函数不依赖任何平台接口,放进公共工具里连单元测试都好写。
const SDK = wx.getSystemInfoSync().SDKVersion;
const canStream = compareVersion(SDK, '3.15.1'); // 低于它就走一次性返回
探测失败就走一次性返回。同一份文档的说法是:「想换非流式(一次性返回整段),改成 model.generateText(...),拿到的就是 result.text」。界面上把打字机换成「正在生成」的进度态,同时把等待上限放宽。
自建路线同样要探测:分块开关也是按版本下发的,不是所有运行环境都能稳定拿到回调。基础库版本、客户端版本、容器环境三者都会改变结果,别只测开发者工具。
四、断流:超过 30 秒的输出别指望一条连接跑完
官方文档对长输出的建议是拆:「输出非常长(> 30 秒持续生成)的场景——小程序前端长连接稳定性弱于云函数,建议拆成多次短调用」。这条建议直接决定产品形态:长文生成要做成分段续写,而不是一个转圈到底。
三条落地策略,按实施成本排序:
- 一次回答拆成 2 到 3 段生成,每段结束把已生成文本落本地存储,续写时把上文摘要一并带上;
- 增量文字只留在内存,历史文本落本地存储,两者分开存,避免每块到达都写一次磁盘;
- 超时上限到了就停止转圈,给「继续」「重新生成」两个明确按钮,不让用户去猜发生了什么。
小程序还有切后台的干扰。切到后台之后不能假设分块依然连续到达,回到前台时要做一次状态对齐:拉一次服务端已生成结果,跟本地文本比对后决定继续渲染还是收尾。少了这一步,用户切个微信回来就会看到半句话卡在屏幕上。
分段还会直接抬高调用次数,成本口径要跟着改。小程序 AI 开发成本拆解把那部分归进了容易漏算的隐性支出。
五、可渲染性:先解决样式再谈打字机
流式文本最终要落到渲染组件上,而小程序的富文本组件对样式的支持是有条件的。那篇跨端实战记了两个具体坑:标签选择器失效时,把富文本组件换成能注入自定义样式的第三方组件;表格边框线丢失时,用内联边框配合合并边框的写法兜底。
取舍是:流式过程中只渲染纯文本和少量行内样式,表格、代码块这类块级结构等整帧到达后再一次性替换。中途拿半截标记语言去解析,得到的往往是错位标签和不断跳动的布局,用户会以为页面坏了。
这条取舍还有一个隐性好处:解析次数少了,写数据的次数也跟着少,前面那套节流策略才不会被块级结构反复打破。
六、上线前的一份验收清单
按顺序过一遍,每一项都要能说清通过或不通过的证据,而不是靠感觉点头。如果这块前端代码本来就是 AI 帮着写的,AI Coding 落地小程序的成本测算里的验收口径可以直接搬过来用。
- 能力探测:在低版本基础库的真机上,平台接口与分块开关是否都进了降级分支;
- 提交频率:统计写数据的调用次数,与分块到达次数对比,比例应明显小于一;
- 首块体验:首块到达前显示加载态,到达后立刻出字,中间没有空白闪烁;
- 断流兜底:中途开飞行模式切断网络,页面在超时后给出可操作按钮;
- 切后台恢复:切出十秒后回到前台,文本状态与历史记录一致;
- 长输出:单次生成超过 30 秒时分段策略生效,第二轮不丢上文;
- 样式兜底:标记语言里的表格、代码块在真机上边框与换行正确;
- 日志:每条对话带请求标识,能按标识回查服务端是否完整生成过。
七、从现象倒推:四类问题的排查顺序
线上收到反馈时,先按现象归类,比漫无目的地翻日志快得多。
- 冒出一句「不是函数」:能力层问题,先查基础库版本和降级分支,不要怀疑网络;
- 转圈结束后一次性吐出整段:分块开关没生效或响应头不对,抓包看有没有分块到达;
- 有字但整屏跳动、列表抽动:渲染频率问题,看写数据次数与分块数的比例;
- 答到一半停住又不报错:断流,查超时设置、前后台切换与续写状态。
处理顺序也有讲究:先修能力层,再修传输层,最后才动渲染层。能力层不通时,任何观感优化都是白做;渲染调优最费联调时间,放最后才不会被前面的改动反复推翻。
八、常见问题
问:小程序能做出那种逐字输出效果吗?
能做出视觉上的逐字效果,但机制不同:分块到达加前端按固定间隔批量渲染,不是浏览器可读流的原生流。评价指标应该是首块到达时间和刷新频率,而不是有没有打字动画。
问:平台内置流式和自己分块,怎么选?
看你要不要把模型网关和密钥交出去。前者省掉协议解析和重连维护,但版本门槛硬;后者可控性更高,代价是缓冲、切帧、超时全部自己扛,联调期至少多一轮真机测试。
问:基础库版本低的老机型怎么办?
探测后走一次性返回的接口,界面换成进度态并把等待上限放宽。不要用前端假打字机去掩盖一次性的长等待,用户会以为是网络卡了而不是模型在生成。
问:断流后要不要自动重试?
长输出建议分段加手动续写,重试交给用户触发。自动重放会让同一段上文被重复请求,成本核算和多轮上下文都难对齐,也容易出现重复文本。
如果你正在深圳或粤港澳大湾区推进小程序 AI 落地,卡在流式体验或审核节奏上,可以把现有架构发给我们过一遍:联系我们。已上线的同类交付结构可以在案例页里看到端侧与周期的分布;本地交付的常见约束与做法,另外整理在深圳软件开发专题;整体从选型到落地的路径,可以对照2026 企业 AI 应用开发实战指南一起看。
