54 Commits

Author SHA1 Message Date
wangle
bf7b5eac72 fix:修复上下文消息构建顺序,确保AI正确理解对话上下文
消息顺序调整为:历史消息 → 知识库内容 → 当前用户消息

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:13:32 +08:00
wangle
d602b805bd docs:更新技术栈版本号并清理文档
- 更新后端架构版本为 Spring Boot 3.5.8 + Langchain4j
- 删除 rag-failures.md 和文件上传接口文档
- 重命名 mcp-api-spec.md 为 MCP工具模块接口文档.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 21:04:31 +08:00
ageerle
9cf18904bb Merge pull request #284 from MuSan-Li/main
添加可观测性功能
2026-04-07 10:04:05 +08:00
evo
2f39fa0f53 feat:调整可观测性监听器逻辑 2026-04-05 21:36:53 +08:00
evo
d2005cfa48 feat:调整可观测性监听器逻辑 2026-04-05 21:34:41 +08:00
evo
4e38f853f3 feat:修复登录校验 & 调整主启动类的kill port 逻辑 2026-04-02 10:07:26 +08:00
evo
3cfb185dde feat:增加可观测性监听器 调整思考输出监听日志 2026-04-01 23:11:54 +08:00
evo
ef99c540bb feat:增加可观测性的相关监听器 & 修复前端问答报错outputkey问题 2026-04-01 22:32:01 +08:00
ageerle
3071bfd0f9 Merge pull request #282 from Anush008/main
docs: Docker Compose setup for Qdrant
2026-03-28 20:33:25 +08:00
Anush008
7bb938c145 docs: Docker Compose setup for Qdrant 2026-03-28 13:37:53 +05:30
ageerle
75b21d3633 Merge pull request #281 from Anush008/main
feat: Adds support for Qdrant vector search
2026-03-27 21:51:03 +08:00
Anush008
7ed9d8def4 chore: Rename METADATA_DOC_ID_KEY 2026-03-27 18:36:30 +05:30
Anush008
63ed7ddb02 feat: Adds support for Qdrant vector search 2026-03-27 18:31:05 +05:30
ageerle
11696a016d fix: 修复文件类型匹配和知识库切割配置问题
1. 修复 ResourceLoaderFactory 文件扩展名匹配问题
   - 去除扩展名前导点,确保 .pdf 能正确匹配 PDF 解析器
   - 修复 PDF/Word/Excel 等文件走错解析逻辑的问题

2. 优化文本切割器动态配置
   - CharacterTextSplitter 和 ExcelTextSplitter 支持从知识库读取配置
   - 根据 kid 查询 separator、textBlockSize、overlapChar
   - 查询失败时降级使用默认配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 18:51:01 +08:00
ageerle
1a10104751 docs: 更新README文档,同步中英文版本
- 移除优秀开源项目推荐章节
- 英文版添加Docker部署完整文档
- 英文版添加技术架构详细描述
- 英文版添加RAG排查手册链接
- 统一核心功能表格格式

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:02:46 +08:00
ageerle
f95cb17933 chore: 删除ruoyi-modules-api模块
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:31:09 +08:00
ageerle
0687b49542 Merge branch 'v3.0.0' into main
合并 v3.0.0 分支到 main,包含以下主要更新:
- 重构聊天模块架构,引入Handler模式
- 添加 Docker 部署支持
- 恢复 MCP 模块功能
- 工作流与大模型聊天对话整合
- 多项 bug 修复和文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:15:40 +08:00
ageerle
27ad00ac3a refactor: 抽离特殊聊天模式处理逻辑
- 将工作流、人机交互恢复、思考模式处理逻辑抽离为独立方法
- 新增 handleSpecialChatModes 方法统一处理特殊模式
- 新增 handleThinkingMode 方法专门处理思考模式
- 简化 sseChat 方法结构,提高代码可读性

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:38:54 +08:00
ageerle
c84d6247b0 refactor: 重构聊天模块架构
- 删除废弃的ChatMessageDTO、ChatContext、AbstractChatMessageService等类
- 迁移ChatServiceFactory和IChatMessageService到ruoyi-chat模块
- 重构ChatHandler体系,移除DefaultChatHandler和ChatContextBuilder
- 优化SSE消息处理,新增SseEventDto
- 简化各AI服务提供商实现类代码
- 优化工作流节点消息处理逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 01:20:41 +08:00
ageerle
f582f38570 docs: 整理Docker配置文件并更新文档
- 将Docker相关配置文件移动到docs/docker/ruoyi-ai/目录
- 更新README.md核心亮点表格格式
- 新增流程编排模块详细说明文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 15:22:47 +08:00
ageerle
13800dc389 Merge pull request #277 from XiaoEns/v3.0.0
fix: 修复知识库附件上传乱码问题
2026-03-17 22:07:32 +08:00
xiaoen
619d9b1e84 fix: 兼容旧代码,添加deepseek服务调用 2026-03-17 21:30:56 +08:00
xiaoen
556cc93f14 fix: 修复知识库附件上传乱码问题 2026-03-17 18:57:30 +08:00
ageerle
a50375616e Merge pull request #276 from LM20230311/v3.0.0
V3.0.0
2026-03-17 14:09:52 +08:00
LM20230311
e33447d023 Merge branch 'v3.0.0' of https://github.com/ageerle/ruoyi-ai into v3.0.0 2026-03-17 13:48:21 +08:00
LM20230311
7be277b3e6 Merge branch 'v3.0.0-deploy' into v3.0.0 2026-03-17 13:47:27 +08:00
LM20230311
5fa385e90b docs: add Docker deployment instructions and service port mappings to README; update sys_client table in MySQL script 2026-03-17 11:09:13 +08:00
LM20230311
0a78966737 chore: update UPSTREAM_HOST configuration in docker-compose-all.yaml to remove http:// prefix 2026-03-17 10:38:43 +08:00
LM20230311
0eb7f00867 chore: add environment variables for backend API configuration in docker-compose-all.yaml 2026-03-16 17:14:01 +08:00
LM20230311
00ce7f2d98 chore: update port mappings in docker-compose.yaml for MySQL, Weaviate, and backend services 2026-03-16 15:32:27 +08:00
ageerle
003c066361 chore(sql): 更新数据库脚本,移除chat_config表
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:57:55 +08:00
ageerle
a5e7c59fd4 refactor: 重构项目架构,优化向量服务
- 移除 Graph 知识图谱相关模块(Neo4j、GraphRAG等)
- 移除 demo、job、wechat 示例模块,简化项目结构
- 修复向量维度获取方式,改为从数据库配置读取
- 添加 gRPC BOM 依赖管理,解决 Milvus SDK 版本冲突
- 新增 PPIO 服务和 Embedding 提供者支持
- 清理冗余代码和未使用的依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:39:30 +08:00
LM20230311
a2dbdb30ff fix: remove unnecessary COPY command for ruoyi-modules-api in Dockerfile.backend 2026-03-11 09:57:47 +08:00
LM20230311
772e4af9bf Merge remote-tracking branch 'upstream/v3.0.0' into v3.0.0-deploy 2026-03-11 09:35:48 +08:00
ageerle
a8bd4b47a0 chore: 移除项目文档和技术交流链接
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:44:07 +08:00
ageerle
a59ddf6070 refactor: 重构Issue模板为通用格式
- 删除企业合作登记模板
- 新增漏洞报告模板
- 新增想法建议模板
- 新增自定义模板

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:39:06 +08:00
ageerle
797ecbb054 feat: 新增联系人/联系方式字段并添加填写示例
- 新增联系人/联系方式字段,支持登记后主动联系
- 在可复制模板中添加完整填写示例

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:30:15 +08:00
ageerle
b6b78afea9 refactor: 优化企业合作登记模板格式
- 改为评论登记模式,用户在Issue下评论填写
- 提供格式预览和可复制模板
- 新增公司Logo和项目Logo字段
- 移除联系方式模块,保护隐私

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:20:31 +08:00
ageerle
02240f3fd0 feat: 添加企业AI应用合作登记Issue模板
- 新增企业合作登记模板,用于收集企业AI应用需求
- 包含基本信息、AI应用需求、联系方式三个模块
- 预设筛选字段便于评估合作匹配度

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:07:25 +08:00
LM20230311
1600ab384e feat: 支持手动挂载数据卷; 2026-03-05 09:35:27 +08:00
LM20230311
418805a1ef feat: 源码docker部署完成; 2026-03-05 09:27:34 +08:00
LM20230311
4c4b52bca7 feat: 忽略data目录; 2026-03-05 09:07:10 +08:00
LM20230311
7245259bc4 fix: 忽略所有错误以确保SQL脚本继续执行 2026-03-04 17:57:08 +08:00
LM20230311
6690c8204c fix: 修复表数量异常问题; 2026-03-04 17:56:20 +08:00
LM20230311
d8fc597f85 fix: 解决mysql容器长时间建表导致失败问题; 2026-03-04 17:34:38 +08:00
LM20230311
5a716da5a6 feat: 添加docker部署文件; 2026-03-04 16:31:54 +08:00
ageerle
a916f14efc Merge pull request #268 from onestardao/main
docs: add structured RAG 16-problem troubleshooting guide and README entry
2026-03-03 10:40:32 +08:00
PSBigBig × MiniPS
523628ade6 docs: add structured RAG 16-problem troubleshooting guide and README entry 2026-03-02 19:01:59 +08:00
PSBigBig × MiniPS
2259a2f717 docs: add structured RAG 16-problem troubleshooting guide and README entry
This commit introduces a structured RAG troubleshooting guide based on a fixed 16-problem failure map.

Changes include:

1. Added a dedicated RAG troubleshooting document:
   - docs/troubleshooting/rag-failures.md
   - Includes full 16-problem map (No.1–No.16) with layer tags [IN]/[RE]/[ST]/[OP]
   - Adds symptom-based entry points
   - Adds layer-based diagnostics section
   - Adds issue reporting template referencing No.X labels

2. Updated README.md:
   - Added entry link under the "使用文档" section
   - Direct link to the new RAG troubleshooting guide
   - Keeps README structure and tone consistent

No functional changes.
Documentation only.
2026-03-02 18:51:36 +08:00
PSBigBig × MiniPS
8df37274da docs: add RAG answer troubleshooting guide 2026-03-02 17:44:59 +08:00
PSBigBig × MiniPS
393057ab24 docs: add RAG answer troubleshooting guide 2026-03-02 17:41:47 +08:00
ageerle
ee8c882b6f Merge pull request #256 from StevenJack666/main
修改AI工作流后端逻辑
2026-02-11 17:03:31 +08:00
zhang
69ec2a33a4 init 2026-02-09 17:47:18 +08:00
zhang
1cd8ae1cd9 人机交互节点逻辑修改 2026-02-09 17:43:29 +08:00
234 changed files with 3802 additions and 13450 deletions

1
.gitignore vendored
View File

