跳到主要内容

在微信小程序中接入 CloudBase AI(DeepSeek / 混元)

一句话定义:用 wx.cloud.extend.AI.createModel("cloudbase") 在小程序里直接调 CloudBase 平台聚合的 DeepSeek / 混元 / MiniMax / Kimi / GLM 等大模型,model.streamText() 返回 textStream,前端 for await 消费增量文本,不需要自建 OpenAI 代理。

预计耗时:20 分钟 | 难度:入门

适用场景

  • AI 客服、智能搜索、文案/邮件/标题生成、AI 摘要等小程序前端直接喂给用户的轻业务场景
  • 不想自建 LLM 网关、不想买 OpenAI key、不想配公网出口和 SSE 透传
  • 新用户首月赠送 100 万 token 试用,跑 demo 阶段基本不花钱(具体额度以 控制台计费页面 为准)

不适用:

  • 已经有海外 API key(OpenAI、Anthropic)且业务必须用海外模型——走 connect-openai-api-cloud-function 用云函数代理
  • 想做 RAG 检索 / Function Calling / 多轮记忆等复杂编排——这些走 Agent 模式或自建编排层,本篇只覆盖最常见的「直接对话」
  • 输出非常长(> 30 秒持续生成)的场景——小程序前端长连接稳定性弱于云函数,建议拆成多次短调用

环境要求

依赖版本
微信开发者工具1.06.x基础库 ≥ 3.15.1,旧版本不支持 createModel("cloudbase") 统一平台调用)
小程序 AppID已绑定 CloudBase 环境(公众平台 → 云开发 / 设置)
CloudBase 环境已开通,且控制台已开通「AI+」能力

不需要装额外 npm 包,wx.cloud.extend.AI 是基础库内置能力。

第一步:控制台开通 AI 能力 + 选模型

  1. CloudBase 控制台 → 选你的环境 → AI+快速接入
  2. 第一次进会有个「立即开通」按钮,点完会自动给环境注入 AI 调用权限。开通是免费的,调用按 token 计费
  3. 在「模型管理」里能看到当前环境可用的模型列表。CloudBase 通过 Token 资源包统一接入 DeepSeek、MiniMax、混元、Kimi、GLM 等主流模型,官方主推 deepseek-v4-flash(性价比 + 通用对话默认),完整列表见 接入大模型

下文示例统一用 deepseek-v4-flash。换模型只要改代码里 model: 那行,其他不动。

如果只想用 Agent(在控制台先把人设、知识库、function 等编排好的「智能体」),那么去「Agent」面板新建一个,记下生成的 botId-xxx,本篇第四步会用到。

第二步:小程序端初始化 SDK

app.js

// app.js
App({
onLaunch() {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力');
return;
}
wx.cloud.init({
env: 'your-env-id', // 替换成你自己的环境 ID
traceUser: true,
});
},
});

任何页面里直接:

const ai = wx.cloud.extend.AI;

wx.cloud.extend.AI 是基础库给 CloudBase AI 的入口,初始化好 wx.cloud 之后即可用,不需要单独登录——小程序端 wx.cloud 调用本身就带了用户身份。

如果你是 Web / H5 用 @cloudbase/js-sdk(不是小程序),用法不一样,必须先登录拿身份:

import cloudbase from '@cloudbase/js-sdk';
const app = cloudbase.init({ env: 'your-env-id' });
const auth = app.auth();
await auth.signInAnonymously();
const ai = app.ai();

本篇后续示例都默认是小程序端 wx.cloud.extend.AI

第三步:模型直调 —— 流式生成文本

最朴素的对话页面,wxml + js 两个文件:

pages/chat/chat.wxml

<view class="chat">
<scroll-view scroll-y class="messages" scroll-into-view="msg-{{messages.length - 1}}">
<view
wx:for="{{messages}}"
wx:key="index"
id="msg-{{index}}"
class="bubble {{item.role}}"
>
<text>{{item.content}}</text>
</view>
</scroll-view>

<view class="input-bar">
<input
class="input"
value="{{draft}}"
bindinput="onInput"
placeholder="问点什么"
disabled="{{loading}}"
/>
<button bindtap="onSend" disabled="{{loading || !draft}}">
{{loading ? '生成中' : '发送'}}
</button>
</view>
</view>

pages/chat/chat.js

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

Page({
data: {
messages: [],
draft: '',
loading: false,
},

onInput(e) {
this.setData({ draft: e.detail.value });
},

async onSend() {
const userText = this.data.draft.trim();
if (!userText) return;

const messages = this.data.messages.concat([
{ role: 'user', content: userText },
{ role: 'assistant', content: '' }, // 占位,等流式增量填进来
]);

this.setData({
messages,
draft: '',
loading: true,
});

const assistantIdx = messages.length - 1;

try {
const res = await model.streamText({
model: 'deepseek-v4-flash',
messages: messages
.slice(0, -1) // 不要把空 assistant 占位发给模型
.map(({ role, content }) => ({ role, content })),
});

// 关键:节流累积,不要每个 chunk 都 setData
let buffer = '';
let lastFlushAt = 0;

for await (const chunk of res.textStream) {
buffer += chunk;
const now = Date.now();
if (now - lastFlushAt > 80) {
this.flushAssistant(assistantIdx, buffer);
lastFlushAt = now;
}
}
// 收尾刷一次,确保最后几个 chunk 不丢
this.flushAssistant(assistantIdx, buffer);
} catch (err) {
console.error('[ai] streamText failed', err);
this.flushAssistant(assistantIdx, `[出错]${err.errMsg || err.message || err}`);
} finally {
this.setData({ loading: false });
}
},

flushAssistant(idx, content) {
this.setData({
[`messages[${idx}].content`]: content,
});
},
});

