semantic-router 配置契约深度解析:v0.3 规范布局、字段所有权与 canonical 加载管线
后端API网关模型推理服务AI Agent【免费下载链接】semantic-routerAn open, programmable decision layer for models and compute.项目地址https://gitcode.com/gh_mirrors/sem/semantic-router点击查看免费下载semantic-router 是 vLLM 项目下的可编程模型与算力决策层而它最核心的工程资产之一就是围绕路由配置建立的一整套“契约contract”规范。本文基于仓库内的 配置契约文档、canonical 加载与校验源码以及 穷举式参考配置系统讲解 v0.3 规范配置的八大顶层区块、providers/evaluation/global等字段的职责边界以及契约变更时的同步检查清单——读完后你能准确理解一份 semantic-router 配置文件为什么长这样、运行时如何拒绝非法输入以及如何在新旧契约之间安全地做迁移。一、契约的核心原则什么是稳态输入配置契约文档 是pkg/config包内写给维护者与协作 Agent 的权威约定它用七条规则定义了 semantic-router 配置体系的设计哲学。第一条也是最根本的一条稳态steady-state输入是规范的version / listeners / providers / evaluation / routing / entrypoints / recipes / global八个顶层键旧布局legacy layouts只允许存在于迁移工具migration tooling中。这句话在源码中有直接体现。canonical_config.go 定义了当前契约版本常量// CanonicalConfigVersion identifies the steady-state public configuration // contract accepted by the Router and published through configschema. const CanonicalConfigVersion v0.3CanonicalConfig结构体canonical_config.go则逐字段对应了这八个顶层键type CanonicalConfig struct { Version string yaml:version,omitempty Listeners []Listener yaml:listeners,omitempty Providers CanonicalProviders yaml:providers,omitempty Evaluation *CanonicalEvaluation yaml:evaluation,omitempty Routing CanonicalRouting yaml:routing,omitempty Entrypoints []CanonicalEntrypoint yaml:entrypoints,omitempty Recipes []CanonicalRecipe yaml:recipes,omitempty Global *CanonicalGlobal yaml:global,omitempty }运行时通过一个轻量的探测函数判断输入是否为规范布局canonical_config.gofunc isCanonicalConfig(raw map[string]interface{}) bool { _, hasRouting : raw[routing] _, hasGlobal : raw[global] _, hasRecipes : raw[recipes] _, hasEntrypoints : raw[entrypoints] return hasRouting || hasGlobal || hasRecipes || hasEntrypoints }版本校验同样严格只要显式声明了version就必须等于v0.3否则直接报错unsupported config versioncanonical_config.go。仓库根部的 config/config.yaml 就是这份契约的穷举式参考实现——它以version: v0.3开头展示了 listeners含 TLS、identity 信任头、providers含 reasoning family、reliability、pricing、多后端权重池、evaluation records、完整 routing 面modelCards / signals / projections / decisions、entrypoints 与 recipes 的真实写法是理解每个顶层键用途的第一手材料。二、evaluation操作者基准与模型卡片的清晰分权契约的第二条规则划定了配置中两个极易混淆的区块的边界evaluation拥有操作者operator的基准定义、索引 DAGindex DAGs和模型关联的记录模型卡Model Cards拥有模型身份与能力而不是基准测量值。从源码看这个分权落在 canonical_config.go 的两个结构体上// CanonicalEvaluation is the single operator-owned evaluation surface. type CanonicalEvaluation struct { Benchmarks []modelcatalog.BenchmarkDefinition yaml:benchmarks,omitempty Indices []modelcatalog.IndexDefinition yaml:indices,omitempty Records []CanonicalEvaluationRecord yaml:records,omitempty } type CanonicalEvaluationRecord struct { Model string yaml:model Benchmark string yaml:benchmark BenchmarkProfile string yaml:benchmark_profile,omitempty ReasoningEffort string yaml:reasoning_effort,omitempty Metrics map[string]float64 yaml:metrics Source string yaml:source,omitempty MeasuredAt string yaml:measured_at,omitempty Metadata map[string]any yaml:metadata,omitempty }三条值得注意的设计三条子面各管一段benchmarks定义考什么indices定义如何聚合版本化的索引 DAGrecords是某个模型在某个基准上测出了什么且record中的模型名指向 canonical Model Card 身份编译器负责分配内部记录身份与溯源用户无需重复仓库字段源码注释见 canonical_config.go。模型卡只管身份RoutingModel即 modelCard 的 Go 类型canonical_config.go承载name、family、param_size、context_window_size、capabilities、modalities、loras等身份与能力字段没有任何 benchmark 得分字段——这正是Model cards own model identity and capabilities, not benchmark measurements的类型级保证。参考配置中的实证config/config.yaml 的evaluation.records用vllm-sr/operator-rating1.0.0这类带版本号的基准 ID 为qwen3-8b、qwen3-32b等模型记录score而routing.modelCards里同一批模型只描述能力如capabilities: [chat, reasoning, tools]两个区块的分工与契约描述完全一致。三、providers默认值、别名与后端绑定的三层职责契约第三条是全文最细的一条把providers拆成三层所有权层级YAML 路径职责源码确认默认选择providers.defaults默认模型与默认 reasoning-effort模型别名providers.models[]请求面别名、可选catalog引用、自定义 reasoning 元数据、具体后端绑定backend_refs、定价与可靠性仓库目录内建模型目录catalog内建 reasoning family、provider/协议元数据对应 Go 类型在 canonical_providers.gotype CanonicalProviderDefaults struct { DefaultModel string yaml:model,omitempty DefaultReasoningEffort string yaml:reasoning_effort,omitempty } type CanonicalProviderModel struct { Name string yaml:name Catalog string yaml:catalog,omitempty Reasoning *CanonicalReasoning yaml:reasoning,omitempty ProviderModelID string yaml:provider_model_id,omitempty BackendRefs []CanonicalBackendRef yaml:backend_refs,omitempty Pricing ModelPricing yaml:pricing,omitempty Reliability ProviderReliability yaml:reliability,omitempty APIFormat string yaml:api_format,omitempty ExternalModelIDs map[string]string yaml:external_model_ids,omitempty }3.1 目录引用catalog与routing.modelCards的互斥约束内置模型可以通过catalog字段引用仓库模型目录从而免去手写的 routing.modelCards 条目。config/README.md 的 Important boundaries 一节明确了规则catalog 支持的模型会自动物化其内建 Model Card、reasoning family、provider 协议、路径与非机密默认值手写的覆盖项必须用规范catalog身份作为routing.modelCards[].name而完全自定义的模型则用其请求别名作为卡名。校验代码canonical_config.go对这条规则做了硬性约束若providers.models[i]既设了catalog又与同名 modelCard 冲突报routing.modelCards[...] is ambiguous: built-in overrides must use catalog name每个providers.models[i]必须提供backend_refs或模型元数据catalog/reasoning/provider_model_id/api_format/external_model_ids/pricing/reliability 之一否则报must define backend_refs or model metadata同一模型卡不能被同时声明为目录支持和自定义两种形态makes model card ambiguous错误。3.2 reasoningfamily 与 inline 二选一CanonicalReasoningcanonical_providers.go支持两种写法引用内建 family如family: qwen3或为私有模型内联定义type/parameter/activation_parameter/effort_flags/levels/default/modes等请求投影字段。config/config.yaml 同时展示了两种形态——qwen3-8b用reasoning.family: qwen3而qwen3-32b用完整的 inline 定义reasoning_effort参数、enable_thinking激活参数、levels: [none, low, medium, high]等。校验函数validateCanonicalReasoningcanonical_config.go强制执行契约中的互斥性family与 inline 字段不可同用must set either family or inline fields, not bothinline 写法必须同时给出type与parameter且 reasoning 块不能为空。这正对应契约第 12 行仓库目录拥有内建 reasoning-family 元数据——family 字符串的解析来自目录而非配置。3.3 后端绑定backend_refs的同构副本约束CanonicalBackendRefcanonical_providers.go描述一个物理后端目标endpoint/base_url、protocol、weight、provider、auth_header/auth_prefix指针类型允许显式置空以关闭目录默认前缀、extra_headers、api_version、chat_path以及凭据api_key或api_key_env。config/README.md 补充了运行时语义同一别名的多个backend_refs是同构副本——HTTP 目标可变主机、端口与权重HTTPS 目标可变端口与权重但必须保持同一 DNS 主机名Provider ID、线协议、凭据、请求路径与 TLS 语义必须一致异构 provider 应拆成不同别名。凭据则必须走环境变量引用而非 YAML 字面量api_key_env优先这一点在参考配置的backend_refsconfig/config.yaml中得到体现本地 vLLM 副本使用api_key_env: VLLM_SR_PRIMARY_API_KEY并带 80/20 权重池。四、global五个平台模块的分层结构契约第四条global继续分层为router、services、stores、integrations与model_catalog。源码 canonical_global.go 精确对应了这五段// CanonicalGlobal contains router-managed runtime defaults plus sparse // overrides, organized into explicit platform modules. type CanonicalGlobal struct { Router CanonicalRouterGlobal yaml:router Services CanonicalServiceGlobal yaml:services Stores CanonicalStoreGlobal yaml:stores Integrations CanonicalIntegrationGlobal yaml:integrations ModelCatalog CanonicalModelCatalog yaml:model_catalog }各模块的归属均来自 canonical_global.gorouter引擎级控制开关——config_source、strategy、auto_model_name、clear_route_cache、streamed_body、skip_processing、model_selection、learning、fallback。契约还指出 Router Learning 位于global.router.learning与单个 decision 的请求期基线算法相互独立见 config/README.md Important boundaries。services路由器对外暴露的共享运行时服务——api、response_api、observability、authz、ratelimit、management_api、router_replay、startup_status。stores存储支撑设施——response_cache、memory、vector_store、tool_sessions后两者是指针形可选字段大多数部署根本不会启用。integrations外部辅助服务——kv_transfer、tools、looper。model_catalog路由器自有的模型资产与模块配置——bindings、deployments、embeddings、system内建能力模型绑定如 decision_model、safety、pii_classifier、external、kbs、modulessafety / prompt_guard / classifier / complexity / hallucination_mitigation 等能力模块、admission以及signal_timeout_ms。这个分层的关键价值是职责隔离路由决策面routing与运行时平台面global各自演化跨切面配置不会散落在 decision 或 recipe 内部。五、signals → decisions → algorithms → plugins四层流水线的所有权契约第五条是 semantic-router 数据模型的骨架信号Signals抽取事实决策Decisions组合事实算法Algorithms选择模型插件Plugins处理被选中的路由。保持各家族的 schema 与校验器由其自身家族所有。在类型层面CanonicalRouting 把这四层组织在一个区块内type CanonicalRouting struct { CandidateRequirements *CandidateRequirements yaml:candidate_requirements,omitempty DataPolicy *RoutingDataPolicy yaml:data_policy,omitempty ModelBindings map[string]ModelBinding yaml:model_bindings,omitempty ModelCards []RoutingModel yaml:modelCards,omitempty Signals CanonicalSignals yaml:signals,omitempty Projections CanonicalProjections yaml:projections,omitempty Decisions []Decision yaml:decisions,omitempty Strategy RoutingStrategy yaml:strategy,omitempty Fallback *fallback.FallbackPolicy yaml:fallback,omitempty }其中CanonicalSignals聚合了 24 个信号家族keywords、embeddings、domains、fact_check、user_feedbacks、reasks、preferences、language、context、structure、complexity、modality、role_bindings、jailbreak、safety、hallucination、pii、kb、conversation、events、metadata、classifiers、input_modality、decision见 canonical_config.go。由家族所有这句话的落点是 routing_surface_catalog.go 中的路由面目录router surface catalog它以代码注册表的形式声明每个信号家族的公共身份YAML 键、显示名、观测键、是否可被 decision 引用、派生引用后缀、每个决策算法static / confidence / fusion / hybrid / kmeans / knn / latency_aware / mlp / multi_factor / ratings / remom / router_dc / svm / workflows / prompt / decision 等 16 种routing_surface_catalog.go与每个路由本地插件response_cache、system_prompt、header_mutation、hallucination、response_jailbreak、router_replay、memory、rag、context_compression、prompt_cache、shadow_dispatch 等routing_surface_catalog.go。每个家族另有独立的validator_*.go校验器pkg/config下有数百个validator_*.go文件如 validator_complexity.go、validator_decision.go与契约要求的validators owned by those families逐一对应。参考配置 config/config.yaml 展示了这四层在真实场景下的组合routing.signals定义 keywords/embeddings/domains/safety/complexity/classifiers 等事实来源routing.projections把信号事实加权合成request_difficulty、request_band等命名输出决策消费这些输出而非内嵌自由计算routing.decisions再以布尔规则组合信号、用modelRefsalgorithmplugins落地具体路由策略例如static_business_route中algorithm: {type: static}配 shadow_dispatch、response_cache、context_compression、tools 等插件链。六、契约变更检查清单fragment、schema、测试与文档同步契约第六条规定了共享契约变更时的同步义务当共享契约变更时同步更新路由器面目录router surface catalog、config/fragments、schemas/生成资产、配置测试与当前公共文档。config/README.md 的 Keep examples in sync 一节把这条规则变成了可执行的流程当公共配置字段或受支持的路由面变化时先更新 Go 类型或注册表再同步更新 fragment、穷举参考、受影响 recipes 与对应网站页面然后重新生成机器可读契约make config-schema-generate # 重新生成 schema make config-schema-check # 校验 schema 与 Go 类型一致 go test ./pkg/config/... # 聚焦的语义门禁 make check # 完整的变更面策略检查生成的机器可读契约就是 src/semantic-router/pkg/configschema/router-config-v0.3.schema.json——它由 Go 配置类型与路由注册表生成不要直接编辑它config/README.md。pkg/config包内还有专门的docs_contract_*.go测试如 docs_contract_test.go、docs_contract_signal_test.go 同族文件用测试断言文档、fragment 与注册表三者不漂移这正是第六条的自动化落地。配套的资产目录也有明确分工见 config/README.md Choose the right assetconfig/fragments/按 signal/decision/algorithm/plugin/global 五个家族存放单能力片段config/recipes/存放完整可运行的场景accuracy、agent、balance、privacy 等九个方向加built-in/版本化虚拟模型config/runtime/存放 memory、response cache、Response API、tools、vector store 等后端支持文件。七、canonical 导入/导出归一化在canonical_*.go运行时绝不静默迁移契约第七条规范的导入/导出与归一化保留在canonical_*.go中运行时加载不得静默执行迁移runtime loading must not silently perform migration。pkg/config目录下这一族文件边界清晰canonical_config.go契约版本、CanonicalConfig类型、normalizeCanonicalConfig校验 → 目录编译 → global 解析 → 路由/recipe 状态应用与全部 canonical 契约校验validateCanonicalContract链canonical_export.go反向导出CanonicalConfigFromRouterConfig把内部运行时配置还原为 v0.3 公共面CanonicalStaticConfigFromRouterConfig则专门为 K8s CRD 协调保留静态基底清空 routing/entrypoints/recipes动态路由状态交给 CRD 提供见 canonical_export.gocanonical_global.go、canonical_providers.go、canonical_recipes.go、canonical_catalog.go 等各顶层键的解析与归一化。不静默迁移的原则可以从迁移代码的写法得到印证确实存在的旧字段迁移被放在显式的、带警告的迁移函数里而不是藏在加载路径中。例如 admission_migration.go 把已弃用的api.batch_classification.max_concurrency迁移为global.model_catalog.admission的 wait 模式默认值时会明确打印一条logging.Warnf告知操作者旧键已弃用、迁移了多少个 deployment、以及请直接配置 admission。与之配合loader.go 的Load/Parse只负责读取、解析与缓存还处理了 K8s ConfigMap 挂载的符号链接解析不承担任何布局改造——旧布局只经由迁移工具显式转换后才能成为稳态输入这正是契约第一条与第七条的合力。八、实操速查从校验到运行把以上契约落到日常操作只需记住参考配置给出的两条命令config/README.mdvllm-sr config validate --config config.yaml # 上线前校验 vllm-sr serve --config config.yaml # 启动编写配置时的自检顺序建议如下布局确认顶层只有version: v0.3、listeners、providers、evaluation、routing、entrypoints、recipes、global八个键外加产品引导用的setup由 Dashboard 在激活后移除模型三分身份能力写routing.modelCards测量值写evaluation.records后端/定价/可靠性写providers.models[]——三者不要互相串位目录优先能用catalog引用的内建模型就不要手写 modelCard手写覆盖必须以 catalog 身份命名全局归位跨切面配置按 router / services / stores / integrations / model_catalog 五段归位不要塞进 routing同步门禁改动任何公共字段后跑make config-schema-generate make config-schema-check go test ./pkg/config/...并同步 fragment、穷举参考、recipes 与文档。小结semantic-router 的pkg/config包用一套自洽的契约文档加大量canonical_*.go实现回答了路由系统最棘手的问题之一配置中每个字段归谁所有、由谁校验、随谁变更。evaluation与 modelCard 的分权、providers三层职责、global五模块分层、signals/decisions/algorithms/plugins 的流水线所有权加上运行时不静默迁移与契约同步检查清单共同构成了一份既可直接指导部署配合 config/config.yaml 穷举参考与config/recipes/完整示例、又能约束后续演进的配置契约。对维护者而言入口就是 AGENTS.md 那七条规则对使用者而言读懂config/README.md的 canonical shape 与 boundaries 一节即可正确产出符合 v0.3 契约的配置文件。赞分享后端API网关模型推理服务AI Agent【免费下载链接】semantic-routerAn open, programmable decision layer for models and compute.项目地址https://gitcode.com/gh_mirrors/sem/semantic-router点击查看免费下载相关推荐微信聊天记录导出工具 PyWxDump 下架了它原本怎么用现在还能跑吗微信聊天记录导出工具 PyWxDump 下架了它原本怎么用现在还能跑吗 PyWxDump 是一款微信数据解析工具能把 Windows 微信的账号信息和聊天hyperframes cinematic-cream 字幕模板规范解析DNA 锁定、safe-zones 布局契约与 plan.json 生成管线hyperframes cinematic cream 字幕模板规范解析DNA 锁定、safe zones 布局契约与 plan.json 生成管线 cine音视频视频AI 技能深入解读 TanStack Router router-core 的 Match Loading 内部架构从匹配、加载到发布的所有权模型深入解读 TanStack Router router core 的 Match Loading 内部架构从匹配、加载到发布的所有权模型 导读 本文基于 pa前端路由SSR上一篇Translumo终极指南如何用这款免费开源工具实现游戏实时翻译下一篇Translumo终极指南5步实现Windows游戏实时翻译的完整解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考