Skip to content

微信小程序 SDK

@hxsyai/aiadp-miniprogram 是 AI 应用开发平台 OpenAPI 的微信小程序 SDK。它提供与 TypeScript SDK 一致的业务命名空间,并使用 wx.requestwx.uploadFilewx.downloadFilewx.connectSocket 适配小程序运行环境。

SDK 负责请求封装、字段转换、分块 SSE、WebSocket、类型和错误处理;微信登录、令牌刷新、凭据保存、录音、播放和页面渲染由接入方负责。

环境要求

接入前需要准备:

  • OpenAPI 地址:https://runtime-api.invalid/v1/openapi
  • 平台签发的 API Key 或业务侧短期访问令牌
  • 支持 enableChunkedRequestTask.onChunkReceivedSocketTask 的微信小程序基础库

凭据安全

不要把 AppSecret、管理员令牌、长期高权限 API Key 或 Nexus 发布凭据写入小程序代码。小程序包可以被下载和分析,应由业务登录流程换取受限、短期的访问凭据。

安装

SDK 发布在公司 Nexus npm 仓库。在小程序项目的 .npmrc 中配置只读仓库:

ini
@hxsyai:registry=https://repo.i.huaxisy.com/repository/npm-releases/

安装最新版本:

bash
npm install @hxsyai/aiadp-miniprogram

安装后,在微信开发者工具中执行“工具 → 构建 npm”。业务代码只需从包入口导入,不要直接引用包内 dist 文件:

ts
import { Client } from "@hxsyai/aiadp-miniprogram";

创建客户端

ts
import { Client } from "@hxsyai/aiadp-miniprogram";

const client = new Client({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  auth: async () => ({
    Authorization: `Bearer ${await getAccessToken()}`,
  }),
  timeout: 30_000,
  streamConnectTimeout: 10_000,
  streamRequestTimeout: 30 * 60 * 1000,
  webSocketConnectTimeout: 10_000,
});

auth(context) 会在每次 HTTP、SSE 或 WebSocket 请求前执行,可以接入业务侧已有的登录态和令牌刷新流程。它可返回普通对象或 Promise,context 包含 methodpathoperation 和重试次数 attempt

固定请求头也可以通过 headers 配置,但不适合需要刷新的令牌:

ts
const client = new Client({
  baseUrl: "https://runtime-api.invalid/v1/openapi",
  headers: {
    Authorization: `Bearer ${accessToken}`,
  },
});

普通 API

appschatknowledgeworkflowthirdparty 与 TypeScript SDK 使用相同的方法、请求类型和响应类型。例如查询应用:

ts
const result = await client.apps.list({
  appType: 2,
  keyword: "助手",
  page: 1,
  pageSize: 10,
});

for (const app of result.items) {
  console.log(app.id, app.name, app.appType);
}

SDK 对外统一使用 camelCase,发送给 OpenAPI 时自动转换为接口字段。

Agent / AgentLite 流式对话

先绑定应用类型、应用 ID 和业务用户 ID:

ts
const agent = client.chat.bind({
  appType: "agent", // AgentLite 使用 "agentLite"
  appId: "<your-app-id>",
  userId: "user-1",
});

原始事件

sendMessagesStream() 默认返回 raw 原始事件:

ts
const stream = await agent.sendMessagesStream(
  { query: "你好" },
  { outputMode: "raw", idleTimeout: 30_000 },
);

try {
  for await (const event of stream) {
    if (event.type === "chunk") {
      console.log(event.data.content);
    }

    if (event.type === "interrupt") {
      console.log("等待用户操作", event.data);
    }
  }
} finally {
  await stream.close();
}

不传 outputMode 时同样默认为 raw。原始流包含正文、思考、工具调用、子 Agent、沙箱、Token 用量、打断、完成和失败等强类型事件。

聚合消息

页面希望直接获得可渲染消息时,使用 aggregate

ts
const stream = await agent.sendMessagesStream(
  { query: "你好" },
  { outputMode: "aggregate", idleTimeout: 30_000 },
);

try {
  for await (const { event, message } of stream) {
    renderMessage(message);
    // event 仍保留,可用于 TTS、HITL 等需要原始事件的场景
  }
} finally {
  await stream.close();
}

