跳到主要内容
SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人(二) | 极客日志
Java AI java
SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人(二) 综述由AI生成 介绍如何使用 Spring AI 结合 Ollama 本地部署 Deepseek 模型构建对话机器人。内容包括:配置 Ollama 与 Deepseek 模型、集成 pgvector 向量数据库实现 RAG 检索增强生成、读取 PDF 文档入库、注册并调用自定义 Function 函数以及利用多模态模型处理图片输入。提供了完整的 Spring Boot 代码示例与配置文件说明。
Elasticer 发布于 2026/4/6 更新于 2026/5/20 21 浏览SpringAI 结合 Ollama 本地部署 Deepseek 实现对话机器人
Java 调用 Deepseek
本地没有安装 Ollama、Docker,openwebUI,可以参考相关文档先进行基础环境搭建。
下载 Deepseek 模型
打开命令行窗口,拉取一下 Deepseek 模型:
ollama run deepseek-r1:7b
本地测试
运行 Open WebUI 后选择 Deepseek-r1 模型进行测试。
Java 调用模型
先把以前的 moonshot 依赖注释掉,然后将 moonshot 相关的删除,不然会报错。
引入 ollama 依赖:
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-ollama-spring-boot-starter</artifactId >
</dependency >
修改配置类:
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;
ChatClient {
ChatClient.builder(model2)
.defaultSystem( )
.defaultAdvisors( (chatMemory))
.build();
}
ChatMemory {
();
}
}
@Bean
public
chatClient
(ChatMemory chatMemory)
return
"假如你是特朗普,接下来的对话你必须以特朗普的语气来进行?"
new
MessageChatMemoryAdvisor
@Bean
public
chatMemory
()
return
new
InMemoryChatMemory
spring:
ai:
ollama:
chat:
options:
model: deepseek-r1:7b
base-url: http://localhost:11434
构建数据库
增强检索 RAG Embedding 是一种将对象(如词语、物品、用户等)表示为数值向量的方法。这种方法在深度学习和推荐系统中非常重要,因为它能够捕捉对象之间的相似性和关系。
我们先用 ollama 拉取一个 embedding 模型(选择的这个模型比较小,适合小项目,不适合企业级项目):
向量数据库 这里使用 pgvector(也可以用 redis)。
pgvector 是一个强大的 PostgreSQL 扩展,它为 PostgreSQL 数据库添加了向量相似性搜索功能。这使得我们可以在关系型数据库中执行语义搜索,将结构化数据查询与非结构化数据的语义理解相结合。
docker run -d --name pgvector -p 5433:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres pgvector/pgvector:pg16
Springboot 集成 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
然后我们使用 springboot 连一下数据库。
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 中放入一个 txt 文件。
然后建一个 vector 文件夹,创建一个 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" ;
}
}
控制台上打印出表示已经导入完毕,我们查看一下数据库。
其实我们 RAG 的能力也是通过 advisor 实现的 ,所以我们需要修改一下 Init 代码:
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.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.memory.InMemoryChatMemory;
import org.springframework.ai.ollama.OllamaChatModel;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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 ();
}
}
chatpdf
<dependency >
<groupId > org.springframework.ai</groupId >
<artifactId > spring-ai-pdf-document-reader</artifactId >
</dependency >
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 调用自定义函数 (温馨提示:AI 还不支持这个功能,比如 Deepseek,然而 Moonshot、OpenAI、Gimini 等是可以的)
首先创建一个逻辑函数,实现 Function 函数:
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) { }
}
然后再将 Function 注册到 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();
}
}
多模态能力 多模态大语言模型 (Multimodal Large Language Models,简称 Multimodal LLMs)是一种能够理解和生成多种类型数据的模型,包括文本、图片、音频和视频等。这些模型可以跨越不同的数据形式,进行信息的交互与生成。例如,传统语言模型只能处理文字,但多模态模型不仅能'读'文字,还能'看'图片、'听'声音,甚至'看'视频,并用文字或其他形式将它们的理解表达出来。
这里提示:Deepseek、Moonshot 等是不支持的,可以下载一下 llava。
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();
}
}
相关免费在线工具 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
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online