@@ -44,6 +44,7 @@ nbdist/
*.log.gz
*.xml.versionsBackup
*.swp
data/
!*/build/*.java
!*/build/*.html

165
README.md
View File

@@ -19,7 +19,7 @@
### 企业级AI助手平台
*开箱即用的全栈AI平台支持多智能体协同、Supervisor模式编排、多种决策模型,提供先进的RAG技术和可视化流程编排能力*
*开箱即用的全栈AI平台支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力*
**[English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** |
**[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
@@ -27,18 +27,15 @@
</div>
## ✨ 核心亮点
| 模块 | 现有能力 | 扩展方向 |
|:---:|---|---|
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成 | 自动模式、容错机制 |
| **知识** | 本地RAG + 向量库(Milvus/Weaviate) + 知识图谱 + 文档解析 +重排序 | 音频视频解析、知识出处 |
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态 | 工具插件市场、toolAgent自动加载工具 |
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点 | 更多节点类型 |
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型 | 智能体可配置 |
| **AI编程** | 智能代码分析、项目脚手架生成、Copilot助手 | 代码生成优化 |
| 模块 | 现有能力
|:----------:|---
| **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成
| **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
| **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
| **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
| **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
## 🚀 快速体验
@@ -65,12 +62,127 @@
## 🛠️ 技术架构
### 核心框架
- **后端架构**Spring Boot 4.0 + Spring ai 2.0 + Langchain4j
- **数据存储**MySQL 8.0 + Redis + 向量数据库Milvus/Weaviate
- **后端架构**Spring Boot 3.5.8 + Langchain4j
- **数据存储**MySQL 8.0 + Redis + 向量数据库Milvus/Weaviate/Qdrant
- **前端技术**Vue 3 + Vben Admin + element-plus-x
- **安全认证**Sa-Token + JWT 双重保障
- **文档处理**PDF、Word、Excel 解析,图像智能分析
- **实时通信**WebSocket 实时通信SSE 流式响应
- **系统监控**:完善的日志体系、性能监控、服务健康检查
## 🐳 Docker 部署
本项目提供两种 Docker 部署方式:
### 方式一:一键启动所有服务(推荐)
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
```bash
# 克隆仓库
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# 启动所有服务(从镜像仓库拉取预构建镜像)
docker-compose -f docker-compose-all.yaml up -d
# 查看服务状态
docker-compose -f docker-compose-all.yaml ps
# 访问服务
# 管理端: http://localhost:25666 (admin / admin123)
# 用户端: http://localhost:25137
# 后端API: http://localhost:26039
```
### 方式二:分步部署(源码编译)
如果您需要从源码构建后端服务,请按照以下步骤操作:
#### 第一步:部署后端服务
```bash
# 进入后端项目目录
cd ruoyi-ai
# 启动后端服务(源码编译构建)
docker-compose up -d --build
# 等待后端服务启动完成
docker-compose logs -f backend
```
#### 第二步:部署管理端
```bash
# 进入管理端项目目录
cd ruoyi-admin
# 构建并启动管理端
docker-compose up -d --build
# 访问管理端
# 地址: http://localhost:5666
```
#### 第三步:部署用户端(可选)
```bash
# 进入用户端项目目录
cd ruoyi-web
# 构建并启动用户端
docker-compose up -d --build
# 访问用户端
# 地址: http://localhost:5137
```
### 服务端口说明
| 服务 | 一键启动端口 | 分步部署端口 | 说明 |
|------|-------------|-------------|------|
| 管理端 | 25666 | 5666 | 管理后台访问地址 |
| 用户端 | 25137 | 5137 | 用户前端访问地址 |
| 后端服务 | 26039 | 6039 | 后端 API 服务 |
| MySQL | 23306 | 23306 | 数据库服务 |
| Redis | 26379 | 6379 | 缓存服务 |
| Weaviate | 28080 | 28080 | 向量数据库 |
| MinIO API | 29000 | 9000 | 对象存储 API |
| MinIO Console | 29090 | 9090 | 对象存储控制台 |
### 镜像仓库
所有镜像托管在阿里云容器镜像服务:
```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
```
可用镜像:
- `mysql:v3` - MySQL 数据库(包含初始化 SQL
- `redis:6.2` - Redis 缓存
- `weaviate:1.30.0` - 向量数据库
- `minio:latest` - 对象存储
- `ruoyi-ai-backend:latest` - 后端服务
- `ruoyi-ai-admin:latest` - 管理端前端
- `ruoyi-ai-web:latest` - 用户端前端
### 常用命令
```bash
# 停止所有服务
docker-compose -f docker-compose-all.yaml down
# 查看服务日志
docker-compose -f docker-compose-all.yaml logs -f [服务名]
# 重启某个服务
docker-compose -f docker-compose-all.yaml restart [服务名]
```
## 📚 使用文档
想要深入了解安装部署、功能配置和二次开发?
@@ -110,9 +222,6 @@
算力和模型 API 服务
- [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务秒级响应按量计费新客免费用。
## 优秀开源项目及社区推荐
- [imaiwork](https://gitee.com/tsinghua-open/imaiwork) - AI手机开源版AI获客手机项目基于无障碍模式RPA比豆包AI手机更强大。
## 💬 社区交流
<div align="center">
@@ -136,30 +245,6 @@
</div>
---
## 📺 视频教程
<div align="center">
<table>
<tr>
<td align="center">
<img src="docs/image/dy.png" alt="微信二维码" width="200" height="200"><br>
<strong>打开抖音扫一扫</strong><br>
<em>获取免费视频教程</em>
</td>
<td align="center">
<img src="docs/image/bibi.png" alt="QQ群二维码" width="200" height="200"><br>
<strong>打开B站扫一扫</strong><br>
<em>获取免费视频教程</em>
</td>
</tr>
</table>
</div>
<div align="center">
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)**

View File

@@ -32,14 +32,13 @@
## ✨ Core Features
| Module | Current Capabilities | Extension Direction |
|:---:|---|---|
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu), multi-modal understanding, Coze/DIFY/FastGPT platform integration | Auto mode, fault tolerance |
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate) + Knowledge Graph + Document parsing + Reranking | Audio/video parsing, knowledge source |
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem | Tool plugin marketplace, toolAgent auto-loading |
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model (with RAG) calls, email sending, manual review nodes | More node types |
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models | Configurable agents |
| **AI Coding** | Intelligent code analysis, project scaffolding generation, Copilot assistant | Code generation optimization |
| Module | Current Capabilities |
|:---:|---|
| **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
| **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
| **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
| **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
| **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models |
## 🚀 Quick Start
@@ -59,19 +58,134 @@
| 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
### Partner Projects
| Project Name | GitHub Repository | Gitee Repository
| Project Name | GitHub Repository | Gitee Repository |
|----------------|-------------------------------------------------------|------------------------------------------------------|
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
## 🛠️ Technical Architecture
### Core Framework
- **Backend**: Spring Boot 4.0 + Spring AI 2.0 + Langchain4j
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate)
- **Backend**: Spring Boot 3.5.8 + Langchain4j
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
- **Frontend**: Vue 3 + Vben Admin + element-plus-x
- **Security**: Sa-Token + JWT dual-layer security
- **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
## 🐳 Docker Deployment
This project provides two Docker deployment methods:
### Method 1: One-click Start All Services (Recommended)
Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
```bash
# Clone the repository
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# Start all services (pull pre-built images from registry)
docker-compose -f docker-compose-all.yaml up -d
# Check service status
docker-compose -f docker-compose-all.yaml ps
# Access services
# Admin Panel: http://localhost:25666 (admin / admin123)
# User Frontend: http://localhost:25137
# Backend API: http://localhost:26039
```
### Method 2: Step-by-step Deployment (Source Build)
If you need to build backend services from source, follow these steps:
#### Step 1: Deploy Backend Service
```bash
# Enter backend project directory
cd ruoyi-ai
# Start backend service (build from source)
docker-compose up -d --build
# Wait for backend service to start
docker-compose logs -f backend
```
#### Step 2: Deploy Admin Panel
```bash
# Enter admin panel project directory
cd ruoyi-admin
# Build and start admin panel
docker-compose up -d --build
# Access admin panel
# URL: http://localhost:5666
```
#### Step 3: Deploy User Frontend (Optional)
```bash
# Enter user frontend project directory
cd ruoyi-web
# Build and start user frontend
docker-compose up -d --build
# Access user frontend
# URL: http://localhost:5137
```
### Service Ports
| Service | One-click Port | Step-by-step Port | Description |
|------|-------------|-------------|------|
| Admin Panel | 25666 | 5666 | Admin backend access |
| User Frontend | 25137 | 5137 | User frontend access |
| Backend Service | 26039 | 6039 | Backend API service |
| MySQL | 23306 | 23306 | Database service |
| Redis | 26379 | 6379 | Cache service |
| Weaviate | 28080 | 28080 | Vector database |
| MinIO API | 29000 | 9000 | Object storage API |
| MinIO Console | 29090 | 9090 | Object storage console |
### Image Registry
All images are hosted on Alibaba Cloud Container Registry:
```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
```
Available images:
- `mysql:v3` - MySQL database (includes initialization SQL)
- `redis:6.2` - Redis cache
- `weaviate:1.30.0` - Vector database
- `minio:latest` - Object storage
- `ruoyi-ai-backend:latest` - Backend service
- `ruoyi-ai-admin:latest` - Admin frontend
- `ruoyi-ai-web:latest` - User frontend
### Common Commands
```bash
# Stop all services
docker-compose -f docker-compose-all.yaml down
# View service logs
docker-compose -f docker-compose-all.yaml logs -f [service-name]
# Restart a service
docker-compose -f docker-compose-all.yaml restart [service-name]
```
## 📚 Documentation
Want to learn more about installation, deployment, configuration, and secondary development?
@@ -109,14 +223,13 @@ Thanks to the following excellent open-source projects for their support:
- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Provides cost-effective GPU computing and model API services
- [Youyun Intelligent Computing](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - Thousands of RTX40 series GPUs + mainstream models API services, second-level response, pay-per-use, free for new customers.
## Outstanding Open-Source Projects and Community Recommendations
- [imaiwork](https://gitee.com/tsinghua-open/imaiwork) - Open-source AI phone, AI customer acquisition phone project, based on accessibility mode and RPA, more powerful than Doubao AI phone.
## 💬 Community Chat
<div align="center">
**[📱 Join Telegram Group](https://t.me/+LqooQAc5HxRmYmE1)**
**[📱 Join Telegram Group](
https://t.me/+LqooQAc5HxRmYmE1)**
</div>

View File

@@ -0,0 +1,12 @@
---
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- 6333:6333
- 6334:6334
volumes:
- qdrant_data:/qdrant/storage
volumes:
qdrant_data:
...

View File

@@ -0,0 +1,36 @@
# RuoYi-AI 后端 Dockerfile
# 基于 Maven + OpenJDK 17
FROM maven:3.9-eclipse-temurin-17 AS builder
# 设置工作目录
WORKDIR /build
# 复制 pom.xml 和源码
COPY pom.xml .
COPY ruoyi-admin ./ruoyi-admin
COPY ruoyi-common ./ruoyi-common
COPY ruoyi-modules ./ruoyi-modules
COPY ruoyi-extend ./ruoyi-extend
# 构建项目 (使用 prod profile)
RUN mvn clean package -Pprod -DskipTests
# 最终运行镜像
FROM eclipse-temurin:17-jre-alpine
# 设置工作目录
WORKDIR /app
# 从构建阶段复制 jar 包
COPY --from=builder /build/ruoyi-admin/target/ruoyi-admin.jar ./ruoyi-admin.jar
# 创建日志目录
RUN mkdir -p /ruoyi/server/logs
# 暴露端口
EXPOSE 6039
# 启动命令
ENTRYPOINT ["java", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"]

View File

@@ -0,0 +1,21 @@
# 基于官方MySQL 8.0镜像构建自定义镜像
# 构建命令: docker build -t registry.cn-hangzhou.aliyuncs.com/ruoyi-ai/mysql:v3 -f Dockerfile.mysql .
FROM mysql:8.0.33
# 设置时区
ENV TZ=Asia/Shanghai
# 复制初始化脚本和SQL文件到镜像中
COPY docs/script/docker/mysql/init/init-db.sh /docker-entrypoint-initdb.d/init-db.sh
COPY docs/script/sql/ruoyi-ai-v3_mysql8.sql /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
# 设置脚本可执行权限
RUN chmod +x /docker-entrypoint-initdb.d/init-db.sh
# MySQL启动参数
CMD ["--default-authentication-plugin=mysql_native_password", \
"--character-set-server=utf8mb4", \
"--collation-server=utf8mb4_general_ci", \
"--explicit_defaults_for_timestamp=true", \
"--lower_case_table_names=1", \
"--skip-ssl"]

View File

@@ -0,0 +1,180 @@
# RuoYi-AI 一键启动全部服务
# 使用方式: docker-compose up -d
#
# 包含服务:
# - MySQL 8.0 (数据库包含初始化SQL)
# - Redis 6.2 (缓存)
# - Weaviate (向量数据库)
# - MinIO (对象存储)
# - RuoYi-Backend (后端服务)
# - RuoYi-Admin (管理端前端)
# - RuoYi-Web (用户端前端)
#
# 镜像仓库地址: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
version: '3.8'
services:
# ==================== MySQL 数据库 ====================
mysql:
# 阿里云镜像地址包含初始化SQL
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/mysql:v3
container_name: ruoyi-ai-mysql
restart: always
ports:
- "23306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ruoyi-ai-agent
TZ: Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
interval: 15s
timeout: 10s
retries: 10
start_period: 60s
networks:
- ruoyi-net
# ==================== Redis 缓存 ====================
redis:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/redis:6.2
container_name: ruoyi-ai-redis
restart: always
ports:
- "26379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ruoyi-net
# ==================== Weaviate 向量数据库 ====================
weaviate:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/weaviate:1.30.0
container_name: ruoyi-ai-weaviate
restart: always
ports:
- "28080:8080"
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: true
PERSISTENCE_DATA_PATH: /var/lib/weaviate
DEFAULT_VECTORIZER_MODULE: none
ENABLE_MODULES: text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai
CLUSTER_HOSTNAME: node1
volumes:
- weaviate-data:/var/lib/weaviate
networks:
- ruoyi-net
# ==================== MinIO 对象存储 ====================
minio:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/minio:latest
container_name: ruoyi-ai-minio
restart: always
ports:
- "29000:9000"
- "29090:9090"
environment:
MINIO_ROOT_USER: ruoyi
MINIO_ROOT_PASSWORD: ruoyi123
volumes:
- minio-data:/data
command: server /data --console-address ":9090"
networks:
- ruoyi-net
# ==================== RuoYi-AI 后端服务 ====================
backend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-backend:latest
container_name: ruoyi-ai-backend
restart: always
ports:
- "26039:6039"
environment:
TZ: Asia/Shanghai
# MySQL 配置
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
# Redis 配置
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
SPRING_DATA_REDIS_DATABASE: 0
# 日志配置
LOGGING_LEVEL_ORG_RUOYI: info
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: warn
SYS_UPLOAD_PATH: /ruoyi/upload
volumes:
- logs-data:/ruoyi/server/logs
- upload-data:/ruoyi/upload
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- ruoyi-net
# ==================== RuoYi-AI 管理端前端 ====================
admin-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-admin:latest
container_name: ruoyi-ai-admin
restart: always
ports:
- "25666:5666"
environment:
# 后端 API 地址 - 运行时动态配置(无需重新构建镜像)
# nginx upstream 配置不需要 http:// 前缀,直接使用 host:port
UPSTREAM_HOST: backend:6039
# 资源限制 - 防止 CPU 和内存耗尽
deploy:
resources:
limits:
cpus: '2'
memory: 3G
reservations:
cpus: '1'
memory: 1G
depends_on:
- backend
networks:
- ruoyi-net
# ==================== RuoYi-AI 用户端前端 ====================
web-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-web:latest
container_name: ruoyi-ai-web
restart: always
ports:
- "25137:5137"
environment:
UPSTREAM_URL: http://backend:6039
depends_on:
- backend
networks:
- ruoyi-net
# ==================== 网络配置 ====================
networks:
ruoyi-net:
driver: bridge
# ==================== 数据卷配置 ====================
volumes:
mysql-data:
redis-data:
weaviate-data:
minio-data:
logs-data:
upload-data:

View File

@@ -0,0 +1,144 @@
# RuoYi-AI 一键启动后端服务
# 使用方式: docker-compose up -d --build
#
# 包含服务:
# - MySQL 8.0 (数据库)
# - Redis 6.2 (缓存)
# - Weaviate (向量数据库)
# - MinIO (对象存储)
# - RuoYi-Backend (后端服务,源码编译)
services:
# MySQL 数据库
mysql:
image: mysql:8.0.33
container_name: ruoyi-ai-mysql
restart: always
ports:
- "23306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ruoyi-ai-agent
TZ: Asia/Shanghai
volumes:
- ./docs/script/docker/mysql/init/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro
- ./docs/script/sql/ruoyi-ai-v3_mysql8.sql:/docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql:ro
- mysql-data:/var/lib/mysql
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--skip-ssl
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
interval: 15s
timeout: 10s
retries: 10
start_period: 60s
networks:
- ruoyi-net
# Redis 缓存
redis:
image: redis:6.2
container_name: ruoyi-ai-redis
restart: always
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ruoyi-net
# Weaviate 向量数据库
weaviate:
image: semitechnologies/weaviate:1.30.0
container_name: ruoyi-ai-weaviate
restart: always
ports:
- "28080:8080"
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: true
PERSISTENCE_DATA_PATH: /var/lib/weaviate
DEFAULT_VECTORIZER_MODULE: none
ENABLE_MODULES: text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai
CLUSTER_HOSTNAME: node1
volumes:
- weaviate-data:/var/lib/weaviate
networks:
- ruoyi-net
# MinIO 对象存储
minio:
image: minio/minio
container_name: ruoyi-ai-minio
restart: always
ports:
- "9000:9000"
- "9090:9090"
environment:
MINIO_ROOT_USER: ruoyi
MINIO_ROOT_PASSWORD: ruoyi123
volumes:
- minio-data:/data
command: server /data --console-address ":9090"
networks:
- ruoyi-net
# RuoYi-AI 后端服务 (源码编译)
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: ruoyi-ai-backend
restart: always
ports:
- "26039:6039"
environment:
TZ: Asia/Shanghai
# MySQL 配置
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
# Redis 配置
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
SPRING_DATA_REDIS_DATABASE: 0
# 日志配置
LOGGING_LEVEL_ORG_RUOYI: info
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: warn
SYS_UPLOAD_PATH: /ruoyi/upload # 新增:对应 sys.upload.path
volumes:
- logs-data:/ruoyi/server/logs
- upload-data:/ruoyi/upload
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- ruoyi-net
networks:
ruoyi-net:
driver: bridge
# 数据卷 支持手动指定 空为默认值
volumes:
mysql-data:
redis-data:
weaviate-data:
minio-data:
logs-data:
upload-data:

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# 数据库初始化脚本
# 使用 --force 参数确保即使出错也继续执行
echo "开始初始化数据库..."
# 使用 --force 参数忽略错误继续执行
mysql -uroot -proot ruoyi-ai-agent --force < /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
echo "数据库初始化完成"

View File

@@ -11,41 +11,13 @@
Target Server Version : 80045 (8.0.45)
File Encoding : 65001
Date: 14/03/2026 14:15:08
Date: 15/03/2026 23:56:19
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for chat_config
-- ----------------------------
DROP TABLE IF EXISTS `chat_config`;
CREATE TABLE `chat_config` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`category` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置类型',
`config_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置名称',
`config_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '配置值',
`config_dict` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '说明',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`version` int NULL DEFAULT NULL COMMENT '版本',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
`update_ip` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新IP',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `unique_category_key`(`category` ASC, `config_name` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2030620372623781891 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '配置信息表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of chat_config
-- ----------------------------
INSERT INTO `chat_config` VALUES (2030620372556673026, 'wechat', 'appid', 'xx', 'appid', 103, '2026-03-08 20:23:19', '1', '1', '2026-03-08 20:23:19', NULL, NULL, '0', NULL, 0);
INSERT INTO `chat_config` VALUES (2030620372623781890, 'wechat', 'secret', 'xx', 'secret', 103, '2026-03-08 20:23:19', '1', '1', '2026-03-08 20:23:19', NULL, NULL, '0', NULL, 0);
-- 忽略所有错误,继续执行
SET sql_mode = '';
-- ----------------------------
-- Table structure for chat_message
@@ -57,10 +29,8 @@ CREATE TABLE `chat_message` (
`user_id` bigint NOT NULL COMMENT '用户id',
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '消息内容',
`role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '对话角色',
`deduct_cost` double(20, 2) NULL DEFAULT 0.00 COMMENT '扣除金额',
`total_tokens` int NULL DEFAULT 0 COMMENT '累计 Tokens',
`model_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称',
`billing_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '计费类型1-token计费2-次数计费)',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` bigint NULL DEFAULT NULL COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
@@ -85,11 +55,8 @@ CREATE TABLE `chat_model` (
`model_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型名称',
`provider_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型供应商',
`model_describe` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '模型描述',
`model_price` double NULL DEFAULT NULL COMMENT '模型价格',
`model_type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '计费类型',
`model_dimension` int NULL DEFAULT NULL COMMENT '模型维度',
`model_show` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '是否显示',
`model_free` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '是否免费',
`priority` int NULL DEFAULT 1 COMMENT '模型优先级(值越大优先级越高)',
`api_host` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求地址',
`api_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密钥',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
@@ -105,8 +72,8 @@ CREATE TABLE `chat_model` (
-- ----------------------------
-- Records of chat_model
-- ----------------------------
INSERT INTO `chat_model` VALUES (2000585866022060033, 'chat', 'deepseek/deepseek-v3.2', 'ppio', 'deepseek', 1, '1', 'Y', 'Y', 1, 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2025-12-15 23:16:54', 1, '2026-02-25 21:46:08', 'DeepSeek-V3.2 是一款在高效推理、复杂推理能力与智能体场景中表现突出的领先模型。其基于 DeepSeek Sparse AttentionDSA稀疏注意力机制在显著降低计算开销的同时优化长上下文性能通过可扩展强化学习框架整体能力达到 GPT-5 同级,高算力版本 V3.2-Speciale 更在推理表现上接近 Gemini-3.0-Pro同时模型依托大型智能体任务合成管线具备更强的工具调用与多步骤决策能力并在 2025 年 IMO 与 IOI 中取得金牌级表现。作为 MaaS 平台,我们已对 DeepSeek-V3.2 完成深度适配,通过动态调度、批处理加速、低延迟推理与企业级 SLA 保障,进一步增强其在企业生产环境中的稳定性、性价比与可控性,适用于搜索、问答、智能体、代码、数据处理等多类高价值场景。', 0);
INSERT INTO `chat_model` VALUES (2007528268536287233, 'vector', 'baai/bge-m3', 'ppio', 'bge-m3', 0, '1', 'N', 'Y', 1, 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2026-01-04 03:03:32', 1, '2026-02-25 21:15:14', 'bge-large-zh-v1.5', 0);
INSERT INTO `chat_model` VALUES (2000585866022060033, 'chat', 'deepseek/deepseek-v3.2', 'ppio', 'deepseek', NULL, 'Y', 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2025-12-15 23:16:54', 1, '2026-03-15 19:18:48', 'DeepSeek-V3.2 是一款在高效推理、复杂推理能力与智能体场景中表现突出的领先模型。其基于 DeepSeek Sparse AttentionDSA稀疏注意力机制在显著降低计算开销的同时优化长上下文性能通过可扩展强化学习框架整体能力达到 GPT-5 同级,高算力版本 V3.2-Speciale 更在推理表现上接近 Gemini-3.0-Pro同时模型依托大型智能体任务合成管线具备更强的工具调用与多步骤决策能力并在 2025 年 IMO 与 IOI 中取得金牌级表现。作为 MaaS 平台,我们已对 DeepSeek-V3.2 完成深度适配,通过动态调度、批处理加速、低延迟推理与企业级 SLA 保障,进一步增强其在企业生产环境中的稳定性、性价比与可控性,适用于搜索、问答、智能体、代码、数据处理等多类高价值场景。', 0);
INSERT INTO `chat_model` VALUES (2007528268536287233, 'vector', 'baai/bge-m3', 'ppio', 'bge-m3', 1024, 'N', 'https://api.ppinfra.com/openai', 'sk_xx', 103, 1, '2026-01-04 03:03:32', 1, '2026-03-15 19:18:51', 'BGE-M3 是一款具备多维度能力的文本嵌入模型可同时实现密集检索、多向量检索和稀疏检索三大核心功能。该模型设计上兼容超过100种语言并支持从短句到长达8192词元的长文本等多种输入形式。在跨语言检索任务中BGE-M3展现出显著优势其性能在MIRACL、MKQA等国际基准测试中位居前列。此外针对长文档检索场景该模型在MLDR、NarritiveQA等数据集上的表现同样达到行业领先水平。', 0);
-- ----------------------------
-- Table structure for chat_provider
@@ -1101,171 +1068,6 @@ INSERT INTO `gen_table_column` VALUES (2018961776721399811, 2018961776515878913,
INSERT INTO `gen_table_column` VALUES (2018961776721399812, 2018961776515878913, 'open_id', '微信用户标识', 'varchar(100)', 'String', 'openId', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 22, 103, 1, '2026-02-04 16:16:13', 1, '2026-02-04 16:20:23');
INSERT INTO `gen_table_column` VALUES (2018961776721399813, 2018961776515878913, 'user_balance', '账户余额', 'double(20,2)', 'Long', 'userBalance', '0', '0', '0', '1', '1', '1', '1', 'EQ', 'input', '', 23, 103, 1, '2026-02-04 16:16:13', 1, '2026-02-04 16:20:23');
-- ----------------------------
-- Table structure for graph_build_task
-- ----------------------------
DROP TABLE IF EXISTS `graph_build_task`;
CREATE TABLE `graph_build_task` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`task_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '任务UUID',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '知识库ID',
`doc_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档ID可选null表示全量构建',
`task_type` tinyint NULL DEFAULT 1 COMMENT '任务类型1全量构建、2增量更新、3重建',
`task_status` tinyint NULL DEFAULT 1 COMMENT '任务状态1待执行、2执行中、3成功、4失败',
`progress` int NULL DEFAULT 0 COMMENT '进度百分比0-100',
`total_docs` int NULL DEFAULT 0 COMMENT '总文档数',
`processed_docs` int NULL DEFAULT 0 COMMENT '已处理文档数',
`extracted_entities` int NULL DEFAULT 0 COMMENT '提取的实体数',
`extracted_relations` int NULL DEFAULT 0 COMMENT '提取的关系数',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`result_summary` json NULL COMMENT '结果摘要(JSON格式)',
`start_time` datetime NULL DEFAULT NULL COMMENT '开始时间',
`end_time` datetime NULL DEFAULT NULL COMMENT '结束时间',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_task_uuid`(`task_uuid` ASC) USING BTREE,
INDEX `idx_graph_uuid`(`graph_uuid` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_task_status`(`task_status` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱构建任务表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_build_task
-- ----------------------------
-- ----------------------------
-- Table structure for graph_entity_type
-- ----------------------------
DROP TABLE IF EXISTS `graph_entity_type`;
CREATE TABLE `graph_entity_type` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`type_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '实体类型名称',
`type_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类型编码',
`description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
`color` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '#1890ff' COMMENT '可视化颜色',
`icon` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图标',
`sort` int NULL DEFAULT 0 COMMENT '显示顺序',
`is_enable` tinyint(1) NULL DEFAULT 1 COMMENT '是否启用0否 1是',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_type_code`(`type_code` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱实体类型定义表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_entity_type
-- ----------------------------
INSERT INTO `graph_entity_type` VALUES (1, '人物', 'PERSON', '人物实体,包括真实人物和虚拟角色', '#1890ff', 'user', 1, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (2, '机构', 'ORGANIZATION', '组织机构,包括公司、政府机构等', '#52c41a', 'bank', 2, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (3, '地点', 'LOCATION', '地理位置,包括国家、城市、地址等', '#fa8c16', 'environment', 3, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (4, '概念', 'CONCEPT', '抽象概念,包括理论、方法等', '#722ed1', 'bulb', 4, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (5, '事件', 'EVENT', '事件记录,包括历史事件、活动等', '#eb2f96', 'calendar', 5, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (6, '产品', 'PRODUCT', '产品或服务', '#13c2c2', 'shopping', 6, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (7, '技术', 'TECHNOLOGY', '技术或工具', '#2f54eb', 'tool', 7, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_entity_type` VALUES (8, '文档', 'DOCUMENT', '文档或资料', '#faad14', 'file-text', 8, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
-- ----------------------------
-- Table structure for graph_query_history
-- ----------------------------
DROP TABLE IF EXISTS `graph_query_history`;
CREATE TABLE `graph_query_history` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`query_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '查询UUID',
`user_id` bigint NOT NULL COMMENT '用户ID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '知识库ID',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图谱UUID',
`query_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '查询文本',
`query_type` tinyint NULL DEFAULT 1 COMMENT '查询类型1实体查询、2关系查询、3路径查询、4混合查询',
`cypher_query` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '生成的Cypher查询',
`result_count` int NULL DEFAULT 0 COMMENT '结果数量',
`response_time` int NULL DEFAULT 0 COMMENT '响应时间(ms)',
`is_success` tinyint(1) NULL DEFAULT 1 COMMENT '是否成功0否 1是',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_query_uuid`(`query_uuid` ASC) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱查询历史表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_query_history
-- ----------------------------
-- ----------------------------
-- Table structure for graph_relation_type
-- ----------------------------
DROP TABLE IF EXISTS `graph_relation_type`;
CREATE TABLE `graph_relation_type` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`relation_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关系名称',
`relation_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关系编码',
`description` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '描述',
`direction` tinyint(1) NULL DEFAULT 1 COMMENT '关系方向0双向、1单向',
`style` json NULL COMMENT '可视化样式(JSON格式)',
`sort` int NULL DEFAULT 0 COMMENT '显示顺序',
`is_enable` tinyint(1) NULL DEFAULT 1 COMMENT '是否启用0否 1是',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_relation_code`(`relation_code` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱关系类型定义表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_relation_type
-- ----------------------------
INSERT INTO `graph_relation_type` VALUES (1, '属于', 'BELONGS_TO', '隶属关系,表示从属或归属', 1, NULL, 1, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (2, '位于', 'LOCATED_IN', '地理位置关系', 1, NULL, 2, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (3, '相关', 'RELATED_TO', '一般关联关系', 0, NULL, 3, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (4, '导致', 'CAUSES', '因果关系', 1, NULL, 4, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (5, '包含', 'CONTAINS', '包含关系', 1, NULL, 5, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (6, '提及', 'MENTIONS', '文档提及实体的关系', 1, NULL, 6, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (7, '部分', 'PART_OF', '部分关系', 1, NULL, 7, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (8, '实例', 'INSTANCE_OF', '实例关系', 1, NULL, 8, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (9, '相似', 'SIMILAR_TO', '相似关系', 0, NULL, 9, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (10, '前序', 'PRECEDES', '时序关系', 1, NULL, 10, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (11, '工作于', 'WORKS_AT', '人物与机构的工作关系', 1, NULL, 11, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (12, '创建', 'CREATED_BY', '创建关系', 1, NULL, 12, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
INSERT INTO `graph_relation_type` VALUES (13, '使用', 'USES', '使用关系', 1, NULL, 13, 1, '', '2025-11-07 16:33:37', '', '2025-11-07 16:33:37', NULL);
-- ----------------------------
-- Table structure for graph_statistics
-- ----------------------------
DROP TABLE IF EXISTS `graph_statistics`;
CREATE TABLE `graph_statistics` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`stat_date` date NOT NULL COMMENT '统计日期',
`total_nodes` int NULL DEFAULT 0 COMMENT '总节点数',
`total_relationships` int NULL DEFAULT 0 COMMENT '总关系数',
`node_type_distribution` json NULL COMMENT '节点类型分布(JSON格式)',
`relation_type_distribution` json NULL COMMENT '关系类型分布(JSON格式)',
`query_count` int NULL DEFAULT 0 COMMENT '查询次数',
`avg_query_time` int NULL DEFAULT 0 COMMENT '平均查询时间(ms)',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_graph_date`(`graph_uuid` ASC, `stat_date` ASC) USING BTREE,
INDEX `idx_stat_date`(`stat_date` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '图谱统计信息表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of graph_statistics
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_attach
-- ----------------------------
@@ -1286,7 +1088,7 @@ CREATE TABLE `knowledge_attach` (
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `idx_kname`(`knowledge_id` ASC, `name` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2016797369199366146 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库附件' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033199209203183619 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库附件' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_attach
@@ -1309,81 +1111,12 @@ CREATE TABLE `knowledge_fragment` (
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2016797369027399683 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识片段' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033199209131880451 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识片段' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_fragment
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_graph_instance
-- ----------------------------
DROP TABLE IF EXISTS `knowledge_graph_instance`;
CREATE TABLE `knowledge_graph_instance` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`graph_uuid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱UUID',
`knowledge_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关联knowledge_info.kid',
`graph_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '图谱名称',
`graph_status` tinyint NULL DEFAULT 10 COMMENT '构建状态10构建中、20已完成、30失败',
`node_count` int NULL DEFAULT 0 COMMENT '节点数量',
`relationship_count` int NULL DEFAULT 0 COMMENT '关系数量',
`config` json NULL COMMENT '图谱配置(JSON格式)',
`model_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT 'LLM模型名称',
`entity_types` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '实体类型(逗号分隔)',
`relation_types` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '关系类型(逗号分隔)',
`error_message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '错误信息',
`create_dept` bigint NULL DEFAULT NULL COMMENT '创建部门',
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT '0' COMMENT '删除标志0代表存在 1代表删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_graph_uuid`(`graph_uuid` ASC) USING BTREE,
INDEX `idx_knowledge_id`(`knowledge_id` ASC) USING BTREE,
INDEX `idx_graph_status`(`graph_status` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识图谱实例表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_graph_instance
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_graph_segment
-- ----------------------------
DROP TABLE IF EXISTS `knowledge_graph_segment`;
CREATE TABLE `knowledge_graph_segment` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '片段UUID',
`kb_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '知识库UUID',
`kb_item_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '知识库条目UUID',
`doc_uuid` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文档UUID',
`segment_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '片段文本内容',
`chunk_index` int NULL DEFAULT 0 COMMENT '片段索引(第几个片段)',
`total_chunks` int NULL DEFAULT 1 COMMENT '总片段数',
`extraction_status` tinyint NULL DEFAULT 0 COMMENT '抽取状态0-待处理 1-处理中 2-已完成 3-失败',
`entity_count` int NULL DEFAULT 0 COMMENT '抽取的实体数量',
`relation_count` int NULL DEFAULT 0 COMMENT '抽取的关系数量',
`token_used` int NULL DEFAULT 0 COMMENT '消耗的token数',
`error_message` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '错误信息',
`user_id` bigint NULL DEFAULT NULL COMMENT '用户ID',
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_uuid`(`uuid` ASC) USING BTREE,
INDEX `idx_kb_uuid`(`kb_uuid` ASC) USING BTREE,
INDEX `idx_kb_item_uuid`(`kb_item_uuid` ASC) USING BTREE,
INDEX `idx_doc_uuid`(`doc_uuid` ASC) USING BTREE,
INDEX `idx_user_id`(`user_id` ASC) USING BTREE,
INDEX `idx_create_time`(`create_time` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识图谱片段表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_graph_segment
-- ----------------------------
-- ----------------------------
-- Table structure for knowledge_info
-- ----------------------------
@@ -1408,7 +1141,7 @@ CREATE TABLE `knowledge_info` (
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户Id',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2018245281372573699 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库' ROW_FORMAT = DYNAMIC;
) ENGINE = InnoDB AUTO_INCREMENT = 2033198818050781187 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '知识库' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of knowledge_info
@@ -2172,6 +1905,7 @@ CREATE TABLE `sys_client` (
-- ----------------------------
INSERT INTO `sys_client` VALUES (1, 'e5cd7e4891bf95d1d19206ce24a7b32e', 'pc', 'pc123', 'password,social', 'pc', 1800, 604800, '0', '0', 103, 1, '2026-02-03 05:14:53', 1, '2026-02-03 05:14:53');
INSERT INTO `sys_client` VALUES (2, '428a8310cd442757ae699df5d894f051', 'app', 'app123', 'password,sms,social', 'android', 1800, 604800, '0', '0', 103, 1, '2026-02-03 05:14:53', 1, '2026-02-03 05:14:53');
INSERT INTO `sys_client` VALUES (2033738530356912129, '0d4c873ff6146ecd7f38e2e45526ab1b', 'web', 'web123', 'sms,email,password', 'pc', 1800, 604800, '0', '0', 103, 1, '2026-03-17 10:53:45', 1, '2026-03-17 10:59:16');
-- ----------------------------
-- Table structure for sys_config
@@ -2639,6 +2373,21 @@ INSERT INTO `sys_logininfor` VALUES (2026654082020204546, '000000', 'admin', 'pc
INSERT INTO `sys_logininfor` VALUES (2026654455514587138, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-02-25 21:44:10');
INSERT INTO `sys_logininfor` VALUES (2027260957187186689, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-02-27 13:54:12');
INSERT INTO `sys_logininfor` VALUES (2030617171346399233, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-08 20:10:35');
INSERT INTO `sys_logininfor` VALUES (2033083137191841794, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 15:29:27');
INSERT INTO `sys_logininfor` VALUES (2033102367094214657, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 16:45:52');
INSERT INTO `sys_logininfor` VALUES (2033116897354551298, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 17:43:36');
INSERT INTO `sys_logininfor` VALUES (2033133175565836289, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 18:48:17');
INSERT INTO `sys_logininfor` VALUES (2033167392953675778, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:04:16');
INSERT INTO `sys_logininfor` VALUES (2033168637663719425, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:09:12');
INSERT INTO `sys_logininfor` VALUES (2033170263812157441, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2026-03-15 21:15:40');
INSERT INTO `sys_logininfor` VALUES (2033170654197002242, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:17:13');
INSERT INTO `sys_logininfor` VALUES (2033170805703651330, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '退出成功', '2026-03-15 21:17:49');
INSERT INTO `sys_logininfor` VALUES (2033170821767835650, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:17:53');
INSERT INTO `sys_logininfor` VALUES (2033170964009267201, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 21:18:27');
INSERT INTO `sys_logininfor` VALUES (2033197762549985282, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:04:56');
INSERT INTO `sys_logininfor` VALUES (2033200372921217025, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '1', '密码输入错误1次', '2026-03-15 23:15:19');
INSERT INTO `sys_logininfor` VALUES (2033200386498179073, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:15:22');
INSERT INTO `sys_logininfor` VALUES (2033210457315696642, '000000', 'admin', 'pc', 'pc', '127.0.0.1', '内网IP', 'MSEdge', 'Windows 10 or Windows Server 2016', '0', '登录成功', '2026-03-15 23:55:23');
-- ----------------------------
-- Table structure for sys_menu
@@ -2831,31 +2580,19 @@ INSERT INTO `sys_menu` VALUES (2000210913846157316, '模型管理新增', 200021
INSERT INTO `sys_menu` VALUES (2000210913846157317, '模型管理修改', 2000210913846157314, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:edit', '#', 103, 1, '2025-12-14 22:27:59', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210913846157318, '模型管理删除', 2000210913846157314, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:remove', '#', 103, 1, '2025-12-14 22:27:59', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210913846157319, '模型管理导出', 2000210913846157314, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:model:export', '#', 103, 1, '2025-12-14 22:28:00', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142145, '聊天配置', 2000209300188356609, 1, 'config', 'chat/config/index', NULL, 1, 0, 'C', '0', '0', 'system:config:list', 'tdesign:task-setting', 103, 1, '2025-12-14 22:27:46', 1, '2025-12-15 00:59:48', '配置信息菜单');
INSERT INTO `sys_menu` VALUES (2000210914299142146, '配置信息查询', 2000210914299142145, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:query', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142147, '配置信息新增', 2000210914299142145, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:add', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142148, '配置信息修改', 2000210914299142145, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:edit', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142149, '配置信息删除', 2000210914299142145, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:remove', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914299142150, '配置信息导出', 2000210914299142145, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:config:export', '#', 103, 1, '2025-12-14 22:27:46', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823809, '聊天消息', 2000209300188356609, 1, 'message', 'chat/message/index', NULL, 1, 0, 'C', '0', '0', 'system:message:list', 'system-uicons:message', 103, 1, '2025-12-14 22:27:54', 1, '2025-12-15 00:53:47', '聊天消息菜单');
INSERT INTO `sys_menu` VALUES (2000210914680823810, '聊天消息查询', 2000210914680823809, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:query', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823811, '聊天消息新增', 2000210914680823809, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:add', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823812, '聊天消息修改', 2000210914680823809, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:edit', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823813, '聊天消息删除', 2000210914680823809, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:remove', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2000210914680823814, '聊天消息导出', 2000210914680823809, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:message:export', '#', 103, 1, '2025-12-14 22:27:54', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813441, '知识', 2006683336984580098, 1, 'info', 'knowledge/info/index', NULL, 1, 0, 'C', '0', '0', 'knowledge:info:list', 'solar:book-line-duotone', 103, 1, '2026-01-01 18:59:05', 1, '2026-01-01 19:08:03', '知识库菜单');
INSERT INTO `sys_menu` VALUES (2006681261898813441, '知识管理', 2000209300188356609, 1, 'info', 'knowledge/info/index', NULL, 1, 0, 'C', '0', '0', 'knowledge:info:list', 'solar:book-line-duotone', 103, 1, '2026-01-01 18:59:05', 1, '2026-03-15 21:07:50', '知识库菜单');
INSERT INTO `sys_menu` VALUES (2006681261898813442, '知识库查询', 2006681261898813441, 1, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:query', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813443, '知识库新增', 2006681261898813441, 2, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:add', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813444, '知识库修改', 2006681261898813441, 3, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:edit', '#', 103, 1, '2026-01-01 18:59:05', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813445, '知识库删除', 2006681261898813441, 4, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:remove', '#', 103, 1, '2026-01-01 18:59:06', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006681261898813446, '知识库导出', 2006681261898813441, 5, '#', '', NULL, 1, 0, 'F', '0', '0', 'system:info:export', '#', 103, 1, '2026-01-01 18:59:06', NULL, NULL, '');
INSERT INTO `sys_menu` VALUES (2006683336984580098, '知识管理', 0, 2, 'knowledge', '', NULL, 1, 0, 'M', '0', '0', NULL, 'bx:book', 103, 1, '2026-01-01 19:06:05', 1, '2026-01-01 19:06:05', '');
INSERT INTO `sys_menu` VALUES (2019464280262905857, '图谱实例', 2019464531388469250, 1, 'graphInstance', 'graph/graphInstance/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:list', 'ant-design:node-index-outlined', 103, 1, '2026-02-06 01:32:59', 1, '2026-02-06 01:40:06', '');
INSERT INTO `sys_menu` VALUES (2019464531388469250, '知识图谱', 2006683336984580098, 15, 'graph', '', NULL, 1, 0, 'M', '0', '0', NULL, 'carbon:chart-relationship', 103, 1, '2026-02-06 01:33:59', 1, '2026-02-06 01:33:59', '');
INSERT INTO `sys_menu` VALUES (2019464779217309697, '图谱可视化', 2019464531388469250, 2, 'graphVisualization', 'graph/graphVisualization/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:view', 'carbon:chart-network', 103, 1, '2026-02-06 01:34:58', 1, '2026-02-06 01:40:14', '');
INSERT INTO `sys_menu` VALUES (2019464917407043585, '图谱检索', 2019464531388469250, 3, 'graphRAG', 'graph/graphRAG/index', NULL, 1, 0, 'C', '0', '0', 'operator:graph:retrieve', 'carbon:search-advanced', 103, 1, '2026-02-06 01:35:31', 1, '2026-02-06 01:40:19', '');
INSERT INTO `sys_menu` VALUES (2031360871412346881, '流程编排', 0, 2, 'aiflow', '', NULL, 1, 0, 'M', '0', '0', NULL, 'fluent:flow-dot-16-filled', 103, 1, '2026-03-10 21:25:47', 1, '2026-03-10 21:25:47', '');
INSERT INTO `sys_menu` VALUES (2031361596464902145, '编排管理', 2031360871412346881, 1, 'aiflow', 'aiflow/index', NULL, 1, 0, 'C', '0', '0', NULL, 'carbon:flow', 103, 1, '2026-03-10 21:28:40', 1, '2026-03-10 21:29:40', '');
INSERT INTO `sys_menu` VALUES (2031361596464902145, '编排管理', 2000209300188356609, 1, 'aiflow', 'aiflow/index', NULL, 1, 0, 'C', '0', '0', NULL, 'carbon:flow', 103, 1, '2026-03-10 21:28:40', 1, '2026-03-15 21:06:01', '');
-- ----------------------------
-- Table structure for sys_notice
@@ -2946,6 +2683,12 @@ INSERT INTO `sys_oss` VALUES (2026640515967557633, '000000', '2026/02/25/afecabe
INSERT INTO `sys_oss` VALUES (2026640548213366785, '000000', '2026/02/25/e16429a462e54e14a1d36673146b9e3c.png', 'ppio-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/e16429a462e54e14a1d36673146b9e3c.png', '{\"fileSize\":\"7382\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:48:55', 1, '2026-02-25 20:48:55', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2026640572443860993, '000000', '2026/02/25/049bb6a507174f73bba4b8d8b9e55b8a.png', 'ppio-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/049bb6a507174f73bba4b8d8b9e55b8a.png', '{\"fileSize\":\"7382\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:49:00', 1, '2026-02-25 20:49:00', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2026640621945036802, '000000', '2026/02/25/de2aa7e649de44f3ba5c6380ac6acd04.png', 'bailian-color.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/02/25/de2aa7e649de44f3ba5c6380ac6acd04.png', '{\"fileSize\":\"5901\",\"contentType\":\"image/png\"}', 103, '2026-02-25 20:49:12', 1, '2026-02-25 20:49:12', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033120065673043969, '000000', '2026/03/15/68c4d853814e444982c2517ffabac0f3.jpg', '9b75e600b2df6160261a507055eabfdf.jpg', '.jpg', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/68c4d853814e444982c2517ffabac0f3.jpg', '{\"fileSize\":\"28027\",\"contentType\":\"image/jpeg\"}', 103, '2026-03-15 17:56:12', 1, '2026-03-15 17:56:12', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033169884118593537, '000000', '2026/03/15/4b7e93a72bf04805ae59985cc0845ef1.png', 'logo.png', '.png', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/4b7e93a72bf04805ae59985cc0845ef1.png', '{\"fileSize\":\"61537\",\"contentType\":\"image/png\"}', 103, '2026-03-15 21:14:10', 1, '2026-03-15 21:14:10', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198191581147137, '000000', '2026/03/15/66d9e6d216c74652bb466a13d24f4440.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/66d9e6d216c74652bb466a13d24f4440.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:06:39', 1, '2026-03-15 23:06:39', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198447232364546, '000000', '2026/03/15/ae1b1e0d363e4bc1b3321d696453fdbf.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/ae1b1e0d363e4bc1b3321d696453fdbf.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:07:39', 1, '2026-03-15 23:07:39', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033198841211727874, '000000', '2026/03/15/83564059b4f643b69a1e0ea727d17364.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/83564059b4f643b69a1e0ea727d17364.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:09:13', 1, '2026-03-15 23:09:13', 1, 'qcloud');
INSERT INTO `sys_oss` VALUES (2033199209064771586, '000000', '2026/03/15/695360eb380d43d6af34e8a308c09696.txt', 'ruoyi-ai介绍.txt', '.txt', 'https://ruoyiai-1254149996.cos.ap-guangzhou.myqcloud.com/2026/03/15/695360eb380d43d6af34e8a308c09696.txt', '{\"fileSize\":\"1166\",\"contentType\":\"text/plain\"}', 103, '2026-03-15 23:10:41', 1, '2026-03-15 23:10:41', 1, 'qcloud');
-- ----------------------------
-- Table structure for sys_oss_config
@@ -2981,7 +2724,7 @@ CREATE TABLE `sys_oss_config` (
INSERT INTO `sys_oss_config` VALUES (1, '000000', 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', '127.0.0.1:9000', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-25 15:44:13', NULL);
INSERT INTO `sys_oss_config` VALUES (2, '000000', 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-03 05:14:52', NULL);
INSERT INTO `sys_oss_config` VALUES (3, '000000', 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-03 05:14:52', NULL);
INSERT INTO `sys_oss_config` VALUES (4, '000000', 'qcloud', 'xx', 'xx', 'ruoyiai-1254149996', '', 'cos.ap-guangzhou.myqcloud.com', '', 'Y', 'ap-guangzhou', '1', '0', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-02-25 16:51:41', '');
INSERT INTO `sys_oss_config` VALUES (4, '000000', 'qcloud', 'xx', 'xx', 'ruoyiai-1254149996', '', 'cos.ap-guangzhou.myqcloud.com', '', 'Y', 'ap-guangzhou', '1', '0', '', 103, 1, '2026-02-03 05:14:52', 1, '2026-03-15 17:56:06', '');
INSERT INTO `sys_oss_config` VALUES (5, '000000', 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', '127.0.0.1:9000', '', 'N', '', '1', '1', '', 103, 1, '2026-02-03 05:14:53', 1, '2026-02-03 05:14:53', NULL);
-- ----------------------------
@@ -3428,7 +3171,7 @@ CREATE TABLE `sys_user` (
-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '000000', 103, 'admin', 'admin', 'sys_user', 'ageerle@163.com', '15888888888', '1', NULL, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-08 20:10:35', 103, 1, '2026-02-05 09:22:12', -1, '2026-03-08 20:10:35', '管理员', NULL, 0.00);
INSERT INTO `sys_user` VALUES (1, '000000', 103, 'admin', 'admin', 'sys_user', 'ageerle@163.com', '15888888888', '1', NULL, '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-15 23:55:23', 103, 1, '2026-02-05 09:22:12', -1, '2026-03-15 23:55:23', '管理员', NULL, 0.00);
INSERT INTO `sys_user` VALUES (3, '000000', 108, 'test', '本部门及以下 密码666666', 'sys_user', '', '', '0', NULL, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2026-02-05 09:22:12', 103, 1, '2026-02-05 09:22:12', 3, '2026-02-05 09:22:12', NULL, NULL, 0.00);
INSERT INTO `sys_user` VALUES (4, '000000', 102, 'test1', '仅本人 密码666666', 'sys_user', '', '', '0', NULL, '$2a$10$b8yUzN0C71sbz.PhNOCgJe.Tu1yWC3RNrTyjSQ8p1W0.aaUXUJ.Ne', '0', '0', '127.0.0.1', '2026-02-05 09:22:12', 103, 1, '2026-02-05 09:22:12', 4, '2026-02-05 09:22:12', NULL, NULL, 0.00);

37
pom.xml
View File

@@ -59,6 +59,8 @@
<langgraph4j.version>1.5.3</langgraph4j.version>
<weaviate.version>1.19.6</weaviate.version>
<dify.version>1.0.7</dify.version>
<!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 -->
<grpc.version>1.62.2</grpc.version>
<!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
<commons-compress.version>1.27.1</commons-compress.version>
@@ -129,6 +131,15 @@
<scope>import</scope>
</dependency>
<!-- gRPC BOM - 解决 Milvus SDK 依赖冲突,强制统一版本 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置-->
<dependency>
<groupId>cn.hutool</groupId>
@@ -352,24 +363,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
@@ -383,13 +382,6 @@
<version>${revision}</version>
</dependency>
<!-- 微信模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
<version>${revision}</version>
</dependency>
<!-- AI流程编排模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
@@ -397,13 +389,6 @@
<version>${revision}</version>
</dependency>
<!-- 企业微信SDK -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>${weixin-java-cp.version}</version>
</dependency>
<!-- Jackson XML -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>

View File

@@ -70,23 +70,12 @@
<artifactId>ruoyi-system</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-job</artifactId>
</dependency>
<!-- 代码生成-->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId>
</dependency>
<!-- demo模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-demo</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
@@ -98,12 +87,6 @@
<artifactId>ruoyi-workflow</artifactId>
</dependency>
<!-- 微信模块 -->
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-wechat</artifactId>
</dependency>
<!-- AI流程编排模块 -->
<dependency>
<groupId>org.ruoyi</groupId>

View File

@@ -4,6 +4,9 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
/**
* 启动程序
*
@@ -13,10 +16,66 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
public class RuoYiAIApplication {
public static void main(String[] args) {
// killPortProcess(6039);
SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args);
System.out.println("(♥◠‿◠)ノ゙ RuoYi-AI启动成功 ლ(´ڡ`ლ)");
System.out.println("(♥◠‿◠)ノ゙ RuoYi-AI启动成功 ლ(´ڡ`ლ)");
}
/**
* 检查并终止占用指定端口的进程
*
* @param port 端口号
*/
private static void killPortProcess(int port) {
try {
if (!isPortInUse(port)) {
return;
}
System.out.println("端口 " + port + " 已被占用,正在查找并终止进程...");
ProcessBuilder pb = new ProcessBuilder("netstat", "-ano");
Process process = pb.start();
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(":" + port + " ") && line.contains("LISTENING")) {
String[] parts = line.trim().split("\\s+");
String pid = parts[parts.length - 1];
System.out.println("找到占用端口 " + port + " 的进程 PID: " + pid + ",正在终止...");
ProcessBuilder killPb = new ProcessBuilder("taskkill", "/F", "/PID", pid);
Process killProcess = killPb.start();
int exitCode = killProcess.waitFor();
if (exitCode == 0) {
System.out.println("进程 " + pid + " 已成功终止");
} else {
System.out.println("终止进程 " + pid + " 失败exitCode: " + exitCode);
}
break;
}
}
// 等待一小段时间确保端口释放
Thread.sleep(500);
} catch (Exception e) {
System.out.println("检查/终止端口进程时发生异常: " + e.getMessage());
}
}
/**
* 检查端口是否被占用
*/
private static boolean isPortInUse(int port) {
try (ServerSocket socket = new ServerSocket()) {
socket.bind(new InetSocketAddress(port));
return false;
} catch (Exception e) {
return true;
}
}
}