几个值得说的细节:

  • model.streamText() 返回一个对象,里面 textStream 是「只吐文字增量」的异步迭代器,dataStream 是「吐完整 chunk 元数据」的异步迭代器。日常对话只关心文字,用 textStream 即可
  • for await (const chunk of res.textStream)chunk 是字符串,每次几个到十几个字。不要在每次循环里都 setData,小程序的 setData 走 native 桥,几十毫秒一次时 UI 就会卡。上面用 80ms 节流够大多数场景了
  • 多轮对话只要把 messages 数组完整传上去,模型会按 OpenAI 风格的 role: user / assistant / system 解释;首条 system 用来塞人设
  • 想换非流式(一次性返回整段),改成 model.generateText(...),拿到的就是 result.text

第四步:进阶 —— 走 Agent 模式

模型直调适合「我自己拼 prompt + messages」的场景。当你想:

  • 在控制台改人设、改知识库挂载、改工具,不发版就生效
  • 让平台自动处理 RAG / 联网搜索 / function calling 这种带「思考」「检索」分层的输出
  • 不同 Agent 给不同角色(客服 Agent / 写作 Agent / 数据分析 Agent)

那就去控制台「AI+ → Agent」建一个 Agent,拿到 botId,前端这样调:

const ai = wx.cloud.extend.AI;

const res = await ai.bot.sendMessage({
botId: 'botId-xxxxxx',
msg: '帮我写一段 CloudBase 的产品介绍',
history: [
{ role: 'user', content: '你是 CloudBase 文档助手' },
],
});

for await (const chunk of res.dataStream) {
// chunk.type 可能是 text / thinking / search / knowledge
// 普通文字回答只取 text
if (chunk.type === 'text') {
console.log(chunk.content);
}
}

Agent 模式的 chunk 结构(res.dataStream 每条):

{
created: 1714000000,
record_id: 'rec-xxx',
model: 'deepseek-v4-flash',
version: '1.0',
type: 'text', // text / thinking / search / knowledge
role: 'assistant',
content: '增量内容',
finish_reasion: 'continue', // 注意:SDK 字段就叫 finish_reasion(平台拼写),不是 finish_reason
usage: { prompt_tokens: 12, completion_tokens: 8, total_tokens: 20 },
}

type 上的几种含义:

  • text:模型最终给用户看的回答增量
  • thinking:思维链(带推理能力的模型如 DeepSeek-R 系列才有),可以选择性渲染成「思考中…」
  • search:联网搜索片段
  • knowledge:命中的知识库片段

如果只想要纯文字,跟模型直调一样用 res.textStream

for await (const text of res.textStream) {
console.log(text);
}

运行验证

  1. 微信开发者工具 → 编译运行 → 调到调试基础库 ≥ 3.15.1
  2. 在 chat 页面输入「用一句话介绍 CloudBase」,点发送
  3. 看 console 不应该有 AI 能力未开通 / model not found / permission denied 类报错
  4. UI 上应该能看到回复一段段冒出来,而不是憋一阵后整段出现
  5. 控制台 → AI+ → 调用记录 / 用量统计,应该能看到刚才那次调用的 token 计数
  6. 真机预览(点开发者工具右上角「预览」),扫码在手机上跑一遍,确认流式渲染在弱网下也行

常见错误

错误信息原因修复
AI 能力未开通 / errCode -501001环境没在控制台 AI+ 开通控制台 → AI+ → 立即开通;开通后等 1~2 分钟函数能力下发
model not found / model xxx is not supported模型 ID 拼错了,或者你环境里这个模型没上架去控制台「模型管理」对照名字,不要照搬 OpenAI / Anthropic 的命名。CloudBase 当前主推 deepseek-v4-flash,完整列表见 接入大模型
createModel is not a function / 模型调用没反应基础库版本 < 3.15.1,不支持 createModel("cloudbase") 统一调用工具 → 详情 → 本地设置,调试基础库升到 3.15.1 或更新
直接 wx.request 调外部 LLM API 报「不在以下 request 合法域名列表中」小程序前端有合法域名白名单不要在小程序里直连境外 LLM API。要么走 CloudBase AI(本篇),要么用 connect-openai-api-cloud-function 代理
流式输出小程序 UI 卡顿 / 掉帧每个 chunk 都 setData 触发渲染像第三步那样按 80ms 节流;或者改成累积 buffer 在 for-await 结束后一次性 setData
for await is not a function调试基础库版本太老(< 3.15.1)或编译选项关闭了 ES2018工具 → 详情 → 本地设置,调试基础库选最新;项目配置 setting.es6 = true
Agent 调用报 botId 不存在控制台建的 Agent 还没发布 / 不是当前环境控制台 → Agent → 状态需要是「已发布」,且 botId 不要带空格或多余引号

错误码完整定义参考 https://docs.cloudbase.net/error-code/

计费提示

  • 新开通环境首月赠送 100 万 token 试用额度(具体以 控制台计费页面 当前披露为准,文档不锁单价)
  • 计费按「输入 token + 输出 token」分别计算,不同模型单价不同;流式调用只是传输方式不同,token 计费跟非流式一致
  • 防刷建议:在小程序前端 onSend 里做客户端节流(比如未拿到上一次响应前禁用按钮,第三步代码里的 loading 标记就是干这个),重要业务在云函数里二次校验调用方身份

相关文档

下一步

跑通之后第一件要做的事是把 messages 数组写进数据库——断点续聊、用户换设备、后续分析都依赖这个,走 add-database-wechat-miniprogram 就够;如果业务要让 AI 答你自己的产品文档/知识库,那就接 add-rag-with-pgvector-cloudbase 把检索片段拼进 messages。