跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava算法

SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人

综述由AI生成SpringAI 项目结合 Ollama 本地部署 Deepseek 模型,实现了从基础对话到 RAG 检索增强的完整流程。内容涵盖向量数据库 pgvector 的配置与集成、PDF 文档解析、Function Call 自定义函数注册以及多模态图片识别功能。通过实际代码示例,展示了如何在 Java 环境中构建具备上下文记忆和外部知识检索能力的本地 AI 应用。

静心发布于 2026/4/9更新于 2026/5/2213 浏览
SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人

SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人

在上一节中我们完成了 Ollama、Open WebUI 和 Docker 的本地可视化部署。本节将深入实战,演示如何在 Java 项目中通过 SpringAI 调用本地运行的 Deepseek 模型,并扩展 RAG 检索、PDF 解析及多模态功能。

Java 调用 Deepseek

首先确保本地已安装 Ollama 并拉取模型。在命令行执行以下命令:

ollama run deepseek-r1:7b

本地测试

启动 Docker Desktop 运行 Open WebUI,选择 deepseek-r1 模型进行基础对话测试,确认服务正常响应。

集成 SpringAI

依赖配置 移除原有的 Moonshot 相关依赖,引入 Ollama Starter:

<!-- 引入 Ollama 依赖 -->
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-ollama-spring-boot-starter</artifactId>
</dependency>

配置类编写 定义 ChatClient 和 ChatMemory Bean,设置系统提示词以模拟特定角色(如特朗普语气),并启用内存对话记忆。

package com.yan.springai;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@RequiredArgsConstructor
public class Init {
    final OllamaChatModel model2;

    @Bean
    public ChatClient chatClient(ChatMemory chatMemory) {
        return ChatClient.builder(model2)
                .defaultSystem("假如你是特朗普,接下来的对话你必须以特朗普的语气来进行?")
                .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory))
                .build();
    }

    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }
}

配置文件 在 application.yml 中指定模型名称和 Ollama 地址:

spring:
  ai:
    ollama:
      chat:
        options:
          model: deepseek-r1:7b
      base-url: http://localhost:11434

运行应用后,控制台应能输出符合设定语气的回复。

构建数据库与 RAG

增强检索 (RAG)

Embedding 是将文本转化为数值向量的过程,用于捕捉语义相似性。我们需要一个 Embedding 模型,这里选用轻量级的 all-minilm:

ollama pull all-minilm

向量数据库 (pgvector)

使用 PostgreSQL 配合 pgvector 扩展存储向量数据。启动容器时注意端口映射:

docker run -d --name pgvector -p 5433:5432 \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=postgres \
pgvector/pgvector:pg16

Spring Boot 集成 引入 pgvector 依赖并配置连接参数:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pgvector-store-spring-boot-starter</artifactId>
</dependency>
spring:
  ai:
    vectorstore:
      pgvector:
        index-type: HNSW
        distance-type: COSINE_DISTANCE
        dimensions: 384
        batching-strategy: TOKEN_COUNT
        max-document-batch-size: 1000
    ollama:
      chat:
        options:
          model: deepseek-r1:7b
      embedding:
        enabled: true
        model: all-minilm
        base-url: http://localhost:11434
    datasource:
      url: jdbc:postgresql://localhost:5433/springai
      username: postgres
      password: postgres

初始化表结构 连接数据库后执行 SQL 脚本创建向量表:

create extension if not exists vector;
create extension if not exists hstore;
create extension if not exists "uuid-ossp";

create TABLE if not exists vector_store(
    id uuid DEFAULT uuid_generate_v4() PRIMARY KEY,
    content text,
    metadata json,
    embedding vector(384)
);

create index on vector_store using HNSW(embedding vector_cosine_ops);

数据导入与检索

在 resources 目录下放置待处理的文本文件(如 ncode.txt)。创建 VectorAPI 控制器读取文件并按句号分片写入向量库:

package com.yan.springai.vector;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;

@RestController
@RequiredArgsConstructor
public class VectorAPI {
    final VectorStore store;

    @GetMapping("/vec/write")
    public String write() throws IOException {
        StringBuffer text = new StringBuffer();
        ClassLoader classLoader = getClass().getClassLoader();
        InputStream inputStream = classLoader.getResourceAsStream("ncode.txt");

        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = reader.readLine()) != null) {
                text.append(line);
            }
        }

        // 按句号分片并写入
        store.write(Arrays.stream(text.toString().split("。"))
                .map(Document::new).toList());
        return "success";
    }
}

调用接口后,查看数据库确认数据已入库。此时若直接提问,模型仅凭自身知识回答。为了利用外部知识库,需修改 Init 类,加入 QuestionAnswerAdvisor:

// ... imports ...

@Configuration
@RequiredArgsConstructor
public class Init {
    final OllamaChatModel model2;
    final VectorStore vectorStore;

    @Bean
    public ChatClient chatClient(ChatMemory chatMemory) {
        return ChatClient.builder(model2)
                .defaultSystem("假如你是特朗普,接下来的对话你必须以特朗普的语气来进行?")
                .defaultAdvisors(
                        new MessageChatMemoryAdvisor(chatMemory),
                        new QuestionAnswerAdvisor(vectorStore)
                )
                .build();
    }

