Skip to content

Commit b43e001

Browse files
committed
add ontology for TIS , add chat-bi by ontology
1 parent 6a5fd29 commit b43e001

10 files changed

Lines changed: 251 additions & 428 deletions

File tree

tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/EnableChatBI.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import com.qlangtech.tis.plugin.annotation.Validator;
3434
import com.qlangtech.tis.plugin.ds.manipulate.ManipulateItemsProcessor;
3535
import com.qlangtech.tis.plugin.manipulate.ManipulatePluginCacheRegister;
36+
import com.qlangtech.tis.plugin.ontology.chatbi.ChatBIResult;
3637
import com.qlangtech.tis.plugin.ontology.chatbi.ChatBIService;
3738
import com.qlangtech.tis.plugin.ontology.chatbi.DefaultChatBIService;
3839
import com.qlangtech.tis.plugin.ontology.chatbi.config.ValidationConfig;
@@ -55,7 +56,7 @@
5556
* @date 2026/5/28
5657
* @see DefaultChatBIService
5758
*/
58-
public class EnableChatBI extends OntologyDomainManipulate implements IManipulateStatus, IdentityDesc<JSONObject>, IPluginStore.BeforePluginSaved, IPluginStore.AfterPluginSaved {
59+
public class EnableChatBI extends OntologyDomainManipulate implements ChatBIService, IManipulateStatus, IdentityDesc<JSONObject>, IPluginStore.BeforePluginSaved, IPluginStore.AfterPluginSaved {
5960

6061
public static final String KEY_ID_NAME = "chat_bi";
6162
private String ontologyDomain;
@@ -110,7 +111,7 @@ public void afterSaved(IPluginContext pluginContext, Optional<Context> context)
110111
/**
111112
* 获取当前域对应的 ChatBIService 实例(懒加载,每个 EnableChatBI 实例独立持有)。
112113
*/
113-
public ChatBIService getChatBIService() {
114+
private ChatBIService getChatBIService() {
114115
if (_chatBIService == null) {
115116
DefaultChatBIService svc = new DefaultChatBIService();
116117
svc.setLlmProvider(LLMProvider.load(
@@ -126,6 +127,16 @@ public ChatBIService getChatBIService() {
126127
return _chatBIService;
127128
}
128129

130+
@Override
131+
public ChatBIResult ask(String domain, String nlq) {
132+
return getChatBIService().ask(domain, nlq);
133+
}
134+
135+
@Override
136+
public void initialize() {
137+
OntologyNeo4jSyncService.getInstance();
138+
}
139+
129140
@Override
130141
protected void afterManipuldateProcess(IPluginContext pluginContext, Optional<Context> context,
131142
ManipulateItemsProcessor itemsProcessor) {
@@ -135,8 +146,8 @@ protected void afterManipuldateProcess(IPluginContext pluginContext, Optional<Co
135146
}
136147

137148
// 初始化 Trace 清理服务
138-
com.qlangtech.tis.plugin.ontology.chatbi.trace.TraceCleanupService.getInstance()
139-
.setConfig(this.traceConfig != null ? this.traceConfig : createDefaultTraceConfig());
149+
// com.qlangtech.tis.plugin.ontology.chatbi.trace.TraceCleanupService.getInstance()
150+
// .setConfig(this.traceConfig != null ? this.traceConfig : createDefaultTraceConfig());
140151

141152
OntologyPluginMeta meta = OntologyPluginMeta.createPluginMeta(itemsProcessor.getPluginMeta());
142153
//OntologySyncQueue.enqueue(() -> {

tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/InferOntologyFromLLMHost.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public void setSteps(OneStepOfMultiSteps[] stepsPlugin) {
3838
this._stepsPlugin = Objects.requireNonNull(stepsPlugin, "stepsPlugin can not be null");
3939
}
4040

41+
@Override
42+
public void initialize() {
43+
44+
}
45+
4146
@Override
4247
protected void afterManipuldateProcess(IPluginContext pluginContext
4348
, Optional<Context> context, ManipulateItemsProcessor itemsProcessor) {

tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/chatbi/ChatBIResult.java

Lines changed: 0 additions & 79 deletions
This file was deleted.

tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/chatbi/ChatBIService.java

Lines changed: 0 additions & 43 deletions
This file was deleted.

tis-ontology-plugin/src/main/java/com/qlangtech/tis/plugin/ontology/chatbi/DefaultChatBIService.java

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.qlangtech.tis.aiagent.core.IAgentContext;
2222
import com.qlangtech.tis.aiagent.llm.LLMProvider;
2323
import com.qlangtech.tis.aiagent.llm.UserPrompt;
24+
import com.qlangtech.tis.datax.TimeFormat;
2425
import com.qlangtech.tis.plugin.ontology.chatbi.prompt.PromptBuilder;
2526
import com.qlangtech.tis.plugin.ontology.chatbi.trace.TraceWriter;
2627
import com.qlangtech.tis.plugin.ontology.chatbi.validation.AstValidator;
@@ -34,8 +35,10 @@
3435
import org.slf4j.LoggerFactory;
3536

3637
import java.util.ArrayList;
38+
import java.util.Date;
3739
import java.util.List;
3840
import java.util.Objects;
41+
import java.util.UUID;
3942

4043
/**
4144
* ChatBI 服务默认实现(§5 T5:重试编排)。
@@ -51,6 +54,9 @@ public class DefaultChatBIService implements ChatBIService {
5154

5255
private static final Logger logger = LoggerFactory.getLogger(DefaultChatBIService.class);
5356

57+
// private static final DateTimeFormatter DATETIME_FORMATTER =
58+
// DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
59+
5460
private final GraphRAGService graphRAGService = DefaultGraphRAGService.getInstance();
5561
private final KeywordWhitelistValidator keywordValidator = new KeywordWhitelistValidator();
5662
private final AstValidator astValidator = new AstValidator();
@@ -71,9 +77,9 @@ public void setLlmProvider(LLMProvider llmProvider) {
7177
}
7278

7379
public void setConfigs(com.qlangtech.tis.plugin.ontology.chatbi.config.RetryConfig retryConfig,
74-
com.qlangtech.tis.plugin.ontology.chatbi.config.ValidationConfig validationConfig,
75-
com.qlangtech.tis.plugin.ontology.chatbi.config.ExecutionConfig executionConfig,
76-
com.qlangtech.tis.plugin.ontology.chatbi.config.RetrievalConfig retrievalConfig) {
80+
com.qlangtech.tis.plugin.ontology.chatbi.config.ValidationConfig validationConfig,
81+
com.qlangtech.tis.plugin.ontology.chatbi.config.ExecutionConfig executionConfig,
82+
com.qlangtech.tis.plugin.ontology.chatbi.config.RetrievalConfig retrievalConfig) {
7783
this.retryConfig = Objects.requireNonNull(retryConfig, "retryConfig can not be null");
7884
this.validationConfig = Objects.requireNonNull(validationConfig, "validationConfig can not be null");
7985
this.executionConfig = Objects.requireNonNull(executionConfig, "executionConfig can not be null");
@@ -82,32 +88,46 @@ public void setConfigs(com.qlangtech.tis.plugin.ontology.chatbi.config.RetryConf
8288

8389
@Override
8490
public ChatBIResult ask(String domain, String nlq) {
91+
return ask(domain, nlq, step -> {});
92+
}
93+
94+
@Override
95+
public ChatBIResult ask(String domain, String nlq, java.util.function.Consumer<TraceStep> stepCallback) {
96+
// 请求 ID:yyyyMMddHHmmss-{uuid32},贯穿整个流水线,用作 trace 文件名
97+
String createTime = TimeFormat.yyyyMMddHHmmss.format(new Date());// LocalDateTime.now().format(DATETIME_FORMATTER);
98+
String reqId = createTime + "-" + UUID.randomUUID().toString().replace("-", "");
99+
85100
List<TraceStep> trace = new ArrayList<>();
86-
long startTime = System.currentTimeMillis();
87101

88102
try {
89103
// Step 1: 检索
90104
long t1 = System.currentTimeMillis();
91105
com.qlangtech.tis.plugin.ontology.graphrag.RetrievalOptions retrievalOptions =
92-
Objects.requireNonNull(retrievalConfig, "retrievalConfig can not be null").toRetrievalOptions();
93-
// : com.qlangtech.tis.plugin.ontology.graphrag.RetrievalOptions.defaults();
106+
retrievalConfig != null ? retrievalConfig.toRetrievalOptions()
107+
: com.qlangtech.tis.plugin.ontology.graphrag.RetrievalOptions.defaults();
94108
RetrievalResult retrievalResult = graphRAGService.retrieve(domain, nlq, retrievalOptions);
95109
long t2 = System.currentTimeMillis();
96-
trace.add(TraceStep.retrieve(retrievalResult.objectTypes().size(), retrievalResult.linkers().size(), t2 - t1));
110+
TraceStep retrieveStep = TraceStep.retrieve(retrievalResult.objectTypes().size(), retrievalResult.linkers().size(), t2 - t1);
111+
trace.add(retrieveStep);
112+
stepCallback.accept(retrieveStep);
97113

98114
if (retrievalResult.objectTypes().isEmpty()) {
99115
String error = "No relevant ontology found for query: " + nlq;
100-
trace.add(TraceStep.error("retrieve", error));
101-
TraceWriter.writeTrace(domain, nlq, trace);
102-
return ChatBIResult.fail(error, trace);
116+
TraceStep errStep = TraceStep.error("retrieve", error);
117+
trace.add(errStep);
118+
stepCallback.accept(errStep);
119+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
120+
return ChatBIResult.fail(error, trace, reqId);
103121
}
104122

105123
// Step 2: 拼装 Prompt
106124
String graphragContext = retrievalResult.promptContext();
107125
List<String> systemPrompt = PromptBuilder.buildSystemPrompt(graphragContext);
108126
UserPrompt userPrompt = PromptBuilder.buildInitialPrompt(nlq, graphragContext);
109127
int tokens = PromptBuilder.estimateTokens(systemPrompt.get(0) + userPrompt.getPrompt());
110-
trace.add(TraceStep.prompt(tokens, systemPrompt.get(0), userPrompt.getPrompt()));
128+
TraceStep promptStep = TraceStep.prompt(tokens, systemPrompt.get(0), userPrompt.getPrompt());
129+
trace.add(promptStep);
130+
stepCallback.accept(promptStep);
111131

112132
// Step 3-5: LLM 调用 + 校验 + 重试循环
113133
String candidateSql = null;
@@ -126,29 +146,39 @@ public ChatBIResult ask(String domain, String nlq) {
126146

127147
if (!llmResponse.isSuccess()) {
128148
String error = "LLM invocation failed: " + llmResponse.getErrorMessage();
129-
trace.add(TraceStep.error("llm", error));
130-
TraceWriter.writeTrace(domain, nlq, trace);
131-
return ChatBIResult.fail(error, trace);
149+
TraceStep llmErrStep = TraceStep.error("llm", error);
150+
trace.add(llmErrStep);
151+
stepCallback.accept(llmErrStep);
152+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
153+
return ChatBIResult.fail(error, trace, reqId);
132154
}
133155

134-
trace.add(TraceStep.llm(llmResponse.getModel(), llmResponse.getPromptTokens(),
135-
llmResponse.getCompletionTokens(), llmResponse.getContent(), t4 - t3));
156+
TraceStep llmStep = TraceStep.llm(llmResponse.getModel(), llmResponse.getPromptTokens(),
157+
llmResponse.getCompletionTokens(), llmResponse.getContent(), t4 - t3);
158+
trace.add(llmStep);
159+
stepCallback.accept(llmStep);
136160

137161
// 提取 SQL
138162
candidateSql = PromptBuilder.extractSqlFromCodeBlock(llmResponse.getContent());
139163
if (candidateSql.isBlank()) {
140164
String error = "Failed to extract SQL from LLM response";
141-
trace.add(TraceStep.error("extract", error));
142-
TraceWriter.writeTrace(domain, nlq, trace);
143-
return ChatBIResult.fail(error, trace);
165+
TraceStep extractErrStep = TraceStep.error("extract", error);
166+
trace.add(extractErrStep);
167+
stepCallback.accept(extractErrStep);
168+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
169+
return ChatBIResult.fail(error, trace, reqId);
144170
}
145-
trace.add(TraceStep.extract(candidateSql));
171+
TraceStep extractStep = TraceStep.extract(candidateSql);
172+
trace.add(extractStep);
173+
stepCallback.accept(extractStep);
146174

147175
// Step 4: 静态校验
148176
validationResult = validateSql(domain, candidateSql, retrievalResult, enableExplain);
149177
JSONObject issues = new JSONObject();
150178
issues.put("issues", validationResult.issues());
151-
trace.add(TraceStep.validate(validationResult.valid(), validationResult.reason(), issues));
179+
TraceStep validateStep = TraceStep.validate(validationResult.valid(), validationResult.reason(), issues);
180+
trace.add(validateStep);
181+
stepCallback.accept(validateStep);
152182

153183
if (validationResult.valid()) {
154184
break; // 校验通过,退出循环
@@ -157,8 +187,8 @@ public ChatBIResult ask(String domain, String nlq) {
157187
// 校验失败:检查是否为关键字白名单失败(不重试)
158188
if (validationResult.reason() != null && validationResult.reason().contains("keyword")) {
159189
logger.warn("Keyword whitelist validation failed (no retry): {}", validationResult.reason());
160-
TraceWriter.writeTrace(domain, nlq, trace);
161-
return ChatBIResult.fail(validationResult.reasonAndIssue(), trace, validationResult.exception());
190+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
191+
return ChatBIResult.fail(validationResult.reasonAndIssue(), trace, reqId, validationResult.exception());
162192
}
163193

164194
// 其它失败:重试
@@ -178,24 +208,27 @@ public ChatBIResult ask(String domain, String nlq) {
178208
long t5 = System.currentTimeMillis();
179209
queryResult = executeQuery(domain, candidateSql);
180210
long t6 = System.currentTimeMillis();
181-
trace.add(TraceStep.execute(queryResult.rowCount(), t6 - t5));
211+
TraceStep execStep = TraceStep.execute(queryResult.rowCount(), t6 - t5);
212+
trace.add(execStep);
213+
stepCallback.accept(execStep);
182214
}
183215

184216
// 写入 trace
185-
TraceWriter.writeTrace(domain, nlq, trace);
217+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
186218

187219
if (validationResult.valid()) {
188-
return ChatBIResult.success(candidateSql, queryResult, trace);
220+
return ChatBIResult.success(candidateSql, queryResult, trace, reqId);
189221
} else {
190-
return ChatBIResult.fail(validationResult.reasonAndIssue(),
191-
trace, validationResult.exception());
222+
return ChatBIResult.fail(validationResult.reasonAndIssue(), trace, reqId, validationResult.exception());
192223
}
193224

194225
} catch (Exception e) {
195226
logger.error("ChatBI ask failed", e);
196-
trace.add(TraceStep.error("exception", e.getMessage()));
197-
TraceWriter.writeTrace(domain, nlq, trace);
198-
return ChatBIResult.fail("Internal error: " + e.getMessage(), trace);
227+
TraceStep exceptionStep = TraceStep.error("exception", e.getMessage());
228+
trace.add(exceptionStep);
229+
stepCallback.accept(exceptionStep);
230+
TraceWriter.writeTrace(domain, nlq, trace, reqId);
231+
return ChatBIResult.fail("Internal error: " + e.getMessage(), trace, reqId);
199232
}
200233
}
201234

0 commit comments

Comments
 (0)