message 会持续累积 contentthinkingitemstoolCallssubAgentsusage。它与 client.chat.history() 返回的消息结构一致。

页面更新

SSE 事件可能到达得很频繁。不要每收到一个 token 就调用一次 setData,应在页面层按时间窗口或字符数量节流,避免频繁渲染影响真机性能。

停止、恢复与断流重连

停止当前任务:

ts
await client.chat.stop(taskId);

收到 interrupt 事件后,由页面收集用户输入,再显式恢复:

ts
const resumed = await agent.resumeStream({
  conversationId: interruptEvent.conversationId,
  checkpointId: interruptEvent.data.checkpointId,
  responses: {
    [interruptEvent.data.interrupts[0].interruptId]: {
      type: "confirm",
      confirm: true,
    },
  },
});

SDK 不会自动重连。业务方应保存 taskIdstream.lastEventId,确认需要恢复后调用:

ts
const reconnected = await agent.reconnectStream({
  taskId,
  lastEventId: stream.lastEventId,
});

resumeStream()reconnectStream() 同样支持 rawaggregate。聚合模式需要延续上一段消息时,传入 initialMessage: stream.message

文本生成

文本生成应用支持阻塞与流式调用:

ts
const text = client.chat.bind({
  appType: "textCompletion",
  appId: "<your-app-id>",
  userId: "user-1",
});

const result = await text.sendMessages({
  input: {
    title: "季度报告",
    tone: "正式",
  },
});

console.log(result.output.content);
ts
const stream = await text.sendMessagesStream(
  { input: { title: "季度报告", tone: "正式" } },
  { outputMode: "raw" },
);

try {
  for await (const event of stream) {
    if (event.type === "chunk") console.log(event.data.content);
  }
} finally {
  await stream.close();
}

文本生成流也可以使用 { outputMode: "aggregate" },并支持 records()recordDetail() 查询生成记录。

工作流

阻塞执行:

ts
const result = await client.workflow.invoke({
  workflowId: "<workflow-id>",
  input: { question: "总结检查结果" },
});

console.log(result.finalOutput);

流式执行:

ts
const stream = await client.workflow.invokeStream(
  {
    workflowId: "<workflow-id>",
    input: { question: "总结检查结果" },
  },
  { idleTimeout: 30_000 },
);

try {
  for await (const event of stream) {
    console.log(event.type, event.data);
  }
} finally {
  await stream.close();
}

文件上传与下载

小程序不能使用浏览器 BlobFormData 上传本地文件。先通过微信 API 获得本地临时路径,再传给 SDK:

ts
const chooseResult = await wx.chooseMessageFile({
  count: 1,
  type: "file",
});

const selected = chooseResult.tempFiles[0];
const file = await client.files.upload({
  userId: "user-1",
  filePath: selected.path,
  fileName: selected.name,
  path: `/reports/${selected.name}`,
});

console.log(file.path);

wx.uploadFile 不能像浏览器 FormData 一样单独指定 multipart 文件名,因此 SDK 会额外发送 file_name 表单字段。

下载返回微信临时文件路径:

ts
const download = await client.files.download({
  userId: "user-1",
  path: "/reports/report.pdf",
});

console.log(download.tempFilePath);
wx.openDocument({ filePath: download.tempFilePath });

tempFilePath 由微信管理,需要长期保存时,请使用微信文件系统 API 复制到业务目录。

分片上传

ts
const initialized = await client.files.multipart.init({
  userId: "user-1",
  path: "/reports/archive.zip",
  totalChunks: chunkFilePaths.length,
});

const parts = [];
for (let index = 0; index < chunkFilePaths.length; index += 1) {
  parts.push(await client.files.multipart.part({
    userId: "user-1",
    path: "/reports/archive.zip",
    uploadId: initialized.uploadId,
    partNumber: index + 1,
    filePath: chunkFilePaths[index],
  }));
}

await client.files.multipart.complete({
  userId: "user-1",
  path: "/reports/archive.zip",
  uploadId: initialized.uploadId,
  parts,
});

SDK 负责分片接口通信,不负责把一个大文件切成多个本地临时文件;切片过程由接入方结合微信文件系统 API 完成。

语音

非流式 TTS/STT 与 TypeScript SDK 参数一致:

