From 2b701406198d9a34f4af2d7601263f1f97b0a24b Mon Sep 17 00:00:00 2001 From: jerryjzhang Date: Sun, 20 Oct 2024 15:23:39 +0800 Subject: [PATCH] [feature][chat]Introduce LLM-based DataInterpreter. #1828 --- .../execute/DataInterpretProcessor.java | 64 +++++++++++++++++++ .../execute/DimensionRecommendProcessor.java | 6 +- .../main/resources/META-INF/spring.factories | 3 +- .../main/resources/META-INF/spring.factories | 3 +- .../com/tencent/supersonic/chat/BaseTest.java | 3 +- 5 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DataInterpretProcessor.java diff --git a/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DataInterpretProcessor.java b/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DataInterpretProcessor.java new file mode 100644 index 000000000..699d3a7dd --- /dev/null +++ b/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DataInterpretProcessor.java @@ -0,0 +1,64 @@ +package com.tencent.supersonic.chat.server.processor.execute; + +import com.tencent.supersonic.chat.api.pojo.response.QueryResult; +import com.tencent.supersonic.chat.server.agent.Agent; +import com.tencent.supersonic.chat.server.pojo.ExecuteContext; +import com.tencent.supersonic.common.pojo.ChatApp; +import com.tencent.supersonic.common.pojo.enums.AppModule; +import com.tencent.supersonic.common.util.ChatAppManager; +import dev.langchain4j.data.message.AiMessage; +import dev.langchain4j.model.chat.ChatLanguageModel; +import dev.langchain4j.model.input.Prompt; +import dev.langchain4j.model.input.PromptTemplate; +import dev.langchain4j.model.output.Response; +import dev.langchain4j.provider.ModelProvider; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +public class DataInterpretProcessor implements ExecuteResultProcessor { + + private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline"); + + public static final String APP_KEY = "DATA_INTERPRETER"; + private static final String INSTRUCTION = "" + + "#Role: You are a data expert who communicates with business users everyday." + + "\n#Task: Your will be provided with a question asked by a user and the relevant " + + "result data queried from the databases, please interpret the data and organize a brief answer." + + "\n#Rules: " + "\n1.The `#Answer` must use the same language as the `#Question`." + + "\n#Question:{{question}} #Data:{{data}} #Answer:"; + + public DataInterpretProcessor() { + ChatAppManager.register(APP_KEY, ChatApp.builder().prompt(INSTRUCTION).name("结果数据解读") + .appModule(AppModule.CHAT).description("通过大模型对结果数据做提炼总结").enable(false).build()); + } + + + @Override + public void process(ExecuteContext executeContext, QueryResult queryResult) { + Agent agent = executeContext.getAgent(); + ChatApp chatApp = agent.getChatAppConfig().get(APP_KEY); + if (Objects.isNull(chatApp) || !chatApp.isEnable()) { + return; + } + + Map variable = new HashMap<>(); + variable.put("question", executeContext.getQueryText()); + variable.put("data", queryResult.getTextResult()); + + Prompt prompt = PromptTemplate.from(chatApp.getPrompt()).apply(variable); + ChatLanguageModel chatLanguageModel = + ModelProvider.getChatModel(chatApp.getChatModelConfig()); + Response response = chatLanguageModel.generate(prompt.toUserMessage()); + String anwser = response.content().text(); + keyPipelineLog.info("DataInterpretProcessor modelReq:\n{} \nmodelResp:\n{}", prompt.text(), + anwser); + if (StringUtils.isNotBlank(anwser)) { + queryResult.setTextResult(anwser); + } + } +} diff --git a/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DimensionRecommendProcessor.java b/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DimensionRecommendProcessor.java index f177bc3d1..5a3bad51b 100644 --- a/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DimensionRecommendProcessor.java +++ b/chat/server/src/main/java/com/tencent/supersonic/chat/server/processor/execute/DimensionRecommendProcessor.java @@ -11,12 +11,13 @@ import com.tencent.supersonic.headless.api.pojo.SchemaElement; import com.tencent.supersonic.headless.api.pojo.SchemaElementType; import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo; import com.tencent.supersonic.headless.server.facade.service.SemanticLayerService; +import org.springframework.util.CollectionUtils; + import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import org.springframework.util.CollectionUtils; /** * DimensionRecommendProcessor recommend some dimensions related to metrics based on configuration @@ -37,7 +38,8 @@ public class DimensionRecommendProcessor implements ExecuteResultProcessor { if (!firstMetric.isPresent()) { return; } - List dimensionRecommended = getDimensions(firstMetric.get().getId(), dataSetId); + List dimensionRecommended = + getDimensions(firstMetric.get().getId(), dataSetId); queryResult.setRecommendedDimensions(dimensionRecommended); } diff --git a/launchers/chat/src/main/resources/META-INF/spring.factories b/launchers/chat/src/main/resources/META-INF/spring.factories index 9e4acc0e1..ed6e5b11c 100644 --- a/launchers/chat/src/main/resources/META-INF/spring.factories +++ b/launchers/chat/src/main/resources/META-INF/spring.factories @@ -20,7 +20,8 @@ com.tencent.supersonic.chat.server.processor.parse.ParseResultProcessor=\ com.tencent.supersonic.chat.server.processor.execute.ExecuteResultProcessor=\ com.tencent.supersonic.chat.server.processor.execute.MetricRecommendProcessor,\ com.tencent.supersonic.chat.server.processor.execute.DimensionRecommendProcessor,\ - com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor + com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor,\ + com.tencent.supersonic.chat.server.processor.execute.DataInterpretProcessor ### auth-authentication SPIs diff --git a/launchers/standalone/src/main/resources/META-INF/spring.factories b/launchers/standalone/src/main/resources/META-INF/spring.factories index cd16dcfc6..cae949e6d 100644 --- a/launchers/standalone/src/main/resources/META-INF/spring.factories +++ b/launchers/standalone/src/main/resources/META-INF/spring.factories @@ -72,7 +72,8 @@ com.tencent.supersonic.chat.server.processor.parse.ParseResultProcessor=\ com.tencent.supersonic.chat.server.processor.execute.ExecuteResultProcessor=\ com.tencent.supersonic.chat.server.processor.execute.MetricRecommendProcessor,\ com.tencent.supersonic.chat.server.processor.execute.DimensionRecommendProcessor,\ - com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor + com.tencent.supersonic.chat.server.processor.execute.MetricRatioProcessor,\ + com.tencent.supersonic.chat.server.processor.execute.DataInterpretProcessor ### auth-authentication SPIs diff --git a/launchers/standalone/src/test/java/com/tencent/supersonic/chat/BaseTest.java b/launchers/standalone/src/test/java/com/tencent/supersonic/chat/BaseTest.java index 7ed95e65c..67cfae626 100644 --- a/launchers/standalone/src/test/java/com/tencent/supersonic/chat/BaseTest.java +++ b/launchers/standalone/src/test/java/com/tencent/supersonic/chat/BaseTest.java @@ -52,7 +52,8 @@ public class BaseTest extends BaseApplication { SemanticParseInfo semanticParseInfo = parseResp.getSelectedParses().get(0); ChatExecuteReq request = ChatExecuteReq.builder().queryText(parseResp.getQueryText()) .user(DataUtils.getUser()).parseId(semanticParseInfo.getId()) - .queryId(parseResp.getQueryId()).chatId(chatId).saveAnswer(true).build(); + .queryId(parseResp.getQueryId()).chatId(chatId).agentId(agentId).saveAnswer(true) + .build(); QueryResult queryResult = chatQueryService.execute(request); queryResult.setChatContext(semanticParseInfo); return queryResult;