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 开发场景。

相关推荐
147API1 小时前
蒸馏模型版本升级怎么做,权重、评测器和服务配置一起管
人工智能·深度学习·蒸馏·模型蒸馏
湘美书院--湘美谈教育1 小时前
湘美书院主理人谈AI文学:提示词与Skill的与时俱进
大数据·人工智能·安全·自动化·生活
漏刻有时1 小时前
本地部署 Dify + DeepSeek 搭建AI知识问答客服全流程复盘
人工智能
weixin_549808361 小时前
人力资源数字化转型:从工具堆叠到AI原生架构的组织级跃迁路径
大数据·人工智能
l0001091 小时前
图书馆静谧环境构建:主流声学品牌产品与服务梳理
大数据·人工智能·声音
倔强的石头1061 小时前
【机器学习】机器学习三大范式_监督无监督强化学习概览
人工智能·机器学习
DO_Community2 小时前
多模型路由怎么选?2026 年 4 款主流方案对比
人工智能
CypressTel2 小时前
Google发布Gemini 3.7 Flash:企业为何要计算AI智能体的任务总成本——赛柏特AI快讯
人工智能
wujian83112 小时前
怎么用千问生成word文档:从「格式崩」到「一键过」,AI导出鸭打通最后半厘米
人工智能·ai·c#·word·豆包·deepseek·ai导出鸭