三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

SpringAI + Ollama 本地大模型

SpringAI + Ollama 本地大模型

一、技术概述

Ollama 是轻量化本地大模型部署工具,支持一键部署 Qwen、Llama、LLaVA 等各类开源模型,无需复杂算力与编译配置,可实现本地私有化、零网络开销、数据不外泄的大模型推理能力。SpringAI 是 Spring 官方标准化 AI 开发框架,提供统一的模型调用抽象 API,可无缝适配云端模型与本地 Ollama 模型,实现业务代码无感切换。

本文基于SpringBootTest 单元测试实现全套实战能力,无需启动 Web 容器,专注模型调用调试,覆盖同步对话、流式输出、多模态图文识别三大核心场景,所有代码可直接运行、注释完整、适合学习与项目落地。

二、环境搭建与工程配置

2.1 Ollama 安装与模型拉取

本地部署 Ollama 并拉取对应模型,分别适配文本对话与图文多模态场景,终端执行以下命令:

  1. 安装 Ollama 客户端,默认本地服务地址:http://localhost:11434

  2. 拉取通用文本对话模型:ollama pull qwen3:7b

  3. 拉取多模态图文识别模型:ollama pull llava:7b

2.2 项目核心依赖(Maven)

项目基于 SpringBoot3,需引入 SpringAI Ollama 核心依赖、WebFlux 流式依赖、单元测试依赖,完整依赖如下:

<?xml version="1.0" encoding="UTF-8"?> <dependencies> <!-- SpringAI Ollama 核心适配依赖 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-ollama</artifactId> <version>1.0.0-M1</version> </dependency> <!-- 流式输出必备 WebFlux 响应式依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <!-- SpringBoot 单元测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>

2.3 全局配置文件(application.yml)

统一配置 Ollama 本地地址、默认模型、推理参数,所有测试类自动读取生效:

spring: ai: ollama: base-url: http://localhost:11434 chat: options: model: qwen3:7b temperature: 0.3 num-ctx: 4096

三、测试工程通用规范

本文所有测试用例统一遵循以下规范,保证代码一致性与可复用性:

  1. 使用@SpringBootTest注解加载 Spring 上下文,自动注入 Ollama 模型客户端;

  2. 同步调用适用于离线批量处理,流式调用适用于实时分段输出场景;

  3. 多模态场景手动切换llava:7b模型,覆盖图文识别能力;

  4. 所有用例无需启动 Tomcat 容器,直接运行单元测试即可调试模型效果。

四、实战一:同步 Chat 对话单元测试

4.1 场景说明

同步调用为一次性阻塞请求,模型完整生成全部内容后统一返回结果,适合离线文本总结、批量问答、后台业务处理场景,代码简单、调试稳定。

4.2 完整可运行代码

