feat: 增加RAG知识库与文档基础骨架

This commit is contained in:
2026-05-18 22:32:53 +08:00
parent 18386fde63
commit 4a20a25282
15 changed files with 360 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
DROP TABLE IF EXISTS rag_document;
CREATE TABLE rag_document (
id BIGSERIAL PRIMARY KEY,
store_id BIGINT NOT NULL,
attachment_id BIGINT NOT NULL,
document_title VARCHAR(255) NOT NULL,
document_summary VARCHAR(1000) DEFAULT '',
parse_status VARCHAR(50) NOT NULL DEFAULT 'UPLOADED',
index_status VARCHAR(50) NOT NULL DEFAULT 'PENDING',
enabled BOOLEAN NOT NULL DEFAULT TRUE,
error_message VARCHAR(1000) DEFAULT '',
version INTEGER NOT NULL DEFAULT 1,
create_time TIMESTAMP,
update_time TIMESTAMP,
remark VARCHAR(500) DEFAULT '',
create_by VARCHAR(64),
update_by VARCHAR(64),
CONSTRAINT uk_rag_document_attachment UNIQUE (attachment_id),
CONSTRAINT fk_rag_document_store_id FOREIGN KEY (store_id) REFERENCES rag_store (id),
CONSTRAINT fk_rag_document_attachment_id FOREIGN KEY (attachment_id) REFERENCES sys_attachment (id)
);
CREATE INDEX idx_rag_document_store_id ON rag_document (store_id);
CREATE INDEX idx_rag_document_parse_status ON rag_document (parse_status);
CREATE INDEX idx_rag_document_index_status ON rag_document (index_status);
CREATE INDEX idx_rag_document_enabled ON rag_document (enabled);
COMMENT ON TABLE rag_document IS 'RAG知识库文档表';
COMMENT ON COLUMN rag_document.id IS 'ID';
COMMENT ON COLUMN rag_document.store_id IS '知识库ID';
COMMENT ON COLUMN rag_document.attachment_id IS '附件ID';
COMMENT ON COLUMN rag_document.document_title IS '文档标题';
COMMENT ON COLUMN rag_document.document_summary IS '文档摘要';
COMMENT ON COLUMN rag_document.parse_status IS '解析状态';
COMMENT ON COLUMN rag_document.index_status IS '索引状态';
COMMENT ON COLUMN rag_document.enabled IS '是否启用';
COMMENT ON COLUMN rag_document.error_message IS '失败原因';
COMMENT ON COLUMN rag_document.version IS '版本';
COMMENT ON COLUMN rag_document.create_time IS '创建时间';
COMMENT ON COLUMN rag_document.update_time IS '更新时间';
COMMENT ON COLUMN rag_document.remark IS '备注';
COMMENT ON COLUMN rag_document.create_by IS '创建者';
COMMENT ON COLUMN rag_document.update_by IS '更新者';

32
script/sql/rag_store.sql Normal file
View File

@@ -0,0 +1,32 @@
DROP TABLE IF EXISTS rag_store;
CREATE TABLE rag_store (
id BIGSERIAL PRIMARY KEY,
store_code VARCHAR(100) NOT NULL,
store_name VARCHAR(200) NOT NULL,
description VARCHAR(1000) DEFAULT '',
status VARCHAR(50) NOT NULL DEFAULT 'ENABLED',
version INTEGER NOT NULL DEFAULT 1,
create_time TIMESTAMP,
update_time TIMESTAMP,
remark VARCHAR(500) DEFAULT '',
create_by VARCHAR(64),
update_by VARCHAR(64),
CONSTRAINT uk_rag_store_code UNIQUE (store_code)
);
CREATE INDEX idx_rag_store_status ON rag_store (status);
CREATE INDEX idx_rag_store_create_time ON rag_store (create_time);
COMMENT ON TABLE rag_store IS 'RAG知识库主表';
COMMENT ON COLUMN rag_store.id IS 'ID';
COMMENT ON COLUMN rag_store.store_code IS '知识库编码';
COMMENT ON COLUMN rag_store.store_name IS '知识库名称';
COMMENT ON COLUMN rag_store.description IS '知识库描述';
COMMENT ON COLUMN rag_store.status IS '状态';
COMMENT ON COLUMN rag_store.version IS '版本';
COMMENT ON COLUMN rag_store.create_time IS '创建时间';
COMMENT ON COLUMN rag_store.update_time IS '更新时间';
COMMENT ON COLUMN rag_store.remark IS '备注';
COMMENT ON COLUMN rag_store.create_by IS '创建者';
COMMENT ON COLUMN rag_store.update_by IS '更新者';

