基于 Spring AI 构建智能餐厅推荐系统:RAG 技术实战

最近在探索 Spring AI 的 RAG 功能,发现它确实是一个很强大的工具。今天就来分享一下如何用 Spring AI 构建一个智能餐厅推荐系统,通过检索增强生成技术让 AI 能够基于真实的餐厅数据给出更准确的推荐。

源代码

如果您想亲自尝试,可以随时查看我的源代码。为此,您必须克隆我的示例 GitHub 仓库。然后,您只需按照我的说明进行操作即可。

🎯 快速预览

在深入技术细节之前,先看看这个系统能做什么:

用户问题"我想在北京找一家川菜馆"

AI 回答

根据我的知识库,为您推荐几家北京的优质川菜餐厅:

峨嵋酒家(西城区车公庄大街1号)

  • 北京老字号川菜,招牌菜宫保鸡丁
  • 人均:100-120元
  • 推荐菜:宫保鸡丁、水煮鱼、夫妻肺片
  • 环境:传统中式装修,适合家庭聚餐
  • 电话:010-6831-2345

锦府盐帮(朝阳区三里屯北路45号)

  • 融合川南盐商菜与经典川菜
  • 人均:120-150元
  • 推荐菜:退秋鱼、盐帮仔蛙、招牌毛血旺
  • 环境:古风庭院,适合商务宴请
  • 电话:010-6415-6789

核心特点

⚡ 5分钟快速体验

如果你想立即体验,可以按照以下步骤:

# 1. 下载项目代码
git clone https://github.com/chensoul/spring-ai-restaurant-showcase.git
cd spring-ai-restaurant-showcase
# 2. 启动数据库
docker-compose up -d
# 3. 启动 Ollama
ollama serve
ollama pull llama3.2
ollama pull mxbai-embed-large
# 4. 启动应用
mvn spring-boot:run -Pollama-ai
# 5. 加载数据
curl -X POST "http://localhost:8080/api/rag/load" \
-H "Content-Type: application/json" \
-d '{"filePath": "classpath:restaurant-knowledge.txt"}'
# 6. 开始聊天
curl -X POST "http://localhost:8080/api/rag/chat" \
-H "Content-Type: application/json" \
-d '"我想在北京找一家川菜馆"'

预期结果:你会看到类似上面的智能推荐回答!

注意:确保你的系统已安装 Docker、Maven 和 Ollama。如果没有安装,可以参考下面的详细安装说明。

为什么选择 RAG?

AI 模型虽然很聪明,但它只能基于训练时的数据回答问题。如果我想让它推荐我所在城市的餐厅,它可能只能给出一些通用的建议,而不是基于真实、最新的餐厅信息。

RAG(Retrieval Augmented Generation) 解决了这个问题:

简单来说:当用户问”北京有什么好吃的川菜馆?“时,AI 从我们精心准备的餐厅数据库中检索相关信息,然后给出具体的推荐。

使用 PgVector 进行矢量存储

为什么选择 PgVector?

经过一番调研,我选择了 PgVector 作为向量存储方案:

安装 PgVector

使用 Docker Compose 安装

PgVector 提供了官方的 Docker 镜像,安装非常简单:

docker-compose.yml
services:
postgres:
image: pgvector/pgvector:pg16
container_name: restaurant-postgres
environment:
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
restart: unless-stopped

启动 PgVector 数据库:

docker-compose up -d

使用 Spring AI 实现 RAG

为什么选择 Spring AI?

在尝试了多种方案后,我最终选择了 Spring AI,原因很简单:

核心依赖

只需要添加几个依赖就能开始:

<!-- RAG 核心依赖 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-vector-store-pgvector</artifactId>
</dependency>
<!-- 文档处理和 Ollama 支持 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-markdown-document-reader</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-advisors-vector-store</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>

详细依赖列表:如果你需要完整的 pom.xml 配置,可以查看项目源码

配置 PgVector

PgVector 的配置很简单,关键是要设置正确的维度:

spring:
vectorstore:
pgvector:
index-type: ivfflat
distance-type: cosine_distance
dimensions: 1024 # 必须与嵌入模型输出维度一致
initialize-schema: true # 自动创建表结构
table-name: vector_store

