# Spring AI RAG 知识库项目重点说明
## 项目概述
基于 Spring AI 1.0.0 + PostgreSQL + pgvector 构建的企业级 RAG(检索增强生成)知识库问答系统,支持本地模型和云端 DeepSeek API 动态切换。
—
## 核心技术架构
### 1. 技术栈
| 层级 | 技术 | 说明 |
|------|------|------|
| 后端框架 | Spring Boot 3.4.3 | Java 17+ |
| AI 框架 | Spring AI 1.0.0 | 统一的 AI 模型抽象 |
| 向量数据库 | PostgreSQL + pgvector | 存储文档向量,支持相似度检索 |
| 本地模型 | Ollama + qwen3.5:4b | 本地对话模型(CPU 推理) |
| Embedding | Ollama bge-m3 | 本地向量化模型(1024 维) |
| 云端模型 | DeepSeek deepseek-chat | 快速对话(需 API Key) |
| 前端 | React + TypeScript + Vite | 聊天界面 + 文件上传 |
### 2. RAG 流程
```
用户提问
↓
向量检索 (VectorStore.similaritySearch)
↓ top-k=5 相关文档块
组装 Prompt (参考材料 + 问题)
↓
LLM 生成回答 (ChatClient)
↓
返回答案
```
—
## 重点配置文件
### application.yml
```yaml
spring:
ai:
ollama:
base-url: http://localhost:11434
chat:
options:
model: qwen3.5:4b # 对话模型
temperature: 0.3
embedding:
model: bge-m3:latest # 向量化模型(1024 维)
vectorstore:
pgvector:
dimensions: 1024 # 向量维度必须与 Embedding 模型一致
distance-type: COSINE_DISTANCE # 余弦相似度
rag:
chunk:
size: 800 # 分块 token 数
overlap: 200 # 块间重叠 token 数
compression-enabled: true # GZIP 压缩存储
max-file-size-mb: 100 # 文件大小限制(MB)
retrieval:
top-k: 5 # 检索返回最相关的 5 个块
memory:
max-messages: 20 # 对话记忆保留最近 20 条消息
```
—
## 核心服务说明
### ChatModelProvider(动态模型切换)
位于 `service/ChatModelProvider.java`
- 维护 `AtomicReference apiKey`
- 根据是否设置 API Key 动态切换对话模型
-
无 API Key → Ollama 本地模型
-
有 API Key → DeepSeek 云端 API
- Embedding 始终使用本地 Ollama bge-m3
```java
public ChatModel getChatModel() {
if (hasApiKey()) {
return createDeepSeekChatModel(); // 动态创建 DeepSeek 模型
}
return ollamaChatModel; // 使用预注入的 Ollama 模型
}
```
### DocumentIngestService(文档处理)
位于 `service/DocumentIngestService.java`
- 支持 13 种格式:pdf, doc, docx, ppt, pptx, xls, xlsx, txt, md, html, htm, rtf, csv
- 使用 Apache Tika 解析文档
- 使用 TokenTextSplitter 分块(默认 800 token, overlap 200)
- 每个文档块附加元数据:docId、category、source、importTime、fileSize
- GZIP 压缩存储:记录压缩前后长度,减少大文本存储开销
- 文件大小限制:默认 100MB,可通过 `rag.chunk.max-file-size-mb` 配置
### RagChatService(RAG 问答)
位于 `service/RagChatService.java`
- 向量相似度检索 → 组装 Prompt → ChatClient 调用 LLM
- 支持同步返回和流式输出(SSE)
- 使用 MessageChatMemoryAdvisor 实现多轮对话记忆
- 对话历史持久化到 PostgreSQL(spring-ai-starter-model-chat-memory-repository-jdbc)
- **元数据过滤**:支持按 category 分类检索,使用 FilterExpressionBuilder
—
## API 接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/documents/upload` | POST | 上传文档(multipart/form-data,file + category)
限流:5次/分钟 |
| `/api/documents/upload/progress` | POST | 上传文档(带进度跟踪,返回 taskId)
限流:5次/分钟 |
| `/api/upload/progress/{taskId}` | GET | 查询上传进度 |
| `/api/upload/progress/{taskId}/stream` | GET | SSE 流式进度推送 |
| `/api/documents/list` | GET | 获取文档列表(可选参数:category) |
| `/api/documents/stats` | GET | 获取文档统计(文档数、块数、总大小) |
| `/api/documents/{docId}` | DELETE | 删除单个文档 |
| `/api/documents/category/{category}` | DELETE | 删除指定分类下的所有文档 |
| `/api/documents/expired` | DELETE | 删除过期文档(参数:retentionDays,默认30) |
| `/api/documents/all` | DELETE | 删除所有文档 |
| `/api/chat` | POST | 同步问答(JSON:question + conversationId + category)
限流:30次/分钟 |
| `/api/chat/stream` | GET | 流式输出(SSE,参数:question + conversationId + category)
限流:30次/分钟 |
| `/api/chat/memory/{conversationId}` | DELETE | 清空指定对话历史 |
| `/api/chat/memory/all` | DELETE | 清空所有对话历史 |
| `/api/chat/memory/stats` | GET | 获取对话统计(会话数、消息数) |
| `/api/config/apikey` | POST | 设置 DeepSeek API Key |
| `/api/config/status` | GET | 获取当前模式(ollama / deepseek) |
### API 限流说明
系统基于客户端 IP 实施限流保护:
| 接口类型 | 限流速率 | 说明 |
|----------|----------|------|
| 聊天接口 | 30 次/分钟 | `/api/chat`、`/api/chat/stream` |
| 上传接口 | 5 次/分钟 | `/api/documents/upload`、`/api/documents/upload/progress` |
超出限流时返回 HTTP 429 状态码和错误消息。
—
## 数据库配置
### 环境要求
- **PostgreSQL 15+**(需编译安装 pgvector v0.8.2+)
- **pgvector 扩展**(用于向量存储和相似度检索)
### 数据库初始化步骤
```sql
-- 1. 创建数据库
CREATE DATABASE rag_db;
-- 2. 创建用户(可选,也可使用 postgres 超级用户)
CREATE USER rag_user WITH PASSWORD ‘rag_pass’;
GRANT ALL PRIVILEGES ON DATABASE rag_db TO rag_user;
-- 3. 启用 pgvector 扩展
\c rag_db
CREATE EXTENSION IF NOT EXISTS vector;
-- 4. 授权 public schema 权限
GRANT ALL ON SCHEMA public TO rag_user;
```
### 数据库连接配置
application.yml 中的数据源配置:
```yaml
spring:
datasource:
url: jdbc:postgresql://localhost:5432/rag_db
username: rag_user
password: rag_pass
driver-class-name: org.postgresql.Driver
```
### pgvector 向量存储配置
```yaml
spring:
ai:
vectorstore:
pgvector:
initialize-schema: true # 启动时自动创建 vector_store 表
dimensions: 1024 # 向量维度(BGE-M3 模型输出 1024 维)
distance-type: COSINE_DISTANCE # 余弦相似度
```
### 自动创建的数据库表
系统启动时由 Spring AI 自动创建以下表:
#### 1. `vector_store`(文档向量存储)
由 `PgVectorStore` 自动创建,存储文档分块后的向量:
| 列名 | 类型 | 说明 |
|------|------|------|
| `id` | VARCHAR(36) | 主键(UUID) |
| `content` | TEXT | 文档块文本内容 |
| `metadata` | JSONB | 元数据(docId、category、source、importTime) |
| `embedding` | VECTOR(1024) | 文档块的向量表示 |
#### 2. `chat_memory`(对话历史存储)
由 `JdbcChatMemoryRepository` 自动创建,存储多轮对话历史:
| 列名 | 类型 | 说明 |
|------|------|------|
| `conversation_id` | VARCHAR(255) | 对话会话 ID |
| `message_id` | VARCHAR(255) | 消息 ID(UUID) |
| `role` | VARCHAR(50) | 角色(user / assistant / system) |
| `content` | TEXT | 消息内容 |
| `created_at` | TIMESTAMP | 创建时间 |
### 验证数据库是否正常
```bash
# 连接数据库
psql -U rag_user -d rag_db
# 查看表
\dt
# 查看 vector_store 表结构
\d vector_store
# 查看 chat_memory 表结构
\d chat_memory
```
### ChatMemory 持久化配置
```yaml
spring:
ai:
chat:
memory:
repository:
jdbc:
initialize-schema: always # 启动时自动初始化对话记忆表
```
—
## 文档管理功能
### 核心组件
| 组件 | 文件 | 说明 |
|------|------|------|
| DocumentRepository | `repository/DocumentRepository.java` | 文档元数据管理,支持查询、删除、统计 |
| DocumentManagementService | `service/DocumentManagementService.java` | 业务逻辑层,提供文档管理方法 |
| DocumentManagementController | `controller/DocumentManagementController.java` | REST API 接口 |
| DocumentCleanupScheduler | `scheduler/DocumentCleanupScheduler.java` | 定时任务,自动清理过期文档 |
### 功能特性
1. **文档列表查询** - 按 docId 分组展示,包含文件名、分类、块数、大小、导入时间
2. **文档删除** - 支持单文档删除、按分类删除、删除过期文档、清空所有文档
3. **统计信息** - 文档数量、块数量、总存储空间大小
4. **自动清理** - 可配置的定时任务,自动清理超过保留天数的文档
### 配置说明
```yaml
rag:
document:
default-retention-days: 30 # 默认保留30天
cleanup-enabled: false # 默认关闭自动清理
cleanup-cron: "0 0 2 \* \* ?" # 每天凌晨2点执行
```
### 前端界面
点击右上角「
Documents」按钮展开文档管理面板:
- 显示文档统计信息(文档数、块数、总大小)
- 表格展示所有文档列表
- 支持单个删除、批量清理过期文档、清空所有文档
—
## 数据库表
系统自动创建以下表(由 Spring AI JdbcChatMemoryRepository 和 PgVectorStore 管理):
- `chat_memory` - 对话历史存储
- `vector_store` - 文档向量存储
—
## 项目文件结构
```
src/main/java/com/example/rag/
├── RagApplication.java # 启动类(启用 @EnableScheduling)
├── config/
│ ├── ChatMemoryConfig.java # 对话记忆配置(MessageWindowChatMemory)
│ ├── EmbeddingConfig.java # Embedding 模型配置
│ ├── OllamaChatConfig.java # Ollama 对话模型配置
│ ├── DeepSeekChatConfig.java # DeepSeek 对话模型配置
│ ├── AsyncConfig.java # 异步线程池配置
│ ├── RateLimitConfig.java # API 限流规则配置
│ └── WebMvcConfig.java # Web MVC 配置(拦截器、CORS)
├── controller/
│ ├── ChatController.java # 同步问答 API
│ ├── StreamController.java # 流式输出 API(SSE)
│ ├── DocumentController.java # 文档上传 API
│ ├── DocumentManagementController.java # 文档管理 API(列表、删除、统计)
│ ├── ConfigController.java # 配置 API(API Key、状态)
│ ├── UploadProgressController.java # 上传进度 API(查询、SSE推送)
│ └── ChatMemoryController.java # 对话记忆 API(清理、统计)
├── service/
│ ├── DocumentIngestService.java # 文档导入服务(多格式解析、分块、向量化)
│ ├── RagChatService.java # RAG 问答服务(检索 + 问答)
│ ├── ChatModelProvider.java # 动态模型切换(Ollama/DeepSeek)
│ ├── DocumentManagementService.java # 文档管理服务(删除、统计、清理)
│ ├── UploadProgressService.java # 上传进度管理(状态跟踪、SSE推送)
│ └── ChatMemoryService.java # 对话记忆服务(清理、统计)
├── repository/
│ └── DocumentRepository.java # 文档元数据访问层
├── scheduler/
│ └── DocumentCleanupScheduler.java # 定时清理任务
├── interceptor/
│ └── RateLimitInterceptor.java # API 限流拦截器
├── dto/
│ ├── ChatRequest.java
│ └── ChatResponse.java
└── exception/
└── GlobalExceptionHandler.java # 全局异常处理(含验证错误处理)
```
—
## 功能特性总结
| 功能模块 | 特性 | 说明 |
|----------|------|------|
| 文档处理 | 多格式支持 | PDF、Word、PPT、Excel、TXT、MD 等 13 种格式 |
| | 智能分块 | TokenTextSplitter,可配置 chunkSize/overlap |
| | GZIP 压缩 | 可选压缩存储,减少存储空间 |
| | 文件大小限制 | 默认 100MB,可配置 |
| 向量检索 | 相似度检索 | 基于 pgvector 的余弦相似度 |
| | 分类过滤 | 支持按 category 检索 |
| | Top-K 配置 | 默认返回前 5 个相关块 |
| 对话能力 | 多轮对话 | MessageWindowChatMemory,保留最近 20 条消息 |
| | 同步/流式 | 支持同步返回和 SSE 流式输出 |
| | 模型切换 | 本地 Ollama / 云端 DeepSeek API |
| 文档管理 | 文档列表 | 按 docId 分组展示 |
| | 删除功能 | 单文档、分类、过期、全部删除 |
| | 统计信息 | 文档数、块数、存储空间 |
| | 自动清理 | 可配置定时任务,清理过期文档 |
—
## 快速开始
### 1. 环境准备
```bash
# 确保已安装
# - PostgreSQL 15+ + pgvector v0.8.2+
# - Ollama + qwen3.5:4b + bge-m3:latest
# 创建数据库
createdb rag_db
psql rag_db -c “CREATE EXTENSION IF NOT EXISTS vector;”
```
### 2. 启动服务
```bash
# 后端(端口 8080)
cd f:\traesolocode\rag
mvn spring-boot:run
# 前端(端口 3000)
cd f:\traesolocode\rag\rag-frontend
npm install
npm run dev
```
### 3. 访问应用
打开浏览器访问:http://localhost:3000
### 4. 配置 DeepSeek API(推荐)
为获得更好的响应速度,建议配置 DeepSeek API:
1. 点击右上角「
Config」按钮
2. 输入 DeepSeek API Key(从 platform.deepseek.com 获取)
3. 点击「Save」
4. 状态标签变为绿色「DeepSeek API」表示切换成功
### 5. 使用流程
1. **上传文档** - 点击文件选择按钮,选择文档(支持 PDF、Word、PPT、TXT 等)
2. **选择分类** - 上传时可选择文档分类(HR/Finance/Tech/Legal/Default)
3. **提问** - 在输入框中输入问题,AI 会基于已上传文档内容进行回答
4. **文档管理** - 点击「
Documents」按钮查看和管理已上传文档
—
## 前端界面说明
### 顶部控制栏
- **状态标签**:显示当前模式(紫色 = Ollama Local,绿色 = DeepSeek API)
- **
Documents**:文档管理面板(点击展开/收起)
- **
Config**:模型配置面板(点击展开/收起)
### 文档管理面板
- **统计信息**:文档数、块数、总存储空间
- **清理按钮**:清理过期文档、删除所有文档
- **文档列表**:文件名、分类、块数、大小、导入时间、删除操作
### 聊天区域
- **文件上传**:支持拖拽或点击选择,显示实时上传进度
- **上传进度条**:显示上传状态、进度百分比、当前处理步骤、块数统计
- **分类过滤**:提问时可选择只检索特定分类的文档
- **消息列表**:用户消息(蓝色)、AI 回答(白色)
- **对话清理**:「
Clear Chat」按钮清空当前对话历史
—
## 常见问题排查
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 检索结果不准确 | 分块参数不合适 | 调整 `rag.chunk.size`(增大或减小) |
| 向量维度不匹配 | Embedding 模型维度与配置不一致 | 确认 `spring.ai.vectorstore.pgvector.dimensions: 1024` |
| pgvector 表未创建 | 数据库连接或权限问题 | 确认 `initialize-schema: true` 且用户有 public schema 权限 |
| DeepSeek API 调用失败 | API Key 无效或额度不足 | 检查 `platform.deepseek.com` 账户状态 |
| 对话无法记住上下文 | conversationId 不一致 | 确认前端每次请求使用相同的 conversationId |
| 文件上传失败(文件过大) | 超过文件大小限制 | 调整 `rag.chunk.max-file-size-mb` |
| 分类过滤不生效 | category 未正确传入 | 确认上传时设置了 category,检索时传入相同 category |
| 对话历史过长导致超时 | 历史消息过多 | 调小 `rag.memory.max-messages` |
