多模型路由与智能选择
上一篇我们从宏观视角看了 infra-ai 模块的整体架构,知道了一次模型调用会经过 ModelSelector → ModelRoutingExecutor → ModelHealthStore → ChatClient 这条链路。其中 ModelSelector 是链路的起点——它决定了候选列表的顺序,而顺序直接决定了优先调谁、失败了切换到谁。
上一篇用一段话概述了它的工作流程:读取配置 → 过滤禁用 → 按优先级排序 → 提升首选模型 → 排除熔断模型 → 返回有序列表。但没有展示代码,那些步骤里的细节都是黑盒。
这一篇打开 ModelSelector 这个黑盒,看看它内部到底是怎么从一份 YAML 配置中选出一个有序的、可用的候选列表的。同时也会讲清楚 ModelTarget 的构建过程和 ModelUrlResolver 的 URL 解析逻辑——它们和 ModelSelector 一起,构成了从配置到实际 HTTP 调用之间的完整桥梁。
ModelSelector 的选择算法
ModelSelector 是一个 Spring 组件,依赖注入两个对象:AIModelProperties(配置)和 ModelHealthStore(熔断器)。
@Slf4j
@Component
@RequiredArgsConstructor
public class ModelSelector {
private final AIModelProperties properties;
private final ModelHealthStore healthStore;
// ...
}
它对外暴露的方法不多,但每一个背后都有一套完整的选择算法。
1. 入口方法
ModelSelector 提供三个入口方法,分别对应三种能力:
public List<ModelTarget> selectChatCandidates(boolean deepThinking) {
AIModelProperties.ModelGroup group = properties.getChat();
if (group == null) {
return List.of();
}
String firstChoiceModelId = resolveFirstChoiceModel(group, deepThinking);
return selectCandidates(group, firstChoiceModelId, deepThinking);
}
public List<ModelTarget> selectEmbeddingCandidates() {
return selectCandidates(properties.getEmbedding());
}
public List<ModelTarget> selectRerankCandidates() {
return selectCandidates(properties.getRerank());
}
Chat 和其他两种能力有一个明显的差异:Chat 多了一个 deepThinking 参数。这个参数决定了是走普通模式还是深度思考模式,两种模式选出来的候选列表可能完全不同——不只是顺序不同,连包含哪些候选都不一样。
Embedding 和 Rerank 的选择逻辑是 Chat 的简化版。它们调 的是一个重载方法,内部不做深度思考过滤,其他步骤和 Chat 一致:
private List<ModelTarget> selectCandidates(AIModelProperties.ModelGroup group) {
if (group == null) {
return List.of();
}
return selectCandidates(group, group.getDefaultModel(), false);
}