关键点mxbai-embed-large 输出 1024 维向量,所以 PgVector 的 dimensions 必须设置为 1024。

配置 AI 模型

为什么选择 Ollama?

在构建 RAG 系统时,我们需要两个关键组件:聊天模型(生成回答)和嵌入模型(文档向量化)。

大多数云服务只提供聊天模型,嵌入模型需要单独的服务。而 Ollama 是少数几个同时支持聊天模型和嵌入模型的本地部署方案,这让 RAG 系统可以完全在本地运行!

我的选择理由

应用配置

spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: llama3.2
embedding:
options:
model: mxbai-embed-large

关键点mxbai-embed-large 输出 1024 维向量,所以 PgVector 的 dimensions 必须设置为 1024。

核心实现

Spring AI 让 RAG 实现变得极其简单,核心代码只有几行:

@Service
public class RagChatService {
private final ChatClient chatClient;
public String chatWithRag(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
}

为什么这么简单? Spring AI 的 QuestionAnswerAdvisor 自动处理了向量检索、上下文构建和提示词增强。

详细实现:完整的代码实现请查看项目源码

餐厅知识库构建

我准备了一个包含北京、武汉、上海、广州四个城市川菜餐厅的 Markdown 文档。数据格式很简单:

# 北京川菜餐厅推荐
### 峨嵋酒家
- 地址:北京市西城区车公庄大街1号
- 特色:北京老字号川菜,招牌菜宫保鸡丁
- 人均:100-120元
- 推荐菜:宫保鸡丁、水煮鱼、夫妻肺片
- 环境:传统中式装修,适合家庭聚餐
- 电话:010-6831-2345

数据特点

为什么选择这种格式? Markdown 结构清晰,Spring AI 的 MarkdownDocumentReader 可以自动解析,非常方便。

运行应用程序

按照”5分钟快速体验”启动系统后,可以开始测试各种功能。详细的测试命令和高级功能请参考附录

启动系统

按照”5分钟快速体验”章节完成环境准备后,启动应用:

# 启动应用
mvn spring-boot:run -Pollama-ai
# 加载餐厅数据
curl -X POST "http://localhost:8080/api/rag/load" \
-H "Content-Type: application/json" \
-d '{"filePath": "classpath:restaurant-knowledge.txt"}'

基础测试

测试 RAG 功能

curl -X POST "http://localhost:8080/api/rag/chat" \
-H "Content-Type: application/json" \
-d '"我想在北京找一家川菜馆"'

测试文档搜索

curl -X POST "http://localhost:8080/api/rag/search" \
-H "Content-Type: application/json" \
-d '{"query": "水煮鱼", "topK": 3}'

监控和调试

常见问题

Q: 应用启动失败? A: 检查数据库是否启动,Ollama 是否运行,端口是否被占用。

Q: 数据加载失败? A: 确保 restaurant-knowledge.txt 文件存在,检查文件路径是否正确。

Q: AI 回答不准确? A: 检查数据是否正确加载,尝试调整检索参数。

附录

测试命令和高级功能

基础测试命令

按城市推荐"我想在北京找一家川菜馆" 按价格推荐"推荐一些人均100元左右的川菜馆" 按场景推荐"适合商务宴请的川菜餐厅有哪些?" 菜品推荐"哪家餐厅的水煮鱼最好吃?"

完整的 curl 命令请参考”运行应用程序”章节。

高级功能

个性化推荐:基于用户偏好的智能推荐

curl -X POST "http://localhost:8080/api/rag/chat-personalized" \
-H "Content-Type: application/json" \
-d '{"message": "推荐川菜馆", "userPreferences": {"city": "北京", "priceRange": "100-150"}}'

向量相似性搜索:基于语义相似度检索相关文档

curl -X POST "http://localhost:8080/api/rag/search" \
-H "Content-Type: application/json" \
-d '{"query": "水煮鱼", "topK": 3}'

性能监控:访问 http://localhost:8080/actuator/prometheus 查看详细指标。

Ollama 安装和配置

安装 Ollama

macOS

brew install ollama

Linux

curl -fsSL https://ollama.ai/install.sh | sh

Windows: 下载安装包:https://ollama.ai/download

下载 AI 模型

聊天模型ollama pull llama3.2(约 4.7GB) 嵌入模型ollama pull mxbai-embed-large(约 1.2GB)

完整的安装步骤请参考”5分钟快速体验”章节。

模型选择理由

关键优势:Ollama 是少数几个同时支持聊天模型和嵌入模型的本地部署方案,这让 RAG 系统可以完全在本地运行!

PgVector 手动安装

如果你更喜欢手动安装,可以:

