【Spring AI 实战】基于 Docker Model Runner 构建本地化 AI 聊天服务:从配置到函数调用全解析
【Spring AI 实战】基于 Docker Model Runner 构建本地化 AI 聊天服务:从配置到函数调用全解析
前沿:本地化 AI 推理的新范式
随着大语言模型(LLM)应用的普及,本地化部署与灵活扩展成为企业级 AI 开发的核心需求。Docker Model Runner 作为 Docker 官方推出的 AI 推理引擎,支持集成多厂商模型并提供标准化 API,结合 Spring AI 的强大生态,可快速构建低成本、高可控的本地化聊天服务。本文将深入解析如何通过 Spring AI 与 Docker Model Runner 的无缝集成,实现开箱即用的 LLM 功能,涵盖环境配置、属性调优、函数调用等核心技术点。
一、环境准备:搭建 Docker Model Runner 基础架构
1. 前提条件
- Docker Desktop 安装:下载并安装适用于 Mac 的 Docker Desktop 4.40.0(其他平台请对应选择)。
- 启用 Model Runner:
选项 1(直接启用):
基 URL 配置为docker desktop enable model-runner --tcp 12434
http://localhost:12434/engines
。
选项 2(Testcontainers 容器化):
通过 Socat 容器映射端口,适用于自动化测试:@Container private static final SocatContainer socat = new SocatContainer().withTarget(80, "model-runner.docker.internal");@Bean public OpenAiApi chatCompletionApi() {var baseUrl = "http://%s:%d/engines".formatted(socat.getHost(), socat.getMappedPort(80));return OpenAiApi.builder().baseUrl(baseUrl).apiKey("test").build(); }
2. Spring AI 依赖配置
在 pom.xml
或 build.gradle
中引入最新 Starter:
<!-- Maven -->
<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-openai</artifactId>
</dependency>
// Gradle
implementation 'org.springframework.ai:spring-ai-starter-model-openai'
二、核心配置:从连接到模型调优
1. 基础连接配置
通过 application.properties
配置 Docker Model Runner 端点:
spring.ai.openai.api-key=test # 任意有效字符串(非真实 OpenAI Key)
spring.ai.openai.base-url=http://localhost:12434/engines # Model Runner 引擎端点
spring.ai.openai.chat.options.model=ai/gemma3:4B-F16 # 选择目标模型(需与 Model Runner 支持的镜像匹配)
2. 聊天属性深度解析
Spring AI 提供细粒度配置,支持重试策略、连接参数及模型行为调优,以下为核心属性表:
重试策略(前缀:spring.ai.retry
)
属性名称 | 描述 | 默认值 |
---|---|---|
max-attempts | 最大重试次数 | 10 |
backoff.initial-interval | 初始回退间隔(秒) | 2 |
backoff.multiplier | 回退间隔乘数(指数增长因子) | 5 |
backoff.max-interval | 最大回退间隔(秒) | 180 |
on-client-errors | 是否重试 4xx 错误 | false |
模型行为配置(前缀:spring.ai.openai.chat.options
)
属性名称 | 描述 | 默认值 |
---|---|---|
temperature | 输出随机性控制(0-1,越高越随机) | 0.8 |
max-tokens | 最大生成令牌数 | 无限制(受模型上下文限制) |
frequencyPenalty | 重复令牌惩罚(-2.0~2.0) | 0.0 |
responseFormat | 强制输出 JSON 格式 | 无 |
tools | 允许调用的工具列表 | 无 |
多模型管理
通过 spring.ai.model.chat
开关启用/禁用 OpenAI 聊天模型:
spring.ai.model.chat=openai # 启用 OpenAI 聊天模型(默认)
# spring.ai.model.chat=none # 禁用聊天模型
三、进阶功能:函数调用与流式响应
1. 智能工具集成(函数调用)
Docker Model Runner 支持模型自动触发注册函数,实现外部服务交互。
示例代码:
@SpringBootApplication
public class DockerModelRunnerDemo {@Bean@Description("获取指定地点天气")public Function<WeatherRequest, WeatherResponse> weatherFunction() {return request -> {double temp = "Amsterdam".equals(request.location()) ? 20 : 25;return new WeatherResponse(temp, request.unit());};}@BeanCommandLineRunner runner(ChatClient chatClient) {return args -> {String response = chatClient.prompt().user("巴黎和阿姆斯特丹的天气如何?").functions("weatherFunction") // 引用 Bean 名称.call().content();System.out.println(response); // 输出:阿姆斯特丹 20℃,巴黎 25℃};}
}record WeatherRequest(String location, String unit) {}
record WeatherResponse(double temp, String unit) {}
2. 流式响应实现
通过 stream()
方法支持实时逐令牌输出,提升交互体验:
@RestController
public class ChatController {private final OpenAiChatModel chatModel;@GetMapping("/ai/generateStream")public Flux<ChatResponse> generateStream(@RequestParam String message) {Prompt prompt = new Prompt(new UserMessage(message));return chatModel.stream(prompt); // 流式返回响应}
}
四、实战示例:构建基础聊天接口
1. 控制器实现
创建 REST 端点处理用户输入并返回生成结果:
@RestController
public class ChatController {private final OpenAiChatModel chatModel;@Autowiredpublic ChatController(OpenAiChatModel chatModel) {this.chatModel = chatModel;}@GetMapping("/ai/generate")public Map<String, String> generate(@RequestParam String message) {String response = chatModel.call(message); // 同步调用模型return Collections.singletonMap("result", response);}
}
2. 禁用无关功能(如 Embedding)
由于 Docker Model Runner 暂不支持 Embedding,需显式关闭:
spring.ai.openai.embedding.enabled=false
五、最佳实践与注意事项
- 模型选择:确保
spring.ai.openai.chat.options.model
与 Model Runner 中加载的镜像标签一致(如ai/gemma3:4B-F16
)。 - 性能优化:通过降低
temperature
(如 0.5)提升输出确定性,或调整max-tokens
避免超长响应。 - 错误处理:利用
retry.exclude-on-http-codes
排除无需重试的状态码(如 404),减少无效重试。
总结:本地化 AI 开发的破局之道
本文通过 Docker Model Runner 与 Spring AI 的集成实践,展示了如何快速构建可控、可扩展的本地化聊天服务。核心优势包括:
- 低成本部署:无需依赖云端 API,降低数据传输延迟与成本;
- 灵活扩展:支持多模型热插拔,通过函数调用无缝连接外部服务;
- 企业级适配:细粒度的配置体系满足高可用、高性能需求。
随着 AI 应用的落地深化,本地化推理与框架级集成将成为企业构建智能应用的核心竞争力。通过 Spring AI 的标准化接口与 Docker Model Runner 的模型管理能力,开发者可聚焦业务逻辑,加速 AI 功能落地。
延伸阅读:
- Spring AI 升级指南
- OpenAI 函数调用规范
相关文章:
【Spring AI 实战】基于 Docker Model Runner 构建本地化 AI 聊天服务:从配置到函数调用全解析
【Spring AI 实战】基于 Docker Model Runner 构建本地化 AI 聊天服务:从配置到函数调用全解析 前沿:本地化 AI 推理的新范式 随着大语言模型(LLM)应用的普及,本地化部署与灵活扩展成为企业级 AI 开发的核心需求。Do…...
前台--Android开发
在 Android 开发中,“前台(Foreground)” 是一个非常重要的概念,它用于描述当前用户正在与之交互的组件或应用状态。理解“前台”的含义有助于更好地管理资源、生命周期和用户体验。 ✅ 一、什么是前台? 简单定义&…...

跨境电商生死局:动态IP如何重塑数据生态与运营效率
凌晨三点的深圳跨境电商产业园,某品牌独立站运营总监李明(化名)正盯着突然中断的广告投放系统。后台日志显示,过去24小时内遭遇了17次IP封禁,直接导致黑五促销期间损失23%的预期流量。这并非个案——2023年跨境电商行业…...

springboot3+vue3融合项目实战-大事件文章管理系统-更新用户信息
在一下三个代码处进行修改 在UserController里面增加uadate方法 PutMapping ("/update")public Result update(RequestBody Validated User user){userService.update(user);return Result.success();}在userservice中增加update方法 void update(User user); 然…...

气象大模型光伏功率预测中的应用:从短期,超短期,中长期的实现与开源代码详解
1. 引言 光伏功率预测对于电力系统调度、能源管理和电网稳定性至关重要。随着深度学习技术的发展,大模型(如Transformer、LSTM等)在时间序列预测领域展现出强大能力。本文将详细介绍基于大模型的光伏功率预测方法,涵盖短期(1-6小时)、超短期(15分钟-1小时)和中长期(1天-1周…...

深度学习:智能车牌识别系统(python)
这是一个基于opencv的智能车牌识别系统,有GUI界面。程序能自动识别图片中的车牌号码,并支持中文和英文字符识别,支持选择本地图片文件,支持多种图片格式(jpg、jpeg、png、bmp、gif)。 下面,我将按模块功能对代码进行分段说明: 1. 导入模块部分 import tkinter as tk…...
[杂谈随感-13]: 人的睡眠,如何布置床的位置比较有安全?感?
睡眠环境中的床位布置直接影响心理安全感与睡眠质量,需从空间防御性、人体感知机制及环境心理学多维度综合设计。 以下基于科学原理与实践案例,系统解析床位布置的核心策略: 一、空间防御性布局:构建心理安全边界 背靠实体墙&a…...

DNS服务实验
该文章将介绍DNS服务的正向和反向解析实验、主从实验、转发服务器实验以及Web解析实验 正向解析实验:将域名解析为对应的IP地址 反向解析实验:将IP地址解析为对应的域名 主从实验:主服务器区域数据文件发送给从服务器,从服务器…...

visual studio 2015 安装闪退问题
参考链接: VS2012安装时启动界面一闪而过问题解决办法 visual studio 2015 安装闪退问题...

C语言复习--动态内存管理
下面我们来看C语言中的动态内存管理,在之后的数据结构中会运用到C语言中的指针,结构体和动态内存管理,所以这部分还是比较重要的.下面进入正题. 为什么要有动态内存分配 但是上面的两种方式开辟的内存的大小都是固定的.数组也是,在数组开辟之前一定要确定好数组大小,并且数组开…...
Python实例题:Python协程详解公开课
目录 Python实例题 题目 课程目标 课程内容规划 1. 课程开场(5 分钟) 2. 基础概念讲解(15 分钟) 并发与并行: 线程与进程: 3. Python 协程的实现方式(20 分钟) 生成器实现…...

青藏高原七大河流源区径流深、蒸散发数据集(TPRED)
时间分辨率 月空间分辨率 1km - 10km共享方式 开放获取数据大小 83.27 MB数据时间范围 1998-07-01 — 2017-12-31元数据更新时间 2024-07-22 数据集摘要 通过构建耦合积雪、冻土、冰川等冰冻圈水文物理过程的WEB-DHM模型(Water and Energy Budget-based Distribute…...
[学习]RTKLib详解:rtksvr.c与streamsvr.c
本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。 [学习] RTKlib详解:功能、工具与源码结构解析 [学习]RTKLib详解:pntpos.c与postpos.c [学习]RTKLib详解&…...
Docker使用小结
概念 镜像( Image ) :相当于一个 root 文件系统;镜像构建时,分层存储、层层构建;容器( Container ) :镜像是静态的定义,容器是镜像运行时的实体;…...

串口屏调试 1.0
http://wiki.tjc1688.com 先把商家的链接贴过来 淘晶驰T1系列3.2寸串口屏tft液晶屏显示屏HMI触摸屏超12864液晶屏 这是主包的型号 打开这个玩意 有十个基本的功能区 新建工程 在界面的右边,指令一定要写在page前面,这里的波特率等等什么的都可以…...

windows 环境下 python环境安装与配置
运行环境安装 第一步安装包下载 python开发工具安装包下载官网: https://www.python.org/ 根据自己的实际需求选择。 这里记录了各个版本的区别和差异。根据区别和差异选择适合自己的版本。 Windows Installer和Windows embeddable package是两种不同的软件包类…...

浅谈装饰模式
一、前言 hello大家好,本次打算简单聊一下装饰者模式,其实写有关设计模式的内容还是蛮有挑战性的,首先呢就是小永哥实力有限担心说不明白,其次设计模式是为了解决某些问题场景,在当前技术生态圈如此完善的情况下&#…...

LeetCode 270:在二叉搜索树中寻找最接近的值(Swift 实战解析)
文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在日常开发中,我们经常需要在一组有序的数据中快速找到最接近某个目标值的元素。LeetCode 第 270 题“Closest Binary Search Tree Value”正是这样一个问题。本文将深入解析该…...

WPF 3D图形编程核心技术解析
一、三维坐标系系统 WPF采用右手坐标系系统,空间定位遵循: X 轴 → 右 Y 轴 → 上 Z 轴 → 观察方向 X轴 \rightarrow 右\quad Y轴 \rightarrow 上\quad Z轴 \rightarrow 观察方向 X轴→右Y轴→上Z轴→观察方向 三维坐标值表示为 ( x , y , z ) (x, y,…...
分布式锁原理
1.锁是什么 一个线程拿到锁,另一个线程就拿不到,满足互斥性。 2.Redis的setnx实现 加锁后解锁,但是要先判断是否是当前线程持有的锁,只能释放本线程的锁。 先判断后释放,两步操作Lua实现原子性 3.为什么要给锁加过期…...

暗物质卯引力挂载技术
1、物体质量以及其所受到的引力约束(暗物质压力差) 自然界的所有物体,其本身都是没有质量的。我们所理解的质量,其实是物体球周空间的暗物质对物体的挤压,压力差。 对于宇宙空间中的单个星球而言,它的球周各处压力是相同的,所以,它处于平衡状态,漂浮在宇宙中。 对于星…...
实现三个采集板数据传送到一个显示屏的方案
实现三个采集板数据传送到一个显示屏的方案 要实现三个相同采集板的数据都传送到一个显示屏上,可行的方案: 方案:串行通信(推荐) 硬件连接: 使用RS485总线连接(适合较长距离)或使用…...

comfyui 如何优雅的从Hugging Face 下载模型,文件夹
如下图所示 使用git 下载整个仓库然后把需要的放到对应的位置...

通过user-agent来源判断阻止爬虫访问网站,并防止生成[ error ] NULL日志
一、TP5.0通过行为(Behavior)拦截爬虫并避免生成 [ error ] NULL 错误日志 1. 创建行为类(拦截爬虫) 在 application/common/behavior 目录下新建BlockBot.php ,用于识别并拦截爬虫请求: <?php name…...
动态规划法:爬楼梯
假如你现在爬楼梯,需要n阶才能到达楼顶,每次可以爬1或2 台阶,你有多少中不同的方法可以爬到楼顶。 例如: 输入:n2 输出:2 //有两种方法可以到达楼顶,1阶1阶,2阶。 输入&…...

IBM BAW(原BPM升级版)使用教程第七讲
续前篇! 一、团队 在 IBM Business Automation Workflow (BAW) 中,团队(Team) 是流程管理的关键部分,用于定义参与某个流程的用户、角色、组以及服务等。在团队配置中,有许多重要概念,特别是 …...

【论文阅读】Efficient and secure federated learning against backdoor attacks
Efficient and secure federated learning against backdoor attacks -- 高效且安全的可抵御后门攻击的联邦学习 论文来源问题背景TLDR系统及威胁模型实体威胁模型 方法展开服务器初始化本地更新本地压缩高斯噪声与自适应扰动聚合与解压缩总体算法 总结优点缺点 论文来源 名称…...

Java中的代理机制
目录 什么叫代理 静态代理 优缺点 优点: 缺点: 动态代理 JDK动态代理 核心类 JDK动态代理的实现 步骤 示例 特点 CGLIB动态代理 代理机制对比 总结 什么叫代理 代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替…...
Kotlin扩展函数提升Android开发效率
在Android开发中,Kotlin的扩展函数(Extension Functions)犹如一把神奇的瑞士军刀,它能显著提升代码简洁性和开发效率。以下是通过实战案例展示的扩展函数魔法手册: 一、扩展函数基础原理 // 给View添加渐显动画扩展 f…...

Jenkins linux安装
jenkins启动 service jenkins start 重启 service jenkins restart 停止 service jenkins stop jenkins安装 命令切换到自己的下载目录 直接用命令下载 wget http://pkg.jenkins-ci.org/redhat-stable/jenkins-2.190.3-1.1.noarch.rpm 下载直接安装 rpm -ivh jenkins-2.190.3-…...