用微信云开发,将你的小程序快速接入微信 AI 生态

使用微信云开发构建小程序 Skills,您无需编写 wx.request、无需自行搭建服务器、也无需维护登录态——通过 wx.cloud.callFunction 即可直连云函数,用户身份 OPENID 由云开发的免鉴权能力自动注入。


写在开头

目前很多开发者都在关注最新推出的小程序 Skills 如何开发,所以我们快速搭好了三个开箱即用的小程序 SKILL 模板。

  • todolist-skill(待办清单):查询、新增、完成切换、删除,基于云开发数据库直读,入门首选 https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/todolist-skill
  • queue-skill(门店排队取号):门店搜索、排队状态查看、线上取号、排队进度查询 https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/queue-skill
  • drink-skill(咖啡饮品点单):推荐 / 搜索饮品 → 选规格 → 填地址 → 下单支付,完整点单链路 https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/drink-skill

每个模板均基于微信云开发实现前后端逻辑,包含了完整的 SKILL.md 业务说明、接口链路图、约束规则和意图分流示例,覆盖了最常见的小程序场景。

下面以 todolist-skill 为例,走一遍完整的开发流程。


一、小程序 Skills 是什么

微信小程序今天推出了 AI 开发模式:你可以把现有小程序的功能,封装成能被小程序 AI 在对话里调用的能力。这个能力单元就叫 SKILL

文档:https://developers.weixin.qq.com/miniprogram/dev/ai/guide.html

跟过去「用户点按钮 → 跳页面 → 填表单」的流程不一样,小程序 Skills 把交互提前到了对话里:

[用户] 在小程序 AI 对话框说:"帮我记个待办:买牛奶"
        ↓
[小程序 AI] 理解意图,自动选中你的 addTodo 能力,填好参数 title="买牛奶"
        ↓
[你的代码] 执行写入,返回结构化数据
        ↓
[小程序 AI] 在聊天流里弹出一张你设计的「待办清单卡片」

你要做的事情就两件,剩下的——这句话该调哪个函数、参数怎么填、什么时候弹卡片——全交给 AI:

  1. 把功能写成函数(官方叫原子接口),就是真正做事的那段代码;
  2. 给函数配一张卡片(官方叫原子组件),把结果渲染成对话流里的 GUI 卡片。

小程序 Skill 的四件套

一个小程序 SKILL 放在独立分包里,包含四个核心文件:

