Spring AI + Ollama 实现 DeepSeek-R1 API 服务和调用

引言

随着大语言模型的快速发展,越来越多的开发者开始探索如何将这些强大的推理模型本地化运行。DeepSeek-R1,作为一款性能卓越的开源AI模型,以其低成本和出色的推理能力在技术圈内引起了广泛关注。本文将详细介绍使用Ollama部署的DeepSeek-R1,如何结合Spring Boot与Spring AI实现API服务调用,帮助开发者在本地化环境下实现高效的AI服务。

使用Spring Boot + Spring AI

在使用Ollama把deepseek-r1跑起来之后,我们就可以开始使用Spring Boot + Spring AI来调用了。

1、添加核心依赖

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.1</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
	<dependencies>
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

2、配置Ollama的相关信息:

server.port=8082
spring.ai.ollama.base-url=http://192.168.10.105:11434
spring.ai.ollama.chat.options.model=deepseek-r1-32b-q4:latest
spring.ai.ollama.chat.options.temperature=0.7

3、存入上下文信息,并调用接口进行聊天

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;

/**
 * 存入上下文信息,并调用接口进行聊天
 */
@Component
public class Completion {
    @Resource
    private OllamaChatModel aiClient;
    /**
     * 最大消息记录数
     */
    private final static Integer MAX_SIZE = 10;
    /**
     * 消息记录
     */
    private List<Message> messages = new ArrayList<>();
    /**
     * 初始化存入系统消息
     */
    @PostConstruct
    private void addSystemMessage() {
        String message = "你好,我是deepSeek 机器人";
        SystemMessage systemMessage = new SystemMessage(message);
        messages.add(systemMessage);
    }
    /**
     * 存储用户发送的消息
     */
    private void addUserMessage(String message) {
        Message userMessage = new UserMessage(message);
        messages.add(userMessage);
    }
    /**
     * 存储AI回复的消息
     */
    private void addAssistantMessage(String message) {
        Message assistantMessage = new AssistantMessage(message);
        messages.add(assistantMessage);
    }
    /**
     * 聊天接口
     */
    public String chat(String message) {
        addUserMessage(message);
        String result = aiClient.call(new Prompt(messages)).getResult().getOutput().getContent();
        addAssistantMessage(result);
        update();
        return result;
    }

    /**
     * 流式聊天接口
     */
    public Flux<String> chatStream(String message) {
        addUserMessage(message);
        StringBuffer fullReply = new StringBuffer();
        Flux<String> fluxResult = aiClient.stream(new Prompt(messages))
                .flatMap(response -> {
                    String reply = response.getResult().getOutput().getContent();
                    //拼接回复内容
                    fullReply.append(reply);
                    return Flux.just(reply);
                })
                .doOnComplete(() -> {
                    //监听流式响应完成,完整回复存入消息记录
                    addAssistantMessage(String.valueOf(fullReply));
                });
        update();
        return fluxResult;
    }

    /**
     * 更新消息记录
     */
    private void update() {
        if (messages.size() > MAX_SIZE) {
            messages = messages.subList(messages.size() - MAX_SIZE, messages.size());
        }
    }
}

4、编写控制器Controller

import jakarta.annotation.Resource;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaOptions;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.Map;

/**
 * @className: OllamaController
 * @author: XJ-YK
 * @date: 2025/2/8 15:46
 **/
@RestController
@RequestMapping("/ollama")
public class OllamaController {

    @Resource
    private OllamaChatModel ollamaChatModel;

    /**
     * 简单调用
     */
    @GetMapping(value = "/ai/ask")
    public Object ask(String msg) {
        String called = ollamaChatModel.call(msg);
        System.out.println(called);
        return called;
    }

    /***
     * 流式方式
     */
    @GetMapping(value = "/stream", produces = MediaType.TEXT_HTML_VALUE + ";charset=UTF-8")
    public Flux<String> stream(String msg) {
        return ollamaChatModel.stream(msg).flatMapSequential(Flux::just);
    }

    private final Completion completion;

    public OllamaController(Completion completion) {
        this.completion = completion;
    }

    /**
     * 分析上下文聊天
     */
    @GetMapping("/chat")
    public String chat(String message) {
        return completion.chat(message);
    }

    /**
     * 流式上下文
     */
    @GetMapping(value = "/chatStream", produces = MediaType.TEXT_HTML_VALUE + ";charset=UTF-8")
    public Flux<String> chatStream(@RequestParam String message) {
        return completion.chatStream(message);
    }
}

5、测试聊天

简单调用

输入:

http://127.0.0.1:8082/ollama/ai/ask?msg=你是谁

回复:

您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手DeepSeek-R1。
如您有任何任何问题,我会尽我所能为您提供帮助。

分析上下文聊天

输入:

http://127.0.0.1:8082/ollama/chat?message=1 3 5 7

回复:

