# qize-spring-ai-platform
**Repository Path**: zhlei2004/qize-spring-ai-platform
## Basic Information
- **Project Name**: qize-spring-ai-platform
- **Description**: 本项目致力于构建基于 Spring Boot 体系的高扩展 AI 能力中台。
该平台通过高度解耦的模块化设计,提供 可移植、即插即用的关键 AI 组件封装,如:上下文管理、嵌入向量库、知识库和统一模型适配层。
核心职责是简化 Spring AI 项目的构建,实现模块的全流程自动配置和快速落地。通过这套中台解决方案,开发者能够专注于业务逻辑,高效构建高扩展、高可用的智能体 (Agent) 应用。
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 4
- **Created**: 2026-07-28
- **Last Updated**: 2026-07-28
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Spring AI 模块
## 介绍
Spring AI 模块是一个基于 Spring Boot 3.x 的高扩展性 AI 能力中台,提供完整的 AI 服务能力封装,帮助企业快速集成 AI 能力到现有业务系统中。
### 核心特性
- **多模型支持**:支持 OpenAI、DeepSeek、Ollama 等多种 AI 模型,轻松切换
- **上下文管理**:支持内存和 Redis 两种上下文存储方式,实现多轮对话
- **知识库检索**:支持 Simple、Hybrid、Graph 三种 RAG 策略,满足不同场景需求
- **向量存储**:支持内存和 Redis 两种向量存储方式,灵活选择
- **插件化架构**:基于 AiProcessor 接口的插件化设计,轻松扩展功能
- **响应式编程**:基于 Project Reactor 的全响应式实现,高性能
- **Graph RAG**:集成 Neo4j 图数据库,实现基于知识图谱的增强检索
### 技术栈
- **JDK**:17+
- **Spring Boot**:3.5.0
- **Spring AI**:1.0.0-M6
- **LangChain4j**:1.8.0
- **Neo4j**:用于 Graph RAG 实现
- **Redis**:用于上下文和向量存储
- **MySQL**:用于持久化存储
- **Apache Tika**:用于文件解析(支持 PDF、Word、Excel 等多种格式)
- **Project Reactor**:响应式编程框架
## 软件架构
### 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ 管理层 (Manager) │
│ - AiManager (核心执行器) │
│ - AiProcessor (插件接口) │
│ - 插件链管理 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 服务层 (Service) │
│ - KnowledgeService (知识库服务) │
│ - ContextManager (上下文管理) │
│ - ModelAdapter (模型适配器) │
│ - VectorStore (向量存储) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 基础设施层 (Infrastructure) │
│ - Neo4j (图数据库) │
│ - Redis (缓存和向量存储) │
│ - MySQL (持久化存储) │
│ - LLM API (OpenAI/DeepSeek/Ollama) │
└─────────────────────────────────────────────────────────────┘
```
### 模块结构
```
ai-spring-module/
├── ai-module-parent/ # Maven 父模块
├── ai-common/ # 通用基础模块
├── ai-context-api/ # 上下文 API 模块
├── ai-context-memory/ # 内存上下文实现
├── ai-context-redis/ # Redis 上下文实现
├── ai-context-starter/ # 上下文 Starter
├── ai-model-api/ # 模型 API 模块
├── ai-model-openai/ # OpenAI 模型适配器
├── ai-model-deepseek/ # DeepSeek 模型适配器
├── ai-model-ollama/ # Ollama 模型适配器
├── ai-model-starter/ # 模型 Starter
├── ai-knowledge-api/ # 知识库 API 模块
├── ai-knowledge-simple/ # Simple 知识库实现
├── ai-knowledge-hybrid/ # Hybrid 知识库实现
├── ai-knowledge-graph/ # Graph 知识库实现
├── ai-knowledge-starter/ # 知识库 Starter
├── ai-vector-api/ # 向量存储 API 模块
├── ai-vector-memory/ # 内存向量存储
├── ai-vector-redis/ # Redis 向量存储
├── ai-vector-starter/ # 向量存储 Starter
├── ai-file-parser-api/ # 文件解析器 API 模块
├── ai-file-parser-tika/ # Apache Tika 文件解析器实现
├── ai-file-parser-starter/ # 文件解析器 Starter
├── ai-manager/ # AI 管理器核心模块
├── ai-prompt-mysql-starter/ # Prompt 持久化 Starter
├── ai-message-mysql-starter/ # 消息持久化 Starter
├── ai-coze-migration-toolkit/ # 扣子平台迁移工具
├── ai-spring-boot-starter/ # 一键全家桶 Starter
├── ai-sample-app/ # 示例应用
└── ai-test/ # 测试模块
```
### 核心流程
```
用户请求 (ChatRequest)
↓
初始化消息管道 (messagePipe)
↓
前置插件链 (preProcessors)
- 人设插件 (SystemMessage 注入)
- 历史记录插件 (ContextProcessor)
- 知识库插件 (KnowledgePreProcessor)
├─ Simple: 直接向量检索
├─ Hybrid: 语义搜索 + 关键词搜索
└─ Graph: 实体识别 + 关系查询 + 向量检索
↓
添加用户消息
↓
消息清洗与排序
↓
调用 AI 模型 (chatModelAdapter.unifiedChat)
↓
后置插件链 (postProcessors)
- 脱敏插件
- 消息存储插件
- 审计日志插件
↓
返回响应 (responseStream)
```
## 安装教程
### 环境要求
- JDK 17+
- Maven 3.6+
- Redis 7.0+ (可选,用于上下文和向量存储)
- Neo4j 5.0+ (可选,用于 Graph RAG)
- MySQL 8.0+ (可选,用于持久化存储)
### 快速开始
#### 1. 添加依赖
在您的 Spring Boot 项目的 `pom.xml` 中添加依赖:
```xml
com.jalon
jalon-ai-spring-boot-starter
0.0.1-SNAPSHOT
com.jalon
ai-file-parser-starter
0.0.1-SNAPSHOT
```
#### 2. 配置文件
在 `application.yml` 中添加配置:
```yaml
jalon:
ai:
project-id: your-project-id
user-id: your-user-id
model:
type: deepseek
deepseek:
api-key: your-deepseek-api-key
base-url: https://api.deepseek.com
model-name: deepseek-chat
context:
type: redis
redis:
host: localhost
port: 6379
ttl: PT1H
knowledge:
enable: true
default-retrieve-type: simple
vector:
type: redis
redis:
host: localhost
port: 6379
file-parser:
max-file-size: 52428800
ocr-enabled: false
splitter:
type: recursive
chunk-size: 1000
chunk-overlap: 200
```
#### 3. 使用 AI 服务
```java
@Service
public class AiService {
@Autowired
private AiManager aiManager;
public String chat(String userMessage) {
ChatRequest request = ChatRequest.builder()
.userMessage(userMessage)
.build();
return aiManager.execute(request)
.collectList()
.block()
.stream()
.map(AiResponse::getText)
.collect(Collectors.joining());
}
}
```
## 使用说明
### 基础对话
ChatRequest request = ChatRequest.builder()
.userMessage("你好")
.build();
Flux response = aiManager.execute(request);
response.subscribe(aiResponse -> {
System.out.println(aiResponse.getText());
});
### 带上下文的对话
```java
ChatRequest request = ChatRequest.builder()
.userMessage("我刚才说了什么?")
.contextId("user-123")
.build();
Flux response = aiManager.execute(request);
```
### RAG 对话
```java
ChatRequest request = ChatRequest.builder()
.userMessage("什么是 Spring AI?")
.knowledgeId("kb-001")
.retrieveType(RetrieveType.SIMPLE)
.topK(5)
.threshold(0.7f)
.build();
Flux response = aiManager.execute(request);
```
### Graph RAG 对话
```java
ChatRequest request = ChatRequest.builder()
.userMessage("Spring AI 和 Spring Boot 有什么关系?")
.knowledgeId("kb-001")
.retrieveType(RetrieveType.GRAPH)
.build();
Flux response = aiManager.execute(request);
```
必须在启动类上加@EnableReactiveNeo4jRepositories(basePackages = "com.jalon.ai.knowledge.graph.repository")
@EntityScan("com.jalon.ai.knowledge.graph.entity")
### 知识导入
```java
KnowledgeDocument document = KnowledgeDocument.builder()
.id("doc-001")
.content("Spring AI 是一个用于构建 AI 应用的框架...")
.metadata(Map.of(
"source", "spring.io",
"category", "framework"
))
.build();
knowledgeService.importDocument("kb-001", document).block();
```
### 上下文管理
```java
// 保存上下文
contextManager.saveContext("user-123", messages).block();
// 获取上下文
List context = contextManager.getContext("user-123").block();
// 清除上下文
contextManager.clearContext("user-123").block();
```
### 文件上传
本 SDK 提供完整的文件上传功能,支持多种文件格式(PDF、Word、Excel、PPT、TXT、HTML、图片等)的上传、解析、切分和向量化存储。
#### 支持的文件类型
- **文档类**:PDF、Word (.doc, .docx)、Excel (.xls, .xlsx)、PowerPoint (.ppt, .pptx)
- **文本类**:TXT、HTML、XML、Markdown
- **图片类**:JPG、JPEG、PNG、GIF、BMP、TIFF(支持 OCR 识别)
#### 依赖配置
在 `pom.xml` 中添加文件解析器依赖:
```xml
com.jalon
ai-file-parser-starter
1.0.0-SNAPSHOT
```
#### 配置文件
在 `application.yml` 中添加文件解析器配置:
```yaml
jalon:
ai:
file-parser:
max-file-size: 52428800
parse-timeout: 60s
max-extract-chars: 100000
default-reader: tika
ocr-enabled: false
ocr-language: chi_sim+eng
allowed-extensions:
- pdf
- doc
- docx
- ppt
- pptx
- xls
- xlsx
- txt
- md
- html
- htm
- xml
- json
- jpg
- jpeg
- png
- gif
- bmp
- tiff
fail-on-error: true
detect-encoding: true
max-concurrent-parses: 8
splitter:
type: recursive
chunk-size: 1000
chunk-overlap: 200
recursive-separators:
- "\n\n"
- "\n"
- '。'
- '!'
- '?'
- ' '
- ''
keep-separator: true
cleaning:
compress-whitespace: true
remove-control-chars: true
ocr:
engine: tesseract
dpi: 300
table-detection: false
```
#### 切分器类型说明
1. **character(字符数切分)**
- 按固定字符数切分文档
- 优点:实现简单,性能高效
- 缺点:可能在句子中间切分,影响语义完整性
2. **paragraph(段落切分)**
- 根据段落分隔符(如换行符)切分文档
- 优点:保持段落语义完整,适合文档检索
- 缺点:段落过长时需要二次切分
3. **recursive(递归切分)**(推荐)
- 优先按段落切分,段落过长再按字符数切分
- 优点:保持语义完整性,同时控制片段大小
- 适用场景:大多数文档类型,特别是长文档
#### 配置参数说明
| 参数 | 说明 | 默认值 |
| ------------------------------- | -------------------- | --------------- |
| `max-file-size` | 最大文件大小(字节) | 52428800 (50MB) |
| `parse-timeout` | 解析超时时间 | 60s |
| `max-extract-chars` | 单文档最大提取字符数 | 100000 |
| `default-reader` | 默认解析器名称 | tika |
| `ocr-enabled` | 是否启用 OCR | false |
| `ocr-language` | OCR 语言 | chi_sim+eng |
| `allowed-extensions` | 允许的文件扩展名 | 见配置示例 |
| `fail-on-error` | 解析失败是否抛异常 | true |
| `detect-encoding` | 是否自动检测编码 | true |
| `max-concurrent-parses` | 最大并发解析数 | CPU 核心数\*2 |
| `splitter.type` | 切分器类型 | recursive |
| `splitter.chunk-size` | 片段大小(字符数) | 1000 |
| `splitter.chunk-overlap` | 片段重叠大小 | 200 |
| `splitter.recursive-separators` | 递归切分分隔符 | 见配置示例 |
| `splitter.keep-separator` | 是否保留分隔符 | true |
| `cleaning.compress-whitespace` | 是否压缩空白字符 | true |
| `cleaning.remove-control-chars` | 是否移除控制字符 | true |
| `ocr.engine` | OCR 引擎 | tesseract |
| `ocr.dpi` | OCR 分辨率 | 300 |
| `ocr.table-detection` | 是否启用表格识别 | false |
#### API 接口
##### 1. 上传文件并存储到向量库
```bash
POST /api/file/upload
Content-Type: multipart/form-data
参数:
- file: 上传的文件(必填)
- knowledgeBaseId: 知识库ID(可选,默认为 "default")
- userId: 用户ID(可选,用于业务元数据)
- projectId: 项目ID(可选,用于业务元数据)
- metadata: 自定义元数据(可选,JSON 格式字符串)
```
**示例:**
```bash
curl -X POST http://localhost:8080/api/file/upload \
-F "file=@document.pdf" \
-F "knowledgeBaseId=kb-001" \
-F "userId=user-123" \
-F "projectId=project-456" \
-F "metadata={\"department\":\"研发部\",\"category\":\"技术文档\"}"
```
**响应示例:**
```json
{
"code": 200,
"status": "success",
"fileName": "document.pdf",
"knowledgeBaseId": "kb-001",
"chunkCount": 15,
"chunkIds": ["chunk-001", "chunk-002", ...]
}
```
**元数据说明:**
上传文件时可以传递业务元数据,这些元数据会被保存到每个文档块中,便于后续检索和过滤。支持的元数据包括:
- **系统元数据**(自动添加):
- `fileName`: 文件名
- `fileType`: 文件类型
- `fileSize`: 文件大小
- `source`: 来源标识(固定为 "file_upload")
- `parent_id`: 父文档 ID(文档切分后自动添加,指向原始文档 ID)
- `chunk_index`: 当前分片索引(从 0 开始,文档切分后自动添加)
- `chunk_count`: 总分片数(文档切分后自动添加)
- **业务元数据**(通过参数传递):
- `userId`: 用户 ID
- `projectId`: 项目 ID
- 其他自定义字段(通过 metadata 参数传递)
**文档切分说明:**
文件上传后会自动进行文档切分,切分后的每个文档块都会继承原始文档的所有元数据,并额外添加以下元数据:
- `parent_id`: 原始文档 ID,用于追溯文档来源
- `chunk_index`: 当前分片在原文档中的位置(0, 1, 2, ...)
- `chunk_count`: 原文档被切分的总块数
**元数据使用示例:**
```java
// 上传文件时传递业务元数据
Map metadata = new HashMap<>();
metadata.put("userId", "user-123");
metadata.put("projectId", "project-456");
metadata.put("department", "研发部");
metadata.put("category", "技术文档");
// 使用 DocumentReader 读取文件时传递元数据
Flux documents = documentReader.read(
inputStream,
"document.pdf",
metadata
);
// 检索时可以根据元数据过滤
VectorRequest searchRequest = VectorRequest.builder()
.payload("查询关键词")
.options(VectorOptions.builder()
.namespace("kb-001")
.topK(10)
.filter(Map.of("userId", "user-123"))
.build())
.build();
```
##### 2. 上传文件并直接导入到知识库
```bash
POST /api/file/import
Content-Type: multipart/form-data
参数:
- file: 上传的文件(必填)
- knowledgeBaseId: 知识库ID(可选,默认为 "default")
- userId: 用户ID(可选,用于业务元数据)
- projectId: 项目ID(可选,用于业务元数据)
- metadata: 自定义元数据(可选,JSON 格式字符串)
```
**示例:**
```bash
curl -X POST http://localhost:8080/api/file/import \
-F "file=@document.pdf" \
-F "knowledgeBaseId=kb-001" \
-F "userId=user-123" \
-F "projectId=project-456" \
-F "metadata={\"department\":\"研发部\",\"category\":\"技术文档\"}"
```
##### 3. 批量上传文件
```bash
POST /api/file/upload/batch
Content-Type: multipart/form-data
参数:
- files: 上传的文件列表(必填)
- knowledgeBaseId: 知识库ID(可选,默认为 "default")
```
**示例:**
```bash
curl -X POST http://localhost:8080/api/file/upload/batch \
-F "files=@document1.pdf" \
-F "files=@document2.docx" \
-F "knowledgeBaseId=kb-001"
```
**响应示例:**
```json
{
"code": 200,
"status": "success",
"fileCount": 2,
"totalChunks": 30,
"results": [
{
"code": 200,
"status": "success",
"fileName": "document1.pdf",
"knowledgeBaseId": "kb-001",
"chunkCount": 15,
"chunkIds": [...]
},
{
"code": 200,
"status": "success",
"fileName": "document2.docx",
"knowledgeBaseId": "kb-001",
"chunkCount": 15,
"chunkIds": [...]
}
]
}
```
##### 4. 获取支持的文件类型
```bash
GET /api/file/supported-types
```
**响应示例:**
```json
{
"code": 200,
"supportedExtensions": [
"pdf",
"doc",
"docx",
"xls",
"xlsx",
"ppt",
"pptx",
"txt",
"html",
"jpg",
"jpeg",
"png",
"gif",
"bmp",
"tiff"
],
"maxFileSize": 52428800,
"maxFileSizeMB": 50
}
```
#### 核心流程
```
文件上传 (MultipartFile)
↓
文件解析 (DocumentReader)
- Apache Tika 解析为文本
- 提取文件元数据(文件名、类型、大小等)
↓
文档切分 (DocumentSplitter)
- 按配置策略切分(character/paragraph/recursive)
- 添加切分元数据(片段索引、片段总数等)
↓
向量化 (EmbeddingAdapter)
- 将每个文本片段转换为向量
↓
存储到向量库 (AiVectorStoreAdapter)
- 存储向量数据到 Redis 或内存
↓
返回结果
- 文件名、知识库ID、片段数量、片段ID列表
```
#### 扩展自定义解析器
如果需要支持特殊的文件格式或自定义解析逻辑,可以实现 `DocumentReader` 接口:
```java
@Component
public class CustomDocumentReader implements DocumentReader {
@Override
public Flux read(File file) {
// 自定义解析逻辑
return Flux.just(VectorDocument.builder()
.id(UUID.randomUUID().toString())
.content("解析后的内容")
.metadata(Map.of(
FileParserConstants.MetadataKeys.FILE_NAME, file.getName(),
FileParserConstants.MetadataKeys.FILE_TYPE, "custom"
))
.build());
}
@Override
public boolean supports(String fileName) {
return fileName.endsWith(".custom");
}
@Override
public String getReaderName() {
return "自定义解析器";
}
@Override
public int getPriority() {
return 200;
}
}
```
#### 扩展自定义切分器
如果需要自定义切分逻辑,可以实现 `DocumentSplitter` 接口:
```java
@Component
public class CustomDocumentSplitter implements DocumentSplitter {
@Override
public Flux split(VectorDocument document) {
// 自定义切分逻辑
return Flux.just(document);
}
@Override
public String getSplitterName() {
return "自定义切分器";
}
@Override
public SplitterType getType() {
return SplitterType.CUSTOM;
}
}
```
#### 注意事项
1. **文件大小限制**:默认最大文件大小为 50MB,可通过配置调整
2. **切分参数**:根据文档类型和 LLM 上下文窗口大小合理设置 `chunk-size` 和 `chunk-overlap`
3. **OCR 功能**:图片文字识别功能默认关闭,开启后会增加处理时间
4. **元数据保留**:文件元数据(文件名、类型、大小等)会自动保留到 VectorDocument 的 metadata 中
5. **切分索引**:每个切分片段会包含 `chunk_index` 和 `chunk_count` 元数据,便于追踪原文档位置
### 完整示例
```java
@RestController
@RequestMapping("/ai")
public class AiController {
@Autowired
private AiManager aiManager;
@Autowired
private KnowledgeService knowledgeService;
@PostMapping("/chat")
public Flux chat(@RequestBody ChatRequest request) {
return aiManager.execute(request)
.map(AiResponse::getText);
}
@PostMapping("/knowledge/import")
public Mono importKnowledge(@RequestBody KnowledgeDocument document) {
return knowledgeService.importDocument("kb-001", document)
.map(v -> "导入成功");
}
}
```
## 特技
### 1. 插件化架构
基于 AiProcessor 接口的插件化设计,支持前置和后置处理,轻松扩展功能。通过实现接口并设置执行顺序,可以灵活添加自定义处理逻辑。
### 2. 多模型适配
支持 OpenAI、DeepSeek、Ollama 等多种 AI 模型,通过配置即可轻松切换,无需修改代码。统一的 ModelAdapter 接口确保模型切换对业务代码透明。
### 3. Graph RAG
集成 Neo4j 图数据库,实现基于知识图谱的增强检索。通过 LLM 驱动的实体识别、Neo4j Cypher 关系查询和向量检索的结合,提供更精准的知识检索能力。
### 4. 响应式编程
基于 Project Reactor 的全响应式实现,支持流式输出、超时控制、异常处理等,提供高性能的非阻塞处理能力。
### 5. 配置热更新
支持通过配置中心或环境变量动态更新配置,无需重启应用即可切换模型、调整参数等。
### 6. 多租户支持
支持多租户隔离,每个租户拥有独立的配置、上下文和知识库,确保数据安全和隔离性。
### 7. 性能优化
- 向量检索支持批量查询和缓存
- 上下文管理支持 TTL 自动过期
- 插件链支持异步并行执行
- 全链路响应式设计,避免阻塞
### 8. 异常降级
完善的异常降级机制,确保服务可用性:
- 知识库检索失败时自动降级为普通对话
- 上下文加载失败时使用空上下文继续执行
- 模型调用失败时返回友好提示
### 9. 扣子平台迁移
提供扣子平台迁移工具,支持将扣子平台的工作流、Prompt 模板等快速迁移到本 SDK,实现原型验证到生产落地的无缝衔接。
### 10. 扩展性强
支持多种扩展方式,无需修改核心代码:
- 新增 AI 模型适配器
- 新增知识库实现(如 Milvus、Chroma)
- 新增上下文存储实现
- 新增向量存储实现
- 新增自定义插件
### 插件说明
本 SDK 采用插件化架构,插件通过 Spring 自动装配,无需手动配置。系统内置以下插件:
#### 前置插件
1. **SystemMessageProcessor** (Order: 0)
- 功能:注入系统人设消息
- 依赖:AiPromptRepository
- 配置:通过 `jalon.ai.persona.storage` 控制持久化行为
2. **ContextProcessor** (Order: 10)
- 功能:加载历史对话上下文
- 依赖:ContextManager
- 说明:只有配置了上下文存储(Redis 或 Memory)时才会加载
3. **KnowledgePreProcessor** (Order: 20)
- 功能:知识库检索增强
- 依赖:KnowledgeService
- 配置:通过 `jalon.ai.knowledge` 控制检索策略
#### 后置插件
后置插件用于异步处理 AI 响应后的逻辑,如消息存储、审计日志等。用户可以根据需要自定义实现 AiProcessor 接口。
### 配置最佳实践
1. **多项目隔离**:每个项目使用独立的 `project-id`,确保配置和数据的隔离
2. **重试策略**:根据业务需求调整 `max-retries` 和 `retry-delay`,避免过度重试
3. **缓存策略**:合理设置 `enable-cache` 和 `cache-ttl`,平衡性能和数据一致性
4. **连接池配置**:根据并发量调整 Hikari 连接池参数,避免连接泄漏
5. **TTL 配置**:根据业务场景设置合理的 TTL,避免内存泄漏和数据过期
6. **阈值配置**:根据实际效果调整 `threshold` 参数,平衡召回率和准确率
## 文档
- [详细使用文档](PROJECT_USAGE_GUIDE.md)
- [配置示例](FULL_CONFIGURATION_EXAMPLE.yaml)
- [配置说明](FULL_CONFIGURATION_REPORT.md)
## 贡献
欢迎提交 Issue 和 Pull Request!
## 许可证