diff --git a/pom.xml b/pom.xml
index 00a58a09..3bbcab6d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -50,6 +50,11 @@
2.0.23
3.1.687
+
+ 5.26.0
+ 2024.1.0
+ 1.2.0-beta8
+
3.2.2
3.2.2
@@ -335,6 +340,33 @@
${revision}
+
+ org.ruoyi
+ ruoyi-graph
+ ${revision}
+
+
+
+
+ org.neo4j.driver
+ neo4j-java-driver
+ ${neo4j-driver.version}
+
+
+
+
+ org.neo4j
+ neo4j-cypher-dsl
+ ${neo4j-cypher-dsl.version}
+
+
+
+
+ dev.langchain4j
+ langchain4j-community-neo4j
+ ${langchain4j-neo4j.version}
+
+
org.ruoyi
ruoyi-aihuman
@@ -493,6 +525,4 @@
-
-
-
+
\ No newline at end of file
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index a5d639e6..95898d4d 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -57,6 +57,11 @@
ruoyi-generator
+
+
+ org.ruoyi
+ ruoyi-graph
+
org.ruoyi
ruoyi-workflow
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index 3e096b45..cb082f50 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -17,8 +17,8 @@ spring:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
- username: ruoyi-ai
- password: 123456
+ username: root
+ password: root
hikari:
# 最大连接池数量
@@ -48,7 +48,7 @@ spring.data:
# 端口,默认为6379
port: 6379
# 数据库索引
- database: 0
+ database: 2
# 密码(如没有密码请注释掉)
# password: 123456
# 连接超时时间
@@ -114,3 +114,54 @@ local:
+--- # Neo4j 知识图谱配置
+neo4j:
+ uri: bolt://127.0.0.1:7687
+ username: neo4j
+ password: MySecurePass123!
+ database: neo4j
+ max-connection-pool-size: 50
+ connection-timeout-seconds: 30
+
+# 知识图谱配置
+knowledge:
+ graph:
+ # 是否启用知识图谱功能
+ enabled: true
+ # 图数据库类型: 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
+
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index a60b4d36..4c6d38a0 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -330,10 +330,12 @@ spring:
servers-configuration: classpath:mcp-server.json
request-timeout: 300s
---- # 向量库配置
+# 向量库配置
vector-store:
- # 向量存储类型 (weaviate/milvus)
+ # 向量存储类型 可选(weaviate/milvus)
+ # 如需修改向量库类型,请修改此配置值!
type: weaviate
+
# Weaviate配置
weaviate:
protocol: http
diff --git a/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/WorkflowUtil.java b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/WorkflowUtil.java
index b4d96b57..adbd581b 100644
--- a/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/WorkflowUtil.java
+++ b/ruoyi-modules-api/ruoyi-workflow-api/src/main/java/org/ruoyi/workflow/workflow/WorkflowUtil.java
@@ -123,14 +123,14 @@ public class WorkflowUtil {
Set nameSet = CollStreamUtil.toSet(refInputs, WfNodeParamRef::getName);
userMessage.stream().filter(item -> nameSet.contains(item.getName()))
- .map(item -> getMessage("role", item.getContent().getValue())).forEach(messages::add);
+ .map(item -> getMessage("user", item.getContent().getValue())).forEach(messages::add);
if (CollUtil.isNotEmpty(messages)) {
return;
}
userMessage.stream().filter(item -> "input".equals(item.getName()))
- .map(item -> getMessage("role", item.getContent().getValue())).forEach(messages::add);
+ .map(item -> getMessage("user", item.getContent().getValue())).forEach(messages::add);
}
/**
diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml
index a520b5bf..ee21cd0e 100644
--- a/ruoyi-modules/pom.xml
+++ b/ruoyi-modules/pom.xml
@@ -22,6 +22,7 @@
ruoyi-system
ruoyi-generator
ruoyi-wechat
+ ruoyi-graph
ruoyi-aihuman
ruoyi-workflow
diff --git a/ruoyi-modules/ruoyi-graph/pom.xml b/ruoyi-modules/ruoyi-graph/pom.xml
new file mode 100644
index 00000000..af1ee8e6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/pom.xml
@@ -0,0 +1,100 @@
+
+
+ 4.0.0
+
+ org.ruoyi
+ ruoyi-modules
+ ${revision}
+ ../pom.xml
+
+
+ ruoyi-graph
+
+
+ 知识图谱模块
+
+
+
+ 1.0.0-beta4
+
+
+
+
+
+
+ dev.langchain4j
+ langchain4j-bom
+ ${langchain4j.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.ruoyi
+ ruoyi-common-web
+
+
+
+ org.ruoyi
+ ruoyi-common-mybatis
+
+
+
+ org.ruoyi
+ ruoyi-common-redis
+
+
+
+ org.ruoyi
+ ruoyi-common-doc
+
+
+
+
+ org.ruoyi
+ ruoyi-knowledge-api
+
+
+
+
+ org.ruoyi
+ ruoyi-chat-api
+
+
+
+
+ org.neo4j.driver
+ neo4j-java-driver
+
+
+
+
+ org.neo4j
+ neo4j-cypher-dsl
+
+
+
+ org.ruoyi
+ ruoyi-chat
+
+
+
+
+ dev.langchain4j
+ langchain4j
+
+
+
+ dev.langchain4j
+ langchain4j-open-ai
+
+
+
+
diff --git a/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphAsyncConfig.java b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphAsyncConfig.java
new file mode 100644
index 00000000..894600c3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphAsyncConfig.java
@@ -0,0 +1,67 @@
+package org.ruoyi.graph.config;
+
+import lombok.extern.slf4j.Slf4j;
+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
+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;
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphProperties.java b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphProperties.java
new file mode 100644
index 00000000..41cde14a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/GraphProperties.java
@@ -0,0 +1,113 @@
+package org.ruoyi.graph.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 知识图谱配置属性
+ *
+ * @author ruoyi
+ * @date 2025-09-30
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "knowledge.graph")
+public class GraphProperties {
+
+ /**
+ * 是否启用知识图谱功能
+ */
+ private Boolean enabled = true;
+
+ /**
+ * 图数据库类型: neo4j 或 apache-age
+ */
+ private String databaseType = "neo4j";
+
+ /**
+ * 是否自动创建索引
+ */
+ private Boolean autoCreateIndex = true;
+
+ /**
+ * 批量处理大小
+ */
+ private Integer batchSize = 1000;
+
+ /**
+ * 最大重试次数
+ */
+ private Integer maxRetryCount = 3;
+
+ /**
+ * 实体抽取配置
+ */
+ private ExtractionConfig extraction = new ExtractionConfig();
+
+ /**
+ * 查询配置
+ */
+ private QueryConfig query = new QueryConfig();
+
+ @Data
+ public static class ExtractionConfig {
+ /**
+ * 置信度阈值(低于此值的实体将被过滤)
+ */
+ private Double confidenceThreshold = 0.7;
+
+ /**
+ * 最大实体数量(每个文档)
+ */
+ private Integer maxEntitiesPerDoc = 100;
+
+ /**
+ * 最大关系数量(每个文档)
+ */
+ private Integer maxRelationsPerDoc = 200;
+
+ /**
+ * 文本分片大小(用于长文档)
+ */
+ private Integer chunkSize = 2000;
+
+ /**
+ * 分片重叠大小
+ */
+ private Integer chunkOverlap = 200;
+ }
+
+ @Data
+ public static class QueryConfig {
+ /**
+ * 默认查询限制数量
+ */
+ private Integer defaultLimit = 100;
+
+ /**
+ * 最大查询限制数量
+ */
+ private Integer maxLimit = 1000;
+
+ /**
+ * 路径查询最大深度
+ */
+ private Integer maxPathDepth = 5;
+
+ /**
+ * 查询超时时间(秒)
+ */
+ private Integer timeoutSeconds = 30;
+
+ /**
+ * 是否启用查询缓存
+ */
+ private Boolean cacheEnabled = true;
+
+ /**
+ * 缓存过期时间(分钟)
+ */
+ private Integer cacheExpireMinutes = 60;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/Neo4jConfig.java b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/Neo4jConfig.java
new file mode 100644
index 00000000..626021b5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/config/Neo4jConfig.java
@@ -0,0 +1,70 @@
+package org.ruoyi.graph.config;
+
+import lombok.Data;
+import org.neo4j.driver.AuthTokens;
+import org.neo4j.driver.Driver;
+import org.neo4j.driver.GraphDatabase;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Neo4j配置类
+ *
+ * @author ruoyi
+ * @date 2025-09-30
+ */
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "neo4j")
+public class Neo4jConfig {
+
+ /**
+ * Neo4j连接URI
+ * 例如: bolt://localhost:7687
+ */
+ private String uri;
+
+ /**
+ * 用户名
+ */
+ private String username;
+
+ /**
+ * 密码
+ */
+ private String password;
+
+ /**
+ * 数据库名称(Neo4j 4.0+支持多数据库)
+ * 默认: neo4j
+ */
+ private String database = "neo4j";
+
+ /**
+ * 最大连接池大小
+ */
+ private Integer maxConnectionPoolSize = 50;
+
+ /**
+ * 连接超时时间(秒)
+ */
+ private Integer connectionTimeoutSeconds = 30;
+
+ /**
+ * 创建Neo4j Driver Bean
+ *
+ * @return Neo4j Driver
+ */
+ @Bean
+ public Driver neo4jDriver() {
+ return GraphDatabase.driver(
+ uri,
+ AuthTokens.basic(username, password),
+ org.neo4j.driver.Config.builder()
+ .withMaxConnectionPoolSize(maxConnectionPoolSize)
+ .withConnectionTimeout(connectionTimeoutSeconds, java.util.concurrent.TimeUnit.SECONDS)
+ .build()
+ );
+ }
+}
diff --git a/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/constants/GraphConstants.java b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/constants/GraphConstants.java
new file mode 100644
index 00000000..832b3233
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/constants/GraphConstants.java
@@ -0,0 +1,103 @@
+package org.ruoyi.graph.constants;
+
+/**
+ * 知识图谱常量
+ *
+ * @author ruoyi
+ * @date 2025-09-30
+ */
+public class GraphConstants {
+
+ /**
+ * 图谱记录分隔符
+ */
+ public static final String GRAPH_RECORD_DELIMITER = "##";
+
+ /**
+ * 图谱元组分隔符
+ */
+ public static final String GRAPH_TUPLE_DELIMITER = "<|>";
+
+ /**
+ * 图谱完成标记
+ */
+ public static final String GRAPH_COMPLETION_DELIMITER = "<|COMPLETE|>";
+
+ /**
+ * 实体类型:人物
+ */
+ public static final String ENTITY_TYPE_PERSON = "PERSON";
+
+ /**
+ * 实体类型:组织机构
+ */
+ public static final String ENTITY_TYPE_ORGANIZATION = "ORGANIZATION";
+
+ /**
+ * 实体类型:地点
+ */
+ public static final String ENTITY_TYPE_LOCATION = "LOCATION";
+
+ /**
+ * 实体类型:概念
+ */
+ public static final String ENTITY_TYPE_CONCEPT = "CONCEPT";
+
+ /**
+ * 实体类型:事件
+ */
+ public static final String ENTITY_TYPE_EVENT = "EVENT";
+
+ /**
+ * 实体类型:产品
+ */
+ public static final String ENTITY_TYPE_PRODUCT = "PRODUCT";
+
+ /**
+ * 实体类型:技术
+ */
+ public static final String ENTITY_TYPE_TECHNOLOGY = "TECHNOLOGY";
+
+ /**
+ * 默认实体抽取类型列表
+ */
+ public static final String[] DEFAULT_ENTITY_TYPES = {
+ ENTITY_TYPE_PERSON,
+ ENTITY_TYPE_ORGANIZATION,
+ ENTITY_TYPE_LOCATION,
+ ENTITY_TYPE_CONCEPT,
+ ENTITY_TYPE_EVENT,
+ ENTITY_TYPE_PRODUCT,
+ ENTITY_TYPE_TECHNOLOGY
+ };
+
+ /**
+ * 元数据键:知识库UUID
+ */
+ public static final String METADATA_KB_UUID = "kb_uuid";
+
+ /**
+ * 元数据键:知识库条目UUID
+ */
+ public static final String METADATA_KB_ITEM_UUID = "kb_item_uuid";
+
+ /**
+ * 元数据键:文档UUID
+ */
+ public static final String METADATA_DOC_UUID = "doc_uuid";
+
+ /**
+ * 元数据键:片段UUID
+ */
+ public static final String METADATA_SEGMENT_UUID = "segment_uuid";
+
+ /**
+ * RAG最大片段大小(token数)
+ */
+ public static final int RAG_MAX_SEGMENT_SIZE_IN_TOKENS = 512;
+
+ /**
+ * RAG片段重叠大小(token数)
+ */
+ public static final int RAG_SEGMENT_OVERLAP_IN_TOKENS = 50;
+}
diff --git a/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/controller/GraphInstanceController.java b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/controller/GraphInstanceController.java
new file mode 100644
index 00000000..871eb2fe
--- /dev/null
+++ b/ruoyi-modules/ruoyi-graph/src/main/java/org/ruoyi/graph/controller/GraphInstanceController.java
@@ -0,0 +1,416 @@
+package org.ruoyi.graph.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.RequiredArgsConstructor;
+import org.ruoyi.common.core.domain.R;
+import org.ruoyi.common.web.core.BaseController;
+import org.ruoyi.graph.domain.GraphBuildTask;
+import org.ruoyi.graph.domain.GraphInstance;
+import org.ruoyi.graph.enums.GraphStatusEnum;
+import org.ruoyi.graph.service.IGraphBuildTaskService;
+import org.ruoyi.graph.service.IGraphInstanceService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 图谱实例管理控制器
+ *
+ * @author ruoyi
+ * @date 2025-09-30
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/graph/instance")
+@Tag(name = "图谱实例管理", description = "知识图谱实例的创建、查询、更新、删除")
+public class GraphInstanceController extends BaseController {
+
+ private final IGraphInstanceService graphInstanceService;
+ private final IGraphBuildTaskService buildTaskService;
+
+ /**
+ * 辅助方法:根据ID或UUID获取图谱实例
+ */
+ private GraphInstance getInstanceByIdOrUuid(String id) {
+ GraphInstance instance = null;
+
+ // 尝试作为数字ID查询
+ try {
+ Long numericId = Long.parseLong(id);
+ instance = graphInstanceService.getById(numericId);
+ } catch (NumberFormatException e) {
+ // 不是数字,尝试作为UUID查询
+ instance = graphInstanceService.getByUuid(id);
+ }
+
+ return instance;
+ }
+
+ /**
+ * 创建图谱实例
+ */
+ @Operation(summary = "创建图谱实例")
+ @PostMapping
+ public R createInstance(@RequestBody GraphInstance graphInstance) {
+ try {
+ if (graphInstance.getKnowledgeId() == null || graphInstance.getKnowledgeId().trim().isEmpty()) {
+ return R.fail("知识库ID不能为空");
+ }
+ if (graphInstance.getInstanceName() == null || graphInstance.getInstanceName().trim().isEmpty()) {
+ return R.fail("图谱名称不能为空");
+ }
+
+ // 创建基础实例
+ GraphInstance instance = graphInstanceService.createInstance(
+ graphInstance.getKnowledgeId(),
+ graphInstance.getInstanceName(),
+ graphInstance.getConfig()
+ );
+
+ // 设置扩展属性
+ boolean needUpdate = false;
+ if (graphInstance.getModelName() != null) {
+ instance.setModelName(graphInstance.getModelName());
+ needUpdate = true;
+ }
+ if (graphInstance.getEntityTypes() != null) {
+ instance.setEntityTypes(graphInstance.getEntityTypes());
+ needUpdate = true;
+ }
+ if (graphInstance.getRelationTypes() != null) {
+ instance.setRelationTypes(graphInstance.getRelationTypes());
+ needUpdate = true;
+ }
+ if (graphInstance.getRemark() != null) {
+ instance.setRemark(graphInstance.getRemark());
+ needUpdate = true;
+ }
+
+ // 如果有扩展属性,更新到数据库
+ if (needUpdate) {
+ graphInstanceService.updateInstance(instance);
+ }
+
+ return R.ok(instance);
+ } catch (Exception e) {
+ return R.fail("创建图谱实例失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 更新图谱实例
+ */
+ @Operation(summary = "更新图谱实例")
+ @PutMapping
+ public R updateInstance(@RequestBody GraphInstance graphInstance) {
+ try {
+ if (graphInstance.getId() == null && (graphInstance.getGraphUuid() == null || graphInstance.getGraphUuid().trim().isEmpty())) {
+ return R.fail("图谱ID不能为空");
+ }
+
+ // 如果有 instanceName,更新基本信息
+ if (graphInstance.getInstanceName() != null) {
+ // 这里可以添加更新实例名称的逻辑
+ }
+
+ // 更新配置
+ if (graphInstance.getConfig() != null) {
+ graphInstanceService.updateConfig(graphInstance.getGraphUuid(), graphInstance.getConfig());
+ }
+
+ // 更新模型名称、实体类型、关系类型等
+ // 注意:这里需要在 Service 层实现完整的更新逻辑
+
+ GraphInstance instance = graphInstanceService.getByUuid(graphInstance.getGraphUuid());
+ return R.ok(instance);
+ } catch (Exception e) {
+ return R.fail("更新图谱实例失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 根据ID或UUID获取图谱实例
+ */
+ @Operation(summary = "获取图谱实例")
+ @GetMapping("/{id}")
+ public R getByUuid(@PathVariable String id) {
+ try {
+ GraphInstance instance = getInstanceByIdOrUuid(id);
+
+ if (instance == null) {
+ return R.fail("图谱实例不存在");
+ }
+ return R.ok(instance);
+ } catch (Exception e) {
+ return R.fail("获取图谱实例失败: " + e.getMessage());
+ }
+ }
+
+ /**
+ * 获取图谱实例列表(支持分页和条件查询)
+ */
+ @Operation(summary = "获取图谱实例列表")
+ @GetMapping("/list")
+ public R