兼容性规定形状,运行约定规定行为
统一的请求与响应格式能减少客户端改造,让应用更容易切换模型或供应商,也便于团队通过同一接口管理接入。这是真实价值。但字段相同,并不说明请求是否已被接受、实际使用了哪家供应商、何时可以重试、部分输出如何定性,以及最终用量如何核对。只要有人依赖这个系统,这些问题就属于产品约定。
因此,网关需要讲清输入校验、准入与策略检查、路由选择、执行、结果分类和用量证据的边界。这是架构职责,并不意味着所有网关都按同一种方式实现。一次 HTTP 通信成功,不等于工作已经完成;反过来,调用方也可能在供应商完成工作后丢失响应。把两种情况都归为普通错误,会掩盖运维人员真正需要作出的决定。
流是一串证据,不是一次性答案
流式传输让应用在模型仍在生成时就显示内容。例如,OpenAI 文档中的 HTTP 流使用服务器发送事件,区分增量输出与完成事件。应用可能已经显示有用的开头,却还不知道回答是否完整。如果客户端收到一段文字后连接超时,可见文字不能证明操作已经完成。[2]
这时,网关应保留已知事实:请求标识、选定路由、上游是否接受调用、已观察到的事件,以及是否确认完成。部分可见的回答应与最终结果分开。这是架构建议,不表示每家供应商都能恢复中断的流。系统可以展示不完整结果,让调用方决定是否发起新尝试,或在供应商支持时查询其响应记录。重要的是明确不确定性,而不是悄悄将其改写为成功或失败。
决定重试前,先考虑重复执行
设想一个明确仅供说明的内容起草请求:应用发送生成请求,供应商开始流式输出,应用收到两段文字后连接超时。供应商可能继续生成,也可能已经产生费用。如果应用立刻发送同一提示词,可能出现第二次生成和第二笔成本,即使最终只向用户展示一份回答。仅凭超时,网关无法断定第一次尝试没有发生。OpenAI 的 Chat Completions 文档也指出,流中断时可能收不到包含最终 token 用量的末尾数据块。[3]
HTTP 语义对此有明确提醒:除非客户端知道非幂等请求实际具有幂等语义,或能确定首次请求没有生效,否则不应自动重试;代理不得自动重试非幂等请求。模型生成常通过 POST 调用,因此不能凭接口看起来熟悉就认定重试安全。[1] 实用策略可以是在派发前重试、在供应商支持时使用幂等机制,或在流结果不明时要求明确发起新尝试。取舍在于速度与便利,和重复生成及费用不明之间。
先决定是否允许执行,再决定在哪里执行
路由回答符合条件的请求应在哪里运行;策略回答请求是否允许运行、需遵守哪些限制。工作负载可能指定模态、上下文长度、地区、获准供应商、工具权限或费用上限。首选供应商不可用时,只有仍满足约束的替代路由才有意义。悄悄改用不合格路由并非可靠性,而是改变了与应用的约定。
一个清晰的示意流程是:校验请求 → 评估策略与预算 → 选择合格路由 → 在时限内执行 → 判定结果 → 记录已观察用量 → 由对应产品自己的系统生成计费事件。这只是架构示意,不描述已上线的 RouterShift 内部实现。它说明路由、故障处理和计量应分别可以解释。确定性规则更易审计;有可靠反馈时,自适应选择可能有帮助,但也需要说明为何作出具体选择。
先测量已知用量,再转化为金额
网关可能观察到请求、执行尝试,有时还能拿到供应商的最终用量记录;三者不是同一事实。流中断时,最终用量可能仍然未知,不能把根据已显示文字推算的部分 token 数当作已结算费用。应保留原始供应商记录、尝试标识与估算依据。权威用量到达后再核对;更正应可追溯,而非悄然改写旧数字。[3]
OpenTelemetry 现行的 GenAI 语义约定提供了输入、输出 token、模型、供应商及错误类别等遥测词汇,但它不是计费系统,也不保证各供应商计量单位一致。规范还提醒,记录消息内容可能包含敏感信息。[4] 定价与余额变动应在测量之后,保留币种、费率版本和审计轨迹。图像、音频或视频任务未必适合只用 token 衡量;系统应保存供应商实际采用的单位与模态。
让日常运维看得见这套约定
遇到问题时,团队应能回答:哪个请求受影响?选择了哪条路由,为什么?上游是否接受?输出是否完整?哪些用量已确认、只是估算,或仍未知?采用了哪一版策略与价格?请求和尝试标识、结果状态以及追踪关联,能帮助团队查清事实,同时避免把提示词内容默认写入日志。界面也应让产品运维人员看懂,而不只让开发者看懂。
这也提供了检验网关主张的方式。供应商在派发前失败,改用另一条合格路由可能直接可行;开始生成后流中断,就应说明结果不完整或尚未确认,并解释下一步选择;缺少用量,就应等核对后再定论。API 兼容降低接入门槛;生产约定决定顺利路径结束后系统是否仍可预测。RouterShift 是 SlateMoth 已上线的模型接入产品。本文解释的是设计问题,不表示文中每项机制都已在 RouterShift 上线。