告别 API 付费!Spring AI + Ollama 本地部署大模型保姆级教程

Ollama 是一个开源的大型语言模型(LLM)平台,提供了简洁易用的命令行界面和服务器,使用户能够轻松下载、运行和管理各种开源 LLM。通过 Ollama,用户可以方便地加载和使用各种预训练的语言模型,支持文本生成、翻译、代码编写、问答等多种自然语言处理任务。

Ollama 官网:https://ollama.com

Spring AI 支持使用 Ollama 管理的模型,下面介绍 Spring AI 中如何使用 Ollama Chat 和 Ollama Embeddings。本文默认已安装好 Ollama。


一、Ollama 下载与安装

1.1 Windows 安装

Ollama 下载地址:https://github.com/ollama/ollama

image.png

下载完成后双击 OllamaSetup.exe 进行安装,默认安装在 C:\users\{user}\AppData\Local\Programs 目录下。建议 C 盘至少要有 10G 剩余磁盘空间,因为后续 Ollama 中还要下载其他模型到相应目录中。

image.png

安装完成后,电脑右下角自动出现 Ollama 图标并开机启动。可以在 cmd 中运行模型进行会话:

# 命令:ollama run + 模型名
ollama run deepseek-r1:1.5b
>>> 你是谁?
<think>
</think>
您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手DeepSeek-R1。如您有任何问题,我会尽我所能为您提供帮助。
>>>

注意:使用 run 命令第一次运行模型时,如果模型不存在会自动下载,然后进入模型交互窗口。后续使用会自动进入交互窗口。

在浏览器中输入 localhost:11434 可以访问 Ollama,输出 Ollama is running。默认情况下,Ollama 服务仅监听本地回环地址(127.0.0.1),这意味着只有本地应用程序才能访问。如果想要通过局域网 IP 访问,需要在环境变量中添加 OLLAMA_HOST=0.0.0.0,使 Ollama 监听所有网络接口。

image.png

注意:以上环境变量设置完成后,需要重启 Ollama 才能生效。

1.2 macOS 安装

第一步:确认已安装 Homebrew,未安装则执行:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

第二步:安装 Ollama

brew install ollama

第三步:后台常驻 + 开机自启

brew services start ollama
# 查看运行状态
brew services list

第四步:验证本地模型

ollama list

在这里插入图片描述


二、Ollama Chat

下面以 Spring AI 中与 Ollama 模型对话为例,演示 Spring AI 的相关配置。

2.1 创建项目

创建 Spring Boot 项目,命名为 SpringAIOllama

在这里插入图片描述

2.2 配置 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.5.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>SpringAIOllama</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringAIOllama</name>
    <description>SpringAIOllama</description>

    <properties>
        <java.version>17</java.version>
    </properties>

    <!-- 导入 Spring AI BOM,统一管理 Spring AI 依赖版本 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-starter-model-ollama</artifactId>
        </dependency>
    </dependencies>

    <!-- 声明仓库,用于获取 Spring AI 预发布版本 -->
    <repositories>
        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
        </repository>
        <repository>
            <name>Central Portal Snapshots</name>
            <id>central-portal-snapshots</id>
            <url>https://central.sonatype.com/repository/maven-snapshots/</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

2.3 配置 application.properties

spring.application.name=SpringAIOllama

server.port=8080

# 配置 Ollama 的基础 URL 和使用模型
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.options.model=deepseek-r1:1.5b
spring.ai.ollama.chat.options.temperature=0.8

2.4 基本聊天

在项目中创建 controller 包,编写 ChatController.java,实现与 Ollama 模型的基本聊天功能:

import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
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 {

    @Autowired
    private OllamaChatModel chatModel;

    @GetMapping("/generate")
    public String generate(@RequestParam(value = "message", defaultValue = "给我讲个笑话") String message) {
        System.out.println("收到消息:" + message);
        String result = chatModel.call(message);
        System.out.println(result);
        return result;
    }
}

启动项目后,浏览器输入 http://localhost:8080/ai/generate?message=你是谁,可以看到输出内容如下:

我是DeepSeek Chat,由深度求索公司(DeepSeek)开发的智能AI助手!✨ 我可以帮你解答问题、提供建议、陪你聊天,还能处理各种文本、文档等内容。无论是学习、工作,还是日常生活中的疑问,都可以来问我哦!😊 有什么我可以帮你的吗?

2.5 Stream 流式聊天

Spring AI 使用 Ollama 模型同样支持 Stream 流式聊天,在 ChatController.java 中添加如下代码:

// 流式获取模型返回的内容
@GetMapping("/generateStream2")
public Flux<String> generateStream2(
        @RequestParam(value = "message", defaultValue = "给我讲个笑话") String message,
        HttpServletResponse response) {
    // 避免返回乱码
    response.setCharacterEncoding("UTF-8");

    System.out.println("收到消息:" + message);
    var prompt = new Prompt(new UserMessage(message));
    Flux<String> result = chatModel.stream(prompt)
            .map(chatResponse -> chatResponse.getResult().getOutput().getText());

    return result;
}

重启项目后,浏览器输入 http://localhost:8080/ai/generateStream2?message=你是谁 即可查看 Stream 流式返回结果。

2.6 运行时参数设置

