AI在线 AI在线

Spring AI + MCP + DeepSeek-R1-7B + SSE 全流程实战指南

本教程将带你从 0 到 1 实现一个完整的 AI 流式问答应用,整合以下组件:Spring Boot Spring AI 构建服务框架MCP(Model Connector Plugin) 用于统一管理本地/云端大模型DeepSeek-R1-7B 国产高性能大模型(OpenAI API 兼容)SSE(Server-Sent Events) 实现前后端实时流式响应Ollama(可选) 更便捷地部署 DeepSeek-R1-7B 模型并提供 OpenAI 接口支持模型部署方式推荐:Ollama 运行 DeepSeek-R1-7B安装 Ollama访问:(以 DeepSeek 为例)复制也可以加载其它模型,如 llama3, qwen:chat, yi:34b, phi3, mistral 等。 启动 Ollama复制Ollama 会自动监听 OpenAI 风格接口(http://localhost:11434/v1/chat/completions),兼容 stream: true。 Spring Boot 接入 SSE 流式输出服务添加依赖(pom.xml)复制WebClient 配置类复制请求体结构封装复制DeepSeek-R1-7B 接口封装(支持 stream: true)复制控制器对外暴露 SSE 接口复制前端 JS 接入 SSE 实现流式展示复制总结通过以上步骤,我们成功实现了:Ollama 部署并运行 DeepSeek-R1-7B 本地大模型Spring Boot 封装 OpenAI 接口 stream: true实现后端 SSE 推流 前端实时 Token 渲染支持国产开源模型的类 ChatGPT 对话功能

本教程将带你从 0 到 1 实现一个完整的 AI 流式问答应用,整合以下组件:

  • Spring Boot + Spring AI 构建服务框架
  • MCP(Model Connector Plugin) 用于统一管理本地/云端大模型
  • DeepSeek-R1-7B 国产高性能大模型(OpenAI API 兼容)
  • SSE(Server-Sent Events) 实现前后端实时流式响应
  • Ollama(可选) 更便捷地部署 DeepSeek-R1-7B 模型并提供 OpenAI 接口支持

模型部署方式推荐:Ollama 运行 DeepSeek-R1-7B

安装 Ollama

访问:https://ollama.com

复制
# macOS / Linux 安装
curl-fsSL https://ollama.com/install.sh |sh

# Windows:安装官方 MSI 安装包

拉取模型(以 DeepSeek 为例)

复制
ollama pull deepseek:chat

也可以加载其它模型,如 llama3, qwen:chat, yi:34b, phi3, mistral 等。

启动 Ollama

复制
ollama run deepseek:chat

Ollama 会自动监听 OpenAI 风格接口(http://localhost:11434/v1/chat/completions),兼容 stream: true。

Spring Boot 接入 SSE 流式输出服务

添加依赖(pom.xml)

复制
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
</dependencies>

WebClient 配置类

复制
@Configuration
public class WebClientConfig {
    @Bean
    public WebClient webClient() {
        return WebClient.builder()
                .baseUrl("http://localhost:11434/v1") // Ollama API 地址
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }
}

请求体结构封装

复制
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ChatCompletionRequest {
    private String model;
    private List<Map<String, String>> messages;
    private boolean stream = true;
    private double temperature = 0.7;
}

DeepSeek-R1-7B 接口封装(支持 stream: true)

复制
@Service
public class DeepSeekStreamingService {


    @Autowired
    private WebClient webClient;


    public void streamChat(String userPrompt, SseEmitter emitter) {
        ChatCompletionRequest request = new ChatCompletionRequest();
        request.setModel("deepseek:chat");
        request.setStream(true);
        request.setMessages(List.of(
                Map.of("role", "user", "content", userPrompt)
        ));


        webClient.post()
                .uri("/chat/completions")
                .body(BodyInserters.fromValue(request))
                .accept(MediaType.TEXT_EVENT_STREAM)
                .retrieve()
                .bodyToFlux(String.class)
                .doOnNext(chunk -> {
                    try {
                        if (chunk.contains("[DONE]")) {
                            emitter.send(SseEmitter.event().data("[DONE]"));
                            emitter.complete();
                        } else if (chunk.startsWith("data:")) {
                            String json = chunk.replaceFirst("data: *", "");
                            String token = parseTokenFromJson(json);
                            emitter.send(SseEmitter.event().data(token));
                        }
                    } catch (Exception e) {
                        emitter.completeWithError(e);
                    }
                })
                .doOnError(emitter::completeWithError)
                .subscribe();
    }


    private String parseTokenFromJson(String json) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(json);
            return node.path("choices").get(0).path("delta").path("content").asText("");
        } catch (Exception e) {
            return "";
        }
    }
}