View File

@@ -0,0 +1,271 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # mcp配置信息
mcp:
sse:
enabled: false
url: http://localhost:8085/sse
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: root
# agent:
# url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# # url: jdbc:mysql://localhost:3306/agent_db
# username: root
# password: root
# driverClassName: com.mysql.cj.jdbc.Driver
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: 123456
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: ruoyi-ai
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: xxx@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol
client-id: 449c4*********937************759
client-secret: ac7***********1e0************28d
redirect-uri: ${justauth.address}/social-callback?source=topiam
scopes: [openid, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
AGENT_ALLOWED_TABLES: "abtest_rule,abtest_project,agent_ban_log,agent_ban_logs,agent_install_sub_task,agent_install_sum_task,agent_install_task"

View File

@@ -125,9 +125,6 @@ security:
- /*/api-docs/**
- /warm-flow-ui/config
- /workflow/run
- /user/qrcode
- /user/login/qrcode
- /weixin/check
# 多租户配置
tenant:
# 是否开启
@@ -206,6 +203,7 @@ springdoc:
name: ageerle
email: ageerle@163.com
url: https://gitee.com/ageerle/ruoyi-ai
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.演示模块
@@ -247,12 +245,6 @@ management:
show-details: ALWAYS
logfile:
external-file: ./logs/sys-console.log
health:
# ⚠️ 禁用 Neo4j 健康检查
# Spring Boot Actuator 会自动为 Neo4j 创建健康检查器
# 这会导致应用在启动时尝试连接到 Neo4j
neo4j:
enabled: false
--- # 默认/推荐使用sse推送
sse:
@@ -283,9 +275,9 @@ warm-flow:
# 向量库配置
vector-store:
# 向量存储类型 可选(weaviate/milvus)
# 向量存储类型 可选(weaviate/milvus/qdrant)
# 如需修改向量库类型,请修改此配置值!
type: weaviate
type: milvus
# Weaviate配置
weaviate:
protocol: http
@@ -295,81 +287,10 @@ vector-store:
milvus:
url: http://localhost:19530
collectionname: LocalKnowledge
chat:
memory:
enabled: true
maxMessages: 20
persistenceEnabled: true
# 企业微信应用
wechat:
cp:
corpId:
appConfigs:
- agentId:
secret: ''
token: ''
aesKey: ''
--- # Neo4j 知识图谱配置
neo4j:
uri: bolt://117.72.192.162:7687
username: neo4j
password: MySecurePass123!
database: neo4j
max-connection-pool-size: 50
connection-timeout-seconds: 30
# 知识图谱配置
knowledge:
graph:
# 是否启用知识图谱功能
enabled: false
# 图数据库类型: neo4j 或 apache-age
database-type: neo4j
# 是否自动创建索引
auto-create-index: true
# 批量处理大小
batch-size: 1000
# 最大重试次数
max-retry-count: 3
# 实体抽取配置
extraction:
# 置信度阈值(低于此值的实体将被过滤)
confidence-threshold: 0.7
# 最大实体数量(每个文档)
max-entities-per-doc: 100
# 最大关系数量(每个文档)
max-relations-per-doc: 200
# 文本分片大小(用于长文档)
chunk-size: 2000
# 分片重叠大小
chunk-overlap: 200
# 查询配置
query:
# 默认查询限制数量
default-limit: 100
# 最大查询限制数量
max-limit: 1000
# 路径查询最大深度
max-path-depth: 5
# 查询超时时间(秒)
timeout-seconds: 30
# 是否启用查询缓存
cache-enabled: true
# 缓存过期时间(分钟)
cache-expire-minutes: 60
--- # MCP 模块配置
app:
mcp:
client:
# 请求超时时间(秒)
request-timeout: 30
# 连接超时时间(秒)
connection-timeout: 10
# 最大重试次数
max-retries: 3
# Qdrant配置
qdrant:
host: localhost
port: 6334
collectionname: LocalKnowledge
api-key:
use-tls: false

View File

@@ -48,11 +48,6 @@ public class ChatMessageBo extends BaseEntity {
*/
private String role;
/**
* 扣除金额
*/
private Long deductCost;
/**
* 累计 Tokens
*/
@@ -63,11 +58,6 @@ public class ChatMessageBo extends BaseEntity {
*/
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
private String billingType;
/**
* 备注
*/

View File

@@ -45,30 +45,15 @@ public class ChatModelBo extends BaseEntity {
*/
private String modelDescribe;
/**
* 模型价格
*/
private Long modelPrice;
/**
* 计费类型
*/
private String modelType;
/**
* 是否显示
*/
private String modelShow;
/**
* 是否免费
* 向量维度
*/
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
private Long priority;
private Integer modelDimension;
/**
* 请求地址

View File

@@ -1,45 +0,0 @@
package org.ruoyi.common.chat.domain.dto;
import lombok.Data;
/**
* 聊天消息DTO - 用于上下文传递
*
* @author ageerle@163.com
* @date 2025/12/13
*/
@Data
public class ChatMessageDTO {
/**
* 消息角色: system/user/assistant
*/
private String role;
/**
* 消息内容
*/
private String content;
public static ChatMessageDTO system(String content) {
ChatMessageDTO msg = new ChatMessageDTO();
msg.role = "system";
msg.content = content;
return msg;
}
public static ChatMessageDTO user(String content) {
ChatMessageDTO msg = new ChatMessageDTO();
msg.role = "user";
msg.content = content;
return msg;
}
public static ChatMessageDTO assistant(String content) {
ChatMessageDTO msg = new ChatMessageDTO();
msg.role = "assistant";
msg.content = content;
return msg;
}
}

View File

@@ -1,11 +1,11 @@
package org.ruoyi.common.chat.domain.dto.request;
import dev.langchain4j.data.message.ChatMessage;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import org.ruoyi.common.chat.domain.dto.ChatMessageDTO;
import java.util.List;
/**
* 对话请求对象
@@ -16,11 +16,15 @@ import java.util.List;
@Data
public class ChatRequest {
@NotEmpty(message = "对话消息不能为空")
private List<ChatMessageDTO> messages;
@NotEmpty(message = "传入的模型不能为空")
private String model;
/**
* 对话消息
*/
@NotEmpty(message = "对话消息不能为空")
private String content;
/**
* 工作流请求体
*/
@@ -31,59 +35,49 @@ public class ChatRequest {
*/
private ReSumeRunner reSumeRunner;
/**
* 是否为人机交互用户继续输入
*/
private Boolean isResume = false;
/**
* 是否启用工作流
*/
private Boolean enableWorkFlow;
private Boolean enableWorkFlow = false;
/**
* 会话id
*/
@JsonSerialize(using = ToStringSerializer.class)
@JSONField(serializeUsing = String.class)
private Long sessionId;
/**
* 应用ID
*/
private String appId;
/**
* 知识库id
*/
private String knowledgeId;
/**
* 对话id(每个聊天窗口都不一样)
* 应用ID
*/
private Long uuid;
private String appId;
/**
* 是否为人机交互用户继续输入
* 对话id(每个聊天窗口都不一样)
*/
private Boolean isResume;
@JsonSerialize(using = ToStringSerializer.class)
@JSONField(serializeUsing = String.class)
private Long uuid;
/**
* 是否启用深度思考
*/
private Boolean enableThinking;
/**
* 是否自动切换模型
*/
private Boolean autoSelectModel;
private Boolean enableThinking = false;
/**
* 是否支持联网
*/
private Boolean enableInternet;
/**
* 会话令牌为避免在非Web线程中获取Request入口处注入
*/
private String token;
/**
* 原生对话对象
*/
private List<ChatMessage> chatMessages;
}

View File

@@ -5,8 +5,6 @@ import cn.idev.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.ruoyi.common.chat.entity.chat.ChatMessage;
import org.ruoyi.common.excel.annotation.ExcelDictFormat;
import org.ruoyi.common.excel.convert.ExcelDictConvert;
import java.io.Serial;
import java.io.Serializable;
@@ -56,12 +54,6 @@ public class ChatMessageVo implements Serializable {
@ExcelProperty(value = "对话角色")
private String role;
/**
* 扣除金额
*/
@ExcelProperty(value = "扣除金额")
private Long deductCost;
/**
* 累计 Tokens
*/
@@ -74,12 +66,6 @@ public class ChatMessageVo implements Serializable {
@ExcelProperty(value = "模型名称")
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
@ExcelProperty(value = "计费类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=-token计费2-次数计费")
private String billingType;
/**
* 备注

View File

@@ -54,17 +54,6 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "模型描述")
private String modelDescribe;
/**
* 模型价格
*/
@ExcelProperty(value = "模型价格")
private Long modelPrice;
/**
* 计费类型
*/
@ExcelProperty(value = "计费类型")
private String modelType;
/**
* 是否显示
@@ -73,16 +62,10 @@ public class ChatModelVo implements Serializable {
private String modelShow;
/**
* 是否免费
* 向量维度
*/
@ExcelProperty(value = "是否免费")
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
@ExcelProperty(value = "模型优先级(值越大优先级越高)")
private Long priority;
@ExcelProperty(value = "向量维度")
private Integer modelDimension;
/**
* 请求地址
@@ -102,11 +85,5 @@ public class ChatModelVo implements Serializable {
@ExcelProperty(value = "备注")
private String remark;
/**
* 模型维度
*/
private Integer dimension;
}

View File

@@ -6,12 +6,14 @@ import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)

View File

@@ -1,63 +0,0 @@
package org.ruoyi.common.chat.entity.chat;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.ruoyi.common.chat.service.chat.IChatService;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
* 聊天对话上下文对象
*
* @author zengxb
* @date 2026-02-14
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Builder
public class ChatContext {
/**
* 模型管理视图对象
*/
@NotNull(message = "模型管理视图对象不能为空")
private ChatModelVo chatModelVo;
/**
* 对话请求对象
*/
@NotNull(message = "对话请求对象不能为空")
private ChatRequest chatRequest;
/**
* SSe连接对象
*/
@NotNull(message = "SSe连接对象不能为空")
private SseEmitter emitter;
/**
* 用户ID
*/
@NotNull(message = "用户ID不能为空")
private Long userId;
/**
* Token
*/
@NotNull(message = "Token不能为空")
private String tokenValue;
/**
* 响应处理器
*/
private StreamingChatResponseHandler handler;
/**
* 聊天服务实例
*/
private IChatService chatService;
}

View File

@@ -48,10 +48,6 @@ public class ChatMessage extends TenantEntity {
*/
private String role;
/**
* 扣除金额
*/
private Long deductCost;
/**
* 累计 Tokens
@@ -63,11 +59,6 @@ public class ChatMessage extends TenantEntity {
*/
private String modelName;
/**
* 计费类型1-token计费2-次数计费)
*/
private String billingType;
/**
* 备注
*/

View File

@@ -48,15 +48,6 @@ public class ChatModel extends TenantEntity {
*/
private String modelDescribe;
/**
* 模型价格
*/
private Long modelPrice;
/**
* 计费类型
*/
private String modelType;
/**
* 是否显示
@@ -64,14 +55,9 @@ public class ChatModel extends TenantEntity {
private String modelShow;
/**
* 是否免费
* 向量维度
*/
private String modelFree;
/**
* 模型优先级(值越大优先级越高)
*/
private Long priority;
private Integer modelDimension;
/**
* 请求地址

View File

@@ -1,7 +1,8 @@
package org.ruoyi.common.chat.service.chat;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.validation.Valid;
import org.ruoyi.common.chat.entity.chat.ChatContext;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
/**
@@ -12,10 +13,15 @@ public interface IChatService {
/**
* 客户端发送对话消息到服务端
*/
SseEmitter chat(@Valid ChatContext chatContext);
SseEmitter chat(@Valid ChatRequest chatRequest);
/**
* 获取服务提供商名称
* 支持外部 handler 的对话接口(跨模块调用)
* 同时发送到 SSE 和外部 handler
*
* @param chatRequest 聊天请求
* @param externalHandler 外部响应处理器(可为 null
*/
String getProviderName();
void chat(@Valid ChatRequest chatRequest, StreamingChatResponseHandler externalHandler);
}

View File

@@ -1,59 +0,0 @@
package org.ruoyi.common.chat.service.chatMessage;
import org.ruoyi.common.chat.domain.bo.chat.ChatMessageBo;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* 聊天信息抽象基类 - 保存聊天信息
*
* @author Zengxb
* @date 2026-02-24
*/
public abstract class AbstractChatMessageService {
/**
* 创建日志对象
*/
Logger log = LoggerFactory.getLogger(AbstractChatMessageService.class);
@Autowired
private IChatMessageService chatMessageService;
/**
* 保存聊天信息
*/
public void saveChatMessage(ChatRequest chatRequest, Long userId, String content, String role, ChatModelVo chatModelVo){
try {
// 验证必要的上下文信息
if (chatRequest == null || userId == null) {
log.warn("缺少必要的聊天上下文信息,无法保存消息");
return;
}
// 创建ChatMessageBo对象
ChatMessageBo messageBO = new ChatMessageBo();
messageBO.setUserId(userId);
messageBO.setSessionId(chatRequest.getSessionId());
messageBO.setContent(content);
messageBO.setRole(role);
messageBO.setModelName(chatRequest.getModel());
messageBO.setBillingType(chatModelVo.getModelType());
messageBO.setRemark(null);
chatMessageService.insertByBo(messageBO);
} catch (Exception e) {
log.error("保存{}聊天消息时出错: {}", getProviderName(), e.getMessage(), e);
}
}
/**
* 获取服务提供商名称
*/
protected String getProviderName(){
return "默认工作流大模型";
}
}

View File

@@ -0,0 +1,61 @@
package org.ruoyi.common.core.utils.file;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: xiaoen
* @Description: Content-Type 映射工具
* @Date: Created in 18:50 2026/3/17
*/
public class ContentTypeUtil {
private static final Map<String, String> CONTENT_TYPE_MAP = new HashMap<>();
static {
// 文本文件
CONTENT_TYPE_MAP.put(".txt", "text/plain; charset=UTF-8");
CONTENT_TYPE_MAP.put(".html", "text/html; charset=UTF-8");
CONTENT_TYPE_MAP.put(".htm", "text/html; charset=UTF-8");
CONTENT_TYPE_MAP.put(".css", "text/css; charset=UTF-8");
CONTENT_TYPE_MAP.put(".js", "application/javascript; charset=UTF-8");
CONTENT_TYPE_MAP.put(".json", "application/json; charset=UTF-8");
CONTENT_TYPE_MAP.put(".xml", "application/xml; charset=UTF-8");
CONTENT_TYPE_MAP.put(".csv", "text/csv; charset=UTF-8");
// 图片文件
CONTENT_TYPE_MAP.put(".jpg", "image/jpeg");
CONTENT_TYPE_MAP.put(".jpeg", "image/jpeg");
CONTENT_TYPE_MAP.put(".png", "image/png");
CONTENT_TYPE_MAP.put(".gif", "image/gif");
CONTENT_TYPE_MAP.put(".bmp", "image/bmp");
CONTENT_TYPE_MAP.put(".webp", "image/webp");
CONTENT_TYPE_MAP.put(".svg", "image/svg+xml");
// 应用文件
CONTENT_TYPE_MAP.put(".pdf", "application/pdf");
CONTENT_TYPE_MAP.put(".doc", "application/msword");
CONTENT_TYPE_MAP.put(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
CONTENT_TYPE_MAP.put(".xls", "application/vnd.ms-excel");
CONTENT_TYPE_MAP.put(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
CONTENT_TYPE_MAP.put(".ppt", "application/vnd.ms-powerpoint");
CONTENT_TYPE_MAP.put(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
// 其他
CONTENT_TYPE_MAP.put(".mp3", "audio/mpeg");
CONTENT_TYPE_MAP.put(".mp4", "video/mp4");
CONTENT_TYPE_MAP.put(".zip", "application/zip");
CONTENT_TYPE_MAP.put(".rar", "application/x-rar-compressed");
}
/**
* 根据后缀返回对应的 content-type
* @param suffix
* @param defaultContentType
* @return
*/
public static String getContentType(String suffix, String defaultContentType) {
String contentType = CONTENT_TYPE_MAP.get(suffix.toLowerCase());
return contentType != null ? contentType : defaultContentType;
}
}

View File

@@ -2,9 +2,11 @@ package org.ruoyi.common.sse.core;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.common.sse.dto.SseEventDto;
import org.ruoyi.common.sse.dto.SseMessageDto;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
@@ -65,7 +67,7 @@ public class SseEmitterManager {
emitter.onCompletion(() -> {
SseEmitter remove = emitters.remove(token);
if (remove != null) {
// remove.complete();
remove.complete();
}
});
emitter.onTimeout(() -> {
@@ -174,9 +176,11 @@ public class SseEmitterManager {
if (MapUtil.isNotEmpty(emitters)) {
for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
try {
// 格式化为标准SSE JSON格式
SseEventDto eventDto = SseEventDto.content(message);
entry.getValue().send(SseEmitter.event()
.name("message")
.data(message));
.data(JSONUtil.toJsonStr(eventDto)));
} catch (Exception e) {
SseEmitter remove = emitters.remove(entry.getKey());
if (remove != null) {
@@ -189,6 +193,33 @@ public class SseEmitterManager {
}
}
/**
* 向指定的用户会话发送结构化事件
*
* @param userId 要发送消息的用户id
* @param eventDto SSE事件对象
*/
public void sendEvent(Long userId, SseEventDto eventDto) {
Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
if (MapUtil.isNotEmpty(emitters)) {
for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
try {
entry.getValue().send(SseEmitter.event()
.name(eventDto.getEvent())
.data(JSONUtil.toJsonStr(eventDto)));
} catch (Exception e) {
SseEmitter remove = emitters.remove(entry.getKey());
if (remove != null) {
remove.complete();
}
}
}
} else {
USER_TOKEN_EMITTERS.remove(userId);
}
}
/**
* 本机全用户会话发送消息
*

View File

@@ -0,0 +1,92 @@
package org.ruoyi.common.sse.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
* SSE 事件数据传输对象
* <p>
* 标准的 SSE 消息格式,支持不同事件类型
*
* @author ageerle@163.com
* @date 2025/03/19
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SseEventDto implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 事件类型
*/
private String event;
/**
* 消息内容
*/
private String content;
/**
* 推理内容(深度思考模式)
*/
private String reasoningContent;
/**
* 错误信息
*/
private String error;
/**
* 是否完成
*/
private Boolean done;
/**
* 创建内容事件
*/
public static SseEventDto content(String content) {
return SseEventDto.builder()
.event("content")
.content(content)
.build();
}
/**
* 创建推理内容事件
*/
public static SseEventDto reasoning(String reasoningContent) {
return SseEventDto.builder()
.event("reasoning")
.reasoningContent(reasoningContent)
.build();
}
/**
* 创建完成事件
*/
public static SseEventDto done() {
return SseEventDto.builder()
.event("done")
.done(true)
.build();
}
/**
* 创建错误事件
*/
public static SseEventDto error(String error) {
return SseEventDto.builder()
.event("error")
.error(error)
.build();
}
}

View File

@@ -1,10 +1,12 @@
package org.ruoyi.common.sse.utils;
import java.util.Collections;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.common.sse.core.SseEmitterManager;
import org.ruoyi.common.sse.dto.SseEventDto;
import org.ruoyi.common.sse.dto.SseMessageDto;
/**
@@ -27,6 +29,7 @@ public class SseMessageUtils {
/**
* 向指定的SSE会话发送消息
* 通过 Redis Pub/Sub 广播,确保跨模块消息可达
*
* @param userId 要发送消息的用户id
* @param message 要发送的消息内容
@@ -35,7 +38,11 @@ public class SseMessageUtils {
if (!isEnable()) {
return;
}
MANAGER.sendMessage(userId, message);
// 通过 Redis 广播,让所有模块的 SseTopicListener 接收并转发到本地 SSE 连接
SseMessageDto dto = new SseMessageDto();
dto.setMessage(message);
dto.setUserIds(Collections.singletonList(userId));
MANAGER.publishMessage(dto);
}
/**
@@ -86,6 +93,58 @@ public class SseMessageUtils {
MANAGER.disconnect(userId, tokenValue);
}
/**
* 向指定的SSE会话发送结构化事件
*
* @param userId 要发送消息的用户id
* @param eventDto SSE事件对象
*/
public static void sendEvent(Long userId, SseEventDto eventDto) {
if (!isEnable()) {
return;
}
MANAGER.sendEvent(userId, eventDto);
}
/**
* 发送内容事件
*
* @param userId 用户ID
* @param content 内容
*/
public static void sendContent(Long userId, String content) {
sendEvent(userId, SseEventDto.content(content));
}
/**
* 发送推理内容事件
*
* @param userId 用户ID
* @param reasoningContent 推理内容
*/
public static void sendReasoning(Long userId, String reasoningContent) {
sendEvent(userId, SseEventDto.reasoning(reasoningContent));
}
/**
* 发送完成事件
*
* @param userId 用户ID
*/
public static void sendDone(Long userId) {
sendEvent(userId, SseEventDto.done());
}
/**
* 发送错误事件
*
* @param userId 用户ID
* @param error 错误信息
*/
public static void sendError(Long userId, String error) {
sendEvent(userId, SseEventDto.error(error));
}
/**
* 是否开启
*/

View File

@@ -12,11 +12,8 @@
<modules>
<module>ruoyi-aiflow</module>
<module>ruoyi-chat</module>
<module>ruoyi-demo</module>
<module>ruoyi-generator</module>
<module>ruoyi-job</module>
<module>ruoyi-system</module>
<module>ruoyi-wechat</module>
<module>ruoyi-workflow</module>
</modules>

View File

@@ -98,7 +98,7 @@ public class WorkflowComponentService extends ServiceImpl<WorkflowComponentMappe
return baseMapper.selectPage(new Page<>(currentPage, pageSize), wrapper);
}
@Cacheable(cacheNames = WORKFLOW_COMPONENTS)
// @Cacheable(cacheNames = WORKFLOW_COMPONENTS)
public List<WorkflowComponent> getAllEnable() {
return ChainWrappers.lambdaQueryChain(baseMapper)
.eq(WorkflowComponent::getIsEnable, true)

View File

@@ -64,7 +64,8 @@ public class WorkflowMessageUtil {
ChatRequest chatRequest = new ChatRequest();
chatRequest.setSessionId(sessionId);
WorkflowUtil workflowUtil = SpringUtils.getBean(WorkflowUtil.class);
workflowUtil.saveChatMessage(chatRequest, userId, message, RoleType.WORKFLOW.getName(), new ChatModelVo());
// todo 保存消息
//workflowUtil.saveChatMessage(chatRequest, userId, message, RoleType.WORKFLOW.getName(), new ChatModelVo());
}
}

View File

@@ -4,23 +4,18 @@ import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import dev.langchain4j.data.message.ChatMessage;
import dev.langchain4j.data.message.SystemMessage;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.bsc.langgraph4j.langchain4j.generators.StreamingChatGenerator;
import org.bsc.langgraph4j.state.AgentState;
import org.ruoyi.common.chat.enums.RoleType;
import org.ruoyi.common.chat.service.chat.IChatModelService;
import org.ruoyi.common.chat.service.chat.IChatService;
import org.ruoyi.common.chat.service.chatMessage.AbstractChatMessageService;
import org.ruoyi.common.chat.service.image.IImageGenerationService;
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
import org.ruoyi.common.chat.entity.chat.ChatContext;
import org.ruoyi.common.chat.entity.image.ImageContext;
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
import org.ruoyi.common.chat.factory.ChatServiceFactory;
import org.ruoyi.common.chat.factory.ImageServiceFactory;
import org.ruoyi.workflow.base.NodeInputConfigTypeHandler;
import org.ruoyi.workflow.entity.WorkflowNode;
@@ -29,9 +24,7 @@ import org.ruoyi.workflow.util.JsonUtil;
import org.ruoyi.workflow.workflow.data.NodeIOData;
import org.ruoyi.workflow.workflow.data.NodeIODataContent;
import org.ruoyi.workflow.workflow.def.WfNodeParamRef;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.*;
@@ -39,10 +32,7 @@ import static org.ruoyi.workflow.cosntant.AdiConstant.WorkflowConstant.DEFAULT_O
@Slf4j
@Service
public class WorkflowUtil extends AbstractChatMessageService {
@Resource
private ChatServiceFactory chatServiceFactory;
public class WorkflowUtil{
@Resource
private ImageServiceFactory imageServiceFactory;
@@ -50,6 +40,9 @@ public class WorkflowUtil extends AbstractChatMessageService {
@Resource
private IChatModelService chatModelService;
@Resource
private IChatService chatService;
public static String renderTemplate(String template, List<NodeIOData> values) {
// 🔒 关键修复:如果 template 为 null直接返回 null 或空字符串
if (template == null) {
@@ -112,54 +105,23 @@ public class WorkflowUtil extends AbstractChatMessageService {
}
public void streamingInvokeLLM(WfState wfState, WfNodeState state, WorkflowNode node, String modelName,
List<SystemMessage> systemMessage, String nodeMessageTemplate) {
String prompt, String nodeMessageTemplate) {
log.info("stream invoke, modelName: {}", modelName);
// 根据模型名称查询模型信息
ChatModelVo chatModelVo = chatModelService.selectModelByName(modelName);
if (chatModelVo == null) {
throw new IllegalArgumentException("模型不存在: " + modelName);
}
// 路由服务提供商
String category = chatModelVo.getProviderCode();
// 根据 category 获取对应的 ChatService不使用计费代理工作流场景单独计费
IChatService chatService = chatServiceFactory.getOriginalService(category);
// 获取用户信息和Token以及SSe连接对象对话接口需要使用
Long sessionId = wfState.getSessionId();
Long userId = wfState.getUserId();
String tokenValue = wfState.getTokenValue();
SseEmitter sseEmitter = wfState.getSseEmitter();
// 构建 ruoyi-ai 的 ChatRequest
List<ChatMessage> chatMessages = new ArrayList<>();
addUserMessage(node, state.getInputs(), chatMessages);
chatMessages.addAll(systemMessage);
// 定义模型调用对象
ChatRequest chatRequest = new ChatRequest();
// 目前工作流深度思考成员变量只能写死
chatRequest.setSessionId(sessionId);
chatRequest.setEnableThinking(false);
chatRequest.setModel(modelName);
chatRequest.setChatMessages(chatMessages);
chatRequest.setContent(prompt);
// 构建流式生成器
StreamingChatGenerator<AgentState> streamingGenerator = StreamingChatGenerator.builder()
.mapResult(response -> {
String responseTxt = response.aiMessage().text();
log.info("llm response:{}", responseTxt);
// 会话ID不为空时插入数据库
if (sessionId != null){
// 获取模板消息拼接信息体
String message = nodeMessageTemplate + responseTxt;
// 保存助手回复消息
saveChatMessage(chatRequest, userId, message, RoleType.ASSISTANT.getName(), chatModelVo);
log.info("{}消息结束,已保存到数据库", getProviderName());
}
// 传递所有输入数据 + 添加 LLM 输出
wfState.getNodeStateByNodeUuid(node.getUuid()).ifPresent(item -> {
List<NodeIOData> outputs = new ArrayList<>(item.getInputs());
@@ -174,21 +136,13 @@ public class WorkflowUtil extends AbstractChatMessageService {
.startingState(state)
.build();
// 构建流式回调响应
StreamingChatResponseHandler handler = streamingGenerator.handler();
// 获取 StreamingChatGenerator 的 handler用于处理流式响应
StreamingChatResponseHandler workflowHandler = streamingGenerator.handler();
//构建聊天对话上下文参数
ChatContext chatContext = ChatContext.builder()
.chatModelVo(chatModelVo)
.chatRequest(chatRequest)
.emitter(sseEmitter)
.userId(userId)
.tokenValue(tokenValue)
.handler(handler)
.build();
// 调用 Chat 服务,传入 workflow 的 handler
// 消息会同时发送到 SSE前端和 workflowHandler工作流处理
chatService.chat(chatRequest, workflowHandler);
// 使用工作流专用方法
chatService.chat(chatContext);
wfState.getNodeToStreamingGenerator().put(node.getUuid(), streamingGenerator);
}

View File

@@ -46,13 +46,11 @@ public class LLMAnswerNode extends AbstractWfNode {
// 调用LLM
WorkflowUtil workflowUtil = SpringUtil.getBean(WorkflowUtil.class);
String modelName = nodeConfigObj.getModelName();
// 转换系统信息结构
List<SystemMessage> systemMessage = List.of(new SystemMessage(prompt));
// 获取节点模板提示词信息
String nodeMessageTemplate = WorkflowMessageUtil.getNodeMessageTemplate(NodeMessageTemplateEnum.LLM_RESPONSE.getValue());
// 发送SSE驱动事件消息
WorkflowMessageUtil.sendEmitterMessage(wfState.getSseEmitter(), node, nodeMessageTemplate);
workflowUtil.streamingInvokeLLM(wfState, state, node, modelName, systemMessage, nodeMessageTemplate);
workflowUtil.streamingInvokeLLM(wfState, state, node, modelName, prompt, nodeMessageTemplate);
return new NodeProcessResult();
}
}

View File

@@ -67,13 +67,12 @@ public class KeywordExtractorNode extends AbstractWfNode {
// 调用 LLM 进行关键词提取
WorkflowUtil workflowUtil = SpringUtil.getBean(WorkflowUtil.class);
String modelName = config.getModelName();
List<SystemMessage> systemMessage = List.of(new SystemMessage(prompt));
// 获取节点模板提示词信息
String nodeMessageTemplate = WorkflowMessageUtil.getNodeMessageTemplate(NodeMessageTemplateEnum.KEYWORD_EXTRACTOR.getValue());
// 发送SSE事件消息
WorkflowMessageUtil.sendEmitterMessage(wfState.getSseEmitter(), node, nodeMessageTemplate);
// 使用流式调用
workflowUtil.streamingInvokeLLM(wfState, state, node, modelName, systemMessage, nodeMessageTemplate);
workflowUtil.streamingInvokeLLM(wfState, state, node, modelName, prompt, nodeMessageTemplate);
return new NodeProcessResult();
}

View File

@@ -151,7 +151,6 @@ public class KnowledgeRetrievalNode extends AbstractWfNode {
// 使用WorkflowUtil调用LLM流式
WorkflowUtil workflowUtil = SpringUtil.getBean(WorkflowUtil.class);
List<SystemMessage> systemMessage = List.of(new SystemMessage(prompt));
// 调用流式LLM
String modelName = StringUtils.isNotBlank(config.getModelName()) ? config.getModelName() : "deepseek-chat";
@@ -161,7 +160,7 @@ public class KnowledgeRetrievalNode extends AbstractWfNode {
tempState,
tempNode,
modelName,
systemMessage,
prompt,
""
);

View File

@@ -0,0 +1,425 @@
# Ruoyi-AI 流程编排模块详细说明文档
## 概述
Ruoyi-AI 工作流模块是一个基于 LangGraph4j 的智能工作流引擎支持可视化工作流设计、AI 模型集成、条件分支、人机交互等高级功能。该模块采用微服务架构,提供完整的
RESTful API 和流式响应支持。
## 模块架构
### 1. 核心依赖
- **LangGraph4j**: 1.5.3 - 工作流图执行引擎
- **LangChain4j**: 1.11.0 - AI 模型集成框架
- **Spring Boot**: 3.5.8 - 应用框架
- **MyBatis Plus**: 数据访问层
- **Redis**: 缓存和状态管理
- **OpenAPI**: API 文档
## 核心功能
### 1. 工作流管理
#### 1.1 工作流定义
- **创建工作流**: 支持自定义标题、描述、公开性设置
- **编辑工作流**: 可视化节点编辑、连接线配置
- **版本控制**: 支持工作流的版本管理和回滚
- **权限管理**: 支持公开/私有工作流设置
#### 1.2 工作流执行
- **流式执行**: 基于 SSE 的实时流式响应
- **状态管理**: 完整的执行状态跟踪
- **错误处理**: 详细的错误信息和异常处理
- **中断恢复**: 支持工作流中断和恢复执行
### 2. 节点类型
#### 2.1 基础节点
- **Start**: 开始节点,定义工作流入口
- **End**: 结束节点,定义工作流出口
#### 2.2 AI 模型节点
- **Answer**: 大语言模型问答节点
- **Dalle3**: DALL-E 3 图像生成
- **Tongyiwanx**: 通义万相图像生成
- **Classifier**: 内容分类节点
#### 2.3 数据处理节点
- **DocumentExtractor**: 文档信息提取
- **KeywordExtractor**: 关键词提取
- **FaqExtractor**: 常见问题提取
- **KnowledgeRetrieval**: 知识库检索
#### 2.4 控制流节点
- **Switcher**: 条件分支节点
- **HumanFeedback**: 人机交互节点
#### 2.5 外部集成节点
- **Google**: Google 搜索集成
- **MailSend**: 邮件发送
- **HttpRequest**: HTTP 请求
- **Template**: 模板转换
### 3. 数据流管理
#### 3.1 输入输出定义
```java
// 节点输入输出数据结构
public class NodeIOData {
private String name; // 参数名称
private NodeIODataContent content; // 参数内容
}
// 支持的数据类型
public enum WfIODataTypeEnum {
TEXT, // 文本
NUMBER, // 数字
BOOLEAN, // 布尔值
FILES, // 文件
OPTIONS // 选项
}
```
#### 3.2 参数引用
- **节点间引用**: 支持上游节点输出作为下游节点输入
- **参数映射**: 自动处理参数名称映射
- **类型转换**: 自动进行数据类型转换
## 数据库设计
### 1. 核心表结构
#### 1.1 工作流定义表 (t_workflow)
```sql
CREATE TABLE t_workflow (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
uuid VARCHAR(32) NOT NULL DEFAULT '',
title VARCHAR(100) NOT NULL DEFAULT '',
remark TEXT NOT NULL DEFAULT '',
user_id BIGINT NOT NULL DEFAULT 0,
is_public TINYINT(1) NOT NULL DEFAULT 0,
is_enable TINYINT(1) NOT NULL DEFAULT 1,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0
);
```
#### 1.2 工作流节点表 (t_workflow_node)
```sql
CREATE TABLE t_workflow_node (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
uuid VARCHAR(32) NOT NULL DEFAULT '',
workflow_id BIGINT NOT NULL DEFAULT 0,
workflow_component_id BIGINT NOT NULL DEFAULT 0,
user_id BIGINT NOT NULL DEFAULT 0,
title VARCHAR(100) NOT NULL DEFAULT '',
remark VARCHAR(500) NOT NULL DEFAULT '',
input_config JSON NOT NULL DEFAULT ('{}'),
node_config JSON NOT NULL DEFAULT ('{}'),
position_x DOUBLE NOT NULL DEFAULT 0,
position_y DOUBLE NOT NULL DEFAULT 0,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0
);
```
#### 1.3 工作流边表 (t_workflow_edge)
```sql
CREATE TABLE t_workflow_edge (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
uuid VARCHAR(32) NOT NULL DEFAULT '',
workflow_id BIGINT NOT NULL DEFAULT 0,
source_node_uuid VARCHAR(32) NOT NULL DEFAULT '',
source_handle VARCHAR(32) NOT NULL DEFAULT '',
target_node_uuid VARCHAR(32) NOT NULL DEFAULT '',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0
);
```
#### 1.4 工作流运行时表 (t_workflow_runtime)
```sql
CREATE TABLE t_workflow_runtime (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
uuid VARCHAR(32) NOT NULL DEFAULT '',
user_id BIGINT NOT NULL DEFAULT 0,
workflow_id BIGINT NOT NULL DEFAULT 0,
input JSON NOT NULL DEFAULT ('{}'),
output JSON NOT NULL DEFAULT ('{}'),
status SMALLINT NOT NULL DEFAULT 1,
status_remark VARCHAR(250) NOT NULL DEFAULT '',
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
is_deleted TINYINT(1) NOT NULL DEFAULT 0
);
```
#### 1.5 工作流组件表 (t_workflow_component)
```sql
CREATE TABLE t_workflow_component (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
uuid VARCHAR(32) DEFAULT '' NOT NULL,
name VARCHAR(32) DEFAULT '' NOT NULL,
title VARCHAR(100) DEFAULT '' NOT NULL,
remark TEXT NOT NULL,
display_order INT DEFAULT 0 NOT NULL,
is_enable TINYINT(1) DEFAULT 0 NOT NULL,
create_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
is_deleted TINYINT(1) DEFAULT 0 NOT NULL
);
```
## API 接口
### 1. 工作流管理接口
#### 1.1 基础操作
```http
#
POST /workflow/add
Content-Type: application/json
{
"title": "",
"remark": "",
"isPublic": false
}
#
POST /workflow/update
Content-Type: application/json
{
"uuid": "UUID",
"title": "",
"remark": ""
}
#
POST /workflow/del/{uuid}
# /
POST /workflow/enable/{uuid}?enable=true
```
#### 1.2 搜索和查询
```http
#
GET /workflow/mine/search?keyword=&isPublic=true&currentPage=1&pageSize=10
#
GET /workflow/public/search?keyword=&currentPage=1&pageSize=10
#
GET /workflow/public/component/list
```
### 2. 工作流执行接口
#### 2.1 流式执行
```http
#
POST /workflow/run
Content-Type: application/json
Accept: text/event-stream
{
"uuid": "UUID",
"inputs": [
{
"name": "input",
"content": {
"type": 1,
"textContent": ""
}
}
]
}
```
#### 2.2 运行时管理
```http
#
POST /workflow/runtime/resume/{runtimeUuid}
Content-Type: application/json
{
"feedbackContent": ""
}
#
GET /workflow/runtime/page?wfUuid=UUID&currentPage=1&pageSize=10
#
GET /workflow/runtime/nodes/{runtimeUuid}
#
POST /workflow/runtime/clear?wfUuid=UUID
```
### 3. 管理端接口
#### 3.1 工作流管理
```http
#
POST /admin/workflow/search
Content-Type: application/json
{
"title": "",
"isPublic": true,
"isEnable": true
}
# /
POST /admin/workflow/enable?uuid=UUID&isEnable=true
```
## 核心实现
### 1. 工作流引擎 (WorkflowEngine)
工作流引擎是整个模块的核心,负责:
- 工作流图的构建和编译
- 节点执行调度
- 状态管理和持久化
- 流式输出处理
```java
public class WorkflowEngine {
// 核心执行方法
public void run(User user, List<ObjectNode> userInputs, SseEmitter sseEmitter) {
// 1. 验证工作流状态
// 2. 创建运行时实例
// 3. 构建状态图
// 4. 执行工作流
// 5. 处理流式输出
}
// 恢复执行方法
public void resume(String userInput) {
// 1. 更新状态
// 2. 继续执行
}
}
```
### 2. 节点工厂 (WfNodeFactory)
节点工厂负责根据组件类型创建对应的节点实例:
```java
public class WfNodeFactory {
public static AbstractWfNode create(WorkflowComponent component,
WorkflowNode node,
WfState wfState,
WfNodeState nodeState) {
// 根据组件类型创建对应的节点实例
switch (component.getName()) {
case "Answer":
return new LLMAnswerNode(component, node, wfState, nodeState);
case "Switcher":
return new SwitcherNode(component, node, wfState, nodeState);
// ... 其他节点类型
}
}
}
```
### 3. 图构建器 (WorkflowGraphBuilder)
图构建器负责将工作流定义转换为可执行的状态图:
```java
public class WorkflowGraphBuilder {
public StateGraph<WfNodeState> build(WorkflowNode startNode) {
// 1. 构建编译节点树
// 2. 转换为状态图
// 3. 添加节点和边
// 4. 处理条件分支
// 5. 处理并行执行
}
}
```
## 流式响应机制
### 1. SSE 事件类型
工作流执行过程中会发送多种类型的 SSE 事件:
```javascript
// 节点开始执行
[NODE_RUN_节点UUID] - 节点执行开始事件
// 节点输入数据
[NODE_INPUT_节点UUID] - 节点输入数据事件
// 节点输出数据
[NODE_OUTPUT_节点UUID] - 节点输出数据事件
// 流式内容块
[NODE_CHUNK_节点UUID] - 流式内容块事件
// 等待用户输入
[NODE_WAIT_FEEDBACK_BY_节点UUID] - 等待用户输入事件
```
### 2. 流式处理流程
1. **初始化**: 创建工作流运行时实例
2. **节点执行**: 逐个执行工作流节点
3. **实时输出**: 通过 SSE 实时推送执行结果
4. **状态更新**: 实时更新节点和工作流状态
5. **错误处理**: 捕获并处理执行过程中的错误
## 扩展开发
### 1. 自定义节点开发
要开发自定义工作流节点,需要:
1. **创建节点类**:继承 `AbstractWfNode`
2. **实现处理逻辑**:重写 `onProcess()` 方法
3. **定义配置类**:创建节点配置类
4. **注册组件**:在组件表中注册新组件
```java
public class CustomNode extends AbstractWfNode {
@Override
protected NodeProcessResult onProcess() {
// 实现自定义处理逻辑
List<NodeIOData> outputs = new ArrayList<>();
// ... 处理逻辑
return NodeProcessResult.success(outputs);
}
}
```
### 2. 自定义组件注册
```sql
-- 在 t_workflow_component 表中添加新组件
INSERT INTO t_workflow_component (uuid, name, title, remark, is_enable)
VALUES (REPLACE(UUID(), '-', ''), 'CustomNode', '自定义节点', '自定义节点描述', true);
```

View File

@@ -19,6 +19,11 @@
<artifactId>ruoyi-common-chat</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-common-sse</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-common-sensitive</artifactId>
@@ -86,6 +91,12 @@
<version>${langchain4j.community.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-qdrant</artifactId>
<version>${langchain4j.community.version}</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-mcp</artifactId>

View File

@@ -6,7 +6,7 @@ import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface ChartGenerationAgent extends Agent {
public interface ChartGenerationAgent {
@SystemMessage("""
You are a chart generation specialist. Your only task is to generate Apache ECharts

View File

@@ -14,7 +14,7 @@ public interface EchartsAgent {
@SystemMessage("""
You are a data visualization assistant that generates Echarts chart configurations.
CRITICAL OUTPUT REQUIREMENTS:
- Return Echarts JSON wrapped in markdown code block
- Use this exact format: ```json\n{...}\n```
@@ -81,7 +81,7 @@ public interface EchartsAgent {
""")
@UserMessage("""
Generate an Echarts chart for: {{query}}
IMPORTANT: Return the Echarts configuration JSON wrapped in markdown code block (```json...```).
""")
@Agent("Data visualization assistant that returns Echarts JSON configurations for frontend rendering")

View File

@@ -1,38 +0,0 @@
package org.ruoyi.agent;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
/**
* User Name Retrieval Agent
* A simple assistant that retrieves user names using the get_name tool.
*/
public interface GetNameInfo {
@SystemMessage("""
You are a user identity assistant. You MUST always use tools to get information.
MANDATORY REQUIREMENTS:
- You MUST call the get_user_name_by_id tool for ANY question about names or identity
- NEVER respond without calling the get_user_name_by_id tool first
- Return ONLY the exact string returned by the get_user_name_by_id tool
- Do not make up names like "John Doe" or any other default names
- Do not use your knowledge to answer - ALWAYS use the tool
Your workflow:
1. Extract userId from the query (if mentioned), or use "1" as default
2. ALWAYS call the get_user_name_by_id tool with the userId parameter
3. Return the exact result as plain text with no additions
CRITICAL: If you don't call the get_user_name_by_id tool, your response is wrong.
""")
@UserMessage("""
Get the user name using the get_user_name_by_id tool. Query: {{query}}
IMPORTANT: Return only the exact result from the tool.
""")
@Agent("User identity assistant that returns user name from get_name tool")
String search(@V("query") String query);
}

View File

@@ -1,42 +0,0 @@
package org.ruoyi.agent;
import dev.langchain4j.agentic.Agent;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
public interface McpAgent extends Agent {
/**
* 系统提示词:通用工具调用智能体
* 不限定具体工具类型,让 LangChain4j 自动传递工具描述给 LLM
*/
@SystemMessage("""
你是一个AI助手可以通过调用各种工具来帮助用户完成不同的任务。
【工具使用规则】
1. 根据用户的请求,判断需要使用哪些工具
2. 仔细阅读每个工具的描述,确保理解工具的功能和参数要求
3. 使用正确的参数调用工具
4. 如果工具执行失败,向用户友好地说明错误原因,并尝试提供替代方案
5. 对于复杂任务,可以分步骤使用多个工具完成
6. 将工具执行结果以清晰易懂的方式呈现给用户
【响应格式】
- 直接回答用户的问题
- 如果使用了工具,说明使用了什么工具以及结果
- 如果遇到错误,提供友好的错误信息和解决建议
""")
@UserMessage("""
{{query}}
""")
@Agent("通用工具调用智能体")
/**
* 智能体对外调用入口
* @param query 用户的自然语言请求
* @return 处理结果
*/
String callMcpTool(@V("query") String query);
}

View File

@@ -11,7 +11,7 @@ import dev.langchain4j.service.V;
* and returning relevant data and analysis results.
*
*/
public interface SqlAgent extends Agent {
public interface SqlAgent {
@SystemMessage("""
This agent is designed for MySQL 5.7

View File

@@ -10,7 +10,7 @@ import dev.langchain4j.service.V;
* A web search assistant that answers natural language questions by searching the internet
* and returning relevant information from web pages.
*/
public interface WebSearchAgent extends Agent {
public interface WebSearchAgent {
@SystemMessage("""
You are a web search assistant. Answer questions by searching and retrieving web content.

View File

@@ -43,7 +43,7 @@ public class ExecuteSqlQueryTool implements BuiltinToolProvider {
@Tool("Execute a SELECT SQL query and return the results. Example: SELECT * FROM sys_user")
public String executeSql(String sql) {
// 2. 手动推入数据源上下文
DynamicDataSourceContextHolder.push("agent");
// DynamicDataSourceContextHolder.push("agent");
if (sql == null || sql.trim().isEmpty()) {
return "Error: SQL query cannot be empty";
}

View File

@@ -1,69 +0,0 @@
package org.ruoyi.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 图谱构建异步任务配置
*
* @author ruoyi
* @date 2025-10-11
*/
@Slf4j
@EnableAsync
@Configuration
@ConditionalOnProperty(prefix = "knowledge.graph", name = "enabled", havingValue = "true")
public class GraphAsyncConfig {
/**
* 图谱构建专用线程池
* 用于执行图谱构建任务,避免阻塞主线程池
*/
@Bean("graphBuildExecutor")
public Executor graphBuildExecutor() {
log.info("初始化图谱构建线程池...");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数CPU核心数
int processors = Runtime.getRuntime().availableProcessors();
executor.setCorePoolSize(processors);
// 最大线程数CPU核心数 * 2
executor.setMaxPoolSize(processors * 2);
// 队列容量100个任务
executor.setQueueCapacity(100);
// 线程空闲时间60秒
executor.setKeepAliveSeconds(60);
// 线程名称前缀
executor.setThreadNamePrefix("graph-build-");
// 拒绝策略:由调用线程处理
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务完成后关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
// 等待时间60秒
executor.setAwaitTerminationSeconds(60);
// 初始化
executor.initialize();
log.info("图谱构建线程池初始化完成: corePoolSize={}, maxPoolSize={}, queueCapacity={}",
processors, processors * 2, 100);
return executor;
}
}

View File

@@ -1,175 +0,0 @@
package org.ruoyi.config;
import org.ruoyi.constant.GraphConstants;
import java.util.Arrays;
import java.util.stream.Collectors;
/**
* 图谱实体关系抽取提示词
* 参考 Microsoft GraphRAG 项目
* https://github.com/microsoft/graphrag/blob/main/graphrag/index/graph/extractors/graph/prompts.py
*
* @author ruoyi
* @date 2025-09-30
*/
public class GraphExtractPrompt {
/**
* 中文实体关系抽取提示词
*/
public static final String GRAPH_EXTRACTION_PROMPT_CN = """
-目标-
给定一个可能与此活动相关的文本文档以及实体类型列表,从文本中识别出所有这些类型的实体以及识别出的实体之间的所有关系。
-步骤-
1. 识别所有实体。对于每个识别出的实体,提取以下信息:
- entity_name实体的名称首字母大写
- entity_type以下类型之一[{entity_types}]
- entity_description实体的属性和活动的全面描述
将每个实体格式化为 ("entity"{tuple_delimiter}<entity_name>{tuple_delimiter}<entity_type>{tuple_delimiter}<entity_description>)
2. 从步骤1中识别出的实体中识别出所有明确相关的 (source_entity, target_entity) 对。
对于每对相关的实体,提取以下信息:
- source_entity在步骤1中识别的源实体的名称
- target_entity在步骤1中识别的目标实体的名称
- relationship_description解释你认为源实体和目标实体之间相关的原因
- relationship_strength一个表示源实体和目标实体之间关系强度的数字分数0-10
将每个关系格式化为 ("relationship"{tuple_delimiter}<source_entity>{tuple_delimiter}<target_entity>{tuple_delimiter}<relationship_description>{tuple_delimiter}<relationship_strength>)
3. 以英文返回输出作为所有在步骤1和步骤2中识别的实体和关系的列表。使用 **{record_delimiter}** 作为列表分隔符。
4. 完成时,输出 {completion_delimiter}
######################
-示例-
######################
示例 1:
Entity_types: ORGANIZATION,PERSON
文本:
The Verdantis's Central Institution is scheduled to meet on Monday and Thursday, with the institution planning to release its latest policy decision on Thursday at 1:30 p.m. PDT, followed by a press conference where Central Institution Chair Martin Smith will take questions. Investors expect the Market Strategy Committee to hold its benchmark interest rate steady in a range of 3.5%-3.75%.
######################
输出:
("entity"{tuple_delimiter}CENTRAL INSTITUTION{tuple_delimiter}ORGANIZATION{tuple_delimiter}The Central Institution is the Federal Reserve of Verdantis, which is setting interest rates on Monday and Thursday)
{record_delimiter}
("entity"{tuple_delimiter}MARTIN SMITH{tuple_delimiter}PERSON{tuple_delimiter}Martin Smith is the chair of the Central Institution)
{record_delimiter}
("entity"{tuple_delimiter}MARKET STRATEGY COMMITTEE{tuple_delimiter}ORGANIZATION{tuple_delimiter}The Central Institution committee makes key decisions about interest rates and the growth of Verdantis's money supply)
{record_delimiter}
("relationship"{tuple_delimiter}MARTIN SMITH{tuple_delimiter}CENTRAL INSTITUTION{tuple_delimiter}Martin Smith is the Chair of the Central Institution and will answer questions at a press conference{tuple_delimiter}9)
{completion_delimiter}
######################
示例 2:
Entity_types: ORGANIZATION
文本:
TechGlobal's (TG) stock skyrocketed in its opening day on the Global Exchange Thursday. But IPO experts warn that the semiconductor corporation's debut on the public markets isn't indicative of how other newly listed companies may perform.
TechGlobal, a formerly public company, was taken private by Vision Holdings in 2014. The well-established chip designer says it powers 85% of premium smartphones.
######################
输出:
("entity"{tuple_delimiter}TECHGLOBAL{tuple_delimiter}ORGANIZATION{tuple_delimiter}TechGlobal is a stock now listed on the Global Exchange which powers 85% of premium smartphones)
{record_delimiter}
("entity"{tuple_delimiter}VISION HOLDINGS{tuple_delimiter}ORGANIZATION{tuple_delimiter}Vision Holdings is a firm that previously owned TechGlobal)
{record_delimiter}
("relationship"{tuple_delimiter}TECHGLOBAL{tuple_delimiter}VISION HOLDINGS{tuple_delimiter}Vision Holdings formerly owned TechGlobal from 2014 until present{tuple_delimiter}5)
{completion_delimiter}
######################
示例 3:
Entity_types: ORGANIZATION,LOCATION,PERSON
文本:
Five Aurelians jailed for 8 years in Firuzabad and widely regarded as hostages are on their way home to Aurelia.
The swap orchestrated by Quintara was finalized when $8bn of Firuzi funds were transferred to financial institutions in Krohaara, the capital of Quintara.
The exchange initiated in Firuzabad's capital, Tiruzia, led to the four men and one woman, who are also Firuzi nationals, boarding a chartered flight to Krohaara.
They were welcomed by senior Aurelian officials and are now on their way to Aurelia's capital, Cashion.
The Aurelians include 39-year-old businessman Samuel Namara, who has been held in Tiruzia's Alhamia Prison, as well as journalist Durke Bataglani, 59, and environmentalist Meggie Tazbah, 53, who also holds Bratinas nationality.
######################
输出:
("entity"{tuple_delimiter}FIRUZABAD{tuple_delimiter}LOCATION{tuple_delimiter}Firuzabad held Aurelians as hostages)
{record_delimiter}
("entity"{tuple_delimiter}AURELIA{tuple_delimiter}LOCATION{tuple_delimiter}Country seeking to release hostages)
{record_delimiter}
("entity"{tuple_delimiter}QUINTARA{tuple_delimiter}LOCATION{tuple_delimiter}Country that negotiated a swap of money in exchange for hostages)
{record_delimiter}
("entity"{tuple_delimiter}TIRUZIA{tuple_delimiter}LOCATION{tuple_delimiter}Capital of Firuzabad where the Aurelians were being held)
{record_delimiter}
("entity"{tuple_delimiter}KROHAARA{tuple_delimiter}LOCATION{tuple_delimiter}Capital city in Quintara)
{record_delimiter}
("entity"{tuple_delimiter}CASHION{tuple_delimiter}LOCATION{tuple_delimiter}Capital city in Aurelia)
{record_delimiter}
("entity"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}PERSON{tuple_delimiter}Aurelian who spent time in Tiruzia's Alhamia Prison)
{record_delimiter}
("entity"{tuple_delimiter}ALHAMIA PRISON{tuple_delimiter}LOCATION{tuple_delimiter}Prison in Tiruzia)
{record_delimiter}
("entity"{tuple_delimiter}DURKE BATAGLANI{tuple_delimiter}PERSON{tuple_delimiter}Aurelian journalist who was held hostage)
{record_delimiter}
("entity"{tuple_delimiter}MEGGIE TAZBAH{tuple_delimiter}PERSON{tuple_delimiter}Bratinas national and environmentalist who was held hostage)
{record_delimiter}
("relationship"{tuple_delimiter}FIRUZABAD{tuple_delimiter}AURELIA{tuple_delimiter}Firuzabad negotiated a hostage exchange with Aurelia{tuple_delimiter}2)
{record_delimiter}
("relationship"{tuple_delimiter}QUINTARA{tuple_delimiter}AURELIA{tuple_delimiter}Quintara brokered the hostage exchange between Firuzabad and Aurelia{tuple_delimiter}2)
{record_delimiter}
("relationship"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}ALHAMIA PRISON{tuple_delimiter}Samuel Namara was a prisoner at Alhamia prison{tuple_delimiter}8)
{record_delimiter}
("relationship"{tuple_delimiter}SAMUEL NAMARA{tuple_delimiter}MEGGIE TAZBAH{tuple_delimiter}Samuel Namara and Meggie Tazbah were exchanged in the same hostage release{tuple_delimiter}2)
{completion_delimiter}
######################
-真实数据-
######################
Entity_types: {entity_types}
文本: {input_text}
######################
输出:
""".replace("{tuple_delimiter}", GraphConstants.GRAPH_TUPLE_DELIMITER)
.replace("{entity_types}", Arrays.stream(GraphConstants.DEFAULT_ENTITY_TYPES).collect(Collectors.joining(",")))
.replace("{completion_delimiter}", GraphConstants.GRAPH_COMPLETION_DELIMITER)
.replace("{record_delimiter}", GraphConstants.GRAPH_RECORD_DELIMITER);
/**
* 继续抽取提示词(当第一次抽取遗漏实体时使用)
*/
public static final String CONTINUE_PROMPT = """
在上一次抽取中遗漏了许多实体和关系。
请记住只提取与之前提取的类型匹配的实体。
使用相同的格式在下面添加它们:
""";
/**
* 循环检查提示词
*/
public static final String LOOP_PROMPT = """
似乎仍然可能遗漏了一些实体和关系。
如果还有需要添加的实体或关系,请回答 YES | NO。
""";
/**
* 生成提取提示词
*
* @param inputText 输入文本
* @return 完整的提示词
*/
public static String buildExtractionPrompt(String inputText) {
return GRAPH_EXTRACTION_PROMPT_CN.replace("{input_text}", inputText);
}
/**
* 生成提取提示词(自定义实体类型)
*
* @param inputText 输入文本
* @param entityTypes 实体类型列表
* @return 完整的提示词
*/
public static String buildExtractionPrompt(String inputText, String[] entityTypes) {
String entityTypesStr = Arrays.stream(entityTypes).collect(Collectors.joining(","));
return GRAPH_EXTRACTION_PROMPT_CN
.replace("{input_text}", inputText)
.replace(Arrays.stream(GraphConstants.DEFAULT_ENTITY_TYPES).collect(Collectors.joining(",")), entityTypesStr);
}
}

Some files were not shown because too many files have changed in this diff Show More