# 性能优化建议

在此模式下,每一次原子接口调用都对应一段完整的「模型决策 → 端侧执行 → 结果回流 → 再次推理」往返,通常带来 1~2 秒的额外耗时。在不调整模型与提示词的前提下,合理设计原子接口即可显著降低响应时延。

本文给出四项优化手段,按改造成本由低到高排列:

优化手段 优化对象 前置条件
输出精简 每段往返的输入规模 无,建议所有 SKILL 均执行
apiCalls 链式调用 往返次数 下游接口的触发与入参可由上游返回结果确定
公共逻辑下沉为中间件 往返次数 逻辑为多接口公共前置或后置,且幂等
绑定接口合并 往返次数 两个接口必然成对且有序出现

其中,输出精简降低的是每段往返的输入量,后三项减少的是往返段数。建议按上述顺序逐项评估。

# 一、输出精简

# 1.1 适用场景

structuredContent 同时面向两类消费者:小程序 AI(理解与推理)与端侧(原子组件渲染、接力)。仅供端侧使用、模型决策用不到的字段——如页面跳转路径、样式与埋点参数、大段枚举码表等——应从 structuredContent 中移出。

原子接口的返回结果会作为历史消息进入后续所有推理,因此该项优化的收益不限于单次调用:它缩减的是当前会话后续每一次调用的输入规模;同时上下文增长变慢,可降低上下文压缩的触发频率,使模型更长时间保有原始对话细节。

# 1.2 字段分工

字段 是否进入模型上下文 用途
content / structuredContent / isError 供模型理解与推理
handoff 接力数据,由小程序页面通过 wx.onAgentHandoff 获取

字段语义详见接入方式「原子接口实现」。

# 1.3 注意事项

  1. 标记为 format: "page-link" 的混排链接字段必须保留在 structuredContent,平台需从中抽取页面路径,详见接入方式「文本混排链接」。
  2. 不建议将后端接口返回的数据不加筛选直接写入 structuredContent

# 二、apiCalls 链式调用

# 2.1 适用场景

当原子接口 A 执行后大概率紧接着调用原子接口 B(例如过半的 A 调用后紧跟 B),且 B 是否触发、入参取值均可由 A 的返回结果确定时,应在 A 的返回值中携带 apiCalls,由框架直接发起 B 的调用,跳过其间的一段模型推理。

# 2.2 声明方式

// 接口 A 的返回值
{
  isError: false,
  content: [{ type: 'text', text: '查询完成' }],
  apiCalls: [{ name: 'B', arguments: { id: result.id } }]
}

# 2.3 示例

仅当天气查询结果中包含台风信息时才需续调台风接口,触发条件完全由返回结果决定:

// getDailyWeatherForecast 的返回处理
const result = await fetchDailyForecast(location, days)
const resp = {
  isError: false,
  content: [{ type: 'text', text: summarize(result) }],
  structuredContent: result,
}
// 仅在返回中包含台风信息时下发 apiCalls
if (result.typhoonWarning != null) {
  resp.apiCalls = [{
    name: 'getTyphoonWarning',
    arguments: { location, typhoonName: result.typhoonWarning.name },
  }]
}
return resp

# 2.4 注意事项

  1. 按条件下发。仅在返回结果满足条件时携带 apiCalls,不应无条件下发。
  2. 依赖用户自由选择的下游接口不适用。B 的触发必须能由 A 的返回结果确定性推出。
  3. apiCalls 不等同于接口合并。A、B 仍是两个独立接口,其他链路仍可单独调用 B。

# 三、公共逻辑下沉为中间件

# 3.1 适用场景

同时满足以下全部条件的接口,应从 mcp.json 的原子接口列表中移除,改为通过 skill.use() 注册为中间件:

  1. 不构成独立的业务目标,用户不会专门为其发起请求;
  2. 其返回值仅作为后续调用的门禁或上下文,如登录态、定位、隐私授权、统一展示卡片;
  3. 是 SKILL 内多数接口的公共前置或公共后置逻辑。

保留为原子接口时,模型每轮都需先决策并调用一次,额外引入一段完整往返。

# 3.2 示例

const skill = wx.modelContext.createSkill(skillPath)

skill.use(async (ctx, next) => {
  // 前置逻辑:每次原子接口调用前自动执行
  const token = wx.getStorageSync('token')
  if (!token) {
    const { code } = await wx.login()
    const res = await wx.request({ url: '.../login', data: { code } })
    wx.setStorageSync('token', res.data.token)
  }
  try {
    await next()          // 执行实际的原子接口
  } finally {
    // 后置逻辑:日志上报、统一展示等
  }
})

中间件的完整语义详见接入方式「中间件机制」。

# 3.3 注意事项

  1. 中间件须保持幂等、无副作用,其在每次原子接口调用前后均会执行。
  2. 整个中间件链与原子接口执行时间共享同一超时上限,中间件内不应引入长耗时逻辑。
  3. 登录与授权场景的处理方式,另见用户登录与授权场景处理建议

# 四、绑定接口合并

# 4.1 适用场景

两个原子接口必然成对出现且调用顺序固定时,应合并为一个接口。

# 4.2 示例

以一段输入前置处理为例:原设计包含 checkContent(内容安全校验与登录检查)与 intentRecognition(意图识别)两个原子接口,两者入参均为用户原始输入,且逻辑上中始终成对出现且不会单独被调用。此类绑定关系应合并为单一接口:

// 合并前:每轮用户输入,模型需连续调用两次
// checkContent({ content, business }) -> intentRecognition({ query })

// 合并后:一次调用同时返回校验结果与识别意图
skill.registerAPI('preprocess', async ({ content, business }) => {
  const check = await checkContentSafety(content)      // 原 checkContent 的逻辑
  if (!check.passed) {
    return {
      isError: false,
      content: [{ type: 'text', text: check.reason }],
      structuredContent: { passed: false },
    }
  }
  if (check.needLogin) {
    // 未登录分支保持原有处理:由 apiCalls 直连登录卡片,不经模型推理
    return {
      isError: false,
      content: [{ type: 'text', text: '请先登录' }],
      structuredContent: { passed: false, needLogin: true },
      apiCalls: [{ name: 'authLogin', arguments: { originQuery: content } }],
    }
  }
  const intent = await recognizeIntent(content)        // 原 intentRecognition 的逻辑
  return {
    isError: false,
    content: [{ type: 'text', text: '前置校验通过' }],
    structuredContent: { passed: true, needLogin: false, intent },
  }
})

合并后,每轮用户输入由 2 次接口调用(2 段模型推理)减少为 1 次。

# 4.3 不适用的情形

  1. 链路中间存在用户决策点,如选择门店、选择商品、确认订单。合并将剥夺用户的选择权。
  2. 仅为高频共现而非绑定关系。此类场景应使用 apiCalls,不应强行合并。