控制器对外暴露 SSE 接口

复制
@RestController
@RequestMapping("/api/ai")
public class ChatSseController {


    @Autowired
    private DeepSeekStreamingService streamingService;


    @GetMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter stream(@RequestParam("prompt") String prompt) {
        SseEmitter emitter = new SseEmitter(0L); // 永不超时
        streamingService.streamChat(prompt, emitter);
        return emitter;
    }
}

前端 JS 接入 SSE 实现流式展示

复制
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>AI 流式问答</title>
</head>
<body>
  <input id="prompt" placeholder="请输入你的问题...">
  <button onclick="startStream()">提问</button>
  <div id="result"></div>


  <script>
    function startStream() {
      const prompt = document.getElementById('prompt').value;
      const eventSource = new EventSource(`/api/ai/stream?prompt=${encodeURIComponent(prompt)}`);
      document.getElementById('result').innerHTML = '';
      eventSource.onmessage = function (event) {
        if (event.data === '[DONE]') {
          eventSource.close();
        } else {
          document.getElementById('result').innerHTML += event.data;
        }
      };
    }
  </script>
</body>
</html>

总结

通过以上步骤,我们成功实现了:

  • Ollama 部署并运行 DeepSeek-R1-7B 本地大模型
  • Spring Boot 封装 OpenAI 接口 stream: true
  • 实现后端 SSE 推流 + 前端实时 Token 渲染
  • 支持国产开源模型的类 ChatGPT 对话功能

相关资讯

告别传统 SSE!fetch-event-source 让 AI 流式处理更高效

在 AI 大模型飞速发展的时代,前端开发者面临着如何高效处理实时数据流的挑战。 服务器发送事件(SSE)作为一种单向通信协议,能够让服务器主动向客户端推送实时更新,广泛应用于实时聊天、新闻推送等场景。 然而,标准的 EventSource API 存在诸多限制,例如只能使用 GET 请求、无法传递请求体等。
3/4/2025 3:00:00 AM
PIG AI

十大步骤详解Spring AI MCP机制底层实现,小白误入!

MCP分为MCP Client和MCP Server:MCP Client负责进行工具发现和工具调用MCP Server负责提供工具和工具执行总体流程图图片十大步骤详解第一步,MCP Client接收用户的问题,比如“今天是几月几号”。 第二步,MCP Client发送tools/list请求给MCP Server进行工具发现。 利用Spring AI开发的MCP Server,可以利用@Tool注解定义工具,比如:图片并利用MethodToolCallbackProvider提供出去:在MCP Server的MpcServerAutoConfiguration自动配置类中定义了一个McpSyncServer的Bean,它会依赖注入ListToolCallbackProvider,这样McpSyncServer中就拿到了MCP Server中定义的所有Tools(调用ToolCallbackProvider的getToolCallbacks()即可拿到)。
4/11/2025 9:01:37 AM
IT周瑜

基于 Spring AI + MCP + DeepSeek-R1-7B 构建企业级智能 Agent 工具调用系统

在大模型 Agent 发展浪潮下,如何通过模型驱动外部工具调用(Tool Calling)已成为构建智能业务系统的关键能力。 本文将手把手带你通过 Spring AI MCP(Model Context Protocol) DeepSeek-R1-7B 打造一个可落地的企业级智能 Agent。 项目背景与架构设计技术选型Spring AISpring 官方推出的 AI 接入框架,支持 LangChain、MCP、RAG 等能力;MCP(Model Context Protocol)模型与工具之间通信的协议桥梁;DeepSeek-R1-7B国产高性能开源大模型,已支持 Chat Completion、Tool Calling 接口;Ragflow用作 RAG 架构引擎(可选);系统功能用户向模型提问模型判断是否调用工具(如数据库查询)MCP 注册的工具服务完成任务模型生成最终响应环境准备安装依赖复制本地部署 DeepSeek-R1-7B 模型推荐使用 vLLM 启动 DeepSeek-R1-7B 模型服务:复制构建 Spring AI MCP 工具服务示例业务:产品信息查询复制注册 MCP 工具复制模型端配置(Ragflow 示例)在 ragflow.config.yaml 中配置模型地址及 MCP 工具启用:复制前端调用(可选)复制测试效果用户输入:复制输出结果:复制模型会自动触发 query-product 工具,无需用户指定,展示 Agent 工具能力。
4/21/2025 4:22:00 AM
编程疏影
  • 1