ts
const synthesized = await client.voice.synthesize({
  provider: "provider-id",
  text: "检查结果正常",
  voiceCode: "voice-code",
  format: "mp3",
});

const recognized = await client.voice.recognize({
  provider: "provider-id",
  audioData: base64Audio,
  sampleRate: 16_000,
});

流式语音使用 wx.connectSocket()。SDK 负责鉴权、连接、音频帧和错误处理;麦克风授权、录音采样和播放由接入方负责。

ts
const session = await client.voice.recognizeStream(
  {
    provider: "provider-id",
    sampleRate: 16_000,
  },
  { connectTimeout: 10_000 },
);

session.sendAudio(frameArrayBuffer);

for await (const result of session) {
  console.log(result.text, result.isFinal);
}

页面卸载或不再使用时应关闭会话:

ts
await session.close();

超时、取消与重试

普通 HTTP 方法支持请求级超时、取消、请求头覆盖和重试选项:

ts
const controller = new AbortController();

const request = client.apps.list(
  { page: 1, pageSize: 10 },
  {
    signal: controller.signal,
    timeout: 15_000,
    retry: { maxRetries: 2, baseDelay: 500 },
  },
);

controller.abort();
await request;

只读、可重试请求默认在网络错误或 502503504 时重试;发送消息、上传等非幂等请求不会自动重试。

流式请求还支持:

  • connectTimeout:等待响应头或首个分块的时间,默认 10 秒;
  • idleTimeout:连接建立后等待下一条完整 SSE 事件的时间,默认关闭;
  • streamRequestTimeout:单次微信分块请求的总生命周期,客户端默认 30 分钟;
  • signal:取消后调用对应微信任务的 abort()

如果目标基础库没有原生 AbortController,可以传入符合 SDK AbortSignalLike 接口的实现。

错误处理

ts
import {
  AiAdpError,
  AbortError,
  TimeoutError,
} from "@hxsyai/aiadp-miniprogram";

try {
  await client.apps.list();
} catch (error) {
  if (error instanceof TimeoutError) {
    console.error("请求超时");
  } else if (error instanceof AbortError) {
    console.error("请求已取消");
  } else if (error instanceof AiAdpError) {
    console.error({
      kind: error.kind,
      operation: error.operation,
      httpStatus: error.httpStatus,
      code: error.code,
      traceId: error.traceId,
    });
  } else {
    throw error;
  }
}

kind 可能为 configurationapihttptransporttimeoutabortdecodestreamunsupported_runtime

小程序后台配置

在微信公众平台分别配置实际使用的合法域名:

微信网络能力SDK 用途
request 合法域名普通 API、Chat SSE、Workflow SSE
uploadFile 合法域名普通上传、分片上传
downloadFile 合法域名文件和目录下载
socket 合法域名流式 TTS/STT

正式环境必须使用 HTTPS 和 WSS。流式接口所在网关需要关闭响应缓冲,否则客户端可能在请求结束后一次性收到全部事件。

Chat 和 Workflow 流默认关闭 HTTP/2,以减少不同真机的分块兼容差异。确认目标基础库和网关兼容后,可以在客户端设置 streamEnableHttp2: true

小程序进入后台后,网络任务可能被暂停或断开。建议:

  • 页面卸载时关闭 Chat、Workflow 和语音流;
  • 保存业务需要的 taskIdlastEventId 和聚合消息;
  • 页面恢复后根据任务状态显式调用 reconnectStream(),不要无限自动重试;
  • 将网络错误与主动取消分别提示。

与 TypeScript SDK 的差异

业务命名空间、普通接口、Chat 事件和 Workflow 事件保持一致,平台相关能力使用小程序语义:

能力TypeScript SDK微信小程序 SDK
包名@hxsyai/aiadp@hxsyai/aiadp-miniprogram
HTTPfetchwx.request
SSEWeb StreamenableChunked + onChunkReceived
上传输入Blob / ArrayBufferfilePath
下载输出二进制响应tempFilePath
WebSocket原生 WebSocket / wswx.connectSocket

完整的请求字段和响应含义以对应的 OpenAPI 接口文档 为准。

AI 应用开发平台 - 面向医疗场景的 AI 应用创新引擎