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