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; }}
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86874.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86874.shtml
英文地址,请注明出处:http://en.pswp.cn/web/86874.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python | numpy小记(四):理解 NumPy 中的 `np.round`:银行家舍入策略

python | numpy小记&#xff08;四&#xff09;&#xff1a;理解 NumPy 中的 np.round&#xff1a;银行家舍入策略 一、函数签名与参数说明二、“银行家舍入”策略三、基础示例四、与 Python 内建 round 的异同五、使用注意事项六、扩展用法&#xff1a;自定义舍入策略七、总结…

shell脚本定时执行收集Oracle大表的日分区及创建分区本地索引

近期业务上了一张大表,每日新增分区,每日分区数据量为3千万行。根据每日分区创建分区本地索引。同事添加定时收集前一日每日分区统计信息。 1、创建分区本地索引 (分区索引数量需要和分区name数量一致) create index nmld.add_event_occur_time on nmld.esa_event (occur…

使用 Spread.net将 Excel 中的文本拆分为多段

引言&#xff1a; 在 .NET 应用程序中处理 Excel 数据时&#xff0c;常常会碰到需要把文本拆分成多段的情况。例如在数据清洗、数据分析等场景下&#xff0c;将长文本按照特定规则拆分为多段能让数据更便于处理和分析。Spread.NET作为一款强大的 .NET 电子表格组件&#xff0c…

QT实现一个三轴位移台的控制界面

文章目录 0 引入1、圆形转盘2、其他3、引用 0 引入 本来想做一个酷炫的3D位移台控制程序&#xff0c;要有一个类似遥控器手柄那种界面&#xff0c;在网上找了半天也没有&#xff0c;想要有那种效果还要用异性按钮做&#xff0c;迫在眉睫的情况下&#xff0c;使用了自己的方法&…

Java 案例 6 - 数组篇(基础)

数组的平均值、最大&#xff08;小&#xff09;值。数组的反转 需求&#xff1a;开发一个程序。假设班级有8名学生&#xff0c;用户可以录入8名学生的Java成绩&#xff0c;成绩类型是小数&#xff0c;并输出平均分&#xff0c;最高分和最低分。 import java.util.Scanner; …

Java外观模式实现方式与测试方法

一、外观模式的实现方式 外观模式的核心是通过封装复杂子系统的调用逻辑&#xff0c;为客户端提供一个统一的简单接口。以下是实现步骤及示例&#xff1a; 定义子系统类 子系统类负责实现具体功能&#xff0c;与外观类解耦。例如&#xff0c;家庭影院系统中的投影仪、音响等组…

《解锁AudioSet:开启音频分析的无限可能》

音频新时代的 “密钥”&#xff1a;AudioSet 登场 在科技飞速发展的今天&#xff0c;音频作为信息传播与交互的关键媒介&#xff0c;早已渗透到现代科技的各个角落。从智能手机中的语音助手&#xff0c;让我们通过简单的语音指令就能查询信息、发送消息&#xff0c;到智能家居系…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | ThemeClock(主题时钟)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— ThemeClock组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 使用 Vue 3 的 Composition API 和 <script setup> 语法结…

直播预告丨聊聊Milvus 2.6新功能及背后的开发故事

7 月 1 日晚上 20:00-21:00&#xff0c;Zilliz 视频号直播间&#xff0c;Zilliz 合伙人和研发VP 栾小凡将带来《一步到位&#xff0c;详解 Milvus 2.6 新功能》的分享&#xff0c;带你拆解 Milvus 2.6 四大突破&#xff1a; 降本增效的底层架构开发者生产力拉满的新功能性能不打…

pyenv-win 配置指南​

在 Python 开发过程中&#xff0c;经常会遇到需要使用不同版本 Python 的情况。比如&#xff0c;旧项目依赖某个特定的 Python 版本&#xff0c;而新项目则要求使用更新的版本。这时&#xff0c;版本管理工具就显得尤为重要。pyenv-win就是一款专门为 Windows 系统设计的 Pytho…

MongoDB 常见查询语法与命令详解

MongoDB 作为文档型数据库&#xff0c;其查询语言基于 BSON&#xff08;二进制 JSON&#xff09;格式&#xff0c;与传统关系型数据库的 SQL 语法有较大差异。 一、基本查询命令 1. find()&#xff1a;查询文档 语法&#xff1a;db.collection.find(查询条件, 投影)示例&…

AlpineLinux安装docker

或许你在docker中使用 Alpine Linux 的镜像使用得多,但是有没有想过在 Alpine Linux 上安装 Docker 来使用呢?默认情况下,Docker 包位于社区仓库中,因此在使用包管理来安装docker之前建议更换为国内源,并开启社区仓库的链接。 下面的操作是在root用户下运行的,如果要使用…

docker安装gitlab并配置ssl证书

本篇安装环境 Docker版本&#xff1a;Docker version 28.3.0 域名&#xff1a;test.disallow.cn 自签证书&#xff1a;/etc/gitlab/ssl&#xff08;已经存放在该目录&#xff09; 一、拉取镜像 docker run -itd \--privilegedtrue \--hostname gitlab.test.disallow.cn \--p…

Java开发者转型AI时代的路径

Java开发者转型AI时代的路径 引言 随着人工智能技术的飞速发展&#xff0c;AI已不再是遥不可及的未来&#xff0c;而是深刻影响着各行各业的当下。对于Java开发者而言&#xff0c;面对AI浪潮&#xff0c;如何顺势而为&#xff0c;实现职业转型与技能升级&#xff0c;成为摆在…

QT6 源(140)模型视图架构里的视图总基类 QAbstractItemView:

&#xff08;1&#xff09;先给出本类的继承关系 &#xff1a; &#xff08;2&#xff09;Qt 已经预先为视图定义了键盘功能&#xff0c;Qt 大师们通过编程&#xff0c;已经完善了视图对键盘的响应操作 &#xff1a; &#xff08;3&#xff09;因为本类是抽象基类&#xff0c;无…

vue上传各种文件,并预览组件,(预览,下载),下载resources目录下文件

前端组件vue 最终效果 <template><div ><div class"file-list" v-if"existingFiles.length > 0"><div class"file-card" v-for"(file, index) in existingFiles" :key"file.id"><div clas…

【CS创世SD NAND征文】SD NAND赋能新一代儿童智能玩具

基于全志F1C100S的高可靠存储方案 文章目录 基于全志F1C100S的高可靠存储方案[toc]前言 一、应用产品介绍&#xff1a;儿童智能玩具的需求演变二、技术方案介绍&#xff1a;构建智能玩具的"大脑"与"记忆库"三、核心技术模块分析3.1 主控芯片&#xff1a;全…

mac触摸板设置右键

在 Mac 笔记本上&#xff0c;触摸板默认没有物理左右键分区&#xff0c;但可以通过以下方式实现“右键”功能&#xff08;称为 辅助点按&#xff09;&#xff1a; 一、启用与使用右键&#xff08;辅助点按&#xff09; 步骤1&#xff1a;检查系统设置 点击屏幕左上角 &#x…

稳定币发行量创纪录地超过 Visa 交易量

稳定币发行量创纪录地超过 Visa 交易量 稳定币的崛起正在重塑全球金融格局&#xff0c;华夏基金首席执行官甘天&#xff08;Gan Tian&#xff09;强调了稳定币的快速增长&#xff0c;并指出稳定币的交易量在短短五年内就超过了Visa 40年的交易量。这凸显了货币使用的转变。 稳…

编程 IDE 混战简史:从 Copilot 到 Claude Code,一场重塑开发方式的战争

unsetunset引言&#xff1a;开发新纪元的序幕unsetunset 编程世界&#xff0c;从最初依赖打孔卡和简陋的命令行工具&#xff0c;到如今功能琳琅满目的集成开发环境&#xff08;IDE&#xff09;&#xff0c;每一步都见证了效率与智能的飞跃。IDE作为开发者与代码交互的核心界面&…