本文讲解Java编程中如何通过Spring AI框架 集成 Redis Stack 向量数据库和Ollama模型服务提供者实现RAG本地外挂知识库。
Redis Stack 部署演示环境可参考:redis-stack 安装(Docker)
本项目基于 Spring Boot 接入Ollama实现与Deepseek简单对话 项目修改。
maven引入必要的向量库依赖:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-redis-store-spring-boot-starter</artifactId>
</dependency>
application.yml配置参考:
spring:
application:
name: demo-boot-ollama
ai:
vectorstore:
redis:
initialize-schema: true
prefix: custom-prefix
index: custom-index
ollama: # ai 提供者 ollama
init:
pull-model-strategy: never # 下载策略
embedding:
additional-models:
- mxbai-embed-large #redis 向量库默认嵌入模型
- nomic-embed-text
# - chroma/all-minilm-l6-v2-f32
base-url: http://192.168.31.162:11434
chat:
options:
model: deepseek-r1:8b
data:
redis:
host: 192.168.31.162
RAG演示controller
@RestController
public class RagController {
@Resource
RedisVectorStore vectorStore;
@Resource
OllamaChatModel chatModel;
// 系统提示词模板
private final static String SYSTEM_PROMPT = """
你需要使用文档内容对用户提出的问题进行回复,同时你需要表现得天生就知道这些内容,
不能在回复中体现出你是根据给出的文档内容进行回复的,这点非常重要。
当用户提出的问题无法根据文档内容进行回复或者你也不清楚时,回复不知道即可。
文档内容如下:
{documents}
""";
@GetMapping("/ai/saveDocument")
public Object saveTextDocument(@RequestParam String text){
Document document = new Document(text);
vectorStore.add(List.of(document));
return "success";
}
@GetMapping("/ai/chatWithVectorStore")
public Object chatWithVectorStore(@RequestParam String message){
List<Message> messages = new ArrayList<>();
//构建用户信息
UserMessage userMessage = new UserMessage(message);
messages.add(userMessage);
//构建基于向量数据库结果的系统数据
List<Document> documents = vectorStore.similaritySearch(message);
if (documents != null &&!documents.isEmpty()){
Message systemMessage = new SystemPromptTemplate(SYSTEM_PROMPT).createMessage(Map.of("documents", documents));
messages.add(systemMessage);
}
// 将Message列表一并发送给大模型
ChatResponse rsp = chatModel.call(new Prompt(messages));
return rsp;
}
}
第一次请求询问:XQLEE是什么
http://localhost:8080/ai/chatWithVectorStore?message=XQLEE是什么
响应内容:
{
"result": {
"output": {
"messageType": "ASSISTANT",
"metadata": {
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "<think>\n\n</think>\n\n截至2024年7月,XQLEE并非一个广为人知的常见术语或技术领域。它可能是某个特定行业、项目或新兴技术的代号或简称。如果你指的是某个特定的概念、产品或技术,请提供更多背景信息,以便更好地帮助你理解。\n\n如果你有其他问题或需要进一步的解释,请随时告诉我!"
},
"metadata": {
"finishReason": "stop",
"contentFilters": [],
"empty": true
}
},
"metadata": {
"id": "",
"model": "deepseek-r1:8b",
"rateLimit": {
"requestsRemaining": 0,
"tokensRemaining": 0,
"requestsReset": "PT0S",
"requestsLimit": 0,
"tokensReset": "PT0S",
"tokensLimit": 0
},
"usage": {
"promptTokens": 7,
"completionTokens": 96,
"totalTokens": 103,
"generationTokens": 96
},
"promptMetadata": [],
"empty": false
},
"results": [
{
"output": {
"messageType": "ASSISTANT",
"metadata": {
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "<think>\n\n</think>\n\n截至2024年7月,XQLEE并非一个广为人知的常见术语或技术领域。它可能是某个特定行业、项目或新兴技术的代号或简称。如果你指的是某个特定的概念、产品或技术,请提供更多背景信息,以便更好地帮助你理解。\n\n如果你有其他问题或需要进一步的解释,请随时告诉我!"
},
"metadata": {
"finishReason": "stop",
"contentFilters": [],
"empty": true
}
}
]
}
第一次提问可以看到result结果中,它并没有明确回答
投喂向量数据库数据:XQLEE是一款视频剪切软件
http://localhost:8080/ai/saveDocument?text=XQLEE是一款视频剪切软件
响应内容:
success
第二次请求询问:XQLEE是什么
http://localhost:8080/ai/chatWithVectorStore?message=XQLEE是什么
响应内容:
{
"result": {
"metadata": {
"finishReason": "stop",
"contentFilters": [],
"empty": true
},
"output": {
"messageType": "ASSISTANT",
"metadata": {
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "<think>\n嗯,用户问的是“XQLEE是什么”,我需要用文档内容来回答。首先看文档内容,里面明确写着“XQLEE是一款视频剪切软件”。所以,我应该直接告诉用户XQLEE是视频剪切软件。\n\n接下来,我要考虑用户可能的需求。他们可能想知道这个软件的功能或者是否适合某个特定的用途。但文档里没有提到更多细节,所以我只能基于提供的信息回答。\n\n另外,用户希望我的回复显得天生就知道这些内容,不要表现出在查找资料。因此,我需要直接明了地告诉用户,不带任何额外的猜测或不确定性。\n\n最后,检查一下是否有无法回答的情况,但这里问题很简单,可以直接解答。\n</think>\n\nXQLEE是一款视频剪切软件。"
}
},
"metadata": {
"id": "",
"model": "deepseek-r1:8b",
"rateLimit": {
"tokensLimit": 0,
"tokensRemaining": 0,
"requestsLimit": 0,
"tokensReset": "PT0S",
"requestsReset": "PT0S",
"requestsRemaining": 0
},
"usage": {
"promptTokens": 167,
"completionTokens": 188,
"totalTokens": 355,
"generationTokens": 188
},
"promptMetadata": [],
"empty": false
},
"results": [
{
"metadata": {
"finishReason": "stop",
"contentFilters": [],
"empty": true
},
"output": {
"messageType": "ASSISTANT",
"metadata": {
"messageType": "ASSISTANT"
},
"toolCalls": [],
"media": [],
"text": "<think>\n嗯,用户问的是“XQLEE是什么”,我需要用文档内容来回答。首先看文档内容,里面明确写着“XQLEE是一款视频剪切软件”。所以,我应该直接告诉用户XQLEE是视频剪切软件。\n\n接下来,我要考虑用户可能的需求。他们可能想知道这个软件的功能或者是否适合某个特定的用途。但文档里没有提到更多细节,所以我只能基于提供的信息回答。\n\n另外,用户希望我的回复显得天生就知道这些内容,不要表现出在查找资料。因此,我需要直接明了地告诉用户,不带任何额外的猜测或不确定性。\n\n最后,检查一下是否有无法回答的情况,但这里问题很简单,可以直接解答。\n</think>\n\nXQLEE是一款视频剪切软件。"
}
}
]
}
第二次提问,已经根据外挂RAG知识向量库进行了准确回答。
https://blog.xqlee.com/article/2502191047576714.html