AgentCard 升级后旧客户端不会调用:能力版本、兼容窗口和灰度契约怎么设计
AgentCard 的能力描述改得更准确,新客户端路由正常,旧客户端却突然不再调用。团队第一反应往往是“平台缓存没刷新”,但真正的问题可能是一次破坏性契约升级:输入类型变了、必填字段多了、旧能力名称被直接替换。能力名片不是宣传页,它也是新旧调用方共同依赖的接口。
验证范围:官方资料用于确认能力方向和版本边界;文中的 TypeScript 代码验证应用侧状态模型。当前电脑安装的是 API 24 SDK,且没有连接 HarmonyOS 7 真机,因此本文不把本机断言写成 API 26 编译或真机实测。接入时仍要以目标版本文档、真实设备日志和平台返回值为准。
先做一组新旧客户端对照
保留一台旧版本客户端和一台新版本客户端,给两边输入完全相同的十条表达。记录是否发现能力、路由到哪个功能、生成的参数和服务端最终错误。再把 AgentCard 中新增字段改为必填,即可观察旧客户端是否在路由前或参数校验阶段失败。
案例一:新增可选字段可以同版本演进
例如增加locale或展示偏好,只要服务端提供默认值,旧客户端不传也能工作。此类变化可以沿用原能力版本,但要在回归样本中覆盖缺省输入。
案例二:输入类型变化必须保留兼容入口
从纯文本改为图片加文字,旧客户端没有图片参数能力。更稳的方式是保留旧功能一段时间,新增带版本标识的能力,并在服务端把两种输入转换到统一领域模型。
版本兼容要检查四个层次
能力发现、路由、参数校验和服务执行是四个不同阶段。只看服务端日志会遗漏“旧客户端根本没有发现能力”;只看路由成功又会遗漏参数缺失。兼容窗口必须覆盖完整链路。
type Card = { version: number; required: string[] }; function compatible(clientMax: number, card: Card, provided: string[]): boolean { if (card.version > clientMax) return false; return card.required.every((key) => provided.includes(key)); } const oldClient = 1; if (!compatible(oldClient, { version: 1, required: ['text'] }, ['text'])) throw new Error('旧契约失效'); if (compatible(oldClient, { version: 2, required: ['text', 'image'] }, ['text'])) throw new Error('新契约被误判兼容');这段代码只做一件事:在发送请求前显式判断调用方支持的能力版本与必填字段。它不代替平台 API,却能把最容易写错的状态判断从页面代码里抽出来,先在本机用确定输入验证,再放进设备联调。
升级策略不能只看最新版本
| 方案 | 适合什么情况 | 主要代价 |
| 原地替换能力 | 没有存量调用方 | 旧版本立即断链 |
| 双版本兼容窗 | 客户端升级节奏不可控 | 服务端维护两份入口 |
| 服务端自动猜参数 | 输入差异很小 | 错误被静默掩盖 |
只要存在存量客户端,我会使用双版本兼容窗,并给旧契约设定有数据依据的下线条件。服务端转换可以减少重复逻辑,但不能靠猜测绕过必填信息。
建立可复用的能力契约清单
把每个功能的名称、版本、输入类型、必填字段、副作用和依赖项保存成契约清单。发布前自动生成新旧差异,标出删除字段、必填变化和输入类型变化。
下线旧契约前的证据
- 旧客户端仍能发现旧能力。
- 相同表达在新旧版本的路由结果可比较。
- 缺少新增字段时有明确错误或默认值。
- 兼容窗的下线指标已定义。
- 回滚时旧 AgentCard 与旧服务仍匹配。
AgentCard 升级不是改一段描述,而是发布一个接口版本。把兼容窗口做成契约,旧客户端“不调用”的问题才不会只能靠猜缓存。
官方资料
- HarmonyOS 7 新能力
- Harmony Intelligence Agent
- 2026 年 9 月开发者月刊