上游大模型接口变更后业务代码怎么保持稳定?适配器层和统一接口应该怎么设计?
把字段命名、鉴权、错误码、流式分片等上游差异收敛在适配器层,业务代码只依赖一套自有的统一接口契约,上游变更时只改适配器和契约测试,业务侧无需跟着发版。该做法适用于长期维护、多上游并存的业务;一次性脚本或纯原型调用不必引入这层抽象。
上游模型接口变更时业务代码要保持稳定,核心是在业务与上游之间增加一层适配器,并用一套自有的统一接口契约把上游差异隔离在外。业务代码只依赖统一契约,字段改名、参数增减、鉴权头变化、返回结构差异、错误码调整都由适配器吸收。这个做法适用于需要长期维护、可能接入多个上游的业务;只跑一次的原型脚本不必为此抽层。不适用边界要写清:如果业务逻辑本身依赖某个上游的独有行为,适配器只能统一格式,不能统一语义。
统一接口的本质是用内部 DTO 替代上游字段名。请求侧统一成模型标识、消息列表、工具定义、流式开关等内部字段,响应侧统一成增量文本、结束原因、用量统计等内部结构。原因在于上游变更多数是命名和层级变化,语义并没有变,业务如果直接引用上游字段名,就会把命名变化当成逻辑变化。做法是禁止业务层直接引入上游 SDK 的返回类型,所有字段先经过适配器转换。
适配器要吸收的变更类型可以归为六类:字段增删改、鉴权与地址变化、错误码变化、限流语义变化、流式分片格式变化、用量计费字段变化。这六类变化每次上游发版都可能出现,逐条写进业务代码会让维护成本线性增长。做法是为每个上游建一份变更清单,变更发生时先改适配器,再跑契约测试。适配器只做翻译,不做业务决策,这条边界要写进代码规范。
错误处理是上游变更最容易击穿业务的一环,上游错误码不能直接透传到业务层。建立内部错误分类,至少区分可重试、不可重试、配额不足、内容安全拦截、超时五类,每个上游错误码映射到内部枚举。业务层只判断内部枚举,不判断上游错误码,这样上游调整错误码含义时只需要改映射表。不适用的是需要向上游反馈原始错误码做对账的场景,那就在适配器里保留原始码但标记为调试字段。
统一接口自身要有版本号,适配器实现按上游加版本注册。没有内部版本号时,任何一次适配器改动都会同时影响所有业务。做法是把内部契约作为发布物管理,破坏性变更升大版本,业务按需升级。新上游接入时先用旁路流量对比输出,格式和语义都对得上再切主流量,灰度期间保留回切开关,避免一次切流把全部请求带到不稳定的新实现上。
上游能力差异要用能力声明处理,不能用散落在业务里的条件分支。不同上游对函数调用、结构化输出、流式返回、多模态输入的支持程度不同,业务按能力声明做降级。例如不支持结构化输出时走提示词加本地校验,不支持流式时走一次性返回再自行分片。能力声明由适配器提供,业务只问这个能力是否可用,这样新增上游时不用翻遍业务代码找分支。
在适配器之上加路由层,可以按可用性、配额、成本、延迟选择上游,失败时自动切换。路由层解决的是单点上游不可用的问题,但切换后输出必须经过同一层归一化,否则业务会收到两种格式。需要注意语义一致性:强依赖某个上游特有行为的任务,比如特定工具调用格式或特定推理风格,自动切换可能改变结果,这类任务要人工评估后再纳入路由。路由策略应是配置项,不是硬编码。
可观测性决定上游变更后能不能快速定位问题。适配器要记录上游原始请求与响应、映射后的内部结构、内部错误码、耗时和用量,敏感字段先脱敏。缺少这层记录时,业务报错只能看到统一契约的输出,无法判断是上游变了还是适配器映射错了。做法是把上游原始响应保留一段时间,按请求 ID 关联。不适用的是涉及敏感数据的场景,记录前要先脱敏或只保留结构指纹。
契约测试是适配器可维护的底线。为每个上游准备固定输入和期望输出快照,上游变更后先跑测试,失败点就是需要改的映射点。没有契约测试时,变更影响只能靠人读代码判断,容易漏掉边界字段。测试要覆盖正常返回、错误返回、流式分片、空响应、超长响应这几类。契约测试跑在适配器层,不依赖真实上游,用录制的样例即可执行。
用量与计费字段也要在适配层归一化。不同上游对 token 计数、缓存命中、工具调用计费的口径不一致,业务若直接读上游用量字段,上游一改口径统计就断。做法是在适配器里把用量统一成内部计量结构,业务只消费内部结构。成本核算需要口径一致,否则切换上游后无法横向比较。适配器不负责定价,只负责把上游的计量字段翻译成内部字段。
上游变更管理要进入工程流程,而不是等到线上报错才处理。上游发布变更公告后,适配器负责人评估影响面,判断是只改映射还是需要改契约。业务代码保持不变或只做最小改动,是这一层设计是否成功的主要衡量标准。变更记录要写明影响的适配器版本和业务范围。没有变更流程时,适配器本身也会变成无人维护的黑盒。
要避免几个反模式:业务层直接引入上游 SDK 返回类型、把上游错误码写进业务分支、把上游返回字段直接当内部字段用、在业务里按上游名字写条件分支。这些做法会让每次上游变更都变成全量改代码,适配器也就失去意义。反过来说,适配器不是越多越好,只有长期维护、多上游并存、上游变更频繁的业务才值得付出这层抽象成本。判断标准很简单:上游换一个字段名,业务要不要跟着发版。