标准答案
- 业务层只表达任务意图,例如“生成摘要”“提取订单字段”或“执行工具调用”,不直接创建供应商 SDK 客户端。应用服务调用统一的 ModelGateway 接口。
- 统一请求至少应包含模型路由、消息或内容块、采样参数、超时、用户或租户标识、响应格式和工具定义;统一响应应包含文本、结构化结果、工具调用、usage、finish reason、供应商请求 ID 和错误分类。
- 每家供应商通过 Adapter 把统一协议转换成自己的 SDK 或 HTTP API。能力不一致时显式返回“未支持”或走降级策略,不能静默忽略关键参数。
题目解析
抽象的目标不是抹平所有差异。流式事件、视觉输入、缓存上下文、工具调用和安全拒答可能有真实差异,应在统一接口中保留能力声明和原始扩展字段。
模型路由应由配置和策略层决定,例如按任务能力、区域、租户策略、成本或故障状态选择供应商。路由结果需要记录,否则线上出现质量差异时无法解释。
适配层要做参数白名单和响应校验。供应商 SDK 升级、模型字段变更或错误格式变化不应直接穿透到业务页面。
测试应包含契约测试和一组跨供应商 Golden Set。只测试“请求能发出去”不足以证明替换后结果、工具调用和错误语义仍然可用。
代码示例
业务代码依赖稳定的中间接口,供应商差异收敛在适配器中。
TypeScript
type GenerateRequest = {
task: 'summarize' | 'extract'
input: string
model?: string
}
type ModelGateway = {
generate(request: GenerateRequest): Promise<{
text: string
usage: { inputTokens: number; outputTokens: number }
providerRequestId?: string
}>
}常见误区
- 只把供应商 SDK 调用包了一层,但把供应商响应类型继续暴露给业务。这样仍然无法真正替换。
- 为了统一而丢弃工具调用、拒答原因和 usage 等重要字段。应保留公共字段,并对供应商特有能力显式建模。
- 认为切换供应商只改环境变量即可。模型能力、上下文、结构化输出和数据策略都需要重新验证。