Spring AI 和 Ollama 实现 DeepSeek-R1 的本地 API 服务与调用
Spring AI 和 Ollama 实现 DeepSeek-R1 的本地 API 服务与调用
最近,DeepSeek
开源了其第一代推理大模型 DeepSeek-R1
,该模型以其极低的成本和与 OpenAI 相媲美的性能,在国内外引发了广泛讨论。作为开发者,我在独立产品中一直使用 DeepSeek 的 API 来实现一些功能,例如在 TransDuck 项目中的字幕翻译和视频翻译,效果非常出色。然而,随着一些私有化需求的增加,直接调用 API 的方式变得不可行,因此不得不转向本地部署大模型并提供 API 服务。
针对这一需求,我尝试使用 Ollama 在本地运行 DeepSeek-R1,并通过 Spring Boot
和 Spring AI
实现对模型的调用
。本文将详细介绍这一过程,如果你有类似需求或对此感兴趣,可以参考以下内容进行实践。
使用 Ollama 运行 DeepSeek-R1
通过 Ollama 运行 DeepSeek-R1 非常简单,尤其是在 Linux 服务器上,只需两步即可完成:
安装 Ollama
在 Linux 服务器上,直接运行以下命令即可完成安装:
curl -fsSL https://ollama.com/install.sh | sh
本地开发环境(MacOS 或 Windows)
如果你是在本地开发环境(如 MacOS 或 Windows)中使用,可以前往 Ollama 官网 下载客户端版本进行安装。
运行 deepseek-r1
ollama run deepseek-r1:1.5b
如果你的环境足够运行其他模型,那么也可以根据你的算力资源情况选择其他参数版本,命令如下:
ollama run deepseek-r1:1.5b
ollama run deepseek-r1:7b
ollama run deepseek-r1:8b
ollama run deepseek-r1:14b
ollama run deepseek-r1:32b
ollama run deepseek-r1:70b
ollama run deepseek-r1:671b
更多关于信息可查看:https://ollama.com/library/deepseek-r1
使用Spring Boot + Spring AI
在使用Ollama把deepseek-r1跑起来之后,我们就可以开始使用Spring Boot + Spring AI来调用了。
POM
<?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.3.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.com.codingce</groupId>
<artifactId>deepseek</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>deepseek</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
<spring-ai.version>1.0.0-M5</spring-ai.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置Ollama的相关信息
application.properties
spring.ai.ollama.base-url=http://localhost:11434
spring.ai.ollama.chat.model=deepseek-r1:1.5b
spring.ai.ollama.base-url: Ollama的API服务地址,如果部署在非本机,就需要做对应的修改
spring.ai.ollama.chat.model: 要调用的模型名称,对应上一节ollama run命令运行的模型名称
单元测试
尝试调用Ollama中的deepseek-r1模型,这里尝试实现一个翻译的功能。
package cn.com.codingce.deepseek;
import org.junit.jupiter.api.Test;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DeepseekApplicationTests {
@Autowired
private OllamaChatModel ollamaChatModel;
@Test
public void testChatModel() {
String prompt = """
你是一个精通中文和英文的翻译大师。如果我给你英文就翻译成中文,给你中文就翻译成英文。
""";
String message = """
Difficult times show us who our true friends are.
""";
String result = ollamaChatModel.call(prompt + ":" + message);
System.out.println(result);
}
}
单元测试结果
<think>
嗯,这个句子是关于困难时期的,用户希望翻译成中文,所以我要确保在中文中表达出同样的意思。首先,“difficult times”应该译为“困难时期”,这是一个常见的表达方式。“show us”就是“表明”或者“暴露”。然后,“who our true friends are”意思是“我们真实的朋友是谁?”,这部分需要准确传达出朋友的意思。
再想一下,整个句子的结构是“在困难时期,我们发现谁才是我们的真正朋友。”所以中文翻译应该是:“在困难时期,我们发现谁才是我们真正的朋友。”
另外,要注意语序和语气是否通顺。中文表达习惯上比较口语化,所以在保持自然的同时,让句子流畅易懂。这里没有复杂的修饰语,直接传达信息即可。
可能存在的疑问是,是否需要用更正式的词汇替换一些短语?比如“暴露”换成“揭示”或者“展现”,但其实“暴露”已经不错了。“真正的朋友”这个词虽然口语化,但在中文中比较常见,所以不需要修改。如果需要保持原意的话,“真正的朋友”也是可以接受的。
总结一下,翻译完成后句子应该是:“在困难时期,我们发现谁才是我们真正的朋友。”
</think>
Difficult times show us who our true friends are.
(在困难时期,我们发现谁才是我们真正的朋友。)
可以看到结果响应分成两部分,先是标签包含的内容,这是模型根据提供的提示,生成了一个思考的过程,最后才输出了翻译后的结果。