  1. 安装 PostgreSQL 16+

  2. 安装 PgVector 扩展

    # 使用 pgxn 安装
    pgxn install vector
    # 或者从源码编译
    git clone --branch v0.5.1 https://github.com/pgvector/pgvector.git
    cd pgvector
    make
    make install
  3. 在数据库中启用扩展

    CREATE EXTENSION vector;

配置详解

为什么是 1024 维?

  1. 模型匹配mxbai-embed-large 模型输出 1024 维向量
  2. 性能平衡:1024 维在精度和性能间取得良好平衡
  3. 存储效率:相比 1536 维(OpenAI),存储空间更小
  4. 检索质量:足够表达语义信息,检索效果优秀

索引类型说明

对于餐厅推荐系统,ivfflat 索引已经足够使用。

PgVector 数据库验证与初始化

如果你需要手动验证数据库安装或重新初始化,可以参考以下步骤:

验证 PgVector 安装

-- 连接到数据库
docker exec -it restaurant-postgres psql -U postgres
-- 检查 PgVector 扩展是否已安装
\dx
-- 如果未安装,则安装扩展
CREATE EXTENSION IF NOT EXISTS vector;

检查向量表

-- 检查 vector_store 表是否存在
\dt vector_store
-- 查看表结构
\d vector_store

重新创建向量表

-- 删除现有表(谨慎操作!)
DROP TABLE IF EXISTS vector_store CASCADE;
-- 创建新的向量表
CREATE TABLE vector_store (
id VARCHAR(255) PRIMARY KEY,
content TEXT NOT NULL,
metadata JSONB,
embedding VECTOR(1024) -- 1024 维向量
);
-- 创建向量索引
CREATE INDEX ON vector_store USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- 创建元数据索引(可选,用于过滤查询)
CREATE INDEX ON vector_store USING GIN (metadata);

验证表创建

-- 检查表是否创建成功
\dt vector_store
-- 查看索引信息
\di
-- 测试插入一条记录
INSERT INTO vector_store (id, content, metadata, embedding)
VALUES (
'test-1',
'测试内容',
'{"source": "test"}'::jsonb,
'[0.1,0.2,0.3]'::vector
);
-- 查询测试记录
SELECT * FROM vector_store WHERE id = 'test-1';
-- 清理测试数据
DELETE FROM vector_store WHERE id = 'test-1';

总结与思考

通过这个项目,我深刻体会到了 Spring AI 的强大之处:

🎯 核心优势

  1. 开箱即用QuestionAnswerAdvisor 让 RAG 实现变得极其简单
  2. 高度集成:与 Spring 生态完美融合,配置简单
  3. Ollama 本地部署:完全免费,隐私安全,性能优秀
  4. 性能监控:内置 Prometheus 支持,便于生产环境监控

💡 关键收获

🚀 下一步计划

  1. 数据优化:收集更多真实的餐厅数据
  2. 功能扩展:支持图片、菜单等多媒体内容
  3. 性能优化:实现缓存、异步处理等
  4. 用户体验:开发前端界面,让普通用户也能使用

📚 学习资源

如果你也想尝试 Spring AI,推荐这些资源:


项目地址GitHub - spring-ai-restaurant-showcase

本文基于 Spring AI 1.1.2 版本编写,代码已在实际项目中验证。

GitHub中配置Renovate自动依赖更新和自动合并PR
基于 Spring AI 构建智能餐厅推荐系统:多模型集成的实践指南