Skip to content

Commit f899d23

Browse files
committed
add new chat corrector
在助理最终执行物理SQL前,加入一步LLM优化性能功能
1 parent 8735553 commit f899d23

File tree

14 files changed

+214
-51
lines changed

14 files changed

+214
-51
lines changed

chat/server/src/main/java/com/tencent/supersonic/chat/server/executor/SqlExecutor.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,12 @@ private QueryResult doExecute(ExecuteContext executeContext) {
7575
return null;
7676
}
7777

78-
QuerySqlReq sqlReq =
79-
QuerySqlReq.builder().sql(parseInfo.getSqlInfo().getCorrectedS2SQL()).build();
78+
// 使用querySQL,它已经包含了所有修正(包括物理SQL修正)
79+
String finalSql = StringUtils.isNotBlank(parseInfo.getSqlInfo().getQuerySQL())
80+
? parseInfo.getSqlInfo().getQuerySQL()
81+
: parseInfo.getSqlInfo().getCorrectedS2SQL();
82+
83+
QuerySqlReq sqlReq = QuerySqlReq.builder().sql(finalSql).build();
8084
sqlReq.setSqlInfo(parseInfo.getSqlInfo());
8185
sqlReq.setDataSetId(parseInfo.getDataSetId());
8286

@@ -90,7 +94,7 @@ private QueryResult doExecute(ExecuteContext executeContext) {
9094
queryResult.setQueryTimeCost(System.currentTimeMillis() - startTime);
9195
if (queryResp != null) {
9296
queryResult.setQueryAuthorization(queryResp.getQueryAuthorization());
93-
queryResult.setQuerySql(queryResp.getSql());
97+
queryResult.setQuerySql(finalSql);
9498
queryResult.setQueryResults(queryResp.getResultList());
9599
queryResult.setQueryColumns(queryResp.getColumns());
96100
queryResult.setQueryState(QueryState.SUCCESS);

chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/AgentServiceImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.beans.BeanUtils;
2323
import org.springframework.beans.factory.annotation.Autowired;
2424
import org.springframework.beans.factory.annotation.Qualifier;
25+
import org.springframework.context.annotation.Lazy;
2526
import org.springframework.stereotype.Service;
2627
import org.springframework.util.CollectionUtils;
2728

@@ -39,6 +40,7 @@ public class AgentServiceImpl extends ServiceImpl<AgentDOMapper, AgentDO> implem
3940
private MemoryService memoryService;
4041

4142
@Autowired
43+
@Lazy
4244
private ChatQueryService chatQueryService;
4345

4446
@Autowired

chat/server/src/main/java/com/tencent/supersonic/chat/server/service/impl/ChatQueryServiceImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.apache.commons.lang3.StringUtils;
5050
import org.apache.commons.lang3.tuple.Pair;
5151
import org.springframework.beans.factory.annotation.Autowired;
52+
import org.springframework.context.annotation.Lazy;
5253
import org.springframework.stereotype.Service;
5354
import org.springframework.util.CollectionUtils;
5455

@@ -66,6 +67,7 @@ public class ChatQueryServiceImpl implements ChatQueryService {
6667
@Autowired
6768
private SemanticLayerService semanticLayerService;
6869
@Autowired
70+
@Lazy
6971
private AgentService agentService;
7072

7173
private final List<ChatQueryParser> chatQueryParsers = ComponentFactory.getChatParsers();

headless/api/src/main/java/com/tencent/supersonic/headless/api/pojo/SqlInfo.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@ public class SqlInfo implements Serializable {
1616

1717
// SQL to be executed finally
1818
private String querySQL;
19+
20+
// Physical SQL corrected by LLM for performance optimization
21+
private String correctedQuerySQL;
1922
}

headless/api/src/main/java/com/tencent/supersonic/headless/api/pojo/enums/ChatWorkflowState.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ public enum ChatWorkflowState {
88
VALIDATING,
99
SQL_CORRECTING,
1010
PROCESSING,
11+
PHYSICAL_SQL_CORRECTING,
1112
FINISHED
1213
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.tencent.supersonic.headless.chat.corrector;
2+
3+
import com.tencent.supersonic.common.pojo.ChatApp;
4+
import com.tencent.supersonic.common.pojo.enums.AppModule;
5+
import com.tencent.supersonic.common.util.ChatAppManager;
6+
import com.tencent.supersonic.headless.api.pojo.SemanticParseInfo;
7+
import com.tencent.supersonic.headless.chat.ChatQueryContext;
8+
import dev.langchain4j.model.chat.ChatLanguageModel;
9+
import dev.langchain4j.model.input.Prompt;
10+
import dev.langchain4j.model.input.PromptTemplate;
11+
import dev.langchain4j.model.output.structured.Description;
12+
import dev.langchain4j.provider.ModelProvider;
13+
import dev.langchain4j.service.AiServices;
14+
import lombok.Data;
15+
import lombok.ToString;
16+
import lombok.extern.slf4j.Slf4j;
17+
import org.apache.commons.lang3.StringUtils;
18+
import org.slf4j.Logger;
19+
import org.slf4j.LoggerFactory;
20+
21+
import java.util.HashMap;
22+
import java.util.Map;
23+
import java.util.Objects;
24+
25+
/**
26+
* 物理SQL修正器 - 使用LLM优化物理SQL性能
27+
*/
28+
@Slf4j
29+
public class LLMPhysicalSqlCorrector extends BaseSemanticCorrector {
30+
31+
private static final Logger keyPipelineLog = LoggerFactory.getLogger("keyPipeline");
32+
33+
public static final String APP_KEY = "PHYSICAL_SQL_CORRECTOR";
34+
private static final String INSTRUCTION = ""
35+
+ "#Role: You are a senior database performance optimization expert experienced in SQL tuning."
36+
+ "\n\n#Task: You will be provided with a user question and the corresponding physical SQL query,"
37+
+ " please analyze and optimize this SQL to improve query performance." + "\n\n#Rules:"
38+
+ "\n1. ALWAYS add appropriate index hints if the database supports them."
39+
+ "\n2. Optimize JOIN order by placing smaller tables first."
40+
+ "\n3. Add reasonable query limits to prevent large result sets if no LIMIT exists."
41+
+ "\n4. Optimize WHERE condition order by placing high-selectivity conditions first."
42+
+ "\n5. Ensure the optimized SQL is syntactically correct and logically equivalent."
43+
+ "\n6. If the SQL is already well-optimized, return 'positive'."
44+
+ "\n\n#Question: {{question}}" + "\n\n#OriginalSQL: {{sql}}" + "\n\n#Response:";
45+
46+
public LLMPhysicalSqlCorrector() {
47+
ChatAppManager.register(APP_KEY, ChatApp.builder().prompt(INSTRUCTION).name("物理SQL修正")
48+
.appModule(AppModule.CHAT).description("通过大模型对物理SQL做性能优化").enable(false).build());
49+
}
50+
51+
@Data
52+
@ToString
53+
static class PhysicalSql {
54+
@Description("either positive or negative")
55+
private String opinion;
56+
57+
@Description("optimized sql if negative")
58+
private String sql;
59+
}
60+
61+
interface PhysicalSqlExtractor {
62+
PhysicalSql generatePhysicalSql(String text);
63+
}
64+
65+
@Override
66+
public void doCorrect(ChatQueryContext chatQueryContext, SemanticParseInfo semanticParseInfo) {
67+
ChatApp chatApp = chatQueryContext.getRequest().getChatAppConfig().get(APP_KEY);
68+
if (!chatQueryContext.getRequest().getText2SQLType().enableLLM() || Objects.isNull(chatApp)
69+
|| !chatApp.isEnable()) {
70+
return;
71+
}
72+
73+
ChatLanguageModel chatLanguageModel =
74+
ModelProvider.getChatModel(chatApp.getChatModelConfig());
75+
PhysicalSqlExtractor extractor =
76+
AiServices.create(PhysicalSqlExtractor.class, chatLanguageModel);
77+
Prompt prompt = generatePrompt(chatQueryContext.getRequest().getQueryText(),
78+
semanticParseInfo, chatApp.getPrompt());
79+
PhysicalSql physicalSql =
80+
extractor.generatePhysicalSql(prompt.toUserMessage().singleText());
81+
keyPipelineLog.info("LLMPhysicalSqlCorrector modelReq:\n{} \nmodelResp:\n{}", prompt.text(),
82+
physicalSql);
83+
if ("NEGATIVE".equalsIgnoreCase(physicalSql.getOpinion())
84+
&& StringUtils.isNotBlank(physicalSql.getSql())) {
85+
semanticParseInfo.getSqlInfo().setCorrectedQuerySQL(physicalSql.getSql());
86+
}
87+
}
88+
89+
private Prompt generatePrompt(String queryText, SemanticParseInfo semanticParseInfo,
90+
String promptTemplate) {
91+
Map<String, Object> variable = new HashMap<>();
92+
variable.put("question", queryText);
93+
variable.put("sql", semanticParseInfo.getSqlInfo().getQuerySQL());
94+
95+
return PromptTemplate.from(promptTemplate).apply(variable);
96+
}
97+
}

headless/chat/src/main/java/com/tencent/supersonic/headless/chat/parser/llm/PromptHelper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ public List<List<Text2SQLExemplar>> getFewShotExemplars(LLMReq llmReq) {
5252
for (int i = 0; i < selfConsistencyNumber; i++) {
5353
List<Text2SQLExemplar> shuffledList = new ArrayList<>(exemplars);
5454
// only shuffle the exemplars from config
55-
List<Text2SQLExemplar> subList=shuffledList.subList(llmReq.getDynamicExemplars().size(),shuffledList.size());
55+
List<Text2SQLExemplar> subList =
56+
shuffledList.subList(llmReq.getDynamicExemplars().size(), shuffledList.size());
5657
Collections.shuffle(subList);
5758
results.add(shuffledList.subList(0, Math.min(shuffledList.size(), fewShotNumber)));
5859
}

headless/server/src/main/java/com/tencent/supersonic/headless/server/utils/ChatWorkflowEngine.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.tencent.supersonic.headless.api.pojo.response.ParseResp;
99
import com.tencent.supersonic.headless.api.pojo.response.SemanticTranslateResp;
1010
import com.tencent.supersonic.headless.chat.ChatQueryContext;
11+
import com.tencent.supersonic.headless.chat.corrector.LLMPhysicalSqlCorrector;
1112
import com.tencent.supersonic.headless.chat.corrector.SemanticCorrector;
1213
import com.tencent.supersonic.headless.chat.mapper.SchemaMapper;
1314
import com.tencent.supersonic.headless.chat.parser.SemanticParser;
@@ -76,6 +77,10 @@ public void start(ChatWorkflowState initialState, ChatQueryContext queryCtx) {
7677
long start = System.currentTimeMillis();
7778
performTranslating(queryCtx, parseResult);
7879
parseResult.getParseTimeCost().setSqlTime(System.currentTimeMillis() - start);
80+
queryCtx.setChatWorkflowState(ChatWorkflowState.PHYSICAL_SQL_CORRECTING);
81+
break;
82+
case PHYSICAL_SQL_CORRECTING:
83+
performPhysicalSqlCorrecting(queryCtx);
7984
queryCtx.setChatWorkflowState(ChatWorkflowState.FINISHED);
8085
break;
8186
default:
@@ -162,4 +167,25 @@ private void performTranslating(ChatQueryContext queryCtx, ParseResp parseResult
162167
parseResult.setErrorMsg(String.join("\n", errorMsg));
163168
}
164169
}
170+
171+
private void performPhysicalSqlCorrecting(ChatQueryContext queryCtx) {
172+
List<SemanticQuery> candidateQueries = queryCtx.getCandidateQueries();
173+
if (CollectionUtils.isNotEmpty(candidateQueries)) {
174+
for (SemanticQuery semanticQuery : candidateQueries) {
175+
for (SemanticCorrector corrector : semanticCorrectors) {
176+
if (corrector instanceof LLMPhysicalSqlCorrector) {
177+
corrector.correct(queryCtx, semanticQuery.getParseInfo());
178+
// 如果物理SQL被修正了,更新querySQL为修正后的版本
179+
SemanticParseInfo parseInfo = semanticQuery.getParseInfo();
180+
if (StringUtils.isNotBlank(parseInfo.getSqlInfo().getCorrectedQuerySQL())) {
181+
parseInfo.getSqlInfo().setQuerySQL(parseInfo.getSqlInfo().getCorrectedQuerySQL());
182+
log.info("Physical SQL corrected and updated querySQL: {}",
183+
parseInfo.getSqlInfo().getQuerySQL());
184+
}
185+
break;
186+
}
187+
}
188+
}
189+
}
190+
}
165191
}

launchers/headless/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ com.tencent.supersonic.headless.chat.parser.SemanticParser=\
1414

1515
com.tencent.supersonic.headless.chat.corrector.SemanticCorrector=\
1616
com.tencent.supersonic.headless.chat.corrector.RuleSqlCorrector,\
17-
com.tencent.supersonic.headless.chat.corrector.LLMSqlCorrector
17+
com.tencent.supersonic.headless.chat.corrector.LLMSqlCorrector,\
18+
com.tencent.supersonic.headless.chat.corrector.LLMPhysicalSqlCorrector
1819

1920
com.tencent.supersonic.headless.chat.knowledge.file.FileHandler=\
2021
com.tencent.supersonic.headless.chat.knowledge.file.FileHandlerImpl

launchers/standalone/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ com.tencent.supersonic.headless.chat.parser.SemanticParser=\
1515

1616
com.tencent.supersonic.headless.chat.corrector.SemanticCorrector=\
1717
com.tencent.supersonic.headless.chat.corrector.RuleSqlCorrector,\
18-
com.tencent.supersonic.headless.chat.corrector.LLMSqlCorrector
18+
com.tencent.supersonic.headless.chat.corrector.LLMSqlCorrector,\
19+
com.tencent.supersonic.headless.chat.corrector.LLMPhysicalSqlCorrector
1920

2021
com.tencent.supersonic.headless.chat.knowledge.file.FileHandler=\
2122
com.tencent.supersonic.headless.chat.knowledge.file.FileHandlerImpl

0 commit comments

Comments
 (0)