【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
本文基于 推理协议契约清单 展开,讲解 semantic-router 如何在 Envoy ExtProc 热路径上,用三层类型体系(线路编解码、协议中立体、策略评估)承载 OpenAI Chat Completions、OpenAI Responses 与 Anthropic Messages 三种线路格式之间的请求/响应/流式翻译。读完本文,你将掌握该契约的类型分层规则、能力声明机制、九宫格(3×3)成对翻译矩阵、八级验证闸门与可执行的回归台账,并知道新增一个线路编解码(codec)时仓库要求你补齐哪些证据。
运行时边界:三层类型体系
推理热路径(inference hot path)上有三个明确划分的类型层:
- pkg/protocolcodec:解析或渲染受支持的线路格式(wire format),即直接面对 provider JSON 与 SSE 事件;
- pkg/llmprotocol:承载协议中立(protocol-neutral)的语义状态,包注释明确规定“线路 JSON 属于 codecs,不得泄漏进本包”(types.go);
- pkg/extproc:基于中立状态评估路由与插件策略,而上游传输完全由 Envoy 负责。
架构规则(architecture-guardrails.md 中的 API 类型契约一节)要求:路由策略不得修改 provider SDK 或线路结构体。provider 特有的 JSON、SSE 事件、stop reason、错误信封都必须留在 codec 层。
请求解码存在两种显式模式,这是理解整个入口设计的钥匙:
- 同格式直通(unchanged same-format codec call):允许保留有界的源字节(bounded source bytes)用于精确重放。对应中立策略中的
SourcePreservation配置,取值为disabled或bounded_same_format,其字节上限SourceEnvelopeBytes与BodyBytes刻意解耦——源保真是可选的保真状态,绝不能导致大请求被复制第二份(见 policy.go); - 路由入口的 mutation-aware 严格解码:因为路由必然改写 provider model 字段,凡是“无法存活于中立契约”的字段,必须在策略执行之前被拒绝,而不是先接受、到派发时才被悄悄抹掉。
这一“宁拒勿丢”原则贯穿全文档:不支持的工具、多模态内容、推理、结构化输出、多候选、流式行为都必须显式失败,翻译绝不能静默丢弃语义字段。
内置线路格式与能力声明
内置编解码矩阵如下(路径以仓库根目录为准,源码均位于 src/semantic-router/ 下):
| 格式 | 缓冲编解码 | 流式编解码 | 兼容性测试 |
|---|---|---|---|
| OpenAI Chat Completions | codec_openai_chat.go | stream_chat.go | matrix_test.go、stream_contract_test.go |
| OpenAI Responses | codec_openai_responses.go | stream_responses.go | 同上 |
| Anthropic Messages | codec_anthropic_messages.go | stream_anthropic.go | 同上 |
从源码看编解码注册与能力声明
registry.go 给出了契约的骨架:
CodecMetadata接口要求每个 codec 声明Format()(稳定线路契约标识)与Capabilities()(能力集),并且Stateless()是显式构造契约——注册进不可变 registry 的 codec 可被并发调用,所有请求状态必须属于返回的流式解码器/编码器;MessageCodec定义四个方向(DecodeRequest/EncodeRequest/DecodeResponse/EncodeResponse),BufferedCodec额外提供TransportErrorCodec用于非 2xx 错误体翻译,StreamCodec通过NewDecoder/NewEncoder为每个请求派生独立的流状态;NewBuiltinRegistry()当前注册三个推理格式外加一个图像格式ImagesCodec;- registry 构造后不可变,
Resolve永不暴露底层 map,重复注册、nil、非无状态 codec 都会在建表时直接失败。
能力集本身是一张位图:capabilities.go 中 Capability 为 uint64 位标志,覆盖文本、图像/音频/视频/文件输入输出、工具与并行工具、推理(含 ReasoningAdaptive、ReasoningSignature、ReasoningDisplay)、严格 JSON Schema、流式、缓存核算、AuthoritativeUsage、MatchedStopSequence、ImageGeneration、CustomTools、TextVerbosity 等。能力在目标编码之前被检查,而不是编码后才发现丢了字段。
两个值得单独展开的能力点:
- Responses 托管图像生成是显式中立能力。它的请求选项、image tool choice、缓冲输出项以及四种进度事件变体都是类型化的;Chat Completions 与 Anthropic 目标会拒绝该能力,而不是把它硬转成普通 image 内容。中立模型中
ContentGeneratedImage与ContentImage刻意区分:前者表示“一次模型托管图像生成操作及其结果”的生命周期,后者是作为模型输入提供的图像(types.go)。 - provider 值域(value domains)保持 provider 特有:Chat Completions 允许 0 输出 token 上限;Responses 要求
max_output_tokens >= 16;Anthropic 允许max_tokens: 0用于 prompt 缓存预热。源端合法但目标端非法的值产生类型化能力错误。Anthropic 启用的 thinking 额外要求budget_tokens >= 1024且严格小于max_tokens;其display控制在 enabled 与 adaptive thinking 下均被保留,无法表示它的目标显式失败。
以上游 OpenAPI 为锚的字段闭合测试
兼容性清单锚定到上游 OpenAI OpenAPI schema(Chat Completions 与 Responses)以及生成的 Anthropic Messages API 类型。official_schema_contract_test.go 中的闭字段测试会在某个上游顶层字段既不被线路 codec 表示、又未被归类为 Router 扩展时直接失败。流式契约对 Chat chunk、Responses 事件判别符、Anthropic 事件与 delta 联合类型、协议原生终端事件施加同样规则。语义上不支持的请求字段以类型化 unsupported_feature 错误失败;不属于模型输出的 provider 响应元数据则通过有界诊断(bounded diagnostics)上报。
中立模型:pkg/llmprotocol 的五份契约
| 位置 | 契约 | 说明 |
|---|---|---|
| types.go | 请求、响应、消息、内容、工具、采样 | 不含线路 JSON 或 provider 传输 |
| stream.go | 中立流事件与请求作用域 codec 接口 | 强制终端与 usage 语义 |
| errors.go | 类型化的协议与传输错误 | HTTP 错误与模型响应资源保持区分 |
| capabilities.go | codec 能力声明与要求 | 在目标编码前检查 |
| policy.go | 边界与未知字段策略 | 同格式保留从来不是跨格式回退 |
两条补充规则:
- 可信身份与关联元数据由传输边界填充,不从不受客户端控制之外解码;
- 策略面(
Policy)除上文提到的SourcePreservation外,还有UnknownFields(reject/preserve_same_format)、LossyFeatures(reject/allow_with_diagnostic)、MissingStableIDs(reject/generate_stable)以及一组Limits(BodyBytes、JSON 深度、引用数量等),并支持ResponseVendor(如 Azure、Cloudflare、Snowflake 的响应侧扩展)与ProviderStopSequences开关——后者让解码器把 provider 非标准匹配停止序列报告为stop_sequence终端,且仅在目标线路格式能够承载匹配停止序列时才开启。
ExtProc 集成:职责拆分表
ExtProc 处理器文件保持“阶段编排器”定位,provider 归一化、流式累积、终端结算、缓存持久化、重放持久化、警告整形都留在独立接缝(seam)上:
| 位置 | 职责 |
|---|---|
| processor_protocol_contract.go | 检测源与目标线路契约,持有请求作用域 codec 状态 |
| processor_req_body.go | 解码一次、调用中立请求策略、为选定后端编码 |
| processor_res_body.go | 解码 provider 输出并编码客户端响应 |
| processor_res_transport_error.go | 翻译非 2xx provider 错误体,且不将其当作模型响应 |
| processor_res_semantic_stream.go | 经中立事件翻译 provider 流帧 |
| processor_res_terminal.go | 结算终端响应、usage、重放、缓存与响应侧策略 |
| processor_response_object.go | 处理已存储的 Response 对象,不把线路状态引入策略 |
Chat 流 usage 有两份独立契约:
- 即使公开客户端没有请求 usage chunk,ExtProc 也会向 Chat 后端请求权威 usage;
- 原始的
stream_options.include_usage偏好保留在中立请求里——同格式流只移除内部请求的 usage 字段并保留 provider 扩展;翻译后的流只在被请求时恰好渲染一次 usage。显式的 OpenAIinclude_obfuscation表示为传输偏好,并有请求侧与流输出侧双重测试覆盖。
矩阵之外的 API 面
以下 API 有意置于推理 codec 矩阵之外:
| 面 | 位置 | 契约 |
|---|---|---|
| Models 列表 | pkg/publicmodels | OpenAI 兼容模型列表,外加有界 Router 发现元数据 |
| Stored Responses 服务 | pkg/responseapi | Responses 端点背后的持久化与对象生命周期 |
| Files 与向量存储 | pkg/openai | 窄向外客户端,受线路兼容性测试覆盖 |
| E2E 请求 fixture | e2e/pkg/fixtures | 测试隔离的最小线路结构 |
回归要求:改协议必须覆盖的清单
任何对 pkg/llmprotocol、pkg/protocolcodec 或 ExtProc 协议接缝的变更,都必须覆盖以下面(逐条继承原文档,不删减):
- 畸形与有界输入;
- 非对象 JSON 文档、重复或未知的传输错误字段、缺失或仅空白的错误判别符与消息;
- 在 Go 大小写不敏感结构匹配覆盖已路由或已认证值之前,精确及大小写折叠的重复 JSON 成员;
- 缓冲请求与响应翻译;
- 传输错误翻译;
- 状态感知的 ExtProc 将非 2xx 传输错误与成功/失败的模型响应资源分离;
- 所有源到目标的格式对;
- 拆分流帧、工具事件、终端事件与最终 usage;
- 并行工具调用(参数片段交错、条目独立完成且顺序独立);
- 托管图像生成选项、null 与空结果的区别、严格 base64 与尺寸限制、单调进度、连续部分索引、条目完成匹配;
- 任意 SSE 字节边界、CR/LF 变体、不完整 UTF-8 片段、重复终端、递减 usage、累计流体限制、合法帧与畸形尾帧合并、部分输出后的错误;
- 跨完整 SSE 帧的 UTF-8 合法性、纯注释 keepalive 与显式空 data 事件的区分、首次流失败后的状态污染;
- provider 资源与事件判别符不匹配、未知终端枚举、缺失联合成员、矛盾的生命周期状态、重复或稀疏候选索引、缺失或负流索引、耦合终端字段、null 必需成员、非 UTF-8 JSON、工具身份变化、重复生命周期事件、终端后输出、单条流内响应身份变化、不成对 Unicode 代理项、以及即使源端省略总数也会溢出的 usage 已知分量计数器;
- 未知字段与不支持能力的失败行为;
- 有状态 Responses 续写:保留历史含有序消息、推理、function calls 与 function outputs;物化必须复用 Responses codec、调和延迟工具链接,并在存储生命周期损坏时拒绝半改活请求;
previous_response_id历史缺失返回类型化 not-found,历史存储不可用返回 service unavailable;两者都不得退化为无状态 200 响应;- 可信元数据隔离;
- 使用 Envoy 常规传输边界的 ExtProc 请求/响应回归。
新增 codec 的定义:直到它完成注册、声明能力并通过完整成对矩阵,都不算完整。
成对 E2E 矩阵:每个客户端格式对每个后端格式
每个客户端格式都通过 Envoy 与 ExtProc 打到每个后端格式上。缓冲与流式契约是独立的闸门,过其一不能替代另一。
| 后端格式 | Chat 客户端 | Responses 客户端 | Messages 客户端 | E2E 闸门 |
|---|---|---|---|---|
| Chat Completions | native | translated | translated | protocol-codec-chat-backend-{buffered,streaming}-matrix |
| OpenAI Responses | translated | native | translated | protocol-codec-responses-backend-{buffered,streaming}-matrix |
| Anthropic Messages | translated | translated | native | protocol-codec-anthropic-backend-{buffered,streaming}-matrix |
矩阵强制规则:拒绝后端事件泄漏、要求恰好一个协议原生终端、检查最终权威 usage、把不完整上游流变成失败终端。
配套闸门(用例见 e2e/testcases 目录):
anthropic-chat-cache-control(anthropic_chat_cache_control.go):验证 OpenAI 兼容缓存标记在缓冲与流式请求中都能到达 Anthropic 后端,且重复缓冲请求报告缓存输入 token;- 三个
protocol-codec-*-backend-tool-lifecycle闸门:发送官方扁平 Responses function tools、消费返回调用、以各后端格式提交内联工具结果;两轮各跑一次缓冲与一次 Responses SSE 流式,流式闸门检查生命周期顺序、调用身份、片段重建、目标原生终端、无后端线路泄漏; - 三个
protocol-codec-*-backend-structured-output闸门(protocol_codec_structured_output.go):完整 JSON Schema 约束经各客户端格式打到各原生后端格式,每对缓冲与流式各跑一次,后端回显证明路由改写与 provider 编码保留了 schema 本身,而非仅仅返回一个合法公开响应; - 三个
protocol-codec-*-backend-error-matrix闸门:强制 provider 侧限流响应,要求每种客户端格式得到原始非成功状态加原生错误信封——后端失败绝不能变成空的模型成功响应; - 三个
protocol-codec-*-backend-midstream-error-matrix闸门:先给部分输出再给协议原生 provider 错误,要求恰好一个客户端原生失败终端、之后不再有成功终端。
失败的资源保留权威 token usage(当 provider 报告失败前工作已完成);错误信封无法携带 usage 的目标会发出有界核算诊断,而结算保持中立 usage 证据。
验证分层:从发布 schema 到 Envoy 传输
协议变更必须通过以下每一层。codec 单元测试不能替代 ExtProc 接缝或 Envoy E2E 闸门。
| 层 | 契约 | 必需闸门 |
|---|---|---|
| 发布 schema | 闭包请求、响应、嵌套、工具、内容、usage 与流判别符清单 | go test ./pkg/protocolcodec -run 'Official' |
| 可评审线路 golden | 编号的请求、响应、传输错误、流转录、目标特定能力、类型化拒绝 JSON fixture,在全部 3×3 协议对上翻译 | go test ./pkg/protocolcodec -run 'Golden' |
| 中立语义 | 全部 3×3 格式的缓冲请求、缓冲响应、工具、多模态顺序、usage 来源、错误与流式 | go test ./pkg/llmprotocol ./pkg/protocolcodec |
| 数据面接缝 | 客户端/后端方向、provider model 改写、API 根路径、缓冲响应与流式(全部 3×3 对) | go test ./pkg/extproc |
| 并发 | 不可变 registry 加并行 3×3 请求、响应、传输错误与流翻译,证明请求作用域的 model、错误、生命周期与累加器状态 | go test -race ./pkg/llmprotocol ./pkg/protocolcodec ./pkg/extproc |
| 健壮性 | 全部格式对的畸形缓冲与任意分块流输入 | 带界 CI 或发布时间预算的 protocol codec fuzz 目标 |
| Envoy 传输 | native 与 translated 的缓冲、流式、工具、provider 错误、不完整流、流中错误 | make e2e-test E2E_PROFILE=response-api 与 make e2e-test E2E_PROFILE=provider-protocols |
| 路由回归 | 既有路由、缓存、工具选择、重放与流式行为 | make e2e-test E2E_PROFILE=envoy-ai-gateway 与 make e2e-test E2E_PROFILE=streaming |
发布 schema 层当前闭合的计数:Chat Completions 对象 3 个 tool_choice 判别符、Responses 30 个 input-item 变体、28 个 output-item 变体、3 个 input-content 变体、2 个 output-message 内容变体、1 个 reasoning-content 变体、16 个 Responses 工具变体、15 个对象 tool_choice 判别符、58 个 Responses 流事件;Anthropic 4 个 tool_choice 判别符、16 个请求内容块、12 个响应内容块、21 个工具、8 个流事件、12 个流内容块、5 个流 delta 变体。内容联合类型按判别符与位置验证,因此同一 wire 结构体无法接受并静默丢弃“来自另一变体的已知字段”。
可评审 golden 层位于 pkg/protocolcodec/testdata/golden,按 {request,response,error,stream,capability,rejection} 分目录。编号文件名把每个源文档与全部三个期望后端文档配对,使线路形状变化在代码评审中可见,而不是藏在 Go 断言里。能力 fixture 按目标记录渲染体或“稳定类型化错误加有界保真诊断”;official-field 能力 fixture 枚举每个顶层请求/响应字段并对照 wire 类型闭合,新字段无法绕过“每个目标协议都有可评审结果”的要求。拒绝 fixture 钉住畸形联合、重复/尾随 JSON、非法工具生命周期、递减 usage、乱序事件、未知判别符与枚举、事件/状态矛盾、不完整生命周期对象、流身份变化;传输错误拒绝另钉畸形信封、全部非对象顶层 JSON 种类、未知/重复字段、非法字段类型、缺失 details、空白必填值;畸形 Unicode 转义与 int64 核算溢出在归一化为不同语义值之前被拒绝。
golden 的再生成是显式开启的(testdata/golden/README.md):
UPDATE_PROTOCOL_GOLDENS=1 go test ./pkg/protocolcodec -run Golden
git diff -- pkg/protocolcodec/testdata/golden
CI 只比较 fixture、对任何语义 JSON 漂移失败,并要求每个输入有精确的三目标输出清单——缺失结果与陈旧文件都会挂闸门。
流 golden 的双重重放:每个流 golden 既按编写时的边界重放,也逐字节(one byte at a time)重放。取消、截止期、不完整 EOF、畸形尾帧、同一传输块内合法输出先于畸形帧、部分输出后 provider 失败、Unicode 分裂、每帧与累计字节上限(含边界)、fail-closed 成功终端、终端幂等性都是矩阵契约的一部分。成功的 provider 终端保持 pending 直到干净的 HTTP 流结束——封闭了“后续传输读入含未终止畸形帧”这一情况。
兼容性回归表:防止重构再犯
协议闸门保留针对“传输重构时极易复现”故障模式的聚焦测试(下表完整继承原文档):
| 契约 | 必需覆盖 |
|---|---|
| 扁平 Responses 工具与内联工具结果 | 全部源/目标对上缓冲与流式工具生命周期,加全部三个后端 E2E profile |
| 逻辑模型别名与 provider 模型 ID | provider 派发在 provider ID 改写之前应用语义控制 |
| Provider API 根 | Chat、Responses、Messages 路径只拼接一次,不重复 /v1 |
| 官方联合类型 | 请求、响应、内容、媒体源、工具与流变体严格解码;不支持的官方判别符以类型化能力错误失败 |
| 工具选择 | 每种后端格式在最终 provider 编码之前恰好一次中立改写 |
tool_choice | 省略即 auto;auto、none、required 与具名选择在每对协议间存活 |
| 缓存指令 | 同格式改写、Chat 到 Messages 翻译、畸形输入、缓存 usage、不支持块错误 |
| 结构化输出 | 完整 JSON Schema 在路由改写后存活 |
Anthropic output_config | 推理 effort 与严格 JSON Schema 在同格式改写与 OpenAI 翻译中存活 |
| 推理流 | 两种 OpenAI 兼容推理别名与有序 Anthropic thinking/signature 块保持显式 |
| 终端原因 | Anthropic 暂停/上下文窗口停止与 Responses 内容过滤不完整保持精确,目标无法表示时显式失败;Anthropic 匹配停止序列是独立响应能力,绝不能静默坍缩为通用 OpenAI stop |
| 流索引 | 源私有中立索引由目标编码器压缩;provider 输出索引必须非负、连续并绑定到一个活跃条目身份 |
| 工具流 | 工具 ID 与名称在发布前存在、条目生命周期内不可变、有界,并配一个最终 JSON 对象参数值 |
| 并行工具流 | 即使 delta 交错或条目乱序完成,每次调用保留独立身份、参数缓冲、生命周期与压缩目标索引 |
| 托管图像生成 | 每个已发布的 Responses 选项、tool choice、输出项与进度事件都是类型化的;校验结果存在性、进度顺序、部分索引、条目身份与终端状态;不支持的目标显式失败 |
| 保留的 Responses 工具 | previous_response_id 在 provider 编码前经中立 codec 物化完整存储调用/结果/推理序列;历史缺失与孤儿存储结果 fail closed |
| Responses 流顺序 | 每个事件带连续 sequence_number;官方响应终端是终结的,[DONE] 作为 Chat 专属哨兵被拒绝 |
| 自定义工具 | 不支持的 custom/freeform 工具判别符在推理前失败,绝不被强转为 function call |
| 流 usage | 中间证据不能终结内容或产生重复 usage 事件;后端核算不能改变公开 include_usage 行为 |
| 不完整流 | 每种客户端格式收到一个失败终端,绝无成功终端 |
| Provider 错误 | 缓冲与流式错误翻译到客户端协议,无模型输出合成 |
这些测试验证的是语义行为,而非序列化字段巧合。同格式请求在相关处被强制经过一次路由改写,使信封重放无法掩盖缺失的中立字段。
活跃回归台账
协议重构必须为每个已接受或未决的线路契约缺陷保留可执行回归。台账记录行为而非实现归属,因此 codec 内部移动时依然有效:
| 回归 | 单元或接缝契约 | Envoy E2E 契约 |
|---|---|---|
| #2492:Responses 流式必须在跨后端格式保留公开事件分类、工具、推理、refusal、头、缓存与连续性 | 完整官方事件清单、3×3 流矩阵、请求上下文传播与响应头改写测试 | Responses 原生加 Chat 与 Messages 后端的流式矩阵 |
| #2486:FullDuplexStreamed 不得以空体替换在途请求 | 非 EOS ExtProc 响应推迟改写,EOS 发出一个完整体 | agentgateway-full-duplex-multiturn |
| #2316:provider SSE 帧可能在任意 Envoy 块边界处分裂 | SSE 缓冲、逐字节重放、CR/LF、分裂 UTF-8 测试 | 三个后端流式矩阵 |
| #3045:当选定后端说 Anthropic Messages 时,Responses 客户端必须收到 Responses SSE | 完整 Responses 事件分类与 3×3 流矩阵 | Anthropic 后端流式矩阵 |
| #913:缓冲语义缓存条目必须重放为合法 SSE | 中立缓存响应经客户端流 codec 编码 | streaming-sse-cache 要求缓存命中、合法 SSE、内容匹配、一个 [DONE] 终端 |
| #2846:中间 usage chunk 不得终结或截断流式内容 | 逐 chunk usage 续写与单终端流状态测试 | streaming profile |
| #3068:Anthropic 后端 profile 绕过第二个协议处理器并在受影响变更 CI 中运行 | profile 拓扑与分类器测试 | provider-protocols profile |
| #3067:扁平 Responses 工具与内联调用结果 | 3×3 请求与工具历史矩阵 | 三个后端工具生命周期用例 |
| #3065:provider API 根拼接 | 协议 × base-URL × 自定义路径表 | 三个后端 profile 使用各自原生路由 |
| #3064(由 #3066 修复):provider 模型 ID 改写 | Chat、Responses、Messages 目标的请求派发测试 | 缓冲 3×3 后端矩阵 |
| #3063:流中 provider 失败 | 3×3 流失败矩阵 | 三个后端 midstream 错误矩阵 |
| #3058 与 #2991:provider 错误不得变成空成功 | 传输错误 3×3 矩阵与 ExtProc 响应接缝 | 三个后端错误矩阵 |
| #3056:有序 Anthropic thinking 与签名 | 缓冲与流式顺序/签名测试 | Anthropic 缓冲与流式矩阵 |
| #3055:缓存指令在 Chat 到 Messages 翻译中存活 | 缓存指令 schema 与成对测试 | anthropic-chat-cache-control |
#3052:省略的 tool choice 具 auto 语义 | 语义默认与四模式 3×3 矩阵 | 工具选择加后端工具生命周期 |
| #3051:工具选择先于 provider 编码 | 恰好一次中立改写接缝测试 | 每种目标格式的后端工具生命周期 |
| #3024:路由模型改写保留完整 JSON Schema 契约 | 结构化输出 3×3 golden 与 TestExtProcStructuredOutputRequestProtocolMatrix | 三个 protocol-codec-*-backend-structured-output 用例,各缓冲与流式 |
| #3013:Responses 客户端绝不得从 Anthropic 后端收到 Chat SSE | 客户端/后端无关的 3×3 流编码器矩阵 | Messages 后端的 Responses 流式 profile |
| #2947:流式缓存核算存活于中间与终端 usage 更新 | 累计 usage 状态测试加 Anthropic 到全目标缓存矩阵 | 缓存 Messages 流经原生后端 profile |
维护纪律:新增或修复协议问题必须在同一变更中更新本台账与对应测试;关闭问题不允许删除其回归。
台账锚定的权威上游契约为:OpenAI OpenAPI(固定到 openai-openapi 仓库的 690521b1753dce0c6d6b275f583d22537679cff9 修订)与 Anthropic Go SDK 生成的 API 类型(固定到 anthropic-sdk-go 的 d19dea9ed85bbb5fdb2d6f20fb6f903920ed23fa 修订)。
推进一次 schema 修订
schema 刷新是契约变更,不是生成代码更新。流程:
- 在顶层与嵌套清单测试中固定新的上游修订;
- 把每个新增字段或联合判别符分类为语义、仅传输、诊断或类型化不支持行为,并为它补上字面 JSON 证据;
- 为每个受影响输入重新生成全部三个目标输出,评审 diff;
- 依次跑缓冲、流式、任意分块、race、有界 fuzz、ExtProc 与 Envoy E2E 闸门。
带未分类字段、陈旧输出、或只做同格式测试(让跨协议行为保持未定义)的修订不得合入。
小结:扩展这个契约体系的路径
从源码结构看,新增一条线路格式的最小完整动作是:实现 Codec 与 StreamCodec(无状态、可并发)、在 NewBuiltinRegistry 注册、声明 Capabilities()、补 official schema 闭合清单与三目标 golden、通过 3×3 成对矩阵与 go test -race、并进入 provider-protocols/response-api 等 Envoy E2E profile(provider-protocols 说明:该 profile 把 Chat、Responses、Messages 客户端经 Envoy 与 Router 路由到 provider-mocker 的原生 Anthropic Messages 端点,用 make e2e-test E2E_PROFILE=provider-protocols 运行,fixture 请求可在 /debug/last-request 观察)。这正对应原文档的收束句:注册、能力声明、完整成对矩阵,三者缺一即不完整。
【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



