# 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! ## 许可证