尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

SpringBoot+Ollama本地免费调用DeepSeek-R1:从部署到Spring AI实战

发布时间:2026/9/26 12:16:02

资讯中心
01
ARTICLE

SpringBoot+Ollama本地免费调用DeepSeek-R1:从部署到Spring AI实战

SpringBoot+Ollama本地免费调用DeepSeek-R1:从部署到Spring AI实战
简介针对希望低成本在本地调用deepseek-r1模型的Java开发者解压后即可获得一套基于Spring Boot与Spring AI框架的示例工程代码围绕Ollama接口封装了从依赖配置、参数设置到请求处理的关键链路。资源共7个文件以2个Java源文件为核心配合XML与Properties配置文件、Git忽略文件、License及README说明文档压缩包仅10KB结构紧凑方便直接导入项目对照修改。目前已有1462人学习下载适合正在搭建本地AI服务或希望降低模型调用成本的中小型项目团队。通过README与源码可以掌握Spring AI调用deepseek-r1的配置要点、请求响应处理逻辑及常见排错思路直接复用工程骨架有效缩短本地部署与调试时间。1. 用SpringBootSpring在本地把deepseek-r1接成免费服务先说清这条路长什么样很多Java团队聊到“把大模型接进业务系统”第一反应是买云厂商的API。直到我把一个内部工单助手接到云端账单和合规两个问题同时找上门单次调用不贵量一大月账单就很扎眼更麻烦的是工单数据不能出域业务方完全不接受。所以我转回了标题里这条路——用SpringBootSpring调用deepseek-r1模型在本地免费使用。这里“本地”指你公司的服务器或开发机“免费”指不按token付费、模型权重公开可下载代价是你得自己准备GPU或足够的内存。整条链路分三段Ollama做推理底座、Spring AI做客户端、Spring Boot做Web层。适合想低成本做内部问答、文档助手又在意数据留在墙内的Java团队。真正决定体验的不是Spring Boot代码而是选对蒸馏版模型和显存。2. 搭好本地推理底座Ollama部署deepseek-r1的模型选型与最小命令2.1 为什么选Ollama当底座而不是直接跑transformers标题里“调用deepseek-r1模型”落地第一步是让模型跑起来并提供HTTP服务。常见做法是装Ollama理由很实际它把模型权重的下载、量化、显存调度、常驻服务和OpenAI兼容API全部封装好了。Spring Boot这边只需要往http://localhost:11434发请求不用自己写Python推理服务也不用处理GPU显存分配这种脏活。对比一下自己搭transformers的方案你得先装Python环境、拉模型权重、写加载和推理脚本、自己管理并发排队、再包一层HTTP接口。对Java团队来说这套维护成本不划算而且transformers默认用fp32跑同样显存下能跑的模型比Ollama的GGUF量化版本小得多。如果你已经有vLLM或者llama.cpp的server在跑Spring这边改个base-url也能接但对新项目我一般直接用Ollama起步。Ollama的另一个好处是模型管理一条命令搞定。换模型、换量化版本不用改Java代码只改配置里的模型名。这对后面做模型对比很有用同一个Spring Boot服务配置指到不同模型测试集一跑效果差异立刻出来。2.2 deepseek-r1的满血版和蒸馏版本地免费使用的前提这里有一个必须提前说破的坑Ollama仓库里的deepseek-r1标签和DeepSeek官方论文里的671B满血版不是一回事。满血DeepSeek-R1是大规模MoE模型跑起来需要几百GB显存个人电脑和普通公司服务器根本背不动。Ollama上能拉到的deepseek-r1:7b、deepseek-r1:14b、deepseek-r1:32b是用DeepSeek-R1蒸馏Qwen或Llama得到的小模型参数量小一个数量级但保留了R1的推理风格会先输出一段思考链再给结论。本地免费使用指的就是这些蒸馏版。选哪个尺寸不是越大越好要看显存和响应速度的平衡。按我的经验可以按这张表起步模型标签最低内存/显存建议适合场景deepseek-r1:1.5b4GB文本分类、实体抽取这类简单任务deepseek-r1:7b8-12GB内部问答、RAG问答最稳的起步选项deepseek-r1:14b16GB需要一定推理能力的代码解释、方案对比deepseek-r1:32b24-32GB追求接近云端体验但响应明显变慢如果只有CPU没有GPU7B以下模型勉强能跑但首token可能要等十几秒只适合离线批量处理不适合做在线接口。我见过不少团队在8GB显存的机器上硬上14B结果Ollama把模型部分卸载到内存一次请求等到超时还误以为是Spring代码的问题。选型这件事宁可往小一档选先把链路跑通。2.3 安装Ollama并拉取模型三条命令加一次接口验证Ollama安装本身没有太多可讲的装完守护进程会自动起来。拉取模型的命令是这样# 确认Ollama服务可用 ollama --version # 拉取deepseek-r1蒸馏版7B在16G内存的机器上能流畅跑 ollama pull deepseek-r1:7b # 查看本地已有模型和实际标签 ollama list模型文件会从官方仓库下载体积在4GB到20GB不等网络慢就耐心等。ollama list输出的NAME列里模型名是带版本的比如deepseek-r1:7b这个标签在后面Spring配置里要原样使用。很多人在这里踩坑配置里写deepseek-r1Ollama却报model not found就是因为标签没写全。模型拉下来后先不要急着写Java代码用curl直接打Ollama的接口确认推理服务是通的curl http://localhost:11434/api/chat \ -H Content-Type: application/json \ -d {model:deepseek-r1:7b,messages:[{role:user,content:用一句话介绍Spring Boot}],stream:false}stream:false表示完整返回不要流式。这一步能正常返回JSON说明模型已经加载成功、推理链路没问题。我习惯再加一句ollama ps看模型是否常驻显存。这样把故障边界划清楚Ollama没起来、模型没拉对、端口不通都在这一个curl里暴露完后面Spring Boot连不上时就不用怀疑底座了。3. SpringBoot接入deepseek-r1Spring AI依赖、配置和两个必调参数3.1 用Spring AI而不是手写RestTemplate的理由标题里同时出现“Spring”和“SpringBoot”实际接入时有两条路。一条是拿Spring的RestTemplate裸调Ollama的HTTP接口自己拼JSON、自己解析流式返回、自己处理错误另一条是用Spring官方出的Spring AI框架它把模型调用抽象成ChatClient和Spring Boot的配置体系、自动装配完全打通。我选后者原因很直接裸调一次问答接口确实只要二十行代码但一旦要调temperature、接多轮历史、解析思考链、切模型手写代码的工作量会迅速膨胀而且每个模型接口的差异都得自己适配。Spring AI目前已经GA依赖管理和Spring Boot版本有对应关系。我用的是Spring Boot 3.3.x加Java 17Spring AI的BOM用1.0.0版本。要注意Spring AI的starter并不是全放在Maven Central默认仓库里就能拉到官方BOM会统一管理版本项目里先import BOM再引依赖避免版本冲突。3.2 最小依赖、配置和第一个对话接口在pom.xml里加两段依赖。第一段是BOM放在dependencyManagement里作用是锁定所有Spring AI组件的版本dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.0.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement第二段是真正的starter只引入Ollama这一个模型客户端不会把OpenAI、Azure之类的实现也带进来dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-ollama/artifactId /dependencyBOM负责版本starter负责自动装配。Spring Boot启动后会自动检测classpath里只有一个ChatModel实现把OllamaChatModel装配成可用Bean。如果项目里同时引了多个AI厂商的starter就需要在配置里指定用哪一个否则启动会报Bean冲突。配置文件application.yml里只需要三组关键项spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: deepseek-r1:7b temperature: 0.7 num-ctx: 8192base-url指Ollama的HTTP监听地址默认就是11434端口。model必须和ollama list里的标签完全一致这是第一个必调参数。temperature是第二个必调参数deepseek-r1这类会先输出思考链的模型温度太高推理会发散0.6到0.7之间比较稳。num-ctx是上下文窗口的token数Ollama默认只有2048对话稍长就被截断我直接调到8192内存够的话可以更大。然后是第一个Controller注入Spring AI的ChatModel写一个同步问答接口package com.example.demo; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatModel; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; RestController RequestMapping(/ai) public class ChatController { private final ChatModel chatModel; public ChatController(ChatModel chatModel) { this.chatModel chatModel; } GetMapping(/chat) public String chat(RequestParam(defaultValue 你好介绍一下你自己) String message) { return ChatClient.builder(chatModel) .build() .prompt() .user(message) .call() .content(); } }这段代码的逻辑是通过ChatClient.builder(chatModel)拿到一个客户端构建器prompt().user(message)设置用户消息call()发起同步调用最终content()取出模型返回的文本。整个调用是阻塞的本地模型推理慢一个请求会占住一个Web线程所以这个接口只适合内部低并发场景。生产环境要走异步或流式后面会讲。参数都在配置文件和ChatClient内部生效代码里不需要再指定模型名。如果某个请求想临时换参数再通过OllamaOptions覆盖这个在3.3节展开。3.3 多轮对话、参数覆盖和上下文长度控制云API调用时多轮对话就是把历史消息数组传给服务端。本地模型也一样但区别在于每次请求模型都要把全部历史token重新算一遍没有云端的“免重复计算”优化所以历史越长响应越慢上下文窗口很快会被撑满。我有一个处理原则本地模型只保留最近几轮对话超过就丢弃。用Spring AI构造多轮消息有两种写法。简单场景用ChatClient的链式方法String reply ChatClient.builder(chatModel) .build() .prompt() .system(你是部署在本机的问答助手回答要简洁。) .user(我的项目用Spring Boot 3.3推荐一个参数校验方案) .call() .content();system()设置系统提示词user()是用户当前问题。这种方式适合单轮问答历史消息需要自己拼接成字符串放进user多轮时容易混乱。更正式的做法是构造消息列表import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.SystemMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.ollama.OllamaOptions; import java.util.List; Listorg.springframework.ai.chat.messages.Message messages List.of( new SystemMessage(你是部署在本机的问答助手回答要简洁。), new UserMessage(我的项目用Spring Boot 3.3), new AssistantMessage(明白。), new UserMessage(推荐一个参数校验方案) ); OllamaOptions options OllamaOptions.builder() .model(deepseek-r1:7b) .temperature(0.6) .numCtx(8192) .numPredict(2048) .build(); String reply ChatClient.builder(chatModel) .build() .prompt(new Prompt(messages, options)) .call() .content();这段代码把system、user、assistant消息按时间顺序放进列表最后一条是当前问题模型会结合之前的上下文回答。OllamaOptions.builder()在这里的作用是单次请求覆盖默认参数numCtx管上下文窗口numPredict管最大生成token数。deepseek-r1的思考链比较长numPredict太小会出现话说到一半被切断的情况2048起步比较合理。多轮对话有一个本地部署特有的坑历史消息里混着很长的思考链Ollama返回的assistant内容会把思考过程和正式答案一起带回来。如果你把整段思考链又塞回prompt里几轮之后上下文就被思考链填满了。我一般只保存正式回答部分或者干脆让前端自己维护历史后端只接收当前问题。4. 本地调用deepseek-r1的五个高频坑从模型名不匹配到上下文截断4.1 配置与连通性三个让Java端直接报错的坑第一个坑现象很典型Spring Boot启动正常Controller也调起来了但一请求就报model not foundOllama服务端日志里明确写着找不到模型。原因基本是配置里的模型名和ollama list里的标签不一致比如写成deepseek-r1实际标签是deepseek-r1:7b。Ollama把带版本标签当成完整模型名不带版本号找不到。解决方法是把spring.ai.ollama.chat.options.model写成和ollama list输出完全一致的字符串一个字符都不能差。第二个坑出现在Docker部署场景。Ollama装在容器里本地curl通Spring Boot却连接超时。原因是容器只暴露了Ollama的web端口但Ollama在容器里监听的是127.0.0.1:11434宿主机访问不到。解决方法是启动容器时加-p 11434:11434并且确认Ollama没把监听地址绑死在localhost。如果是Docker Compose部署还要检查服务名和端口映射对不对。这个坑的本质是“能跑通”和“能被外部访问”是两回事先用curl http://容器IP:11434验证再说。第三个坑是Spring AI的依赖拉不下来。现象是Maven报错找不到spring-ai-starter-model-ollama或者版本冲突。原因通常是BOM没有import成功或者IDE缓存了旧的依赖索引。解决方法是先确认spring-ai-bom的版本写对type是pom、scope是import然后强制刷新Maven。Spring AI的1.0.0版本依赖的Spring Boot版本有下限如果项目还停在Spring Boot 2.x那直接升级Boot版本更省事硬降Spring AI版本会踩到一堆API不兼容。4.2 推理质量与资源两个运行时才暴露的坑第四个坑是整个链路最常遇到的第一次请求特别慢要等十几秒甚至更久然后Spring端直接超时。原因是Ollama默认按需加载模型第一次请求要把几个GB的权重文件读进显存或内存这个过程跟模型大小直接相关。我见过7B模型在机械硬盘上加载花了二十秒后来换了SSD才降到几秒。解决的办法有两个一是启动Spring Boot时做一次预热在ApplicationRunner里调用一次ChatClient让模型提前加载进内存二是设置Ollama的环境变量OLLAMA_KEEP_ALIVE让模型在内存里常驻不要空闲几分钟就被卸载。预热的代码很短import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.model.ChatModel; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; Component public class ModelWarmupRunner implements ApplicationRunner { private static final Logger log LoggerFactory.getLogger(ModelWarmupRunner.class); private final ChatModel chatModel; public ModelWarmupRunner(ChatModel chatModel) { this.chatModel chatModel; } Override public void run(ApplicationArguments args) { long start System.currentTimeMillis(); String reply ChatClient.builder(chatModel) .build() .prompt() .user(ping) .call() .content(); log.info(deepseek-r1 预热完成耗时 {}ms模型返回{}, System.currentTimeMillis() - start, reply); } }这段逻辑是Spring Boot启动完成后自动执行一次最小调用把加载延迟从第一个真实用户的请求里挪走。日志里的耗时可以作为一次性能参考。第五个坑是回答中途被截断或者上下文一长就开始胡说。现象是模型说了一段话突然停住没有完整的结束。原因有两个层面一是num-ctx太小历史消息加当前问题超出了上下文窗口模型只能看到被截断的输入二是numPredict限制了最大生成token数deepseek-r1的思考链很长2048的生成上限可能被思考链先占满正式答案还没写完就停了。解决方法是把numCtx调到8192以上numPredict调到4096同时观察显存占用上下文窗口越大占用的显存也越多。如果显存不够调大numCtx只会让Ollama把更多的K/V cache卸载到内存速度反而更慢。还有一个和并发相关的坑Ollama默认单并发两个请求同时进来会排队。症状是第二个请求的响应时间翻倍但不是模型变快了是一个在等另一个。解决方法是设置OLLAMA_NUM_PARALLEL环境变量允许一个模型并行处理多个请求前提是显存够用。我的经验是8GB显存跑7B模型并发调成2基本是上限再高就会OOM。5. 从“能出字”到“能干活”验证输出质量与两个可落地的进阶用法本地跑通deepseek-r1只是第一步真正要投入内部使用得先回答一个问题这个蒸馏版模型的输出质量比花钱调云端API差多少。我习惯准备一个固定冒烟测试集不用多五个prompt就够一个Spring Boot知识问答、一个代码生成、一个逻辑推理、一个长文本总结、一个开放写作。同样的prompt分别打到本地模型和云端API对比的不是单个句子的好坏而是结构性差异比如是否丢关键步骤、代码能否直接运行、长上下文是否丢失前面信息。响应耗时也是一个观察点本地首token普遍比云端慢但数据不出域这个收益是否能覆盖延迟代价只有业务方自己能评估。如果质量达标下一步我建议做两件事。第一是接本地embedding模型做RAG把内部文档向量化Spring AI的OllamaEmbeddingModel可以复用同一套Ollama底座拉一个nomic-embed-text模型就能把文档切块、向量化、存到本地向量库问答时先检索再交给deepseek-r1生成这比把整个文档塞进上下文靠谱得多。第二是把接口改成流式输出ChatModel的stream()方法返回FluxString前端用SSE逐字展示本地模型慢的体验会被大幅拉平。我的习惯是模型标签永远写全Ollama单独放一台机器Spring Boot启动时做一次预热健康检查每次升级Spring AI版本前先看release notes确认属性名有没有变。这三点是血泪换来的希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。