refs #731: guard missing game identifiers in few-shot prompt

This commit is contained in:
devmrko
2026-07-24 16:14:18 +09:00
parent 00b62bfb41
commit da992ff524
2 changed files with 15 additions and 7 deletions

View File

@@ -33,6 +33,10 @@ public class SelectAiService {
private static final int MAX_FEW_SHOT_EXAMPLES = 3; private static final int MAX_FEW_SHOT_EXAMPLES = 3;
private static final int MAX_FEW_SHOT_SQL_CHARS = 4_000; private static final int MAX_FEW_SHOT_SQL_CHARS = 4_000;
private static final int MAX_ENRICHED_PROMPT_LENGTH = 16_000; private static final int MAX_ENRICHED_PROMPT_LENGTH = 16_000;
private static final String POLICY_PREFIX =
"Answer the original user question using the current approved object list and policy. "
+ "If no game identifier resolves through game-alias metadata, do not select a prefix-specific object "
+ "and do not infer a default game. State that the required game identifier is missing instead.\n\n";
private static final Pattern UNSAFE_SQL = Pattern.compile( private static final Pattern UNSAFE_SQL = Pattern.compile(
"(?is)\\b(?:insert|update|delete|merge|alter|drop|create|truncate|grant|revoke|" "(?is)\\b(?:insert|update|delete|merge|alter|drop|create|truncate|grant|revoke|"
+ "commit|rollback|savepoint|lock|call|exec(?:ute)?|begin|declare|for\\s+update|" + "commit|rollback|savepoint|lock|call|exec(?:ute)?|begin|declare|for\\s+update|"
@@ -174,19 +178,22 @@ public class SelectAiService {
.search(bearerToken, prompt, fewShotTopK(selectAi)) .search(bearerToken, prompt, fewShotTopK(selectAi))
.examples(); .examples();
if (examples.isEmpty()) { if (examples.isEmpty()) {
return new EnrichedPrompt(prompt, "NO_MATCH", 0); return new EnrichedPrompt(composePolicyPrompt(prompt), "NO_MATCH", 0);
} }
return new EnrichedPrompt( return new EnrichedPrompt(
composeFewShotPrompt(prompt, examples), "APPLIED", Math.min(examples.size(), MAX_FEW_SHOT_EXAMPLES)); composeFewShotPrompt(prompt, examples), "APPLIED", Math.min(examples.size(), MAX_FEW_SHOT_EXAMPLES));
} catch (Exception ignored) { } catch (Exception ignored) {
// Vector retrieval is an optional prompt aid; preserve the normal Text2SQL path on failure. // Vector retrieval is an optional prompt aid; preserve the normal Text2SQL path on failure.
return new EnrichedPrompt(prompt, "UNAVAILABLE", 0); return new EnrichedPrompt(composePolicyPrompt(prompt), "UNAVAILABLE", 0);
} }
} }
static String composePolicyPrompt(String prompt) {
return POLICY_PREFIX + "Original user question:\n" + prompt;
}
static String composeFewShotPrompt(String prompt, List<QaVectorService.VectorExample> examples) { static String composeFewShotPrompt(String prompt, List<QaVectorService.VectorExample> examples) {
StringBuilder enriched = new StringBuilder( StringBuilder enriched = new StringBuilder(POLICY_PREFIX
"Answer the original user question using the current approved object list and policy. "
+ "The verified examples below are guidance only: use only relevant SQL patterns, do not invent " + "The verified examples below are guidance only: use only relevant SQL patterns, do not invent "
+ "identifiers, and do not override current metadata or game-alias resolution policy.\n\n" + "identifiers, and do not override current metadata or game-alias resolution policy.\n\n"
+ "Verified few-shot examples:\n"); + "Verified few-shot examples:\n");
@@ -208,7 +215,7 @@ public class SelectAiService {
included++; included++;
} }
if (included == 0) { if (included == 0) {
return prompt; return composePolicyPrompt(prompt);
} }
return enriched.append("Original user question:\n").append(prompt).toString(); return enriched.append("Original user question:\n").append(prompt).toString();
} }

View File

@@ -25,6 +25,7 @@ class SelectAiFewShotPromptTest {
.contains("Verified few-shot examples") .contains("Verified few-shot examples")
.contains("SELECT COUNT(*) AS AU_COUNT FROM APP_USER") .contains("SELECT COUNT(*) AS AU_COUNT FROM APP_USER")
.contains("Original user question:\ncurrent active users") .contains("Original user question:\ncurrent active users")
.contains("current approved object list and policy"); .contains("current approved object list and policy")
.contains("do not infer a default game");
} }
} }