API 客户端、内部代理和上游服务会独立升级。同一个团队可能同时运行桌面自动更新版、固定 CLI、CI 容器和内部兼容实现;一句“我们已经升级”无法说明哪些组合真的通过验证。只手动发送一条短请求,也覆盖不了子路径、工具调用、流式中断和错误转换。长期治理需要一张版本契约矩阵:记录每个可部署组合的不可变版本、协议行为、固定测试和最近结果,未验证组合不能默认进入生产。本文给出矩阵字段、用例结构和灰度更新流程。

版本矩阵记录实际构建

至少包含:

字段 说明
客户端类型 桌面、CLI、CI 或内部实现
客户端版本 完整版本与安装来源
客户端摘要 二进制哈希或镜像摘要
代理版本 提交标识或不可变镜像摘要
协议模式 当前实际使用的端点与功能路径
测试身份 不含密钥的凭据标识
测试模型或资源 请求和实际映射标识
契约集版本 固定用例集合版本
最近验证 时间、结果和负责人
允许环境 开发、测试或生产

不要写 latest,也不要只记录可移动标签。无法还原构建就无法复现兼容问题。

先定义不可变的契约用例

契约测试至少覆盖:

基础非流式请求
流式响应正常结束
流式连接中断后的客户端行为
结构化输出解析
单个与多个工具调用
长会话整理后的继续执行
认证失败和权限不足
不存在的端点或资源
限流和服务端错误的保真
重试是否遵守幂等边界

每个用例定义输入、前置条件和可观察断言,不依赖模型文字完全一致。

一个可复用的用例结构

case_id: long-session-continue-01
contract_version: "v3"
preconditions:
  client_version: "<actual-version>"
  proxy_version: "<commit-or-digest>"
  test_identity: "<non-secret-id>"
steps:
  - "建立包含固定目标与三条约束的测试会话"
  - "触发客户端当前版本的上下文整理行为"
  - "发送下一次普通请求"
assertions:
  - "下一次请求命中声明的端点"
  - "目标与三条约束仍可由响应确认"
  - "已完成的工具动作不被重复执行"
  - "请求资源与实际资源映射可观察"
  - "代理状态与上游原始状态均被记录"

占位符由测试运行器注入。用例文件不保存真实 Key、用户会话或生产正文。

错误契约检查语义而非固定文本

客户端看到的错误可能经过代理转换。测试应同时断言:

upstream_status
upstream_error_category
proxy_status
proxy_error_category
client_visible_category
retry_count
actual_route

例如认证失败不应被重试成服务不可用;权限不足不应被包装成不存在而失去调查线索。具体状态映射要依据接口合同,不使用一张通用表强加给所有服务。

长会话测试验证状态而非“还能回答”

长会话整理后,需要检查:

测试材料使用无敏感信息的固定场景。不要用真实用户长会话触发兼容测试。

对资源回退做显式契约

如果代理允许回退,测试必须同时记录 requested_resourceeffective_resource,并断言调用方能够观察变化。不同动作分开定义:

同资源切换健康上游
切换到已验收的等价部署
切换到不同资源或能力
停止并向调用方返回失败

切换到不同资源不能藏在请求规范化中。它需要独立策略、审批和结果验收。

更新矩阵的灰度流程

每次客户端或代理升级:

  1. 创建新的矩阵行,不覆盖旧结果;
  2. 在隔离测试身份下运行完整契约集;
  3. 对失败用例保存入站、规范化和上游结构摘要;
  4. 通过后只开放给明确的测试人群或项目;
  5. 观察契约外的实际错误类别和人工反馈;
  6. 达到退出条件后扩大范围;
  7. 保留旧组合直到回滚演练通过。

灰度必须写明范围、负责人、观察指标、停止条件和恢复版本。仅让少量用户“先试试”不构成可审计灰度。

用凭据和环境隔离测试

开发、契约测试和生产使用不同凭据。测试身份只开放用例需要的资源和权限,并设置可控的调用范围。矩阵保存凭据标识,不保存秘密值。

同一测试必须固定身份和路由。动态账号池会让结果同时混入权限差异,破坏版本对比。

客户端与代理分别记录元数据

客户端适合记录版本、会话散列、功能触发状态和本地错误类别;代理适合记录请求标识、路由、请求资源、实际资源、上游状态和重试。两侧通过非敏感关联标识连接。

默认不记录完整提示词、工具结果、文件正文、Cookie 和认证信息。记录更多内容前先说明用途、访问范围和删除责任。

复盘保留证据等级

故障报告将信息分为:

已确认事实:由请求、日志或契约测试直接证明
外部线索:来自 issue、文档或其他环境的观察
工程假设:等待单变量实验验证
最终结论:能够由本环境复现和反向验证

升级后恢复只说明版本变化与结果相关,不自动证明某个 Header 或字段是唯一根因。

定期清理未验证组合

当客户端停止支持、代理版本过期或测试身份失效时,矩阵行标为退役并从允许环境中移除。保留历史结果用于事故追踪,但不能让旧“曾经通过”继续代表当前上游行为。

模型、工具 Schema、认证方式或上游接口发生变化时,找到受影响契约并重新运行,而不是等待用户报告错误。

结论与限制

协议兼容性不是一个版本号,而是客户端、代理、上游资源和测试合同的组合。维护不可变版本矩阵,用固定契约覆盖基础请求、长会话、工具调用和错误保真,再通过隔离身份灰度更新,才能知道哪些组合真正可部署。

本文提供通用治理结构,不规定任何客户端的具体压缩方式、端点或错误码映射。实际契约必须依据所用版本的官方接口和本地实现编写,并在生产数据之外执行。