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

ollama官网:https://ollama.com

Spring AI支持使用Ollama管理的模型,下面介绍Spring AI中如何使用OllamaChat和Ollama Embeddings。这里默认已经安装好ollama。

Ollama下载与安装

Ollama下载地址:https://github.com/ollama/ollama,这里以window中下载为例

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

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

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

在浏览器中输入“localhost:11434”可以访问ollama,输出“Ollama is running”。默认情况下,Ollama 服务仅监听本地回环地址(127.0.0.1),这意味着只有在本地计算机上运行的应用程序才能访问该服务,如果想要使用“windows ip:11434”访问ollama需要在环境变量中加入“OLLAMA_HOST”为“0.0.0.0”,这样就将 Ollama 的监听地址设置为 0.0.0.0,使其监听所有网络接口,包括本机 IP 地址。

注意:以上环境变量设置完成后,需要重启ollama

Ollama Chat

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

1) 创建SpringBoot项目,命名为“SpringAIOllama”

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 依赖的版本,
   引用每个 Spring AI 模块时不用再写 <version>,只要依赖什么模块 Mavens 自动使用 BOM 推荐的版本 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.ai</groupId>
                <artifactId>spring-ai-bom</artifactId>
                <version>1.0.0-SNAPSHOT</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>

基本聊天

Stream流式聊天

//流式获取模型返回的内容,获取返回的 Text 内容
@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流式返回结果

运行时参数设置

Spring AI 使用Ollama中的模式时也支持运行参数设置,可以在调用模型时,创建一个prompt,并嵌入一个新的OllamaOptions来覆盖启动配置。

在“SpringAIOllama”项目的“/controller/ChatController.java”代码中准备如下方法:

//运行时参数设置
@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 的 DeepSeekChatOptions,覆盖默认 temperature
        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)。使用Ollam Embeddings你需要准备如下内容:

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

下载Embedding模型

Embedding案例-查找相似文本

按照如下步骤完成Ollama Embedding案例,该案例和上一章节中 “Embedding案例1”代码一样,只是换成了Ollama中的Embedding模型,需要准备如下内容:

* 创建SpringBoot项目,引入“spring-ai-starter-model-ollama”相关依赖
* 在resources/application.properties配置中引入Ollama的嵌入模型

**1) 准备Service及对应方法**

在“SpringAIOllama”项目中创建“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));
    }

}

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