Spring AI 使用 Ollama 模型时也支持运行时参数设置,可以在调用模型时通过 OllamaOptions 覆盖启动配置:

// 运行时参数设置
@GetMapping("/runtimeOptions")
public String runtimeOptions(
        @RequestParam(value = "message") String message,
        @RequestParam(value = "temp", required = false) Double temp
) {
    System.out.println("收到消息:" + message);

    Prompt prompt;
    if (temp != null) {
        // 构建带 temperature 的 OllamaOptions,覆盖默认配置
        var opts = OllamaOptions.builder()
                .temperature(temp)
                .build();
        prompt = new Prompt(message, opts);
        System.out.println("使用运行时覆盖 temperature=" + temp);
    } else {
        // 无 temperature 传入时,使用默认配置
        prompt = new Prompt(message);
        System.out.println("使用默认 temperature");
    }

    ChatResponse resp = chatModel.call(prompt);
    String result = resp.getResult().getOutput().getText();
    System.out.println("模型返回:" + result);
    return result;
}

重启项目后,可以传入不同参数进行测试:

http://localhost:8080/ai/runtimeOptions?message=1加1等于几&temp=0.1

三、Ollama Embeddings

Ollama Embeddings 是基于 Spring AI 中 EmbeddingModel 接口的实现,使用 Ollama 本地部署的模型生成文本嵌入(embeddings)。使用前需要准备如下内容:

  • 本地安装 Ollama
  • Ollama 中拉取下载了 Embedding 模型

3.1 下载 Embedding 模型

Ollama 支持很多模型,可以通过 https://ollama.com/library 查看可用模型列表。

内存要求参考:运行 7B 模型至少需要 8GB 内存;运行 13B 模型至少需要 16GB 内存;运行 33B 模型至少需要 32GB 内存。

其中 “7B”、“13B”、“33B” 分别表示模型参数量为 70 亿、130 亿、330 亿。参数越多,模型越复杂,所需内存也越大。

这里下载 nomic-embed-text 嵌入模型:

ollama pull nomic-embed-text

3.2 Embedding 案例 —— 查找相似文本

按照如下步骤完成 Ollama Embedding 案例,需要准备:

  • 创建 Spring Boot 项目,引入 spring-ai-starter-model-ollama 相关依赖
  • application.properties 中配置 Ollama 的嵌入模型
第一步:准备 Service

在项目中创建 service 包,并创建 EmbeddingService.java

import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class EmbeddingService {

    private EmbeddingModel embeddingModel;

    private final List<float[]> docVectors;

    // 1. 准备知识库文本内容
    private final List<String> docs = List.of(
            "美食非常美味,服务员也很友好。",
            "这部电影既刺激又令人兴奋。",
            "阅读书籍是扩展知识的好方法。"
    );

    public EmbeddingService(EmbeddingModel embeddingModel) {
        this.embeddingModel = embeddingModel;
        // 2. 启动时,将所有文档向量化
        this.docVectors = this.embeddingModel.embed(docs);
    }

    /**
     * 输入用户查询,返回最相似文档的索引(使用余弦相似度计算)
     * @param query 用户输入的查询文本
     * @return 最相似的知识库文本
     */
    public String queryBestMatch(String query) {
        // 将用户输入通过 EmbeddingModel 转换成向量
        float[] queryVec = embeddingModel.embed(query);

        int bestIdx = -1;     // 记录最匹配文档的索引
        double bestSim = -1;  // 记录最高相似度

        // 遍历所有文档向量,计算与查询向量的相似度
        for (int i = 0; i < docVectors.size(); i++) {
            double sim = cosineSimilarity(queryVec, docVectors.get(i));
            if (sim > bestSim) {
                bestSim = sim;
                bestIdx = i;
            }
        }
        return docs.get(bestIdx);
    }

    // 余弦相似度实现
    // 计算两个向量之间的余弦相似度,数值范围在 [-1, 1] 之间
    // 越接近 1 表示越相似,越接近 0 表示越不相似
    private double cosineSimilarity(float[] a, float[] b) {
        double dot = 0, na = 0, nb = 0;
        for (int i = 0; i < a.length; i++) {
            dot += a[i] * b[i];
            na += a[i] * a[i];
            nb += b[i] * b[i];
        }
        return dot / (Math.sqrt(na) * Math.sqrt(nb));
    }
}
第二步:准备 Controller

controller 包中创建 EmbeddingController.java,注入依赖并添加接口方法:

@Autowired
private EmbeddingService service;

// 文本相似度检测
@GetMapping("/similarity")
public Map<String, String> similarity(@RequestParam("query") String query) {
    String ans = service.queryBestMatch(query);
    return Map.of("query", query, "answer", ans);
}
第三步:启动项目并测试

启动 Spring Boot 项目,浏览器中输入如下内容进行相似文本查找(由于 Embedding 模型大小限制,匹配可能不够精准):

# 输入:http://localhost:8080/ai/similarity?query=美食
{
  "query": "美食",
  "answer": "美食非常美味,服务员也很友好。"
}

# 输入:http://localhost:8080/ai/similarity?query=电影
{
  "query": "电影",
  "answer": "美食非常美味,服务员也很友好。"
}

# 输入:http://localhost:8080/ai/similarity?query=书籍
{
  "query": "书籍",
  "answer": "美食非常美味,服务员也很友好。"
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