View File

@@ -0,0 +1,11 @@
package com.bruce.rag.constant;
public final class RagSystemConstants {
public static final String RAG_STORE = "RAG_STORE";
public static final String RAG_DOCUMENT = "RAG_DOCUMENT";
private RagSystemConstants() {
}
}

View File

@@ -0,0 +1,29 @@
package com.bruce.rag.controller;
import com.bruce.rag.entity.RagDocument;
import com.bruce.rag.service.IRagDocumentService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "RAG知识库文档管理")
@RestController
@RequestMapping("/api/rag/documents")
public class RagDocumentController {
private final IRagDocumentService ragDocumentService;
public RagDocumentController(IRagDocumentService ragDocumentService) {
this.ragDocumentService = ragDocumentService;
}
@Operation(summary = "查询全部知识库文档")
@GetMapping
public List<RagDocument> list() {
return ragDocumentService.list();
}
}

View File

@@ -0,0 +1,29 @@
package com.bruce.rag.controller;
import com.bruce.rag.entity.RagStore;
import com.bruce.rag.service.IRagStoreService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "RAG知识库管理")
@RestController
@RequestMapping("/api/rag/stores")
public class RagStoreController {
private final IRagStoreService ragStoreService;
public RagStoreController(IRagStoreService ragStoreService) {
this.ragStoreService = ragStoreService;
}
@Operation(summary = "查询全部知识库")
@GetMapping
public List<RagStore> list() {
return ragStoreService.list();
}
}

View File

@@ -0,0 +1,51 @@
package com.bruce.rag.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.bruce.common.entity.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("rag_document")
@Schema(description = "RAG知识库文档")
public class RagDocument extends BaseEntity {
@Schema(description = "知识库ID")
@TableField("store_id")
private Long storeId;
@Schema(description = "附件ID")
@TableField("attachment_id")
private Long attachmentId;
@Schema(description = "文档标题")
@TableField("document_title")
private String documentTitle;
@Schema(description = "文档摘要")
@TableField("document_summary")
private String documentSummary;
@Schema(description = "解析状态")
@TableField("parse_status")
private String parseStatus;
@Schema(description = "索引状态")
@TableField("index_status")
private String indexStatus;
@Schema(description = "是否启用")
private Boolean enabled;
@Schema(description = "失败原因")
@TableField("error_message")
private String errorMessage;
@Schema(description = "备注")
private String remark;
}

View File

@@ -0,0 +1,31 @@
package com.bruce.rag.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.bruce.common.entity.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
@TableName("rag_store")
@Schema(description = "RAG知识库")
public class RagStore extends BaseEntity {
@Schema(description = "知识库编码")
private String storeCode;
@Schema(description = "知识库名称")
private String storeName;
@Schema(description = "知识库描述")
private String description;
@Schema(description = "状态")
private String status;
@Schema(description = "备注")
private String remark;
}

View File

@@ -0,0 +1,9 @@
package com.bruce.rag.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bruce.rag.entity.RagDocument;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RagDocumentMapper extends BaseMapper<RagDocument> {
}

View File

@@ -0,0 +1,9 @@
package com.bruce.rag.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.bruce.rag.entity.RagStore;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RagStoreMapper extends BaseMapper<RagStore> {
}

View File

@@ -0,0 +1,7 @@
package com.bruce.rag.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bruce.rag.entity.RagDocument;
public interface IRagDocumentService extends IService<RagDocument> {
}

View File

@@ -0,0 +1,7 @@
package com.bruce.rag.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.bruce.rag.entity.RagStore;
public interface IRagStoreService extends IService<RagStore> {
}

View File