文件
作用
mcp.json
向 AI 声明:有哪些函数、参数怎么填、用哪张卡片展示
apis/*.js
原子接口——真正做事的函数
index.js
把函数注册给运行时
components/
原子组件——展示结果的卡片
SKILL.md
(可选)
业务 SOP,告诉 AI 这个场景的流程编排

底层是小程序 MCP 协议:微信客户端运行时与小程序 AI 后台之间基于该协议交互,你不用理解协议细节,按规范把 SKILL 实现完整就行。

注意:这个模式目前还在内测,暂时没开放代码提审。别把相关代码合进正式版本提交审核。


二、绕不开的问题:登录态怎么办

原子接口跑在微信客户端一个独立的 JS 环境里,跟小程序主环境是隔离的。AI 调你函数的时候,你得自己在函数里搞清楚「这个用户是谁」。

传统做法:自建后端 + 鉴权中间件

如果你的后端是自己搭的服务器,标准流程是这样的:

  1. 调 wx.login() 拿临时 code
  2. 把 code 发给你的后端;
  3. 后端用 code + AppSecret 调微信的 code2session 接口换 openid 和 session_key
  4. 后端生成自定义登录态 token 返回;
  5. 把 token 存进 storage,后续请求都带上;
  6. 多个原子接口都要走这套,于是你还得写一个中间件统一处理。

落到代码上就是下面这样——每个 Skill 都得维护这么一段:

// index.js —— 传统自建后端方案:必须写中间件维护登录态
const skill = wx.modelContext.createSkill('skills/todo-skill')
skill.registerAPI('addTodo', addTodo)

skill.use(async (ctx, next) => {
// 统一登录态:没 token 就走一遍换登录态流程
let token = wx.getStorageSync('token')
if (!token) {
    const { code } = await wx.login()
    const res = await wx.request({
      url'https://your-server.com/login',  // 你自己的后端
      data: { code }
    })
    token = res.data.token
    wx.setStorageSync('token', token)
  }
await next()
})

然后后端还得写一套 code2session 的换取逻辑、session_key 的存储、token 的签发与校验。这部分代码跟业务没任何关系,纯粹是为了「知道用户是谁」而存在的样板。


三、用微信云开发:不用管登录态,直接拿 openid

用微信云开发做后端,上面那一整套样板代码可以全删掉。

原子接口环境原生支持云开发接口(wx.cloud.initwx.cloud.callFunctionwx.cloud.database 都能直接用)。云函数有个特性:调用方身份由微信底层链路天然带过来,你在云函数里一行代码就能拿到当前用户的 openid,不需要 wx.login、不需要 code2session、不需要自建鉴权服务、不需要中间件维护 token。

环节
自建后端
微信云开发
wx.login()
 拿 code
必须
不需要
后端 code2session 换 openid
必须自己实现
底层自动带上
签发 / 校验自定义 token
必须
不需要
维护登录态的中间件
必须写
不需要
在服务端读取 openid
经过一串转换
cloud.getWXContext().OPENID
 一行搞定

下面用一个完整的 todo 待办清单 SKILL 来演示,看看代码能精简到什么程度。


四、动手做一个待办清单的小程序 Skill

目标很简单:用户用大白话说「记一下」就新增、「看看我的待办」就查看、点卡片就标记完成。

第 1 步:声明分包与 SKILL(app.json)

SKILL 必须放在独立分包里,按需注入和云开发都要开:

{
  "lazyCodeLoading""requiredComponents",
"cloud"true,
"subPackages": [
    {
      "root""skills/todo-skill",
      "independent"true,
      "pages": []
    }
  ],
"agent": {
    "skills": [
      {
        "name""todo",
        "description""待办清单业务",
        "path""skills/todo-skill"
      }
    ]
  }
}

第 2 步:向 AI 声明能力(mcp.json)

待办场景有三个动作:新增、查看、完成。参数说明里要写清楚「取值来源」和「缺失时怎么办」,并且明确告诉 AI 别自己编——这直接决定了 AI 能不能调对接口、填对参数:

{
  "apis": [
    {
      "name""addTodo",
      "description""新增一条待办事项。当用户说『记一下/帮我记/加个待办』并给出具体内容时调用。",
      "_meta": { "ui": { "componentPath""components/todo-card/index" } },
      "inputSchema": {
        "type""object",
        "properties": {
          "title": {
            "type""string",
            "description""待办内容,取自用户原话(如『买牛奶』)。用户未说出具体内容时禁止填写,应反问『您要记什么待办?』。"
          }
        },
        "required": ["title"]
      }
    },
    {
      "name""listTodos",
      "description""查看当前用户的全部待办清单。当用户说『看看我的待办/还有什么没做』时调用,无需任何参数。",
      "_meta": { "ui": { "componentPath""components/todo-card/index" } },
      "inputSchema": { "type""object""properties": {} }
    },
    {
      "name""completeTodo",
      "description""把一条待办标记为已完成。",
      "_meta": { "ui": { "componentPath""components/todo-card/index" } },
      "inputSchema": {
        "type""object",
        "properties": {
          "todoId": {
            "type""string",
            "description""待办唯一标识,必须来自上游 listTodos 返回的 todoId 原值。禁止编造,也禁止从用户自然语言推断;上下文无可用 todoId 时应先调 listTodos。"
          }
        },
        "required": ["todoId"]
      }
    }
  ],
"components": [
    { "path""components/todo-card/index""relatedPage""/pages/index/index" }
  ]
}

三个接口共用同一张 todo-card 卡片渲染。relatedPage 是卡片右上角「进入小程序」入口关联的页面,填你小程序里真实的待办页路径就行。

第 3 步:原子接口直接调微信云开发(index.js)

index.js 跑在原子接口环境里。初始化 wx.cloud 后就地实现并注册接口。注意:写操作走云函数,只读操作直连云数据库,用户身份全程由微信底层自动带上:

// skills/todo-skill/index.js
wx.cloud.init({ env'your-env-xxxxxx' })  // 换成你的云开发环境 ID

const skill = wx.modelContext.createSkill('skills/todo-skill')

// 添加待办:写操作走云函数(OPENID 由云开发自动注入,无需登录)
skill.registerAPI('addTodo'async ({ title }) => {
if (!title) return { isErrortruecontent: [{ type'text'text'缺少待办内容,请反问用户要记什么,禁止编造。' }] }

const { result } = await wx.cloud.callFunction({ name'addTodo'data: { title } })
return {
    content: [{ type'text'text`已添加「${title}」,请展示最新待办清单卡片。` }],
    structuredContent: { todos: result.todos }
  }
})

// 查看待办:只读,直接连云数据库
skill.registerAPI('listTodos'async () => {
const { data } = await wx.cloud.database().collection('todos').orderBy('createTime''desc').get()
return {
    content: [{ type'text'text`共 ${data.length} 条待办,请展示清单卡片,禁止纯文本罗列。` }],
    structuredContent: { todos: data.map(t => ({ todoId: t._id, title: t.title, done: t.done })) }
  }
})

// 完成待办:写操作走云函数
skill.registerAPI('completeTodo'async ({ todoId }) => {
if (!todoId) return { isErrortruecontent: [{ type'text'text'todoId 须来自 listTodos 返回值,禁止编造。' }] }

await wx.cloud.callFunction({ name'completeTodo'data: { todoId } })
return { content: [{ type'text'text'已标记完成,请刷新待办清单卡片。' }] }
})

module.exports = skill

content 给 AI 看,建议用「陈述事实 + 指示下一步」两段式;structuredContent 既给 AI 理解,也传给组件渲染。整段代码没有 skill.use(...) 维护登录态的样板。

第 4 步:云函数里一行拿到 openid(cloudfunctions/)

云函数天然知道用户是谁。写操作在云函数里落库,顺手做好所有权校验:

// cloudfunctions/addTodo/index.js
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()

exports.main = async (event) => {
// ✨ 免鉴权:直接拿到当前用户 openid,无需 wx.login,无需 code2session
const { OPENID } = cloud.getWXContext()
const title = String(event.title || '').slice(0100)   // 服务端二次校验
if (!title) return { code1msg'内容为空' }

await db.collection('todos').add({ data: { _openid: OPENID, title, donefalsecreateTime: db.serverDate() } })
const { data } = await db.collection('todos').where({ _openid: OPENID }).orderBy('createTime''desc').get()
return { code0todos: data.map(t => ({ todoId: t._id, title: t.title, done: t.done })) }
}
// cloudfunctions/completeTodo/index.js
const cloud = require('wx-server-sdk')
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()

exports.main = async (event) => {
  const { OPENID } = cloud.getWXContext()
  // where 同时带上 _openid,确保只能改自己的待办(越权校验)
  await db.collection('todos').where({ _id: event.todoId, _openid: OPENID }).update({ data: { donetrue } })
  return { code0 }
}

AI 生成参数不可信任。免鉴权解决的是「用户是谁」,而「这个 todoId 是不是这个用户的」还是要靠 where 里带上 _openid 来兜底。

第 5 步:做一张卡片(components/todo-card/index.js)

组件环境不支持 wx.cloud,数据全部来自接口返回的 structuredContent。用户点某条待办时,通过代用户上行消息触发 completeTodo

Component({
  data: { todos: [] },
lifetimes: {
    created() {
      this.ctx = wx.modelContext.getContext(this)
      // 监听原子接口返回结果,渲染卡片
      this.ctx.on(wx.modelContext.NotificationType.Result, ({ result }) => {
        this.setData({ todos: (result.structuredContent || {}).todos || [] })
      })
    }
  },
methods: {
    onTapTodo(e) {
      const { todoId, title } = e.currentTarget.dataset.todo
      this.ctx.sendFollowUpMessage({
        content: [
          { type'text'text`完成「${title}」` },
          { type'api/call'data: { name'completeTodo'arguments: { todoId } } }
        ]
      })
    }
  }
})

对应的 index.wxml

<view class="card">
  <view wx:for="{{todos}}" wx:key="todoId" class="item {{item.done ? 'done' : ''}}"
        data-todo="{{item}}" bindtap="onTapTodo">
    {{item.done ? '✓' : '○'}} {{item.title}}
  </view>
</view>

在开发者工具里把编译模式切到「小程序 AI 编译」,在对话里输入「帮我记个待办:买牛奶」,就能看到 AI 调用 addTodo 并弹出待办清单卡片。点一下某条待办,会自动触发 completeTodo 刷新卡片。


五、为什么微信云开发和小程序 Skills 特别搭

1. 省掉一整层登录样板

原子接口跑在独立 JS 环境里,传统方案要靠 wx.login + 自建后端 code2session + token 中间件来识别用户。云函数里 cloud.getWXContext().OPENID 一行就拿到了。你写的每一行代码都是业务,没有一行是为了搞清楚用户是谁。

2. 不存在登录态过期这回事

自定义 token 会过期,过期了要刷新,刷新逻辑还得在中间件里兜底。云开发的身份是请求级别天然携带的,根本没有「登录态失效弹窗重登」这条链路,对话体验也顺很多。

3. 后端能力开箱即用

数据库、存储、定时触发器在云函数里随手就用:

const { OPENID } = cloud.getWXContext()
// 读用户专属数据,天然带权限隔离
const todos = await db.collection('todos')
  .where({ _openid: OPENID })
  .get()

云数据库默认按 _openid 做数据归属,放到 Skills 场景里,用户只能看到自己的数据——这种权限隔离几乎是免费的,不用额外写一层 AuthZ 校验。


六、小结

把小程序接入 AI 对话,最枯燥也最容易出错的部分,往往不是业务逻辑,而是在隔离环境里搞清楚用户是谁。

  • 小程序 Skills 让你的功能能被 AI 在对话里直接调用,你只要写好「函数 + 卡片」;
  • 微信云开发让「识别用户」这件事不用你操心——不写中间件、不换登录态、一行 getWXContext().OPENID 直达。

两者一搭,就能把精力全放在「这个 Skill 到底要帮用户做成什么事」上。


想跑通第一个例子,参考微信官方的小程序 AI 开发模式文档和示例项目 ai-mode-demo(需要用申请了开发模式的 AppID)。相关资源链接见文末附录。


附录:参考链接

  1. 小程序 AI 开发模式官方文档与示例项目:ai-mode-demo — https://github.com/wechat-miniprogram/ai-mode-demo
  2. 待办清单 SKILL 模板(todolist-skill) — https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/todolist-skill
  3. 门店排队 SKILL 模板(queue-skill) — https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/queue-skill
  4. 咖啡点单 SKILL 模板(drink-skill) — https://github.com/TencentCloudBase/awesome-miniprogram-skills/tree/main/skills/drink-skill

实战分享

如何写好 Skill:一份终极实战经验手册

2026-6-6 16:36:00

行业动态

3天500万播放量,小丑自嘲文案火了!(附详细教程)

2025-5-9 14:48:22

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