import jakarta.annotation.Resource; import org.junit.jupiter.api.Test; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.ollama.OllamaChatModel; import org.springframework.ai.ollama.api.OllamaChatOptions; import org.springframework.boot.test.context.SpringBootTest; /** * Ollama 同步对话单元测试 * 适用场景:离线问答、文本总结、批量数据处理 */ @SpringBootTest public class OllamaSyncChatTest { // 自动注入Ollama模型客户端,读取yml全局配置 @Resource private ChatModel ollamaChatModel; @Test void testSyncChat() { // 1. 定义用户提问内容 String question = "用简短语言解释SpringAI是什么"; //手动设置大模型 OllamaChatOptions ollamaChatOptions = OllamaChatOptions.builder() .model("qwen2.5:7b") .build(); // Prompt第二个参数:传入本次运行时option Prompt prompt = new Prompt(question, ollamaChatOptions); // 3. 同步调用本地大模型,阻塞等待完整返回 var chatResponse = ollamaChatModel.call(prompt); // 4. 标准化提取AI回答内容 String answer = chatResponse.getResult().getOutput().getText(); // 控制台输出结果,方便调试查看 System.out.println("===== 同步问答完整回答 ====="); System.out.println(answer); } }

五、实战二:SSE 流式输出单元测试

5.1 场景说明

流式输出基于 WebFlux 响应式 Flux 实现,模型逐段返回文本分片,模拟前端打字机效果,解决长文本超时、响应卡顿问题,适配实时对话、交互式问答场景。单元测试通过blockLast()阻塞主线程,等待全部数据流接收完毕。

5.2 完整可运行代码

import org.junit.jupiter.api.Test; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.PromptTemplate; import org.springframework.boot.test.context.SpringBootTest; import reactor.core.publisher.Flux; import javax.annotation.Resource; import java.util.Map; import java.util.StringJoiner; /** * Ollama 流式对话单元测试 * 适用场景:实时对话、打字机效果、长文本流式输出 */ @SpringBootTest public class OllamaStreamChatTest { @Resource private ChatModel ollamaChatModel; @Test void testStreamChat() { // 1. 定义用户提问内容 String question = "用简短语言解释SpringAI是什么"; //手动设置大模型 OllamaChatOptions ollamaChatOptions = OllamaChatOptions.builder() .model("qwen2.5:7b") .build(); // Prompt第二个参数:传入本次运行时option Prompt prompt = new Prompt(question, ollamaChatOptions); // 用于拼接所有流式分片,生成完整回答 StringJoiner fullContent = new StringJoiner(""); // 开启流式响应,逐段接收模型输出 Flux<String> streamFlux = ollamaChatModel.stream(prompt) .map(resp -> resp.getResult().getOutput().getText()) .doOnNext(chunk -> { // 实时打印每一段分片,模拟前端实时渲染 System.out.print(chunk); fullContent.add(chunk); }); // 阻塞主线程,等待所有流式数据推送完成 streamFlux.blockLast(); // 输出拼接后的完整回答 System.out.println("\n\n===== 流式拼接完整内容 ====="); System.out.println(fullContent); } }

六、实战三:多模态图文识别单元测试

6.1 场景说明

基于llava:7b多模态模型,支持图片+文本联合提问,实现图片内容识别、图像描述、看图问答等能力,可应用于图片解析、截图分析、图像内容审核等场景。

6.2 完整可运行代码

import org.junit.jupiter.api.Test; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.chat.prompt.ChatOptions; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.UrlResource; import javax.annotation.Resource; import java.net.MalformedURLException; /** * Ollama 多模态图文识别单元测试 * 依赖模型:llava:7b * 功能:图片解析、图文问答、图像内容描述 */ @SpringBootTest public class OllamaMultiModalTest { @Resource private ChatModel ollamaChatModel; @Test void testImageChat() throws MalformedURLException { // 1. 动态覆盖模型,指定多模态图文模型 ChatOptions multiModelOptions = ChatOptions.builder() .model("llava:7b") .temperature(0.2) .build(); // 2. 替换为自己的有效可访问图片公网链接 // 1。本地磁盘绝对路径 D:/test/a.jpg 或者 /opt/image/a.jpg String localFilePath = "C:/Users/65739/Downloads/ac1db2e4-80fb-4f92-bdc2-95a28b16dd75-1.png"; FileSystemResource imageResource = new FileSystemResource(localFilePath); //2.资源文件下的图片路径 // ClassPathResource imageResource = new ClassPathResource("image/cat.jpg"); // 3. 替换为自己的有效可访问图片公网链接 // String imageUrl = "https://pic.baike.soso.com/ugc/baikepic2/21123/20220313152217_9856.jpg/0"; // UrlResource imageResource = new UrlResource(imageUrl); //2.构建Media对象,封装图片资源 + MIME类型 Media media = Media.builder() .mimeType(MimeTypeUtils.IMAGE_JPEG) .data(imageResource) .build(); //3.构建UserMessage,文本+图片媒体 String userQuestion = "详细描述这张图片里面有什么内容"; UserMessage userMsg = UserMessage.builder() .text(userQuestion) .media(media) .build(); //4.组装Prompt,同时运行时指定多模态模型(llava) Prompt prompt = new Prompt(List.of(userMsg), multiModelOptions); var response = ollamaChatModel.call(prompt); String result = response.getResult().getOutput().getText(); // 输出图片识别结果 System.out.println("===== 图片识别回答 ====="); System.out.println(result); } }

七、运行注意事项与避坑指南

  1. 服务前置校验:运行测试前必须启动 Ollama 本地服务,确保127.0.0.1:11434可正常访问。

  2. 模型匹配校验:图文多模态场景必须指定llava:7b,文本模型无法解析图片资源。

  3. 流式依赖必填:流式输出必须引入 WebFlux 依赖,否则 Flux 响应式类无法加载,测试报错。

  4. 硬件适配说明:7B 模型建议 4G 及以上独立显卡,无 N 卡将走 CPU 推理,速度大幅降低。

  5. 图片资源规范:多模态测试需使用有效可访问图片链接,无效/失效图片地址会导致解析失败。

八、方案优势总结

  1. 调试高效:基于单元测试运行,无需启动 Web 容器,节省项目启动耗时。

  2. 数据安全:全程本地模型推理,业务数据不上公网,满足私有化合规需求。

  3. 代码通用:遵循 SpringAI 统一 API,可无缝迁移为 Web 接口或云端模型调用。

  4. 场景全覆盖:同时支持文本问答、流式交互、图文多模态,满足绝大多数本地 AI 开发场景。

← 返回列表