fix: 修复 AUTO 策略空分块兜底

- AUTO 推荐无分块时回退自然段长度拆分

- 保留默认或页面传入的分段长度与重叠参数

- 补充默认、自定义与显式策略回归测试
This commit is contained in:
2026-08-07 12:21:02 +08:00
parent 170b315459
commit 7082041e6e
2 changed files with 145 additions and 1 deletions

View File

@@ -7,6 +7,11 @@ import com.easyagents.core.model.embedding.EmbeddingModel;
import com.easyagents.core.store.DocumentStore;
import com.easyagents.core.store.StoreOptions;
import com.easyagents.core.store.StoreResult;
import com.easyagents.rag.core.RagChunk;
import com.easyagents.rag.core.RagDefaults;
import com.easyagents.rag.core.RagStrategyCodes;
import com.easyagents.rag.ingestion.RagIngestionService;
import com.easyagents.rag.ingestion.model.AnalysisResult;
import com.easyagents.rag.ingestion.model.StrategyConfig;
import com.easyagents.search.engine.service.DocumentSearcher;
import org.apache.ibatis.annotations.Update;
@@ -1151,6 +1156,108 @@ public class KnowledgeDocumentImportTaskAppServiceTest {
Mockito.verifyNoInteractions(searcher);
}
/**
* 验证 AUTO 空结果使用默认长度与重叠参数回退自然段长度拆分。
*
* @throws Exception 反射调用异常
*/
@Test
public void autoEmptyChunksShouldFallbackWithDefaultParagraphSettings()
throws Exception {
assertAutoParagraphFallback(RagDefaults.CHUNK_SIZE, RagDefaults.OVERLAP_SIZE);
}
/**
* 验证手动预览选择 AUTO 时,兜底保留页面传入的长度与重叠参数。
*
* @throws Exception 反射调用异常
*/
@Test
public void autoEmptyChunksShouldFallbackWithRequestedParagraphSettings()
throws Exception {
assertAutoParagraphFallback(768, 192);
}
/**
* 验证显式选择非 AUTO 策略时不触发兜底。
*
* @throws Exception 反射调用异常
*/
@Test
public void explicitStrategyEmptyChunksShouldNotFallback() throws Exception {
KnowledgeDocumentImportTaskAppService service =
new KnowledgeDocumentImportTaskAppService();
RagIngestionService ragIngestionService = Mockito.mock(RagIngestionService.class);
setField(service, "ragIngestionService", ragIngestionService);
AnalysisResult analysis = Mockito.mock(AnalysisResult.class);
StrategyConfig requestedStrategy = StrategyConfig.defaults();
requestedStrategy.setStrategyCode(RagStrategyCodes.OUTLINE_SECTION);
StrategyConfig effectiveStrategy = requestedStrategy.copy();
Mockito.when(ragIngestionService.split(analysis, effectiveStrategy))
.thenReturn(List.of());
List<RagChunk> chunks = invokeAutoParagraphFallback(
service, analysis, requestedStrategy, effectiveStrategy);
Assert.assertTrue(chunks.isEmpty());
Assert.assertEquals(RagStrategyCodes.OUTLINE_SECTION, effectiveStrategy.getStrategyCode());
Mockito.verify(ragIngestionService).split(analysis, effectiveStrategy);
}
private static void assertAutoParagraphFallback(int chunkSize, int overlapSize) throws Exception {
KnowledgeDocumentImportTaskAppService service =
new KnowledgeDocumentImportTaskAppService();
RagIngestionService ragIngestionService = Mockito.mock(RagIngestionService.class);
setField(service, "ragIngestionService", ragIngestionService);
AnalysisResult analysis = Mockito.mock(AnalysisResult.class);
StrategyConfig requestedStrategy = StrategyConfig.defaults();
requestedStrategy.setChunkSize(chunkSize);
requestedStrategy.setOverlapSize(overlapSize);
StrategyConfig effectiveStrategy = requestedStrategy.copy();
effectiveStrategy.setStrategyCode(RagStrategyCodes.OUTLINE_SECTION);
RagChunk fallbackChunk = new RagChunk();
List<String> invokedStrategies = new ArrayList<String>();
Mockito.when(ragIngestionService.split(
Mockito.eq(analysis), Mockito.any(StrategyConfig.class)))
.thenAnswer(invocation -> {
StrategyConfig config = invocation.getArgument(1);
invokedStrategies.add(
config.getStrategyCode() + ":" + config.getChunkSize() + ":" + config.getOverlapSize());
return invokedStrategies.size() == 1
? List.of()
: List.of(fallbackChunk);
});
List<RagChunk> chunks = invokeAutoParagraphFallback(
service, analysis, requestedStrategy, effectiveStrategy);
Assert.assertEquals(List.of(fallbackChunk), chunks);
Assert.assertEquals(
List.of(
RagStrategyCodes.OUTLINE_SECTION + ":" + chunkSize + ":" + overlapSize,
RagStrategyCodes.PARAGRAPH_LENGTH + ":" + chunkSize + ":" + overlapSize),
invokedStrategies);
Assert.assertEquals(
RagStrategyCodes.PARAGRAPH_LENGTH, effectiveStrategy.getStrategyCode());
}
@SuppressWarnings("unchecked")
private static List<RagChunk> invokeAutoParagraphFallback(
KnowledgeDocumentImportTaskAppService service,
AnalysisResult analysis,
StrategyConfig requestedStrategy,
StrategyConfig effectiveStrategy) throws Exception {
Method method = KnowledgeDocumentImportTaskAppService.class.getDeclaredMethod(
"splitWithAutoParagraphFallback",
AnalysisResult.class,
StrategyConfig.class,
StrategyConfig.class);
method.setAccessible(true);
return (List<RagChunk>) method.invoke(
service, analysis, requestedStrategy, effectiveStrategy);
}
private static DocumentMapper mockDocumentMapper(tech.easyflow.ai.entity.Document persistedDocument,
AtomicReference<tech.easyflow.ai.entity.Document> updatedDocumentRef) {
return (DocumentMapper) Proxy.newProxyInstance(