# cloud.ai

支持端:云函数

wx-server-sdk4.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,提供 generateTextstreamText

# 使用示例

const ai = cloud.ai()
const model = ai.createModel('cloudbase')

内置模型名(命中后走对应实现,忽略 defaultModelSubUrl):

hunyuanhunyuan-betahunyuan-exphunyuan-opendeepseekmoonshotzhipudashscopeark01-ai

未命中内置名时(例如 "cloudbase"),走默认实现,请求路径为 {model}{defaultModelSubUrl},即默认 {model}/chat/completions

具体用哪个对话模型,在 generateText / streamTextmodel 字段里指定(以环境中已开通的为准)。

# 类型声明

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
}>

ReactModelInputBaseChatModelInput 上增加了 topPtoolChoicemaxStepsonStepFinish,并把 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 会被封装成 textStreamdataStream

# 使用示例

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-imagehunyuan-image-v3.0-v1.0.4hunyuan-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_urlsimages 二选一,用于传入垫图。

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 的入参为 cloudPathfileContentBufferReadStream),成功时返回 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 为 propsstream: true

本 SDK 类型里,sendMessage 只声明了 botIdmsghistory

# 使用示例

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 }
}