# cloud.ai
支持端:云函数
wx-server-sdk 从 4.0.1 起提供 cloud.ai()。该接口返回底层 @cloudbase/node-sdk 的 AI 实例,用于调用大模型、混元生图和 Agent。
# 初始化
先调用 cloud.init,再取 AI 实例。
云函数中推荐使用当前环境:
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
timeout: 60000,
})
timeout 默认 15000(毫秒)。AI 请求会使用 cloud.init 传入的 timeout;单次 generateText / streamText / sendMessage 也可再传 options.timeout 覆盖。
本地 Node.js 可同时传入环境 ID 和密钥(会转交给 @cloudbase/node-sdk):
const cloud = require('wx-server-sdk')
cloud.init({
env: '<你的环境ID>',
secretId: '<SecretId>',
secretKey: '<SecretKey>',
timeout: 60000,
})
const ai = cloud.ai()
cloud.ai() 需要 wx-server-sdk 4.0.1 或更高版本。
# 大模型
# AI.createModel()
创建文生文模型。返回 ReactModel,提供 generateText、streamText。
# 使用示例
const ai = cloud.ai()
const model = ai.createModel('cloudbase')
内置模型名(命中后走对应实现,忽略 defaultModelSubUrl):
hunyuan、hunyuan-beta、hunyuan-exp、hunyuan-open、deepseek、moonshot、zhipu、dashscope、ark、01-ai。
未命中内置名时(例如 "cloudbase"),走默认实现,请求路径为 {model}{defaultModelSubUrl},即默认 {model}/chat/completions。
具体用哪个对话模型,在 generateText / streamText 的 model 字段里指定(以环境中已开通的为准)。
# 类型声明
function createModel(model: string, options?: { defaultModelSubUrl?: string }): ReactModel
# 参数
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| model | 是 | string | 模型组名称。内置名见上;其他名称走默认路径 |
| options.defaultModelSubUrl | 否 | string | 仅非内置名生效。默认 "/chat/completions" |
# ReactModel.generateText()
非流式生成文本。
# 使用示例
const ai = cloud.ai()
const model = ai.createModel('cloudbase')
const res = await model.generateText({
model: 'hy3-preview',
messages: [{ role: 'user', content: '你好' }],
})
console.log(res.text)
console.log(res.usage)
# 类型声明
function generateText(input: ReactModelInput, options?: { timeout?: number }): Promise<{
text: string
messages: Array<ChatModelMessage>
usage: Usage
rawResponses: Array<unknown>
error?: any
}>
ReactModelInput 在 BaseChatModelInput 上增加了 topP、toolChoice、maxSteps、onStepFinish,并把 tools 扩成 ModelTool | FunctionTool。
interface BaseChatModelInput {
model: string
messages: Array<ChatModelMessage>
temperature?: number
top_p?: number
tools?: Array<ModelTool>
tool_choice?: 'none' | 'auto' | 'custom'
}
未出现在 maxSteps / onStepFinish / topP / toolChoice 中的其余字段会随请求体传给模型。
# 参数
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| input.model | 是 | string | 对话模型名 |
| input.messages | 是 | ChatModelMessage[] | 消息列表 |
| input.temperature | 否 | number | 采样温度 |
| input.topP | 否 | number | 若传入,会写成请求里的 top_p |
| input.top_p | 否 | number | 与 topP 相同含义;topP 优先 |
| input.tools | 否 | Array<ModelTool \| FunctionTool> | 工具列表。带 fn 的项只会把 schema 发给模型,不会自动注册 fn |
| input.toolChoice | 否 | "none" \| "auto" \| "custom" | 若传入,会写成请求里的 tool_choice |
| input.tool_choice | 否 | "none" \| "auto" \| "custom" | 与 toolChoice 相同含义;toolChoice 优先 |
| input.maxSteps | 否 | number | 自动执行 tool call 的最大轮数,默认 10,必须 >= 1 |
| input.onStepFinish | 否 | (prop: IOnStepFinish) => unknown | 每一轮模型请求结束时的回调 |
| options.timeout | 否 | number | 本次请求超时(毫秒) |
自动执行工具前必须先调用 ai.registerFunctionTool,把同名 fn 写入内部 toolMap。只把带 fn 的对象放进 tools 不够。
# 返回值
| 属性名 | 类型 | 说明 |
|---|---|---|
| text | string | 最后一轮助手消息的 content,没有则为 '' |
| messages | ChatModelMessage[] | 调用结束后的消息列表 |
| usage | Usage | 各轮 token 累加 |
| rawResponses | unknown[] | 各轮原始响应 |
| error | any | 工具执行抛错时返回,此时 text 为 '' |
# ReactModel.streamText()
流式生成文本。SSE 会被封装成 textStream 和 dataStream。
# 使用示例
const ai = cloud.ai()
const model = ai.createModel('cloudbase')
const res = await model.streamText({
model: 'hy3-preview',
messages: [{ role: 'user', content: 'hi' }],
})
for await (const str of res.textStream) {
console.log(str)
}
for await (const data of res.dataStream) {
console.log(data)
}
const messages = await res.messages
const usage = await res.usage
textStream 的增量来自 chunk.choices[0].delta.content(仅当该值为 string 时入队)。
# 类型声明
function streamText(input: ReactModelInput, options?: { timeout?: number }): Promise<{
dataStream: AsyncIterable<BaseDoStreamOutputChunk & { rawResponse?: any }>
textStream: AsyncIterable<string>
messages: Promise<Array<ChatModelMessage>>
usage: Promise<Usage>
error?: any
}>
# 参数
与 generateText() 相同。
# 返回值
| 属性名 | 类型 | 说明 |
|---|---|---|
| textStream | AsyncIterable<string> | 增量文本 |
| dataStream | AsyncIterable | 解析后的 SSE JSON 片段 |
| messages | Promise<ChatModelMessage[]> | 结束后的消息列表 |
| usage | Promise<Usage> | token 用量 |
| error | any | 工具执行抛错时存在 |
dataStream 元素的类型字段:
| 属性名 | 类型 | 说明 |
|---|---|---|
| choices | Array | 可选 |
| choices[n].finish_reason | string | 可选。工具调用时为 "tool_calls" |
| choices[n].delta | ChatModelMessage | 可选。本次增量 |
| usage | Usage | 可选 |
| rawResponse | any | 可选。该片段的原始对象 |
# AI.registerFunctionTool()
把工具函数登记到内部 toolMap。模型返回 tool call 后,SDK 用 toolMap.get(name)(JSON.parse(arguments)) 执行。
# 使用示例
const ai = cloud.ai()
const getWeatherTool = {
name: 'get_weather',
description: "返回某个城市某天的温度。调用示例:get_weather({city: '北京', date: '03-19'})",
fn: ({ city, date }) => `${city}在${date}的温度是:${20 + Math.random() * 10}`,
parameters: {
type: 'object',
properties: {
city: { type: 'string', description: '要查询的城市' },
date: { type: 'string', description: '要查询的日期' },
},
required: ['city', 'date'],
},
}
ai.registerFunctionTool(getWeatherTool)
const model = ai.createModel('cloudbase')
const result = await model.generateText({
model: 'hy3-preview',
tools: [getWeatherTool],
messages: [{ role: 'user', content: '请告诉我北京今天的天气' }],
})
console.log(result.text)
同名工具重复注册会 console.warn 并覆盖。
# 类型声明
function registerFunctionTool(functionTool: FunctionTool): void
type FunctionTool = {
name: string
description: string
fn: CallableFunction
parameters: object
}
type ModelTool = {
type: string
function: {
name: string
description: string
parameters: object
}
}
# 参数
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| functionTool.name | 是 | string | 工具名,对应 toolMap 的 key |
| functionTool.description | 是 | string | 工具描述 |
| functionTool.fn | 是 | function | 实际执行函数 |
| functionTool.parameters | 是 | object | 入参 JSON Schema |
# 生图
生图只在云函数 / Node.js 服务端通过 wx-server-sdk 调用。
当前可用模型:
| 能力 | model |
|---|---|
| 文生图 | HY-Image-3.0-Plus-4090-Tob-v1.0 |
| 图生图 | HY-Image-v3.0-I2I-ToB-v1.0.1 |
以下模型已下线,不要再传:hunyuan-image、hunyuan-image-v3.0-v1.0.4、hunyuan-image-v3.0-v1.0.1。对应的 HunyuanGenerateImageInput 也不再使用。
# AI.createImageModel()
创建指定的 AI 图像生成模型。返回 DefaultImageModel 实例(文档里也称 ImageModel),提供 generateImage。
# 使用示例
const ai = cloud.ai()
const imageModel = ai.createImageModel('hunyuan-image')
# 类型声明
function createImageModel<T extends 'hunyuan-image' | (string & {})>(provider: T): DefaultImageModel<T>
# 参数
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| provider | 是 | string | 模型提供方标识。混元生图传 "hunyuan-image" |
# DefaultImageModel.generateImage()
根据 input.model 选择请求子路径,再把 input 作为请求体发送。
完整 URL 为 {aiBaseUrl}/{provider}/{subUrl}。subUrl 来自 generateImageSubUrlConfig[provider][model],未命中则用默认值 images/generations。
# 文生图
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
timeout: 150000,
})
exports.main = async (event) => {
const ai = cloud.ai()
const imageModel = ai.createImageModel('hunyuan-image')
const res = await imageModel.generateImage({
model: 'HY-Image-3.0-Plus-4090-Tob-v1.0',
prompt: '一只胖胖的橘猫坐在窗台上打盹,水彩风格,温暖色调',
size: '1024x1024',
seed: 42,
footnote: 'Generated by Cloudbase',
revise: { value: true },
enable_thinking: { value: false },
})
console.log(res.data[0].url)
console.log(res.data[0].revised_prompt)
return { url: res.data[0].url }
}
# 图生图
image_urls 与 images 二选一,用于传入垫图。
const res = await imageModel.generateImage({
model: 'HY-Image-v3.0-I2I-ToB-v1.0.1',
prompt: '把猫咪改成水彩风格',
image_urls: ['https://example.com/cat.jpg'],
revise: { value: true },
})
console.log(res.data[0].url)
console.log(res.data[0].revised_prompt)
也可以传 images(垫图 base64 列表)代替 image_urls。
# 类型声明
function generateImage(input: HunyuanARGenerateImageInput): Promise<HunyuanARGenerateImageOutput>
# 参数
| 参数名 | 必填 | 类型 | 说明 |
|---|---|---|---|
| model | 是 | string | 文生图用 "HY-Image-3.0-Plus-4090-Tob-v1.0",图生图用 "HY-Image-v3.0-I2I-ToB-v1.0.1" |
| prompt | 是 | string | 用于生成图片的文本 |
| size | 否 | string | 图片尺寸,格式 "${宽}x${高}" |
| seed | 否 | number | 生成种子 |
| footnote | 否 | string | 水印 |
| revise | 否 | { value: boolean } | 是否改写 prompt |
| enable_thinking | 否 | { value: boolean } | 改写是否开启 thinking 模式 |
| image_urls | 否 | string[] | 图生图垫图 URL 列表,与 images 二选一 |
| images | 否 | string[] | 图生图垫图 base64 列表,与 image_urls 二选一 |
# 返回值
| 属性名 | 类型 | 说明 |
|---|---|---|
| id | string | 此次请求的 id |
| created | number | unix 时间戳 |
| data | Array | 返回的图片生成内容 |
| data[n].url | string | 生成的图片 url |
| data[n].revised_prompt | string | 可选。改写后的 prompt |
把生成结果上传到云存储时,cloud.uploadFile 的入参为 cloudPath、fileContent(Buffer 或 ReadStream),成功时返回 fileID:
const https = require('https')
function downloadImage(url) {
return new Promise((resolve, reject) => {
https.get(url, (response) => {
const chunks = []
response.on('data', (chunk) => chunks.push(chunk))
response.on('end', () => resolve(Buffer.concat(chunks)))
response.on('error', reject)
})
})
}
exports.main = async (event) => {
const imageModel = cloud.ai().createImageModel('hunyuan-image')
const res = await imageModel.generateImage({
model: 'HY-Image-3.0-Plus-4090-Tob-v1.0',
prompt: event.prompt,
})
const imageBuffer = await downloadImage(res.data[0].url)
const uploadRes = await cloud.uploadFile({
cloudPath: `ai-images/${Date.now()}.jpg`,
fileContent: imageBuffer,
})
return { fileID: uploadRes.fileID }
}
# Agent
# AI.bot.sendMessage()
与 Agent 对话。请求 POST 到 {aiBotBaseUrl}/bots/{botId}/send-message,body 为 props,stream: true。
本 SDK 类型里,sendMessage 只声明了 botId、msg、history。
# 使用示例
const ai = cloud.ai()
const res = await ai.bot.sendMessage({
botId: 'botId-xxx',
msg: '你好',
history: [{ role: 'user', content: '你是李白。' }],
})
for await (const str of res.textStream) {
console.log(str)
}
for await (const data of res.dataStream) {
console.log(data)
}
textStream 的增量来自 dataStream 各项的 content(没有则为 '')。遇到 SSE 数据为 "[DONE]" 时结束 dataStream。
# 类型声明
function sendMessage(props: IBotSendMessage, options?: { timeout?: number }): Promise<StreamResult>
interface IBotSendMessage {
botId: string
msg: string
history: Array<{
role: string
content: string
}>
}
// dataStream 元素
type BotEventStreamData = {
content: string
}
// eventSourceStream 元素
interface ParsedEvent {
type: 'event'
event?: string
id?: string
data: string
}
StreamResult 提供:
| 属性名 | 类型 | 说明 |
|---|---|---|
| eventSourceStream | AsyncIterable<ParsedEvent> | 解析后的 SSE 事件 |
| dataStream | AsyncIterable<{ content: string }> | 将 ParsedEvent.data JSON.parse 后的对象 |
| textStream | AsyncIterable<string> | content 字段组成的文本流 |
# 参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| props.botId | string | 是 | Agent ID,用于拼 URL |
| props.msg | string | 是 | 本次消息 |
| props.history | Array<{ role: string, content: string }> | 是 | 历史消息 |
| props.history[n].role | string | 是 | 角色 |
| props.history[n].content | string | 是 | 内容 |
| options.timeout | number | 否 | 本次请求超时(毫秒) |
# 类型定义
# ChatModelMessage
type UserMessage = { role: 'user'; content: string }
type SystemMessage = { role: 'system'; content: string }
type PlainAssistantMessage = { role: 'assistant'; content: string }
type ToolCallAssistantMessage = {
role: 'assistant'
tool_calls: Array<ToolCall>
content?: string
}
type AssistantMessage = PlainAssistantMessage | ToolCallAssistantMessage
type ToolMessage = { role: 'tool'; tool_call_id: string; content: string }
type ChatModelMessage = UserMessage | SystemMessage | AssistantMessage | ToolMessage
# ToolCall
type ToolCall = {
id: string
type: string
function: {
name: string
arguments: string
}
}
# Usage
type Usage = {
completion_tokens: number
prompt_tokens: number
total_tokens: number
}
# IOnStepFinish
interface IOnStepFinish {
messages: Array<ChatModelMessage>
text?: string
toolCall?: ToolCall
toolResult?: unknown
finishReason?: string
stepUsage?: Usage
totalUsage?: Usage
}
# 完整云函数示例
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
timeout: 60000,
})
exports.main = async (event) => {
const ai = cloud.ai()
const { type, messages, prompt } = event
if (type === 'image') {
const imageModel = ai.createImageModel('hunyuan-image')
const res = await imageModel.generateImage({
model: 'HY-Image-3.0-Plus-4090-Tob-v1.0',
prompt: prompt || '一只可爱的猫咪在草地上玩耍',
})
return { url: res.data[0].url }
}
const model = ai.createModel('cloudbase')
const result = await model.generateText({
model: 'hy3-preview',
messages: messages || [{ role: 'user', content: '你好' }],
})
return { text: result.text, usage: result.usage }
}