# 流式输出

流式输出可以让 AI 的回复像打字一样逐字显示,而不是等全部生成完才展示,显著提升用户体验。

# 基本用法

使用 streamText() 进行流式调用,通过 textStream 逐步获取文本:

const model = wx.cloud.extend.AI.createModel("cloudbase");

const res = await model.streamText({
    data: {
        model: "hy3-preview",
        messages: [{role: "user", content: "介绍一下云开发"}],
    },
});

let fullText = "";
for await (const text of res.textStream) {
    fullText += text;
    console.log("当前文本:", fullText);
}

# 在小程序中实时更新 UI

流式输出的核心场景是实时更新页面显示:

Page({
  data: {
    answer: "",
    isLoading: false,
  },

  async askAI() {
    this.setData({ answer: "", isLoading: true });

    try {
      const model = wx.cloud.extend.AI.createModel("cloudbase");

      const res = await model.streamText({
        data: {
          model: "hy3-preview",
          messages: [{ role: "user", content: "写一首关于春天的诗" }],
        },
      });

      let answer = "";
      for await (const text of res.textStream) {
        answer += text;
        this.setData({ answer });
      }
    } catch (error) {
      console.error("调用失败:", error);
    } finally {
      this.setData({ isLoading: false });
    }
  },
});

对应的 WXML:

<view class="container">
  <view class="answer">{{answer}}</view>
  <button bindtap="askAI" disabled="{{isLoading}}">
    {{isLoading ? '生成中...' : '开始生成'}}
  </button>
</view>

# 使用 eventStream 获取完整数据

textStream 只返回文本片段,如果需要获取完整的 SSE 事件数据(如 token 使用量、finish_reason 等),使用 eventStream

const res = await model.streamText({
  data: {
    model: "hy3-preview",
    messages: [{ role: "user", content: "你好" }],
  },
});

for await (const event of res.eventStream) {
  if (event.data === "[DONE]") {
    console.log("流式传输结束");
    break;
  }

  const data = JSON.parse(event.data);
  const delta = data.choices[0]?.delta;

  if (delta?.content) {
    console.log("文本片段:", delta.content);
  }
}

# 检测流结束

for await (const text of res.textStream) {
  console.log(text);
}
// textStream 循环结束后,流式传输已完成
console.log("流式传输结束");

或者通过 eventStream 检测 [DONE] 信号:

for await (const event of res.eventStream) {
  if (event.data === "[DONE]") {
    break;
  }
}

# 超时处理

流式调用耗时较长,建议在 app.json 中配置全局超时时间:

{
  "networkTimeout": {
    "request": 600000
  }
}

# 注意事项

  1. textStreameventStream 不能同时消费:一个响应只能选择其中一种方式读取
  2. setData 频率:小程序的 setData 频率过高可能影响性能,可考虑合并多次文本片段后再更新
  3. 用户中断:用户离开页面时,流式请求仍会继续,建议在 onUnload 中处理