@@ -0,0 +1,11 @@
package com.bruce.rag.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bruce.rag.entity.RagDocument;
import com.bruce.rag.mapper.RagDocumentMapper;
import com.bruce.rag.service.IRagDocumentService;
import org.springframework.stereotype.Service;
@Service
public class RagDocumentServiceImpl extends ServiceImpl<RagDocumentMapper, RagDocument> implements IRagDocumentService {
}

View File

@@ -0,0 +1,11 @@
package com.bruce.rag.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bruce.rag.entity.RagStore;
import com.bruce.rag.mapper.RagStoreMapper;
import com.bruce.rag.service.IRagStoreService;
import org.springframework.stereotype.Service;
@Service
public class RagStoreServiceImpl extends ServiceImpl<RagStoreMapper, RagStore> implements IRagStoreService {
}

View File

@@ -0,0 +1,30 @@
package com.bruce.common.enumconfig;
import com.bruce.common.enums.BaseDictEnum;
import com.bruce.common.enums.EnableStatusEnum;
import com.bruce.rag.enums.RagIndexStatusEnum;
import com.bruce.rag.enums.RagParseStatusEnum;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class EnumDefinitionTests {
@Test
void enumDefinitionsShouldExist() {
assertTrue(BaseDictEnum.class.isAssignableFrom(EnableStatusEnum.class));
assertTrue(BaseDictEnum.class.isAssignableFrom(RagParseStatusEnum.class));
assertTrue(BaseDictEnum.class.isAssignableFrom(RagIndexStatusEnum.class));
}
@Test
void enumCodesShouldBeStable() {
assertEquals("ENABLED", EnableStatusEnum.ENABLED.getCode());
assertEquals("DISABLED", EnableStatusEnum.DISABLED.getCode());
assertEquals("UPLOADED", RagParseStatusEnum.UPLOADED.getCode());
assertEquals("FAILED", RagParseStatusEnum.FAILED.getCode());
assertEquals("PENDING", RagIndexStatusEnum.PENDING.getCode());
assertEquals("INDEXED", RagIndexStatusEnum.INDEXED.getCode());
}
}

View File

@@ -0,0 +1,49 @@
package com.bruce.rag;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bruce.rag.constant.RagSystemConstants;
import com.bruce.rag.controller.RagDocumentController;
import com.bruce.rag.controller.RagStoreController;
import com.bruce.rag.entity.RagDocument;
import com.bruce.rag.entity.RagStore;
import com.bruce.rag.mapper.RagDocumentMapper;
import com.bruce.rag.mapper.RagStoreMapper;
import com.bruce.rag.service.IRagDocumentService;
import com.bruce.rag.service.IRagStoreService;
import com.bruce.rag.service.impl.RagDocumentServiceImpl;
import com.bruce.rag.service.impl.RagStoreServiceImpl;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class RagComponentStructureTests {
@Test
void ragComponentsShouldReuseMybatisPlusBaseTypes() {
assertTrue(BaseMapper.class.isAssignableFrom(RagStoreMapper.class));
assertTrue(BaseMapper.class.isAssignableFrom(RagDocumentMapper.class));
assertTrue(IService.class.isAssignableFrom(IRagStoreService.class));
assertTrue(IService.class.isAssignableFrom(IRagDocumentService.class));
assertTrue(ServiceImpl.class.isAssignableFrom(RagStoreServiceImpl.class));
assertTrue(ServiceImpl.class.isAssignableFrom(RagDocumentServiceImpl.class));
}
@Test
void ragSourceTypesAndDocumentRelationShouldExist() throws NoSuchFieldException {
Field storeIdField = RagDocument.class.getDeclaredField("storeId");
Field attachmentIdField = RagDocument.class.getDeclaredField("attachmentId");
assertEquals("RAG_STORE", RagSystemConstants.RAG_STORE);
assertEquals("RAG_DOCUMENT", RagSystemConstants.RAG_DOCUMENT);
assertEquals(Long.class, storeIdField.getType());
assertEquals(Long.class, attachmentIdField.getType());
assertTrue(RagStore.class.getSimpleName().contains("RagStore"));
assertTrue(RagStoreController.class.getSimpleName().contains("RagStoreController"));
assertTrue(RagDocumentController.class.getSimpleName().contains("RagDocumentController"));
}
}