- 后端
- API网关
- 模型推理服务
- AI Agent
【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
本文聚焦 semantic-router 路由配置中的routing.projections.partitions分区机制:它在信号提取之后、决策评估之前,把相互竞争的domain(领域)或embedding(嵌入意图)信号协调成单一胜者,从而简化下游决策规则。读完本文,你将掌握分区的运行时语义、exclusive与softmax_exclusive两种胜者选择模式、完整的 YAML 与 DSL 配置方法、default回退的合成行为,以及它和 mapping 投影之间的边界。
分区要解决什么问题
semantic-router 作为模型与算力的可编程决策层,会同时运行多类检测器:领域分类(domain)、嵌入意图(embedding)、关键词(keyword)、复杂度(complexity)等。没有分区时,一个请求可能同时命中多个相近的领域或嵌入通道,例如一条法律咨询请求同时以 60% 命中law、以 55% 命中business、以 50% 命中history。这种重叠对路由通常不理想:
- 一个请求通常应有一个主要领域胜者,而不是四个部分匹配的领域;
- 一个意图通道通常应在决策评估前,折叠成一个最匹配的嵌入类别;
- 当每个决策都必须防御性地处理重叠匹配时,重复的路由规则会变得更难推理、更难维护。
分区正是为消除这类重叠而设计的:它只协调检测器已经产出的结果,不做任何额外的模型调用(既不发起 LLM 调用,也不重复做嵌入推理),纯在信号匹配集合层面完成「竞争者 → 胜者」的收敛。
分区在运行时如何表现
从配置校验与分类执行代码可以确认,分区遵循以下硬性规则:
- 分区只接受
domain或embedding成员,两者不可混用; - 同一分区中的所有成员必须类型相同(要么全是领域,要么全是嵌入),否则配置校验直接报错;
default是必需字段,且必须同时出现在members列表中;- 若多个成员匹配,运行时只保留一个胜者;
- 若没有任何成员匹配,运行时把
default成员合成进匹配集合。
其中前两条「类型一致性」约束由校验器强制执行,见 validator_projection.go 的projectionPartitionMemberType:它会逐个核对每个成员是否在已声明的 domain/embedding 信号表中,并确保所有成员共享同一类型;default必须在members中这一约束由validateProjectionPartitionDefault检查。semantics只接受exclusive与softmax_exclusive两个取值(见 validator_projection.go)。
支持的胜者选择语义有两种:
| 语义 | 行为 |
|---|---|
exclusive | 按原样保留最高置信度胜者,其余竞争者的置信度被丢弃 |
softmax_exclusive | 保留同一个最高置信度胜者,但用带temperature的 softmax 对竞争者的置信度重新归一化 |
关于softmax_exclusive有两个实际后果值得注意:
- 决策仍然按其原生类型引用获胜成员,例如
type: domain或type: embedding,获胜者的信号名保持不变; - 决策不引用分区名本身。
因此,分区不是 mapping 那种「命名投影输出」,而是对现有信号名的协调——它只负责在既有信号集合内部决出胜负,不产生新的投影命名空间。这一点正是它与 mapping(阈值分档产出命名输出)的本质区别。
运行时执行顺序与源码路径
分区在分类器信号分组阶段执行。入口是 classifier_signal_groups.go 的applySignalGroups:它在MatchedDomainRules(领域匹配集合)和MatchedEmbeddingRules(嵌入匹配集合)上分别应用分区,随后把收敛后的匹配集合交给决策评估。
对单个分区的收敛逻辑在 classifier_signal_group_resolution.go 的applySignalGroupToMatches中:
- 从当前匹配集合中筛出属于该分区
members且带有置信度分数的成员,作为contenders; - 若
contenders为空,走applySignalGroupDefaultFallback:如果default尚未匹配,则把它合成进匹配集合(这是回退行为,并非「默认值实际匹配了请求」的证据); - 若
contenders只有一个,直接保留原匹配集合,无需竞争; - 若有多个竞争者,通过
selectSignalGroupWinner选出胜者:exclusive取原始置信度最高者;softmax_exclusive先做 softmax 归一化再取同一胜者,并把胜者的置信度更新为归一化后的值; - 其余竞争者从匹配集合与置信度表中移除,仅胜者保留。
sftmaxScores的实现(见 classifier_signal_group_resolution.go)采用标准 softmax 且做了数值稳定性处理:先减去最大值再除以temperature求指数,再归一化。temperature越小,胜者与竞争者之间的置信度差距被拉得越大,胜者越「果断」;temperature越大,归一化后的分布越平坦。若temperature <= 0,代码会将其兜底为1.0——但配置校验层已经阻止了非正值通过(见validateProjectionPartitionTemperature),因此运行时兜底仅作为防御。
嵌入分区的质心相似度告警
对softmax_exclusive的嵌入分区,分类器还提供一项静态分析能力:AnalyzeSoftmaxSignalGroupCentroids(见 classifier_signal_group_similarity.go)会计算分区内所有嵌入成员候选文本的质心(centroid),并两两计算余弦相似度。若某对成员的相似度超过阈值(默认0.7),说明这两个意图通道过于接近,softmax_exclusive分区可能难以产生清晰胜者——这通常意味着这些嵌入规则需要补充更差异化的候选短语。该分析可作为嵌入分区调优时的诊断工具。
配置方法:YAML
在路由配置文件的routing.projections.partitions下声明分区。原文档给出的标准示例:
routing: projections: partitions: - name: balance_domain_partition semantics: softmax_exclusive temperature: 0.10 members: [law, business, health, history, other] default: other - name: balance_intent_partition semantics: softmax_exclusive temperature: 0.18 members: [code_general, architecture_design, research_synthesis, general_chat_fallback] default: general_chat_fallback第一个分区balance_domain_partition协调五个领域信号:法律、商业、健康、历史与其他兜底;第二个分区balance_intent_partition协调四个嵌入意图信号,并在没有意图命中时合成general_chat_fallback兜底。
仓库内的真实完整示例
仓库中 config/recipes/balance/config.yaml 的 balance recipe 使用了同样的分区模式,规模更大、更贴近生产:
routing: projections: partitions: - default: other members: - biology - business - chemistry - computer science - economics - engineering - health - history - law - math - other - philosophy - physics - psychology name: balance_domain_partition semantics: softmax_exclusive temperature: 0.1 - default: general_chat_fallback members: - agentic_workflows - architecture_design - business_analysis - code_general - complex_stem - creative_tasks - fast_qa_en - fast_qa_zh - general_chat_fallback - health_guidance - history_explainer - interpersonal_drafting - premium_legal_analysis - psychology_support - reasoning_general_en - reasoning_general_zh - research_synthesis name: balance_intent_partition semantics: softmax_exclusive temperature: 0.18balance_domain_partition的 14 个成员与routing.signals.domains中声明的领域一一对应(见 config/recipes/balance/config.yaml);balance_intent_partition的 17 个成员则对应routing.signals.embeddings中声明的嵌入意图规则(每个嵌入规则由candidates候选短语、threshold阈值与aggregation_method组成,例如fast_qa_en、fast_qa_zh分别用中英文候选短语覆盖通用快问快答)。只有先在这些信号声明中存在,分区成员才能通过校验。
配置字段速查
| 字段 | 类型 | 含义与约束 |
|---|---|---|
name | string | 分区标识符,用于配置与 DSL 引用,须唯一 |
semantics | string | 胜者选择模式,仅支持exclusive或softmax_exclusive,二者均只保留最高置信度胜者 |
temperature | float | 仅对softmax_exclusive有意义,必须> 0;值越低胜者越果断,softmax 分布越尖锐 |
members | string[] | 要协调的现有domain或embedding信号名,不能为空,且所有成员必须同类型 |
default | string | 必须非空且同时出现在members中;无成员匹配时合成的回退成员 |
配置结构在源码中的对应定义是 projection_config.go 的ProjectionPartition结构体(temperature带omitempty,default带omitempty)。JSON Schema 校验也完全一致:ProjectionPartition定义于 router-config-v0.3.schema.json,仅允许name、semantics、temperature、members、default五个字段(additionalProperties: false),并且routing.projections之下只允许partitions、scores、mappings三类集合(见同文件 CanonicalProjections 定义)。
配置方法:DSL
分区同样可以用语义路由 DSL 声明,语法为PROJECTION partition <name> { ... }:
PROJECTION partition balance_intent_partition { semantics: "softmax_exclusive" temperature: 0.18 members: ["code_general", "architecture_design", "research_synthesis", "general_chat_fallback"] default: "general_chat_fallback" }DSL 的 AST 定义见 ast.go 的ProjectionPartitionDecl,文法上PROJECTION关键字后接受partition、score、mapping三种声明(见 ast.go)。DSL 编译器在编译流程的第三步(compileProjectionPartitions,见 compiler.go)把 partition 声明直接转换为等价的config.ProjectionPartition,因此YAML 与 DSL 两种写法表达同一个运行时语义。DSL 同样会对softmax_exclusive的领域分区做 domain 名校验(见 compiler_fields.go):成员必须使用受支持的路由领域名,或在 domain 声明中显式给出mmlu_categories。平衡 recipe 的 DSL 版本见 config/recipes/balance/recipe.dsl。
何时使用分区
在以下情况使用分区:
- 一个请求在路由前应该有一个主导领域(例如把多个相近领域收敛为一个主领域,避免多领域并存);
- 若干嵌入通道表示互斥意图,应折叠成一个胜者(例如把快问快答、代码、架构设计等意图收敛为单一意图通道);
- 希望下游决策保持简单,直接读取获胜的原始信号(决策条件中引用
type: domain或type: embedding的成员名,而无需感知分区本身)。
分区不做额外模型调用——它们只协调成员信号已经产生的结果。同时务必记住:配置里的default是路由回退,不是「默认值实际匹配了请求」的证据,它只会在没有任何成员匹配时被合成进集合。
何时不使用分区
在以下情况不要使用分区:
- 多个成员应当对决策保持独立可见(例如两个嵌入意图分别控制不同的路由策略,不应互相竞争);
- 该组混合了不应互相竞争的无关概念(例如把法律领域与图片检测塞进同一个分区);
- 需要可复用的命名档位(如
balance_reasoning、balance_medium这类由阈值分档产出的命名输出)——那属于 mapping 投影,而不是分区。
对第三点可以补充一个来自真实配置的对照:在 config/recipes/balance/config.yaml 中,urgency_band等 mapping 投影先通过sigmoid_distance标定、再按threshold_bands分档产出urgency_standard/urgency_elevated等命名输出,供决策条件以type: projection引用;而分区只收敛既有信号,不产出新名字。两者一个「造新名字」,一个「内部决胜负」,使用场景需要区分清楚。
小结
分区是 semantic-router 投影体系(partitions/scores/mappings)中负责信号收敛的一环:它不引入新信号,不调用模型,只把同类型的domain或embedding竞争者折叠为单一胜者,必要时合成default兜底。exclusive适合简单取最高分,softmax_exclusive适合需要在保留胜者的同时对置信度分布做温度控制的场景。配置入口为routing.projections.partitions(YAML)或PROJECTION partition(DSL),完整生产示例可参考 config/recipes/balance/config.yaml,实现与校验逻辑可深入阅读 classifier_signal_group_resolution.go 与 validator_projection.go。
- 后端
- API网关
- 模型推理服务
- AI Agent
【免费下载链接】semantic-router
An open, programmable decision layer for models and compute.
相关推荐
semantic-router 投影分区(Partitions)完全指南:用互斥 winner 收敛 domain 与 embedding 信号
semantic router 投影分区(Partitions)完全指南:用互斥 winner 收敛 domain 与 embedding 信号 导读 本文详解
后端API网关模型推理服务AI Agentsemantic-router 偏好信号路由(Preference Signal Routing)实战指南:用 LLM 与 Embedding 实现细粒度请求路由
semantic router 偏好信号路由(Preference Signal Routing)实战指南:用 LLM 与 Embedding 实现细粒度请求路
后端API网关模型推理服务AI Agent电视盒怎么装 Armbian:3 步把闲置安卓盒子完整复用成 Linux 服务器
电视盒怎么装 Armbian:3 步把闲置安卓盒子完整复用成 Linux 服务器 amlogic s9xxx armbian 是一个把 Armbian(Debi
后端API网关模型推理服务AI Agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考