mirror of
https://gitcode.com/ageerle/ruoyi-ai.git
synced 2026-09-12 16:05:05 +00:00
refactor: move RAG trace classes to argtrace package and update SQL schema
- Rename org.ruoyi.trace package to org.ruoyi.argtrace for RagTraceNodeTypes and RagTracePayloadBuilder; fix package declarations and update imports in ChatServiceFacade and KnowledgeRetrievalServiceImpl - Remove obsolete RagTracePayloadBuilderTest - Switch supervisor response strategy from SUMMARY to LAST in ChatServiceFacade - Refresh docs/script/sql/ruoyi-ai.sql with the latest full schema dump - Add live demo links (admin panel, user frontend, commercial edition) to README.md and README_ZH.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,13 @@
|
||||
</div>
|
||||
|
||||
|
||||
## 🚀 Live Demo
|
||||
|
||||
| Service | URL | Default Account |
|
||||
|---|---|---|
|
||||
| Admin Panel | http://129.226.199.247:25666 | admin / admin123 |
|
||||
| User Frontend | http://129.226.199.247:25137 | admin / admin123 |
|
||||
| Commercial Edition | https://web.ruoyiai.chat | WeChat QR code login |
|
||||
|
||||
## ✨ Core Features
|
||||
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
</div>
|
||||
|
||||
|
||||
## 🚀 演示地址
|
||||
|
||||
| 服务 | 访问地址 | 默认账号 |
|
||||
|---|---|---|
|
||||
| 管理端 | http://129.226.199.247:25666 | admin / admin123 |
|
||||
| 用户端 | http://129.226.199.247:25137 | admin / admin123 |
|
||||
| 商业版 | https://web.ruoyiai.chat | 微信扫码登录 |
|
||||
|
||||
## ✨ 核心亮点
|
||||
|
||||
| 模块 | 现有能力
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
package org.ruoyi.trace;
|
||||
package org.ruoyi.argtrace;
|
||||
|
||||
/**
|
||||
* RAG trace 业务与节点类型常量。
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.ruoyi.trace;
|
||||
package org.ruoyi.argtrace;
|
||||
|
||||
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||
@@ -80,8 +80,8 @@ import org.ruoyi.service.chat.impl.memory.PersistentChatMemoryStore;
|
||||
import org.ruoyi.service.knowledge.IKnowledgeInfoService;
|
||||
import org.ruoyi.service.retrieval.KnowledgeRetrievalService;
|
||||
import org.ruoyi.service.knowledge.retriever.CustomVectorRetriever;
|
||||
import org.ruoyi.trace.RagTraceNodeTypes;
|
||||
import org.ruoyi.trace.RagTracePayloadBuilder;
|
||||
import org.ruoyi.argtrace.RagTraceNodeTypes;
|
||||
import org.ruoyi.argtrace.RagTracePayloadBuilder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
@@ -348,7 +348,7 @@ public class ChatServiceFacade implements IChatService {
|
||||
.subAgents(skillsAgent, searchAgent, sqlAgent, chartGenerationAgent, echartsAgent, chitChatAgent)
|
||||
.supervisorContext("仅当请求是问候或简单闲聊、不需要任何数据、搜索、技能或图表时,才使用 chitChatAgent;"
|
||||
+ "其余情况必须使用对应的专业 Agent")
|
||||
.responseStrategy(SupervisorResponseStrategy.SUMMARY);
|
||||
.responseStrategy(SupervisorResponseStrategy.LAST);
|
||||
SupervisorAgent supervisor = supervisorBuilder.build();
|
||||
|
||||
// 知识库增强:智能体绑定了知识库时,对 supervisor 输入做一次 RAG 增强(全程唯一一次检索)
|
||||
|
||||
@@ -21,8 +21,8 @@ import org.ruoyi.mapper.knowledge.KnowledgeFragmentMapper;
|
||||
import org.ruoyi.service.rerank.RerankModelService;
|
||||
import org.ruoyi.service.retrieval.KnowledgeRetrievalService;
|
||||
import org.ruoyi.service.vector.VectorStoreService;
|
||||
import org.ruoyi.trace.RagTraceNodeTypes;
|
||||
import org.ruoyi.trace.RagTracePayloadBuilder;
|
||||
import org.ruoyi.argtrace.RagTraceNodeTypes;
|
||||
import org.ruoyi.argtrace.RagTracePayloadBuilder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
@@ -128,7 +128,7 @@ public class KnowledgeRetrievalServiceImpl implements KnowledgeRetrievalService
|
||||
// 如果启用重排序,适当扩大召回数量
|
||||
int originalMaxResults = queryVectorBo.getMaxResults() != null ? queryVectorBo.getMaxResults() : 10;
|
||||
int targetMaxResults = originalMaxResults;
|
||||
if (Boolean.TRUE.equals(queryVectorBo.getEnableRerank()) &&
|
||||
if (Boolean.TRUE.equals(queryVectorBo.getEnableRerank()) &&
|
||||
StringUtils.isNotBlank(queryVectorBo.getRerankModelName())) {
|
||||
targetMaxResults = originalMaxResults * RERANK_EXPANSION_FACTOR;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ public class KnowledgeRetrievalServiceImpl implements KnowledgeRetrievalService
|
||||
if (!Boolean.TRUE.equals(queryVectorBo.getEnableHybrid())) {
|
||||
QueryVectorBo vectorQuery = copyOf(queryVectorBo, targetMaxResults);
|
||||
List<KnowledgeRetrievalVo> results = vectorStoreService.search(vectorQuery);
|
||||
|
||||
|
||||
// 应用基础相似度阈值过滤(如果有)
|
||||
if (queryVectorBo.getSimilarityThreshold() != null) {
|
||||
results = results.stream()
|
||||
@@ -214,7 +214,7 @@ public class KnowledgeRetrievalServiceImpl implements KnowledgeRetrievalService
|
||||
rerankInputPayload);
|
||||
try {
|
||||
RerankModelService rerankModel = rerankModelFactory.createModel(queryVectorBo.getRerankModelName());
|
||||
|
||||
|
||||
List<String> contents = coarseResults.stream()
|
||||
.map(KnowledgeRetrievalVo::getContent)
|
||||
.collect(Collectors.toList());
|
||||
@@ -241,7 +241,7 @@ public class KnowledgeRetrievalServiceImpl implements KnowledgeRetrievalService
|
||||
|
||||
// 按新分排序
|
||||
reranked.sort((a, b) -> b.getScore().compareTo(a.getScore()));
|
||||
|
||||
|
||||
// 截断到 topN
|
||||
List<KnowledgeRetrievalVo> results = reranked.subList(0, Math.min(topN, reranked.size()));
|
||||
finishTraceNode(traceNode, TraceConstants.STATUS_SUCCESS, null,
|
||||
@@ -285,9 +285,9 @@ public class KnowledgeRetrievalServiceImpl implements KnowledgeRetrievalService
|
||||
List<KnowledgeRetrievalVo> fusedResults = new ArrayList<>();
|
||||
for (Map.Entry<String, KnowledgeRetrievalVo> entry : allMap.entrySet()) {
|
||||
String id = entry.getKey();
|
||||
double finalScore = (1 - alpha) * vectorScores.getOrDefault(id, 0.0) +
|
||||
double finalScore = (1 - alpha) * vectorScores.getOrDefault(id, 0.0) +
|
||||
alpha * keywordScores.getOrDefault(id, 0.0);
|
||||
|
||||
|
||||
KnowledgeRetrievalVo vo = entry.getValue();
|
||||
vo.setScore(finalScore * 60.0); // 归一化缩放
|
||||
fusedResults.add(vo);
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package org.ruoyi.trace;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.ruoyi.common.chat.domain.dto.request.ChatRequest;
|
||||
import org.ruoyi.common.chat.domain.vo.chat.ChatModelVo;
|
||||
import org.ruoyi.domain.bo.vector.QueryVectorBo;
|
||||
import org.ruoyi.domain.vo.knowledge.KnowledgeRetrievalVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class RagTracePayloadBuilderTest {
|
||||
|
||||
@Test
|
||||
void chatRequestSummaryShouldHandleNullsAndAvoidPromptBody() {
|
||||
ChatRequest request = new ChatRequest();
|
||||
request.setSessionId(100L);
|
||||
request.setModel("qwen-plus");
|
||||
request.setKnowledgeId("200");
|
||||
request.setContent("secret prompt body");
|
||||
|
||||
ChatModelVo model = new ChatModelVo();
|
||||
model.setProviderCode("dashscope");
|
||||
request.setChatModelVo(model);
|
||||
|
||||
String payload = RagTracePayloadBuilder.chatRequestSummary(request);
|
||||
|
||||
assertTrue(payload.contains("\"sessionId\":100"));
|
||||
assertTrue(payload.contains("\"contentLength\":18"));
|
||||
assertTrue(payload.contains("\"providerCode\":\"dashscope\""));
|
||||
assertFalse(payload.contains("secret prompt body"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievalInputSummaryShouldUseSummaryOnly() {
|
||||
QueryVectorBo query = new QueryVectorBo();
|
||||
query.setKid("200");
|
||||
query.setQuery("private retrieval query");
|
||||
query.setMaxResults(5);
|
||||
query.setEnableRerank(true);
|
||||
query.setRerankModelName("gte-rerank");
|
||||
query.setRerankTopN(null);
|
||||
|
||||
String payload = RagTracePayloadBuilder.retrievalInputSummary(query);
|
||||
|
||||
assertTrue(payload.contains("\"kid\":\"200\""));
|
||||
assertTrue(payload.contains("\"queryLength\":23"));
|
||||
assertTrue(payload.contains("\"enableRerank\":true"));
|
||||
assertFalse(payload.contains("private retrieval query"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void retrievalOutputSummaryShouldAvoidFragmentContent() {
|
||||
KnowledgeRetrievalVo result = new KnowledgeRetrievalVo();
|
||||
result.setId("fragment-1");
|
||||
result.setDocId("doc-1");
|
||||
result.setIdx(1);
|
||||
result.setScore(0.85);
|
||||
result.setContent("sensitive knowledge fragment");
|
||||
|
||||
String payload = RagTracePayloadBuilder.retrievalOutputSummary(List.of(result));
|
||||
|
||||
assertTrue(payload.contains("\"resultCount\":1"));
|
||||
assertTrue(payload.contains("\"contentLength\":28"));
|
||||
assertTrue(payload.contains("\"fragment-1\""));
|
||||
assertFalse(payload.contains("sensitive knowledge fragment"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void summariesShouldAcceptNullValuesWithoutMapOfNpe() {
|
||||
assertTrue(RagTracePayloadBuilder.chatRequestSummary(null).contains("\"requestPresent\":false"));
|
||||
assertTrue(RagTracePayloadBuilder.retrievalInputSummary(null).contains("\"queryPresent\":false"));
|
||||
assertTrue(RagTracePayloadBuilder.retrievalOutputSummary(null).contains("\"resultCount\":0"));
|
||||
assertTrue(RagTracePayloadBuilder.rerankInputSummary(null, 0, null).contains("\"candidateCount\":0"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user