Springai 指定模型的三種方式(Ollama)
在實際開發中,Ollama 支持三種常用的模型指定方式:
1. 從 yml 配置讀取默認模型
注意: 這是最基礎、最推薦的方式,必須先配置好才能用自動注入的 OllamaChatModel。
spring:ai:ollama:base-url: http://localhost:11434chat:options:model: deepseek-r1:7b
@Autowired
private OllamaChatModel chatModel;
// 直接調用 chatModel.call(...) 即用默認模型
2. Prompt 臨時指定模型
通過 Prompt 構造時傳入 OllamaOptions,可臨時切換模型:
import org.springframework.ai.ollama.api.OllamaOptions;Prompt prompt = new Prompt(messageList,OllamaOptions.builder().model("qwen2.5-vl") // 臨時指定模型.build());return chatModel.stream(prompt);
3. 創建多個 OllamaChatModel 動態切換
可在配置類中為不同模型創建多個 Bean,或用工廠模式動態切換:
@Bean
public OllamaChatModel ollamaQwenModel() {OllamaApi ollamaApi = OllamaApi.builder().baseUrl("http://localhost:11434").build();// 解析參數OllamaOptions.Builder optionsBuilder = OllamaOptions.builder().model("qwen2.5-vl:3b");return OllamaChatModel.builder().ollamaApi(ollamaApi).defaultOptions(optionsBuilder.build()).build();
}@Bean
public OllamaChatModel ollamaLlamaModel() {OllamaApi ollamaApi = OllamaApi.builder().baseUrl("http://localhost:11434").build();// 解析參數OllamaOptions.Builder optionsBuilder = OllamaOptions.builder().model("llama2:7b");return OllamaChatModel.builder().ollamaApi(ollamaApi).defaultOptions(optionsBuilder.build()).build();
}
或通過自定義工廠類,根據參數動態返回不同模型實例:
public class DynamicModelFactory {public OllamaChatModel getModelByName(String modelName) {// ...根據modelName返回不同OllamaChatModel實例...}
}
接口調用時根據參數動態切換:
OllamaChatModel model = dynamicModelFactory.getModelByName(modelName);
return model.stream(prompt);
建議所有模型還是維護到數據庫,因為大部分模型特別是相同供應商的調用方式都一樣
CREATE TABLE `ai_model` (`id` bigint NOT NULL AUTO_INCREMENT,`vendor` varchar(64) NOT NULL COMMENT '供應商',`icon` varchar(255) DEFAULT NULL COMMENT '圖標URL',`name` varchar(128) NOT NULL COMMENT '模型名稱',`api_key` varchar(255) DEFAULT NULL COMMENT '密鑰',`api_url` varchar(255) NOT NULL COMMENT '模型API地址',`tags` varchar(255) DEFAULT NULL COMMENT '標簽(推理、對話、圖片、語音等,逗號分隔)',`type` varchar(32) NOT NULL COMMENT '類型(對話、圖片、音頻、視頻、量化)',`status` tinyint NOT NULL DEFAULT 1 COMMENT '模型可用狀態 1:可用 0:不可用',`description` text COMMENT '模型描述',`params` json DEFAULT NULL COMMENT '模型參數(如溫度等)',`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_german2_ci;
DynamicModelFactory.java
/*** 動態模型工廠,項目啟動時緩存所有模型*/
@Component
public class DynamicModelFactory {@Autowiredprivate AiModelRepository aiModelRepository;private final HashMap<String, MyModel> modelHashMap = new HashMap<>();@PostConstructpublic void init() {List<AiModel> models = aiModelRepository.findAll();ObjectMapper objectMapper = new ObjectMapper();for (AiModel m : models) {MyModel myModel = new MyModel();myModel.vendor = m.getVendor();myModel.name = m.getName();myModel.apiKey = m.getApiKey();myModel.apiUrl = m.getApiUrl();myModel.type = m.getType();myModel.status = m.getStatus();myModel.params = m.getParams();// 這里只實現Ollama,后續可擴展其他供應商if ("ollama".equalsIgnoreCase(m.getVendor())) {OllamaApi ollamaApi = OllamaApi.builder().baseUrl(m.getApiUrl()).build();// 解析參數OllamaOptions.Builder optionsBuilder = OllamaOptions.builder().model(m.getName());if (m.getParams() != null && !m.getParams().isEmpty()) {try {Map<String, Object> paramMap = objectMapper.readValue(m.getParams(), Map.class);if (paramMap.containsKey("temperature")) {optionsBuilder.temperature(Double.parseDouble(paramMap.get("temperature").toString()));}// 可擴展更多參數} catch (Exception ignored) {}}myModel.chatModel = OllamaChatModel.builder().ollamaApi(ollamaApi).defaultOptions(optionsBuilder.build()).build();}// TODO: 其他供應商實現modelHashMap.put(m.getName(), myModel);}}public MyModel getModelByName(String name) {return modelHashMap.get(name);}public void refreshModel(String modelName) {AiModel m = aiModelRepository.findByName(modelName);if (m == null) return;MyModel myModel = new MyModel();myModel.vendor = m.getVendor();myModel.name = m.getName();myModel.apiKey = m.getApiKey();myModel.apiUrl = m.getApiUrl();myModel.type = m.getType();myModel.status = m.getStatus();myModel.params = m.getParams();if ("ollama".equalsIgnoreCase(m.getVendor())) {OllamaApi ollamaApi = OllamaApi.builder().baseUrl(m.getApiUrl()).build();OllamaOptions.Builder optionsBuilder = OllamaOptions.builder().model(m.getName());if (m.getParams() != null && !m.getParams().isEmpty()) {try {Map<String, Object> paramMap = new ObjectMapper().readValue(m.getParams(), Map.class);if (paramMap.containsKey("temperature")) {optionsBuilder.temperature(Double.parseDouble(paramMap.get("temperature").toString()));}} catch (Exception ignored) {}}myModel.chatModel = OllamaChatModel.builder().ollamaApi(ollamaApi).defaultOptions(optionsBuilder.build()).build();}// TODO: 其他供應商實現modelHashMap.put(m.getName(), myModel);}public static class MyModel {@Schema(description = "供應商")private String vendor;@Schema(description = "模型名稱")private String name;@Schema(description = "密鑰")private String apiKey;@Schema(description = "模型API地址")private String apiUrl;@Schema(description = "類型(對話、圖片、音頻、視頻、量化)")private String type;@Schema(description = "模型可用狀態 1:可用 0:不可用")private Integer status;@Schema(description = "模型參數(如溫度等,json格式)")private String params;@Schema(description = "ollama對應的會話對象")private OllamaChatModel chatModel;// TODO: 其他供應商的會話ChatModelpublic OllamaChatModel getChatModel() { return chatModel; }public String getVendor() { return vendor; }public String getName() { return name; }public String getApiKey() { return apiKey; }public String getApiUrl() { return apiUrl; }public String getType() { return type; }public Integer getStatus() { return status; }public String getParams() { return params; }}
}