    @Bean
    public ChatMemory chatMemory() {
        return new InMemoryChatMemory();
    }
}

再次测试,模型现在能基于向量库中的文档内容回答问题了。

PDF 文档处理

SpringAI 支持直接读取 PDF 文件并转为向量。引入依赖:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-pdf-document-reader</artifactId>
</dependency>

编写 Controller 读取 baogao.pdf 并写入向量库:

package com.yan.springai.Pdf;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class Pdf {
    final VectorStore store;

    @GetMapping("/pdf/read")
    public String getDocsFromPdf() {
        PagePdfDocumentReader pdfReader = new PagePdfDocumentReader(
                "classpath:/baogao.pdf",
                PdfDocumentReaderConfig.builder()
                        .withPageTopMargin(0)
                        .withPageExtractedTextFormatter(
                                ExtractedTextFormatter.builder()
                                        .withNumberOfTopTextLinesToDelete(0)
                                        .build()
                        )
                        .withPagesPerDocument(1)
                        .build()
        );
        store.write(pdfReader.read());
        return "success";
    }
}

Function Call 自定义函数

部分模型支持 Function Calling,允许 AI 调用外部逻辑。注意 Deepseek 在此功能上支持有限,Moonshot 或 OpenAI 效果更佳。

定义服务

package com.yan.springai.func;

import java.util.function.Function;

public class OaService implements Function<OaService.Rquest, OaService.Response> {
    public Response apply(Rquest rquest) {
        System.err.printf("%s is token off%n", rquest.who);
        return new Response(10);
    }

    public record Rquest(String who) { }
    public record Response(int days) { }
}

注册到 Spring 容器

package com.yan.springai.func;

import org.springframework.ai.model.function.FunctionCallback;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FunctionRegistry {
    @Bean
    public FunctionCallback askForLeaveCallBack() {
        return FunctionCallback.builder()
                .function("askForLeave", new OaService())
                .description("当有人请假时,返回请假天数")
                .build();
    }
}

调用示例

package com.yan.springai.func;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class FuncAPI {
    final ChatClient chatClient;

    @GetMapping("/ai/func")
    public String funcCall(@RequestParam(value = "message") String message) {
        return chatClient.prompt(message)
                .functions("askForLeave")
                .call().content();
    }
}

多模态能力

多模态模型(如 LLaVA)能理解图片内容。Deepseek 原生不支持,需切换模型。

拉取模型

ollama run llava

代码实现

将图片放入 resources 目录,编写接口接收请求:

package com.yan.springai.model;

import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.ChatOptions;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.model.Media;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.ollama.api.OllamaModel;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequiredArgsConstructor
public class ImageAPI {
    final OllamaChatModel model;

    @GetMapping("/ai/chatWithPic")
    public String chatWithPic() {
        ClassPathResource imageData = new ClassPathResource("/cat.png");
        Message userMessage = new UserMessage(
                "请用中文描述一下这张图片是什么东西?",
                List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData))
        );
        return model.call(new Prompt(
                List.of(userMessage),
                ChatOptions.builder()
                        .model(OllamaModel.LLAVA.getName())
                        .build()
        )).getResult().getOutput().getText();
    }
}

至此,我们完成了从文本对话、知识库检索、文档解析到图像识别的全流程搭建。

目录

  1. SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人
  2. Java 调用 Deepseek
  3. 本地测试
  4. 集成 SpringAI
  5. 构建数据库与 RAG
  6. 增强检索 (RAG)
  7. 向量数据库 (pgvector)
  8. 数据导入与检索
  9. PDF 文档处理
  10. Function Call 自定义函数
  11. 多模态能力
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 降低 AIGC 率的 Prompt 指令策略与代码实践
  • Llama-Factory 中启用梯度裁剪保护训练稳定性
  • HarmonyOS6 RcImage 组件核心架构与状态管理机制
  • 宇树 Go2 机器人强化学习开发实操指南
  • 基于 LLaMA-Factory 与 LoRA 微调 GPT-OSS-20B 模型实战
  • Python 反爬进阶:Token/时间戳/签名机制无痕绕过实战
  • 一文说清FPGA如何实现高速数字信号处理
  • 前端安全实践:防止 XSS、CSRF 与数据泄露
  • Eino 组件核心:Retriever 在 RAG 中的检索协议与实现
  • HTML/CSS 实现 520 表白信封 3D 翻转效果
  • 企业级黑词分析组件:双面板交互与进度监控实现
  • Ubuntu 下 llama.cpp 编译与性能调优实战
  • AI 上下文优化实战:解决过载与不足的平衡之道
  • 位运算算法实战:判断字符唯一、丢失数字与两数之和等题目解析
  • 2023 电赛 H 题信号分离装置 FPGA+STM32 解法
  • 智慧企业为何选择大模型重塑客服体系
  • MySQL 基本查询与增删改查实战指南
  • CTFShow Web 入门:题目 21-28 爆破解析
  • 论文阅读:Vision-Language-Action (VLA) 模型概念、进展与应用挑战
  • 数据结构核心:二叉树、堆与遍历算法实现

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online