好的,我现在要解决的问题是:
给定四个数字1、3、5、7,通过加减乘除运算得到24点。
我需要找到一个正确的表达式来达到这个目标。 
首先,我会回顾一下基本的算术运算符:加法(+)、减法(-)、括号(())可以帮助改变运算顺序,乘法(×),除法(÷)。
然后,我需要考虑如何排列这四个数字,并通过这些运算符组合起来得到24点。 
接下来,我可以尝试不同的组合方式。
例如,看看是否有办法把较大的数相乘或者相加,然后再进行调整。
比如,7和3相乘是21,如果能找到剩下的两个数1和5的某种组合来补上剩下的差值,这样可能可以达到24。 
然后,我想到或许可以把7和3结合起来,再加上其他数字的操作。
例如: (7 - 3) = 4;然后看看能否用1和5得到6,再与4相乘得到24(因为4×6=24)。
那么问题转化为如何用1和5得到6,这似乎比较容易:5 + 1 = 6。
这样的话,就可以把整个表达式写成: ((7 - 3) × (5 + 1)) = 4 × 6 = 24。 
这样看来,这个方法似乎是可行的。
不过,我要确保是否所有的运算符和数字都得到了正确的使用,并且每个数字只能用一次。 
让我再检查一下:在这个表达式中,我使用了7、3、5、1四个数,每个只出现了一次,而且运算符正确地应用了加法和乘法,以及括号来改变运算顺序。
因此,这个解法是正确的。 
当然,还可能有其他的组合方式,例如: (5 - 1) × (7 + 3) = 4 × 10 = 40,这超过了24; 或者,7 + 3 + 5 + 1 = 16,太小了,不行。 
再试另一个可能性:比如用分数来达到目标。
例如: (3 - (1 ÷ 5)) × 7 ≈ (3 - 0.2) ×7 = 2.8×7=19.6,这也不对。
或者,考虑使用除法在不同的位置: (5 + 7) ÷ (3 - 1) = 12 ÷ 2 = 6,这样不够; 再比如,1 × (5 + 7) × 3?那会是1×12×3=36,太大了。 
所以看来,最初找到的表达式可能就是正确的解法。
我需要确认一下计算步骤是否正确: 首先计算括号里的内容: - 7 - 3 =4 -5 +1=6 然后进行乘法:4 ×6=24。 
没错,这个过程是正确的,并且满足使用每个数字一次的条件。 
因此,最终的答案应该是: (7 - 3) × (5 + 1) =24。 
要通过加减乘除运算将1、3、5、7这四个数组合得到24点,可以按照以下步骤进行计算: 1. 计算括号内的部分: - \(7 - 3 = 4\) - \(5 + 1 = 6\) 2. 将上述结果相乘: - \(4 \times 6 = 24\) 因此,正确的表达式为: \[ (7 - 3) \times (5 + 1) = 24 \] 最终答案是: \[ \boxed{(7 - 3) \times (5 + 1) = 24} \]
### 使用 Spring 框架集成调用 DeepSeek-R1 API 服务 #### 创建 Spring Boot 项目并配置依赖 为了开始这个过程,在构建工具中初始化一个新的 Spring Boot 应用程序。通过 Spring Initializr 可以轻松完成这一步骤,同时确保 pom.xml 文件内包含了必要的依赖项以便支持与 DeepSeek-R1 的交互[^2]。 ```xml <dependency> <groupId>com.spring.ai</groupId> <artifactId>spring-ai-core</artifactId> <version>${spring-ai.version}</version> </dependency> ``` 上述 XML 片段展示了如何向 Maven 构建文件添加 `spring-ai-core` 依赖,这是用于处理人工智能相关功能的关键库之一。 #### 配置应用程序属性 在 src/main/resources/application.properties 或 application.yml 文件里定义连接至 DeepSeek-R1 所需的服务端点其他必要参数: ```yaml deeplearn: api-url: http://localhost:8080/deepseek-r1/api/v1/ key: your_api_key_here ``` 此部分设置允许开发者指定目标 API 地址以及访问密钥等重要信息。 #### 编写 REST 客户端代码 接下来编写一段简单的 Java 类用来封装 HTTP 请求逻辑并与远程服务器通信。这里推荐采用 RestTemplate 来简化网络请求的操作: ```java @Service public class DeepSeekClient { private final String apiUrl; private final String apiKey; @Autowired public DeepSeekClient(@Value("${deeplearn.api-url}") String apiUrl, @Value("${deeplearn.key}") String apiKey) { this.apiUrl = apiUrl; this.apiKey = apiKey; } public ResponseEntity<String> callApi(String endpoint, HttpMethod method, Object requestPayload){ RestTemplate restTemplate = new RestTemplate(); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("Authorization", "Bearer " + apiKey); HttpEntity<Object> entity = new HttpEntity<>(requestPayload, headers); return restTemplate.exchange(apiUrl + endpoint, method, entity, String.class); } } ``` 这段代码实现了基本的客户端类 `DeepSeekClient` ,它负责发送带有适当头部信息(如 Content-Type Authorization)的 HTTP 请求给 DeepSeek-R1 API,并接收响应数据。 #### 测试接口调用 最后可以通过控制器方法测试新建立起来的数据通路是否正常工作: ```java @RestController @RequestMapping("/api/test") public class TestController { private final DeepSeekClient deepSeekClient; @Autowired public TestController(DeepSeekClient deepSeekClient) { this.deepSeekClient = deepSeekClient; } @GetMapping("/invoke-deepseek") public ResponseEntity<?> invokeDeepSeek() throws Exception{ try { ResponseEntity<String> response = deepSeekClient.callApi("some-endpoint", HttpMethod.GET, null); if (response.getStatusCode().is2xxSuccessful()) { return ResponseEntity.ok(response.getBody()); } else { throw new RuntimeException("Failed to get a successful response from the server."); } } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); } } } ``` 以上就是基于 Spring Boot Spring AIDeepSeek-R1 API 进行集成的一个简单实例说明[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

loser.with.m

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值