优化llm接口
This commit is contained in:
parent
54a9241dbb
commit
d3fb2d829a
@ -1,5 +1,6 @@
|
||||
package com.knowledge.base.application.service;
|
||||
|
||||
import com.knowledge.base.infrastructure.north.dto.llm.WorkspaceAttachment;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.util.List;
|
||||
@ -30,9 +31,10 @@ public interface LLMAppService {
|
||||
* @param llmToken LLM鉴权token
|
||||
* @param workspaceSlug 当前工作区slug
|
||||
* @param keywords 搜索关键词
|
||||
* @param question 当前的问题
|
||||
* @return 本次被pin的docPath集合
|
||||
*/
|
||||
List<String> pinDocsByKeywords(String llmToken, String workspaceSlug, List<String> keywords);
|
||||
List<WorkspaceAttachment> pinDocsByKeywords(String llmToken, String workspaceSlug, List<String> keywords, String question);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -22,6 +22,8 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@ -37,6 +39,12 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
|
||||
private final FileElasticsearchGateway esGateway;
|
||||
|
||||
/**
|
||||
* pin和unpin的并发控制
|
||||
*/
|
||||
private static boolean PROCESSING = false;
|
||||
private static String PROCESSING_QUESTION = StrUtil.EMPTY;
|
||||
|
||||
|
||||
@Override
|
||||
public String getToken(String password) throws Exception {
|
||||
@ -46,8 +54,7 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
@Override
|
||||
public SseEmitter ask(String llmToken, String question, Map<String, Object> params) throws Exception {
|
||||
SseEmitter emitter = new SseEmitter(300 * 1000L); // 超时时间设为5分钟
|
||||
String keyword = (String) params.get("keyword");
|
||||
pinDocsByKeywords(llmToken, ConstantConfig.DEFAULT_SLUG_ID, Lists.newArrayList(keyword));
|
||||
List<WorkspaceAttachment> pinnedDocs = pinDocsByKeywords(llmToken, ConstantConfig.DEFAULT_SLUG_ID, extractKeywords(question), question);
|
||||
|
||||
ThreadPoolUtil.execute(() -> {
|
||||
try {
|
||||
@ -63,6 +70,16 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
} catch (IOException ioException) {
|
||||
log.warn("SSE发送错误信息失败", ioException);
|
||||
}
|
||||
} finally {
|
||||
// 问题结束后,需要unpin掉
|
||||
pinnedDocs.forEach(doc -> {
|
||||
try {
|
||||
anythingLLMService.updatePin(llmToken, ConstantConfig.DEFAULT_SLUG_ID, doc.getDocpath(), false);
|
||||
} catch (Exception e) {
|
||||
log.warn("unpin失败: {}", doc, e);
|
||||
}
|
||||
});
|
||||
PROCESSING = false;
|
||||
}
|
||||
}, ThreadPoolConfig.SSE_POOL);
|
||||
|
||||
@ -70,11 +87,16 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> pinDocsByKeywords(String llmToken, String workspaceSlug, List<String> keywords) {
|
||||
public List<WorkspaceAttachment> pinDocsByKeywords(String llmToken, String workspaceSlug, List<String> keywords, String question) {
|
||||
if(CollectionUtil.isEmpty(keywords)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if(PROCESSING) {
|
||||
log.info("有问题正在处理,请稍等,question: {}", PROCESSING_QUESTION);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<FileEsModel> fileEsModels = esGateway.searchByKeywords(keywords);
|
||||
Set<String> esFilepaths = fileEsModels.stream()
|
||||
.map(FileEsModel::getFilepath)
|
||||
@ -86,6 +108,9 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
// 将当前问题标注为处理中
|
||||
markQuestionProcessing(question);
|
||||
|
||||
// 2. 获取当前工作区所有附件(docPath -> url)
|
||||
List<WorkspaceAttachment> attachments = anythingLLMService.fetchAttachments(llmToken, workspaceSlug);
|
||||
if (attachments == null || attachments.isEmpty()) {
|
||||
@ -94,9 +119,9 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
}
|
||||
|
||||
// 3. 找到需要pin的docPath集合
|
||||
Set<WorkspaceAttachment> toPinDocs = attachments.stream()
|
||||
List<WorkspaceAttachment> toPinDocs = attachments.stream()
|
||||
.filter(att -> esFilepaths.stream().anyMatch(f -> att.getUrl().endsWith(f)))
|
||||
.collect(Collectors.toSet());
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 4. 只unpin之前已pin的文档
|
||||
attachments.stream()
|
||||
@ -121,6 +146,26 @@ public class LLMAppServiceImpl implements LLMAppService {
|
||||
|
||||
log.info("[pinDocsByKeywords] 共pin住文档{}条: {}", toPinDocs.size(), JSONUtil.toJsonStr(toPinDocs));
|
||||
|
||||
return toPinDocs.stream().map(WorkspaceAttachment::getUrl).collect(Collectors.toList());
|
||||
return toPinDocs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取所有被LEFT & RIGHT 包裹的子串,返回数组
|
||||
*/
|
||||
public static List<String> extractKeywords(String text) {
|
||||
List<String> keywords = new ArrayList<>();
|
||||
Pattern pattern = Pattern.compile(ConstantConfig.KEYWORD_PATTERN_LEFT + "(.*?)" + ConstantConfig.KEYWORD_PATTERN_RIGHT);
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
while (matcher.find()) {
|
||||
keywords.add(matcher.group(1));
|
||||
}
|
||||
return keywords;
|
||||
}
|
||||
|
||||
public static void markQuestionProcessing(String question) {
|
||||
PROCESSING = true;
|
||||
PROCESSING_QUESTION = question;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -34,6 +34,6 @@ public class ConstantConfig {
|
||||
* 以下是AnythingLLM相关
|
||||
*/
|
||||
public static final String DEFAULT_SLUG_ID = "87e14982-a821-48d8-9c6b-3557d0bb2f96";
|
||||
|
||||
|
||||
public static final String KEYWORD_PATTERN_LEFT = "[";
|
||||
public static final String KEYWORD_PATTERN_RIGHT = "]";
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.knowledge.base.infrastructure.config.ConstantConfig;
|
||||
import com.knowledge.base.infrastructure.north.dto.llm.WorkspaceAttachment;
|
||||
import com.knowledge.base.infrastructure.south.llm.AnythingLLMServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@ -46,7 +47,7 @@ public class LLMAppServiceImplTest {
|
||||
@Test
|
||||
public void testPinDocsByKeywords() throws Exception {
|
||||
try {
|
||||
List<String> result = llmAppService.pinDocsByKeywords(token, getSlug(), Lists.newArrayList("商业"));
|
||||
List<WorkspaceAttachment> result = llmAppService.pinDocsByKeywords(token, getSlug(), Lists.newArrayList("商业"), "[[商业]] 的本质是什么?");
|
||||
log.info("result: {}", JSONUtil.toJsonStr(result));
|
||||
} catch (Exception e) {
|
||||
log.warn("测试 pinDocsByKeywords 失败!: {}", e.getMessage(), e);
|
||||
|
||||
@ -149,7 +149,7 @@ public class AnythingLLMServiceTest {
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("wsName", "部门知识库");
|
||||
llmService.streamAnswer(token, "介绍一下黄金圈法则", params, writer);
|
||||
// llmService.streamAnswer(token, "介绍一下黄金圈法则", params, writer);
|
||||
} catch (Exception e) {
|
||||
log.warn("测试 streamAnswer 异常", e);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user