# SpringAi-Study **Repository Path**: rednoob/spring-ai-study ## Basic Information - **Project Name**: SpringAi-Study - **Description**: 学习ai - **Primary Language**: Java - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-03-28 - **Last Updated**: 2026-06-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Spring AI Study - RAG 智能对话系统 基于 **Spring AI** + **Ollama** + **RAG** 技术的本地化智能对话系统学习项目。 ## 📖 项目简介 本项目是一个完整的 RAG(Retrieval-Augmented Generation)实现示例,通过结合向量知识库和大语言模型,实现基于特定领域知识的智能问答系统。 ### 项目总结 这是一个用于学习和验证 Spring AI 生态能力的 Spring Boot 项目,核心链路是“知识文件导入 → 文本切分 → 向量化入库 → 检索增强问答”。项目同时集成了本地 Ollama 模型、PostgreSQL + pgvector 向量库、Redis 会话记忆、MCP 工具调用、多数据源、Quartz 定时任务、Knife4j 文档和基础的分布式治理组件,适合作为 RAG、本地大模型应用和 Spring Cloud 组件整合的实验工程。 ### 核心特性 - ✅ **RAG 智能对话**:基于向量知识库的准确回答 - ✅ **知识来源追溯**:支持显示回答的参考来源 - ✅ **本地化部署**:使用 Ollama 运行本地大模型,保护数据隐私 - ✅ **中文优化**:自定义中文文本分块器 - ✅ **批量处理**:优化的文档导入流程,避免内存溢出 - ✅ **API 文档**:Knife4j 接口文档,方便调试和测试 - ✅ **记忆功能**:支持对话记忆,上下文理解更自然 - ✅ **SpringCloud**:支持Spring Cloud 应用, nacos, loadbalancer, openfeign - ✅ **多数据库支持**:整合mybatis-plus和dynamic-datasource - ✅ **分布式事务**:整合Seata,支持分布式事务 - ✅ **日志**:集成p6spy,支持SQL日志、慢SQL报警、日志级别配置 - ✅ **定时任务**:集成Quartz,支持定时任务, 支持分布式任务 - ✅ **redis**:集成redis,支持分布式缓存、会话管理 - ✅ **redisson**:集成redisson,支持分布式锁、分布式集合 - ✅ **Jwt**:集成jwt,支持分布式认证 - ✅ **整合plumelog**:整合plumelog,支持分布式日志 - ✅ **知识库版本管理**:支持知识库快照、版本回溯、增量更新和版本对比 - ✅ **多租户完整隔离**:基于 TransmittableThreadLocal 的租户上下文,支持异步场景(Phase 1-9 已完成) - ✅ **其他功能**:集成MCP(Model Context Protocol), 集成Tool工具 ### 📋 待开发功能 #### 高优先级功能 - ❎ **租户配额管理**:文档数量、存储空间、API 调用次数的实时监控和限制 - ❎ **租户使用统计**:调用次数、存储使用量、活跃度等多维度统计分析 - ❎ **租户数据导出/导入**:支持租户级别的知识库备份和迁移 - ❎ **多模态支持**:支持图片、音频等多模态内容的向量化和检索 - ❎ **混合检索**:结合关键词检索(BM25)和向量检索提升召回率 #### 中优先级功能 - ❎ **文档格式扩展**:支持 PDF、Word、Markdown、HTML 等多种格式导入 - ❎ **智能重排序(Rerank)**:对检索结果进行二次排序,提升相关性 - ❎ **问答质量评估**:集成评估指标(BLEU、ROUGE、准确率等)监控 RAG 效果 - ❎ **对话流程编排**:可视化配置对话流程和意图识别 - ❎ **模型切换支持**:支持在线切换不同的 LLM 和 Embedding 模型 - ❎ **API 限流与监控**:集成 Prometheus + Grafana 监控和限流策略 - ❎ **知识库分类管理**:支持多个知识库分类和权限隔离 - ❎ **对话质量反馈**:用户满意度评分和答案纠正机制 ## 🛠️ 技术栈 | 技术 | 版本 | 说明 | |------|------|------| | **Java** | 21 | 开发语言 | | **Spring Boot** | 3.4.13 | 应用框架 | | **Spring AI** | 1.1.4 | AI 集成框架 | | **Ollama** | Latest | 本地大模型运行平台 | | **PostgreSQL** | Latest | 关系型数据库 | | **Pgvector** | Latest | 向量数据库扩展 | | **TransmittableThreadLocal** | 2.14.5 | 阿里 TTL,支持异步上下文传递 | | **Knife4j** | 4.5.0 | API 文档工具 | | **Lombok** | Latest | 代码简化工具 | ### 模型配置 - **聊天模型**:`qwen2.5:7b-instruct` - **Embedding 模型**:`qwen3-embedding:0.6b`(维度:1536) ## 🔐 安全配置 ### 环境变量配置 为保证系统安全,必须配置以下环境变量: ```bash # JWT 密钥(至少32位字符) export JWT_SECRET="YourSuperSecretKeyForJWTGenerationThatIsAtLeast32CharactersLong!" # 数据库连接信息 export DB_AI_USERNAME=postgres export DB_AI_PASSWORD=1Qaz@123456 export DB_MASTER_USERNAME=postgres export DB_MASTER_PASSWORD=1Qaz@123456 export DB_DETIAL_USERNAME=postgres export DB_DETIAL_PASSWORD=1Qaz@123456 export DB_COLLECT_USERNAME=dev export DB_COLLECT_PASSWORD= # Nacos 配置 export NACOS_USERNAME=nacos export NACOS_PASSWORD=nacos # Knife4j 认证 export KNAIFE_BASIC_USERNAME=varya export KNAIFE_BASIC_PASSWORD=varya ``` ## 🚀 快速开始 ### 环境要求 1. **JDK 21+** 2. **Maven 3.6+** 3. **PostgreSQL 13+**(需安装 pgvector 扩展) 4. **Ollama**(已安装并配置好模型) 5. **Node.js**(用于MCP工具) ### 安装步骤 #### 1. 克隆项目 ```bash git clone https://gitee.com/rednoob/spring-ai-study.git cd spring-ai-study ``` #### 2. 配置 PostgreSQL 1. 启动 PostgreSQL 服务 2. 创建数据库: ```sql CREATE DATABASE vector_store; CREATE DATABASE detial; CREATE DATABASE detial2; ``` 3. 启用 pgvector 扩展: ```sql -- 连接到每个数据库并执行 CREATE EXTENSION IF NOT EXISTS vector; ``` #### 3. 配置 Ollama 1. 启动 Ollama 服务 ```bash ollama serve ``` 2. 拉取聊天模型 ```bash ollama pull qwen2.5:7b-instruct ``` 3. 拉取 embedding 模型 ```bash ollama pull qwen3-embedding:0.6b ``` #### 4. 配置环境变量 创建 `.env` 文件或在启动前设置环境变量: ```bash export JWT_SECRET="YourSuperSecretKeyForJWTGenerationThatIsAtLeast32CharactersLong!" export DB_AI_PASSWORD=your_secure_password # ... 其他环境变量 ``` #### 5. 初始化向量库表 项目启动时会自动初始化所需的向量库表结构。 #### 6. 启动项目 ```bash mvn clean install mvn spring-boot:run ``` 或者打包后运行: ```bash mvn package java -jar target/springAi_study-0.0.1-SNAPSHOT.jar ``` 启动项目后访问:`http://localhost:9999` ## 🏢 多租户隔离 ### 设计架构 项目采用 **共享数据库 + 租户字段** 的多租户方案,使用 **TransmittableThreadLocal** 确保异步场景下的上下文安全传递。 ### ✅ 已完成功能(Phase 1-9) #### Phase 1-3: 基础设施 - ✅ 租户管理(CRUD API + 状态管理) - ✅ TenantContext(TransmittableThreadLocal) - ✅ TenantInterceptor(HTTP 请求拦截) - ✅ MyBatis-Plus 多租户插件配置 #### Phase 4-5: 数据层改造 - ✅ 业务表添加 tenant_id 字段 - ✅ TenantMetaObjectHandler(自动填充) - ✅ Service 层查询自动过滤 - ✅ Mapper XML 租户条件 #### Phase 6: 向量库隔离 - ✅ 文档导入时添加 tenant_id 元数据 - ✅ 向量检索时租户过滤 - ✅ vector_store 表支持多租户 #### Phase 7: Redis 会话隔离 - ✅ RedisChatMemory 改造 - ✅ Redis key 格式:`conversation:{tenantId}:{sessionId}` - ✅ 会话列表按租户隔离 #### Phase 8-9: 前端和文档 - ✅ 多租户测试页面 - ✅ 完整测试文档和使用指南 ### 快速开始 #### 1. 数据库初始化 ```bash # 创建租户表 psql -U postgres -d postgres -f src/main/resources/sql/tenant/create_tenant_table.sql # 为业务表添加 tenant_id psql -U postgres -d postgres -f src/main/resources/sql/tenant/add_tenant_id_to_tables.sql ``` #### 2. 创建测试租户 ```bash curl -X POST http://localhost:9999/api/admin/tenant \ -H "Content-Type: application/json" \ -d '{ "tenantCode": "tenant-a", "tenantName": "租户A", "contactName": "张三", "maxUsers": 50 }' ``` #### 3. 使用租户隔离 所有 API 请求都需要添加 `X-Tenant-Id` 请求头: ```bash # 租户A导入文档 curl -X POST http://localhost:9999/api/admin/knowledge/upload \ -H "X-Tenant-Id: tenant-a" \ -F "file=@document.txt" # 租户A检索 curl "http://localhost:9999/api/test/vector-search?query=测试" \ -H "X-Tenant-Id: tenant-a" # 租户A的RAG对话 curl "http://localhost:9999/api/chat/rag?query=你好&sessionId=session-001" \ -H "X-Tenant-Id: tenant-a" ``` #### 4. 测试页面 访问 `http://localhost:9999/multi-tenant-test.html` 使用图形化界面测试多租户功能。 ### 核心特性 | 功能 | 说明 | 隔离方式 | |------|------|---------| | 租户管理 | CRUD、状态管理、配额限制 | - | | 数据库 | 业务表数据隔离 | tenant_id 字段 + MyBatis-Plus 插件 | | 向量库 | 文档、向量数据隔离 | 元数据 tenant_id + FilterExpression | | Redis 会话 | 对话历史隔离 | Key 前缀:`conversation:{tenantId}:*` | | 异步场景 | @Async、线程池、CompletableFuture | TransmittableThreadLocal | ### 技术实现 #### 租户上下文传递 ```java // 拦截器自动提取 @Component public class TenantInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, ...) { String tenantId = request.getHeader("X-Tenant-Id"); TenantContext.setTenantId(tenantId != null ? tenantId : "default"); return true; } } // 业务代码中使用 String tenantId = TenantContext.getTenantId(); ``` #### 自动填充租户ID ```java @Component public class TenantMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { String tenantId = TenantContext.getTenantId(); this.strictInsertFill(metaObject, "tenantId", String.class, tenantId); } } // 实体类 @TableField(fill = FieldFill.INSERT) private String tenantId; ``` #### 向量检索租户过滤 ```java // 构建租户过滤器 FilterExpressionBuilder filterBuilder = new FilterExpressionBuilder(); Filter.Expression tenantFilter = filterBuilder.eq("tenant_id", tenantId).build(); SearchRequest searchRequest = SearchRequest.builder() .query(query) .topK(topK) .filterExpression(tenantFilter) // 租户过滤 .build(); ``` ### 文档 - 📖 [多租户测试文档](docs/MULTI_TENANT_TEST.md) - 完整的测试用例和验证步骤 - 🧪 [测试页面](http://localhost:9999/multi-tenant-test.html) - 图形化测试界面 ### 数据库初始化 #### 创建租户表 执行 SQL:`src/main/resources/sql/tenant/create_tenant_table.sql` ```sql CREATE TABLE IF NOT EXISTS sys_tenant ( id BIGSERIAL PRIMARY KEY, tenant_code VARCHAR(50) NOT NULL UNIQUE, tenant_name VARCHAR(100) NOT NULL, contact_name VARCHAR(50), contact_phone VARCHAR(20), contact_email VARCHAR(100), status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE', expire_time TIMESTAMP, max_users INT DEFAULT 10, max_storage BIGINT DEFAULT 1073741824, remark TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_by VARCHAR(50), updated_by VARCHAR(50) ); -- 创建索引 CREATE INDEX IF NOT EXISTS idx_tenant_code ON sys_tenant(tenant_code); CREATE INDEX IF NOT EXISTS idx_tenant_status ON sys_tenant(status); -- 插入默认租户 INSERT INTO sys_tenant (tenant_code, tenant_name, contact_name, status, remark, created_by) VALUES ('default', '默认租户', '系统管理员', 'ACTIVE', '系统默认租户', 'system') ON CONFLICT (tenant_code) DO NOTHING; -- PostgreSQL 字段注释 COMMENT ON TABLE sys_tenant IS '租户表'; COMMENT ON COLUMN sys_tenant.tenant_code IS '租户编码(唯一标识)'; COMMENT ON COLUMN sys_tenant.tenant_name IS '租户名称'; COMMENT ON COLUMN sys_tenant.status IS '状态:ACTIVE-激活,DISABLED-禁用,EXPIRED-过期'; -- 其他字段注释见 SQL 文件 ``` #### 业务表改造 执行 SQL:`src/main/resources/sql/tenant/add_tenant_id_to_tables.sql` 为以下表添加 tenant_id 字段: - `kb_version` - 知识库版本 - `kb_document` - 文档元数据 - `kb_version_document` - 版本文档关联 - `kb_vector_snapshot` - 向量快照 - `vector_store` - 向量存储 ## 📁 项目结构 ``` src/main/java/com/rednoob/springai_study/ ├── config/ # 配置类 │ ├── AiConfiguration.java # AI相关配置 │ ├── JwtUtil.java # JWT工具类 │ ├── RedisService.java # Redis服务 │ └── WebMvcConfig.java # MVC配置 ├── controller/ # 控制器层 │ ├── RagChatController.java # RAG对话控制器 │ ├── KnowledgeAdminController.java # 知识库管理控制器 │ ├── KbVersionController.java # 版本管理控制器 │ └── TestController.java # 测试控制器 ├── service/ # 服务层 │ ├── DocumentIngestService.java # 文档导入服务 │ ├── VectorRetrievalService.java # 向量检索服务 │ ├── KbVersionService.java # 版本管理服务 │ └── VectorSnapshotService.java # 向量快照服务 ├── mapper/ # 数据访问层 │ ├── KbVersionMapper.java # 版本数据访问 │ ├── KbDocumentMapper.java # 文档数据访问 │ └── KbVersionDocumentMapper.java # 版本文档关系 ├── domain/ # 领域模型 │ ├── entity/ # 实体类 │ │ ├── KbVersion.java # 版本实体 │ │ ├── KbDocument.java # 文档实体 │ │ └── KbVersionDocument.java # 版本文档关系 │ ├── dto/ # 数据传输对象 │ │ ├── CreateSnapshotRequest.java │ │ ├── CreateIncrementalVersionRequest.java │ │ ├── RollbackRequest.java │ │ └── CompareVersionsRequest.java │ ├── vo/ # 视图对象 │ │ ├── VersionVO.java │ │ ├── VersionDetailVO.java │ │ ├── DocumentVO.java │ │ └── VersionDiffVO.java │ └── enums/ # 枚举类 │ ├── VersionType.java │ ├── VersionStatus.java │ └── OperationType.java ├── util/ # 工具类 │ ├── DocumentHashUtil.java # 文档哈希工具 │ └── ApiResponse.java # 统一响应封装 └── tool/ # MCP工具类 ``` ## 📡 API 接口 ### 主要使用入口: - **RAG 对话**:`http://localhost:9999/rag-chat.html` - **知识导入**:`http://localhost:9999/knowledge-import.html` - **版本管理**:`http://localhost:9999/kb-version.html` ### 管理工具: - **API 文档**:`http://localhost:9999/doc.html` - **系统诊断**:`http://localhost:9999/diagnose.html` ### 调试测试: - **快速测试**:`http://localhost:9999/quick-test.html` ### API 列表: | 功能 | 方法 | 路径 | 说明 | |------|------|------|------| | RAG 对话详情 | GET | `/api/rag/chat/detail` | 返回回答、来源和会话 ID,参数:`message`、`sessionId`(可选) | | RAG 来源查询 | GET | `/api/rag/chat/sources` | 仅返回检索到的知识来源,参数:`message`、`sessionId`(可选) | | RAG SSE 流式对话 | GET | `/api/rag/chat/stream` | `text/event-stream` 流式输出回答 | | RAG Streamable 输出 | GET | `/api/rag/chat/streamable` | 使用 `StreamingResponseBody` 输出回答 | | 上传知识文件 | POST | `/api/admin/knowledge/upload` | 上传 TXT 文件并导入向量库,表单字段:`file` | | 清空知识库 | POST | `/api/admin/knowledge/clear` | 当前仅返回提示,需手动清空数据库表 | | **创建完整快照** | **POST** | **`/api/kb/version/snapshot`** | **创建知识库完整快照,Body: `CreateSnapshotRequest`** | | **创建增量版本** | **POST** | **`/api/kb/version/incremental`** | **创建增量版本,Body: `CreateIncrementalVersionRequest`** | | **查询版本列表** | **GET** | **`/api/kb/version/list`** | **分页查询版本列表,参数:`page`、`size`** | | **获取版本详情** | **GET** | **`/api/kb/version/{versionId}`** | **获取指定版本的详细信息** | | **获取激活版本** | **GET** | **`/api/kb/version/active`** | **获取当前正在使用的版本** | | **版本回滚** | **POST** | **`/api/kb/version/rollback`** | **回滚到指定版本,Body: `RollbackRequest`** | | **版本对比** | **POST** | **`/api/kb/version/compare`** | **对比两个版本差异,Body: `CompareVersionsRequest`** | | **删除版本** | **DELETE** | **`/api/kb/version/{versionId}`** | **软删除指定版本(不能删除激活中的版本)** | | 系统时间 | GET | `/api/test/system-time` | 返回当前服务器系统时间、时区和毫秒时间戳 | | 向量检索测试 | GET | `/api/test/vector-search` | 参数:`query`、`topK`、`threshold` | | 知识库状态 | GET | `/api/test/knowledge-status` | 查看知识库示例数据 | | 向量库诊断 | GET | `/api/test/vector-store/diagnose` | 检查向量库状态 | | 原始数据查看 | GET | `/api/test/vector-store/raw-data` | 查看向量库原始数据,参数:`limit` | | Embedding 测试 | GET | `/api/test/embedding/test` | 测试文本向量化能力 | | MCP 工具列表 | GET | `/api/mcp-client/tools` | 查看 MCP Client 可用工具 | | MCP 对话 | GET | `/api/mcp-client/chat` | 调用 MCP 工具增强对话 | | Quartz 任务列表 | GET | `/api/quartz/list` | 查看定时任务 | ## 🧪 测试 运行单元测试: ```bash mvn test ``` 当前 `pom.xml` 中配置了 `maven.test.skip=true`,默认构建会跳过测试。需要强制执行测试时可使用: ```bash mvn -Dmaven.test.skip=false test ``` ## 🚨 安全注意事项 1. **JWT 密钥**:必须使用强密钥,长度至少32位 2. **数据库密码**:不要在代码中硬编码,使用环境变量 3. **API 密钥**:敏感配置应存储在安全的位置 4. **依赖更新**:定期更新依赖包以修复安全漏洞 ## 🤝 贡献 欢迎提交 Issue 和 Pull Request 来帮助改进这个项目! ## 📄 许可证 本项目采用 MIT 许可证。