# 性能优化建议

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

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

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

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

## 一、输出精简

### 1.1 适用场景

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

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

### 1.2 字段分工

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

字段语义详见[接入方式](/miniprogram/dev/ai/integration)「原子接口实现」。

### 1.3 注意事项

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

## 二、`apiCalls` 链式调用

### 2.1 适用场景

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

### 2.2 声明方式

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

### 2.3 示例

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

```javascript
// 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 示例

```javascript
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 {
    // 后置逻辑：日志上报、统一展示等
  }
})
```

中间件的完整语义详见[接入方式](/miniprogram/dev/ai/integration)「中间件机制」。

### 3.3 注意事项

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

## 四、绑定接口合并

### 4.1 适用场景

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

### 4.2 示例

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

```javascript
// 合并前：每轮用户输入，模型需连续调用两次
// 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`，不应强行合并。
