feat(rag): 补齐知识工作台聚合与转换分层

This commit is contained in:
2026-06-01 03:38:41 +08:00
parent 07ad8bb36b
commit d9cf838ace
15 changed files with 823 additions and 79 deletions

View File

@@ -9,6 +9,7 @@ import com.bruce.rag.dto.request.RagDocumentSaveRequest;
import com.bruce.rag.entity.RagDocument;
import com.bruce.rag.enums.RagIndexStatusEnum;
import com.bruce.rag.enums.RagParseStatusEnum;
import com.bruce.rag.factory.RagDocumentFactory;
import com.bruce.rag.service.IRagDocumentAutoParseService;
import com.bruce.rag.service.impl.RagDocumentServiceImpl;
import org.junit.jupiter.api.Test;
@@ -42,6 +43,9 @@ class RagDocumentServiceImplTests {
@Mock
private IRagDocumentAutoParseService ragDocumentAutoParseService;
@Spy
private RagDocumentFactory ragDocumentFactory;
@Test
void batchUploadShouldUseRagSourceTypeAndStoreIdAsSourceId() {
MockMultipartFile file = new MockMultipartFile(

View File

@@ -3,8 +3,11 @@ package com.bruce.rag;
import com.bruce.common.enums.EnableStatusEnum;
import com.bruce.rag.dto.request.RagStoreSaveRequest;
import com.bruce.rag.entity.RagStore;
import com.bruce.rag.factory.RagStoreFactory;
import com.bruce.rag.service.IRagDocumentService;
import com.bruce.rag.service.impl.RagStoreServiceImpl;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -12,9 +15,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
class RagStoreSaveValidationTests {
private final IRagDocumentService ragDocumentService = Mockito.mock(IRagDocumentService.class);
private final RagStoreFactory ragStoreFactory = new RagStoreFactory();
@Test
void saveShouldRejectBlankStoreCode() {
RagStoreServiceImpl service = new RagStoreServiceImpl();
RagStoreServiceImpl service = new RagStoreServiceImpl(ragDocumentService, ragStoreFactory);
RagStoreSaveRequest request = new RagStoreSaveRequest();
request.setStoreName("产品制度库");
@@ -23,7 +29,7 @@ class RagStoreSaveValidationTests {
@Test
void saveShouldRejectBlankStoreName() {
RagStoreServiceImpl service = new RagStoreServiceImpl();
RagStoreServiceImpl service = new RagStoreServiceImpl(ragDocumentService, ragStoreFactory);
RagStoreSaveRequest request = new RagStoreSaveRequest();
request.setStoreCode("PROD_DOC");
@@ -32,7 +38,7 @@ class RagStoreSaveValidationTests {
@Test
void saveShouldAcceptMinimalValidRequest() {
RagStoreServiceImpl service = new RagStoreServiceImpl();
RagStoreServiceImpl service = new RagStoreServiceImpl(ragDocumentService, ragStoreFactory);
RagStoreSaveRequest request = new RagStoreSaveRequest();
request.setStoreCode("PROD_DOC");
request.setStoreName("产品制度库");
@@ -42,12 +48,14 @@ class RagStoreSaveValidationTests {
@Test
void saveShouldDefaultStatusToEnabledEnumLabel() {
RagStoreServiceImpl service = new RagStoreServiceImpl();
RagStoreSaveRequest request = new RagStoreSaveRequest();
request.setStoreCode("PROD_DOC");
request.setStoreName("产品制度库");
RagStore ragStore = service.buildEntity(request);
RagStore ragStore = ragStoreFactory.toEntity(request);
if (ragStore.getStatus() == null) {
ragStore.setStatus(EnableStatusEnum.ENABLED.getLabel());
}
assertEquals(EnableStatusEnum.ENABLED.getLabel(), ragStore.getStatus());
}

View File

@@ -0,0 +1,129 @@
package com.bruce.rag.factory;
import com.bruce.rag.dto.request.RagDocumentSaveRequest;
import com.bruce.rag.dto.request.RagStoreSaveRequest;
import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreResponse;
import com.bruce.rag.entity.RagDocument;
import com.bruce.rag.entity.RagStore;
import org.junit.jupiter.api.Test;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
class RagFactoryTests {
private final RagStoreFactory ragStoreFactory = new RagStoreFactory();
private final RagDocumentFactory ragDocumentFactory = new RagDocumentFactory();
@Test
void ragStoreFactoryShouldTrimAndBuildEntity() {
RagStoreSaveRequest request = new RagStoreSaveRequest();
request.setId(1001L);
request.setStoreCode(" PROD_DOC ");
request.setStoreName(" 产品制度库 ");
request.setDescription(" 产品制度、业务规范、流程材料 ");
request.setStatus(" 启用 ");
request.setRemark(" 核心制度库 ");
RagStore entity = ragStoreFactory.toEntity(request);
assertNotNull(entity);
assertEquals(1001L, entity.getId());
assertEquals("PROD_DOC", entity.getStoreCode());
assertEquals("产品制度库", entity.getStoreName());
assertEquals("产品制度、业务规范、流程材料", entity.getDescription());
assertEquals("启用", entity.getStatus());
assertEquals("核心制度库", entity.getRemark());
}
@Test
void ragStoreFactoryShouldConvertEntityToResponse() {
RagStore entity = new RagStore();
entity.setId(1001L);
entity.setStoreCode("PROD_DOC");
entity.setStoreName("产品制度库");
entity.setDescription("产品制度、业务规范、流程材料");
entity.setStatus("启用");
entity.setRemark("核心制度库");
entity.setCreateTime(new Date(1747816496000L));
entity.setUpdateTime(new Date(1747820096000L));
RagStoreResponse response = ragStoreFactory.toResponse(entity);
assertNotNull(response);
assertEquals(1001L, response.getId());
assertEquals("PROD_DOC", response.getStoreCode());
assertEquals("产品制度库", response.getStoreName());
assertEquals("产品制度、业务规范、流程材料", response.getDescription());
assertEquals("启用", response.getStatus());
assertEquals("核心制度库", response.getRemark());
assertEquals(new Date(1747816496000L), response.getCreateTime());
assertEquals(new Date(1747820096000L), response.getUpdateTime());
}
@Test
void ragDocumentFactoryShouldApplyEditableFieldsToEntity() {
RagDocumentSaveRequest request = new RagDocumentSaveRequest();
request.setId(3003L);
request.setStoreId(1001L);
request.setAttachmentId(2002L);
request.setDocumentTitle(" 新标题 ");
request.setDocumentSummary(" 新摘要 ");
request.setParseStatus(" PARSED ");
request.setIndexStatus(" INDEXED ");
request.setEnabled(false);
request.setErrorMessage(" 已修复 ");
request.setRemark(" 备注信息 ");
RagDocument entity = ragDocumentFactory.toEntity(request);
assertNotNull(entity);
assertEquals(3003L, entity.getId());
assertEquals(1001L, entity.getStoreId());
assertEquals(2002L, entity.getAttachmentId());
assertEquals("新标题", entity.getDocumentTitle());
assertEquals("新摘要", entity.getDocumentSummary());
assertEquals("PARSED", entity.getParseStatus());
assertEquals("INDEXED", entity.getIndexStatus());
assertEquals(false, entity.getEnabled());
assertEquals("已修复", entity.getErrorMessage());
assertEquals("备注信息", entity.getRemark());
}
@Test
void ragDocumentFactoryShouldConvertEntityToResponse() {
RagDocument entity = new RagDocument();
entity.setId(3003L);
entity.setStoreId(1001L);
entity.setAttachmentId(2002L);
entity.setDocumentTitle("people_profiles.txt");
entity.setDocumentSummary("测试人员信息");
entity.setParseStatus("PARSED");
entity.setIndexStatus("INDEXED");
entity.setEnabled(true);
entity.setErrorMessage(null);
entity.setRemark("测试文档");
entity.setCreateTime(new Date(1747816496000L));
entity.setUpdateTime(new Date(1747820096000L));
RagDocumentResponse response = ragDocumentFactory.toResponse(entity);
assertNotNull(response);
assertEquals(3003L, response.getId());
assertEquals(1001L, response.getStoreId());
assertEquals(2002L, response.getAttachmentId());
assertEquals("people_profiles.txt", response.getDocumentTitle());
assertEquals("测试人员信息", response.getDocumentSummary());
assertEquals("PARSED", response.getParseStatus());
assertEquals("INDEXED", response.getIndexStatus());
assertEquals(true, response.getEnabled());
assertNull(response.getErrorMessage());
assertEquals("测试文档", response.getRemark());
assertEquals(new Date(1747816496000L), response.getCreateTime());
assertEquals(new Date(1747820096000L), response.getUpdateTime());
}
}

View File

@@ -0,0 +1,120 @@
package com.bruce.rag.workspace;
import com.bruce.modelprovider.dto.response.RagStoreModelConfigResponse;
import com.bruce.modelprovider.service.IRagStoreModelConfigService;
import com.bruce.rag.dto.response.RagDocumentResponse;
import com.bruce.rag.dto.response.RagStoreResponse;
import com.bruce.rag.service.IRagChunkEmbeddingService;
import com.bruce.rag.service.IRagChunkService;
import com.bruce.rag.service.IRagDocumentParseResultService;
import com.bruce.rag.service.IRagDocumentService;
import com.bruce.rag.service.impl.KnowledgeWorkspaceServiceImpl;
import com.bruce.rag.vo.KnowledgeWorkspaceVO;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Date;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class KnowledgeWorkspaceServiceTests {
@Mock
private com.bruce.rag.service.IRagStoreService ragStoreService;
@Mock
private IRagDocumentService ragDocumentService;
@Mock
private IRagDocumentParseResultService ragDocumentParseResultService;
@Mock
private IRagChunkService ragChunkService;
@Mock
private IRagChunkEmbeddingService ragChunkEmbeddingService;
@Mock
private IRagStoreModelConfigService ragStoreModelConfigService;
@InjectMocks
private KnowledgeWorkspaceServiceImpl knowledgeWorkspaceService;
@Test
void getWorkspaceShouldAggregateStoreConfigAndDocumentHealth() {
RagStoreResponse store = new RagStoreResponse();
store.setId(1001L);
store.setStoreCode("PROD_DOC");
store.setStoreName("产品制度库");
store.setDescription("产品制度、业务规范、流程材料");
store.setStatus("启用");
store.setRemark("核心制度库");
RagDocumentResponse parsedIndexedDocument = createDocument(11L, true, "PARSED", "INDEXED", new Date(1747816496000L));
RagDocumentResponse parseFailedDocument = createDocument(12L, true, "FAILED", "FAILED", new Date(1747820096000L));
RagDocumentResponse pendingIndexDocument = createDocument(13L, true, "PARSED", "PENDING", new Date(1747823696000L));
RagStoreModelConfigResponse modelConfig = new RagStoreModelConfigResponse();
modelConfig.setStoreId(1001L);
modelConfig.setEmbeddingModelId(88L);
modelConfig.setEmbeddingDimension(1024);
modelConfig.setChunkStrategy(1);
modelConfig.setChunkSize(800);
modelConfig.setChunkOverlap(120);
modelConfig.setIndexVersion(14);
when(ragStoreService.getResponseById(1001L)).thenReturn(store);
when(ragDocumentService.query(org.mockito.ArgumentMatchers.any())).thenReturn(List.of(
parsedIndexedDocument,
parseFailedDocument,
pendingIndexDocument
));
when(ragStoreModelConfigService.getByStoreId(1001L)).thenReturn(modelConfig);
when(ragChunkService.count(org.mockito.ArgumentMatchers.any())).thenReturn(24L);
when(ragChunkEmbeddingService.count(org.mockito.ArgumentMatchers.any())).thenReturn(18L);
KnowledgeWorkspaceVO workspace = knowledgeWorkspaceService.getWorkspace(1001L);
assertNotNull(workspace);
assertEquals(1001L, workspace.getStoreId());
assertEquals("PROD_DOC", workspace.getStoreCode());
assertEquals("产品制度库", workspace.getStoreName());
assertEquals("启用", workspace.getStatus());
assertEquals(3, workspace.getDocumentCount());
assertEquals(2, workspace.getParsedDocumentCount());
assertEquals(1, workspace.getParseFailedDocumentCount());
assertEquals(1, workspace.getIndexedDocumentCount());
assertEquals(1, workspace.getPendingIndexDocumentCount());
assertEquals(66, workspace.getHealthScore());
assertEquals(88L, workspace.getEmbeddingModelId());
assertEquals(1024, workspace.getEmbeddingDimension());
assertEquals(1, workspace.getChunkStrategy());
assertEquals(800, workspace.getChunkSize());
assertEquals(120, workspace.getChunkOverlap());
assertEquals(14, workspace.getIndexVersion());
assertEquals(24L, workspace.getChunkCount());
assertEquals(18L, workspace.getEmbeddingCount());
assertEquals(1, workspace.getPendingTaskCount());
assertEquals("更新后需要重新验证 Workflow / Agent 的知识引用效果", workspace.getPublishImpact());
assertEquals(3, workspace.getDocuments().size());
}
private RagDocumentResponse createDocument(Long id, boolean enabled, String parseStatus, String indexStatus, Date updateTime) {
RagDocumentResponse response = new RagDocumentResponse();
response.setId(id);
response.setStoreId(1001L);
response.setEnabled(enabled);
response.setParseStatus(parseStatus);
response.setIndexStatus(indexStatus);
response.setDocumentTitle("文档-" + id);
response.setUpdateTime(updateTime);
return response;
}
}