Skip to content

Commit 05001d2

Browse files
feat(n2sql): reconstruct the prompt word configuration to support the… (#2112)
* feat(n2sql): reconstruct the prompt word configuration to support the optimization of prompt word functions * fix conflict * delete package * fix format * fix: update system prompt references to use optimization prompt * fix: add Apache License header to PromptOptimizationConfig.vue * fix: remove unused import for LocalDateTime in UserPromptConfigService.java * fix: remove deprecated custom prompt methods from UserPromptConfigService.java * Update PromptConfigDTO.java fix optimizationPrompt * Update PromptHelper.java improve optimization section handling
1 parent 5bade36 commit 05001d2

File tree

8 files changed

+853
-59
lines changed

8 files changed

+853
-59
lines changed

spring-ai-alibaba-nl2sql/spring-ai-alibaba-nl2sql-chat/src/main/java/com/alibaba/cloud/ai/dto/PromptConfigDTO.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@
2121
*
2222
* @author Makoto
2323
*/
24+
2425
public record PromptConfigDTO(String id, // Configuration ID (required for update)
2526
String name, // Configuration name
2627
String promptType, // Prompt type
27-
String systemPrompt, // User-defined system prompt content
28+
String optimizationPrompt, // User-defined system prompt content
2829
Boolean enabled, // Whether to enable this configuration
2930
String description, // Configuration description
3031
String creator // Creator
3132
) {
32-
public PromptConfigDTO(String promptType, String systemPrompt) {
33-
this(null, null, promptType, systemPrompt, true, null, null);
33+
public PromptConfigDTO(String promptType, String optimizationPrompt) {
34+
this(null, null, promptType, optimizationPrompt, true, null, null);
3435
}
3536

3637
@Override
@@ -61,8 +62,8 @@ public String promptType() {
6162
}
6263

6364
@Override
64-
public String systemPrompt() {
65-
return systemPrompt;
65+
public String optimizationPrompt() {
66+
return optimizationPrompt;
6667
}
6768

6869
@Override

spring-ai-alibaba-nl2sql/spring-ai-alibaba-nl2sql-chat/src/main/java/com/alibaba/cloud/ai/node/ReportGeneratorNode.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.alibaba.cloud.ai.node;
1818

19+
import com.alibaba.cloud.ai.entity.UserPromptConfig;
1920
import com.alibaba.cloud.ai.enums.StreamResponseType;
2021
import com.alibaba.cloud.ai.graph.OverAllState;
2122
import com.alibaba.cloud.ai.graph.action.NodeAction;
@@ -136,14 +137,15 @@ private Flux<ChatResponse> generateReport(String userInput, Plan plan, HashMap<S
136137
// Build analysis steps and data results description
137138
String analysisStepsAndData = buildAnalysisStepsAndData(plan, executionResults);
138139

139-
// Get custom prompt content if available
140-
String customPrompt = promptConfigService.getCustomPromptContent("report-generator");
140+
// Get optimization configs if available
141+
List<UserPromptConfig> optimizationConfigs = promptConfigService.getOptimizationConfigs("report-generator");
141142

142-
// Use PromptHelper to build report generation prompt with custom prompt support
143-
String reportPrompt = PromptHelper.buildReportGeneratorPromptWithCustom(userRequirementsAndPlan,
144-
analysisStepsAndData, summaryAndRecommendations, customPrompt);
143+
// Use PromptHelper to build report generation prompt with optimization support
144+
String reportPrompt = PromptHelper.buildReportGeneratorPromptWithOptimization(userRequirementsAndPlan,
145+
analysisStepsAndData, summaryAndRecommendations, optimizationConfigs);
145146

146-
logger.info("Using {} prompt for report generation", customPrompt != null ? "custom" : "default");
147+
logger.info("Using {} prompt for report generation",
148+
!optimizationConfigs.isEmpty() ? "optimized (" + optimizationConfigs.size() + " configs)" : "default");
147149

148150
return chatClient.prompt().user(reportPrompt).stream().chatResponse();
149151
}

spring-ai-alibaba-nl2sql/spring-ai-alibaba-nl2sql-chat/src/main/java/com/alibaba/cloud/ai/prompt/PromptHelper.java

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
import com.alibaba.cloud.ai.dto.schema.ColumnDTO;
2323
import com.alibaba.cloud.ai.dto.schema.SchemaDTO;
2424
import com.alibaba.cloud.ai.dto.schema.TableDTO;
25+
import com.alibaba.cloud.ai.entity.UserPromptConfig;
26+
2527
import org.apache.commons.lang3.BooleanUtils;
2628
import org.apache.commons.lang3.StringUtils;
29+
import org.springframework.ai.chat.prompt.PromptTemplate;
2730
import org.apache.commons.collections.CollectionUtils;
2831

2932
import java.util.*;
@@ -235,21 +238,20 @@ public static String buildSemanticConsistenPrompt(String nlReq, String sql) {
235238
* @param customPrompt user-defined prompt content, use default prompt if null
236239
* @return built prompt
237240
*/
238-
public static String buildReportGeneratorPromptWithCustom(String userRequirementsAndPlan,
239-
String analysisStepsAndData, String summaryAndRecommendations, String customPrompt) {
241+
public static String buildReportGeneratorPromptWithOptimization(String userRequirementsAndPlan,
242+
String analysisStepsAndData, String summaryAndRecommendations, List<UserPromptConfig> optimizationConfigs) {
243+
240244
Map<String, Object> params = new HashMap<>();
241245
params.put("user_requirements_and_plan", userRequirementsAndPlan);
242246
params.put("analysis_steps_and_data", analysisStepsAndData);
243247
params.put("summary_and_recommendations", summaryAndRecommendations);
244248

245-
if (customPrompt != null && !customPrompt.trim().isEmpty()) {
246-
// Use custom prompt
247-
return new org.springframework.ai.chat.prompt.PromptTemplate(customPrompt).render(params);
248-
}
249-
else {
250-
// Use default prompt
251-
return PromptConstant.getReportGeneratorPromptTemplate().render(params);
252-
}
249+
// Build optional optimization section content from user configs
250+
String optimizationSection = buildOptimizationSection(optimizationConfigs, params);
251+
params.put("optimization_section", optimizationSection);
252+
253+
// Render using the default report generator template
254+
return PromptConstant.getReportGeneratorPromptTemplate().render(params);
253255
}
254256

255257
public static String buildSqlErrorFixerPrompt(String question, DbConfig dbConfig, SchemaDTO schemaDTO,
@@ -285,4 +287,49 @@ public static String buildSemanticModelPrompt(List<SemanticModelDTO> semanticMod
285287
return PromptConstant.getSemanticModelPromptTemplate().render(params);
286288
}
287289

290+
/**
291+
* 构建优化提示词部分内容
292+
* @param optimizationConfigs 优化配置列表
293+
* @param params 模板参数
294+
* @return 优化部分的内容
295+
*/
296+
private static String buildOptimizationSection(List<UserPromptConfig> optimizationConfigs,
297+
Map<String, Object> params) {
298+
299+
if (optimizationConfigs == null || optimizationConfigs.isEmpty()) {
300+
return "";
301+
}
302+
303+
StringBuilder result = new StringBuilder();
304+
result.append("## 优化要求\n");
305+
306+
for (UserPromptConfig config : optimizationConfigs) {
307+
String optimizationContent = renderOptimizationPrompt(config.getSystemPrompt(), params);
308+
if (!optimizationContent.trim().isEmpty()) {
309+
result.append("- ").append(optimizationContent).append("\n");
310+
}
311+
}
312+
313+
return result.toString().trim();
314+
}
315+
316+
/**
317+
* 渲染优化提示词模板
318+
* @param optimizationPrompt 优化提示词模板
319+
* @param params 参数
320+
* @return 渲染后的内容
321+
*/
322+
private static String renderOptimizationPrompt(String optimizationPrompt, Map<String, Object> params) {
323+
if (optimizationPrompt == null || optimizationPrompt.trim().isEmpty()) {
324+
return "";
325+
}
326+
try {
327+
return new PromptTemplate(optimizationPrompt).render(params);
328+
}
329+
catch (Exception e) {
330+
// 如果模板渲染失败,直接返回原始内容
331+
return optimizationPrompt;
332+
}
333+
}
334+
288335
}

spring-ai-alibaba-nl2sql/spring-ai-alibaba-nl2sql-chat/src/main/java/com/alibaba/cloud/ai/service/UserPromptConfigService.java

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.stereotype.Service;
2727

2828
import java.util.*;
29+
import java.util.concurrent.ConcurrentHashMap;
2930

3031
/**
3132
* User Prompt Configuration Management Service Provides CRUD functionality for prompt
@@ -41,21 +42,31 @@ public class UserPromptConfigService {
4142
@Autowired
4243
private UserPromptConfigMapper userPromptConfigMapper;
4344

45+
/**
46+
* 内存存储,用于缓存配置(可选的性能优化)
47+
*/
48+
private final Map<String, UserPromptConfig> configStorage = new ConcurrentHashMap<>();
49+
50+
/**
51+
* 根据提示词类型存储启用的配置ID列表(支持多个配置同时启用)
52+
*/
53+
private final Map<String, List<String>> promptTypeToConfigIds = new ConcurrentHashMap<>();
54+
4455
/**
4556
* Create or update prompt configuration
4657
* @param configDTO configuration data transfer object
4758
* @return saved configuration object
4859
*/
4960
public UserPromptConfig saveOrUpdateConfig(PromptConfigDTO configDTO) {
50-
logger.info("保存或更新提示词配置:{}", configDTO);
61+
logger.info("保存或更新提示词优化配置:{}", configDTO);
5162

5263
UserPromptConfig config;
5364
if (configDTO.id() != null) {
5465
// Update existing configuration
5566
config = userPromptConfigMapper.selectById(configDTO.id());
5667
if (config != null) {
5768
config.setName(configDTO.name());
58-
config.setSystemPrompt(configDTO.systemPrompt());
69+
config.setSystemPrompt(configDTO.optimizationPrompt());
5970
config.setEnabled(configDTO.enabled());
6071
config.setDescription(configDTO.description());
6172
userPromptConfigMapper.updateById(config);
@@ -66,7 +77,7 @@ public UserPromptConfig saveOrUpdateConfig(PromptConfigDTO configDTO) {
6677
config.setId(configDTO.id());
6778
config.setName(configDTO.name());
6879
config.setPromptType(configDTO.promptType());
69-
config.setSystemPrompt(configDTO.systemPrompt());
80+
config.setSystemPrompt(configDTO.optimizationPrompt());
7081
config.setEnabled(configDTO.enabled());
7182
config.setDescription(configDTO.description());
7283
config.setCreator(configDTO.creator());
@@ -78,13 +89,19 @@ public UserPromptConfig saveOrUpdateConfig(PromptConfigDTO configDTO) {
7889
config = new UserPromptConfig();
7990
config.setName(configDTO.name());
8091
config.setPromptType(configDTO.promptType());
81-
config.setSystemPrompt(configDTO.systemPrompt());
92+
config.setSystemPrompt(configDTO.optimizationPrompt());
8293
config.setEnabled(configDTO.enabled());
8394
config.setDescription(configDTO.description());
8495
config.setCreator(configDTO.creator());
8596
userPromptConfigMapper.insert(config);
8697
}
8798

99+
// 更新缓存
100+
configStorage.put(config.getId(), config);
101+
102+
// 更新类型映射(支持多个配置)
103+
updatePromptTypeMapping(config);
104+
88105
// If the configuration is enabled, disable other configurations of the same type
89106
if (Boolean.TRUE.equals(config.getEnabled())) {
90107
userPromptConfigMapper.disableAllByPromptType(config.getPromptType());
@@ -104,13 +121,40 @@ public UserPromptConfig getConfigById(String id) {
104121
return userPromptConfigMapper.selectById(id);
105122
}
106123

124+
/**
125+
* 根据提示词类型获取所有启用的配置
126+
* @param promptType 提示词类型
127+
* @return 配置列表
128+
*/
129+
public List<UserPromptConfig> getActiveConfigsByType(String promptType) {
130+
List<String> configIds = promptTypeToConfigIds.get(promptType);
131+
if (configIds == null || configIds.isEmpty()) {
132+
return new ArrayList<>();
133+
}
134+
135+
return configIds.stream()
136+
.map(configStorage::get)
137+
.filter(Objects::nonNull)
138+
.filter(config -> Boolean.TRUE.equals(config.getEnabled()))
139+
.sorted(Comparator.comparing(UserPromptConfig::getUpdateTime).reversed())
140+
.toList();
141+
}
142+
107143
/**
108144
* Get enabled configuration by prompt type
109145
* @param promptType prompt type
110146
* @return configuration object, returns null if not exists
111147
*/
112148
public UserPromptConfig getActiveConfigByType(String promptType) {
113-
return userPromptConfigMapper.selectActiveByPromptType(promptType);
149+
// 优先从数据库获取
150+
UserPromptConfig dbConfig = userPromptConfigMapper.selectActiveByPromptType(promptType);
151+
if (dbConfig != null) {
152+
return dbConfig;
153+
}
154+
155+
// 备用:从内存缓存获取
156+
List<UserPromptConfig> configs = getActiveConfigsByType(promptType);
157+
return configs.isEmpty() ? null : configs.get(0);
114158
}
115159

116160
/**
@@ -139,8 +183,12 @@ public List<UserPromptConfig> getConfigsByType(String promptType) {
139183
public boolean deleteConfig(String id) {
140184
UserPromptConfig config = userPromptConfigMapper.selectById(id);
141185
if (config != null) {
186+
// 从数据库删除
142187
int deleted = userPromptConfigMapper.deleteById(id);
143188
if (deleted > 0) {
189+
// 从内存缓存和类型映射中移除该配置
190+
configStorage.remove(id);
191+
removeFromPromptTypeMapping(config);
144192
logger.info("已删除配置:{}", id);
145193
return true;
146194
}
@@ -162,6 +210,10 @@ public boolean enableConfig(String id) {
162210
// Enable the current configuration
163211
int updated = userPromptConfigMapper.enableById(id);
164212
if (updated > 0) {
213+
// 更新内存缓存
214+
config.setEnabled(true);
215+
configStorage.put(id, config);
216+
updatePromptTypeMapping(config);
165217
logger.info("已启用配置:{}", id);
166218
return true;
167219
}
@@ -177,6 +229,12 @@ public boolean enableConfig(String id) {
177229
public boolean disableConfig(String id) {
178230
int updated = userPromptConfigMapper.disableById(id);
179231
if (updated > 0) {
232+
// 更新内存缓存
233+
UserPromptConfig config = configStorage.get(id);
234+
if (config != null) {
235+
config.setEnabled(false);
236+
removeFromPromptTypeMapping(config);
237+
}
180238
logger.info("已禁用配置:{}", id);
181239
return true;
182240
}
@@ -187,29 +245,43 @@ public boolean disableConfig(String id) {
187245
* Disable all configurations of specified type
188246
* @param promptType prompt type
189247
*/
190-
public void disableConfigsByType(String promptType) {
191-
userPromptConfigMapper.disableAllByPromptType(promptType);
248+
private void updatePromptTypeMapping(UserPromptConfig config) {
249+
if (Boolean.TRUE.equals(config.getEnabled())) {
250+
promptTypeToConfigIds.computeIfAbsent(config.getPromptType(), k -> new ArrayList<>());
251+
List<String> configIds = promptTypeToConfigIds.get(config.getPromptType());
252+
if (!configIds.contains(config.getId())) {
253+
configIds.add(config.getId());
254+
logger.info("已将配置 {} 添加到提示词类型 [{}] 的映射中", config.getId(), config.getPromptType());
255+
}
256+
}
257+
else {
258+
removeFromPromptTypeMapping(config);
259+
}
192260
}
193261

194262
/**
195263
* Get custom prompt content, returns null if no custom configuration
196264
* @param promptType prompt type
197265
* @return custom prompt content
198266
*/
199-
public String getCustomPromptContent(String promptType) {
200-
// TODO 需要优化,提示词不能完全替代现有的,仅用作补充使用
201-
return null;
202-
// UserPromptConfig config = getActiveConfigByType(promptType);
203-
// return config != null ? config.getSystemPrompt() : null;
267+
private void removeFromPromptTypeMapping(UserPromptConfig config) {
268+
List<String> configIds = promptTypeToConfigIds.get(config.getPromptType());
269+
if (configIds != null) {
270+
configIds.remove(config.getId());
271+
if (configIds.isEmpty()) {
272+
promptTypeToConfigIds.remove(config.getPromptType());
273+
}
274+
logger.info("已从提示词类型 [{}] 的映射中移除配置 {}", config.getPromptType(), config.getId());
275+
}
204276
}
205277

206278
/**
207279
* Check if there is custom configuration
208280
* @param promptType prompt type
209281
* @return whether there is custom configuration
210282
*/
211-
public boolean hasCustomConfig(String promptType) {
212-
return getActiveConfigByType(promptType) != null;
283+
public List<UserPromptConfig> getOptimizationConfigs(String promptType) {
284+
return getActiveConfigsByType(promptType);
213285
}
214286

215287
}

spring-ai-alibaba-nl2sql/spring-ai-alibaba-nl2sql-chat/src/main/resources/prompts/report-generator.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,6 @@
4949
## 总结建议要求
5050
{summary_and_recommendations}
5151

52+
{optimization_section}
53+
5254
请根据以上信息生成一份专业、全面的数据分析报告。

0 commit comments

Comments
 (0)