From da992ff524d76adc78ecc647601df53b36da9ab4 Mon Sep 17 00:00:00 2001 From: devmrko Date: Fri, 24 Jul 2026 16:14:18 +0900 Subject: [PATCH] refs #731: guard missing game identifiers in few-shot prompt --- .../service/SelectAiService.java | 19 +++++++++++++------ .../service/SelectAiFewShotPromptTest.java | 3 ++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java b/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java index 548056e..65e64e0 100644 --- a/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java +++ b/src/main/java/com/cloudhandson/vpdbackoffice/service/SelectAiService.java @@ -33,6 +33,10 @@ public class SelectAiService { 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_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( "(?is)\\b(?:insert|update|delete|merge|alter|drop|create|truncate|grant|revoke|" + "commit|rollback|savepoint|lock|call|exec(?:ute)?|begin|declare|for\\s+update|" @@ -174,20 +178,23 @@ public class SelectAiService { .search(bearerToken, prompt, fewShotTopK(selectAi)) .examples(); if (examples.isEmpty()) { - return new EnrichedPrompt(prompt, "NO_MATCH", 0); + return new EnrichedPrompt(composePolicyPrompt(prompt), "NO_MATCH", 0); } return new EnrichedPrompt( composeFewShotPrompt(prompt, examples), "APPLIED", Math.min(examples.size(), MAX_FEW_SHOT_EXAMPLES)); } catch (Exception ignored) { // 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 examples) { - StringBuilder enriched = new StringBuilder( - "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 " + StringBuilder enriched = new StringBuilder(POLICY_PREFIX + + "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" + "Verified few-shot examples:\n"); int included = 0; @@ -208,7 +215,7 @@ public class SelectAiService { included++; } if (included == 0) { - return prompt; + return composePolicyPrompt(prompt); } return enriched.append("Original user question:\n").append(prompt).toString(); } diff --git a/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiFewShotPromptTest.java b/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiFewShotPromptTest.java index c9fed89..57df87b 100644 --- a/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiFewShotPromptTest.java +++ b/src/test/java/com/cloudhandson/vpdbackoffice/service/SelectAiFewShotPromptTest.java @@ -25,6 +25,7 @@ class SelectAiFewShotPromptTest { .contains("Verified few-shot examples") .contains("SELECT COUNT(*) AS AU_COUNT FROM APP_USER") .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"); } }