refs #739: preserve Smilegate changes before repository layout migration
This commit is contained in:
22
database/adb/100_sgmp_czn05_country_business_au_fewshot.sql
Normal file
22
database/adb/100_sgmp_czn05_country_business_au_fewshot.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
-- Approve the reviewed customer QA example for a grouped business-AU query.
|
||||
-- Empty result sets remain valid executed query results.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
answer_text = 'Expected focus: aggregate business AU by the user-master country attribute. '
|
||||
|| 'Join CZN_CUSTOM_BIZ_USER_TXN to CZN_COMN_USER_MST by GUID and BASE_DT; filter BIZ_AU_FLAG=1 and EXPT_USER_YN=''N'', then group by LAST_CONN_COUNTRY_CD. '
|
||||
|| 'A successfully executed query with no country rows is a valid result, not a SQL failure. '
|
||||
|| 'Historical answer: no result rows.',
|
||||
inspection_note = 'Customer QA verified: country business-AU is a grouped join; an empty result is a valid query outcome.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-05';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, source_case_id, answer_text
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-05';
|
||||
16
database/adb/101_sgmp_czn06_country_standard_au_fewshot.sql
Normal file
16
database/adb/101_sgmp_czn06_country_standard_au_fewshot.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
-- Approve the reviewed customer QA example for a grouped standard-AU query.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
answer_text = 'Expected focus: aggregate standard AU by user-master country, joining COMN_COUNTRY_BAS only for the country display name. '
|
||||
|| 'Use CZN_COMN_USER_MST with AU_FLAG=1 and EXPT_USER_YN=''N'', grouped by LAST_CONN_COUNTRY_CD and COUNTRY_KR_NM. '
|
||||
|| 'The label standard AU does not imply STD_USER_YN. A successfully executed empty result is valid. '
|
||||
|| 'Historical answer: no result rows.',
|
||||
inspection_note = 'Customer QA verified: country standard-AU is grouped AU_FLAG aggregation; empty output is valid.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-06';
|
||||
|
||||
COMMIT;
|
||||
15
database/adb/102_sgmp_czn07_crystal_holdings_fewshot.sql
Normal file
15
database/adb/102_sgmp_czn07_crystal_holdings_fewshot.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Approve the reviewed customer QA example for daily in-game currency holdings.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
answer_text = 'Expected focus: daily crystal holdings use CZN_CUSTOM_GOODS_HAVE_TXN joined to CZN_COMN_USER_MST and CZN_COMN_SVC_DIM_BAS. '
|
||||
|| 'Filter the goods dimension to crystal, nonzero HAVE_CNT, eligible returning-user population, and the requested date range; group by BASE_DT. '
|
||||
|| 'A successfully executed empty result is valid. Historical answer: no result rows.',
|
||||
inspection_note = 'Customer QA verified: daily crystal holdings are a date-grouped goods/user/dimension join; empty output is valid.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-07';
|
||||
|
||||
COMMIT;
|
||||
15
database/adb/103_sgmp_czn08_crystal_average_fewshot.sql
Normal file
15
database/adb/103_sgmp_czn08_crystal_average_fewshot.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- Approve the exact customer QA for standard-AU crystal holdings per user.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
answer_text = 'Use the verified customer SQL template for crystal holdings among standard AU. '
|
||||
|| 'The standard-AU population uses AU_FLAG=1 and EXPT_USER_YN=''N''; do not add STD_USER_YN unless explicitly requested. '
|
||||
|| 'Use the template population denominator for the per-user average. Null aggregate values are valid when the qualifying set is empty.',
|
||||
inspection_note = 'Customer QA verified: retain the approved standard-AU population and average denominator semantics.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-08';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Customer-provided CZN benchmark examples are the approved reference corpus
|
||||
-- for exact-question Few-shot retrieval. Their SQL and expected-answer text
|
||||
-- remain the source of metric semantics; no runtime game/table branching is added.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Customer QA benchmark approved for exact-question Few-shot retrieval.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id LIKE 'CZN-%'
|
||||
AND reference_status <> 'APPROVED';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT source_case_id, reference_status, inspection_status
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id LIKE 'CZN-%'
|
||||
ORDER BY source_case_id;
|
||||
11
database/adb/105_sgmp_czn13_zero_aggregate_fewshot.sql
Normal file
11
database/adb/105_sgmp_czn13_zero_aggregate_fewshot.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- Preserve customer QA output semantics for empty numeric aggregates.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET answer_text = NVL(answer_text, '') || ' For this approved metric, normalize an empty numeric aggregate to 0 in the returned result. Preserve the template join from CZN_CUSTOM_GOODS_CHANGE_TXN to CZN_COMN_USER_MST, apply u.EXPT_USER_YN=''N'', and count distinct u.GUID.',
|
||||
inspection_note = 'Customer QA verified: empty total Ether usage is reported as numeric zero with the template user-master join, excluded-user filter, and user population.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-13';
|
||||
|
||||
COMMIT;
|
||||
@@ -0,0 +1,21 @@
|
||||
-- Approve the remaining customer-provided standard QA references for exact-question Few-shot retrieval.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Customer QA benchmark approved for exact-question Few-shot retrieval.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id LIKE 'STD-%'
|
||||
AND reference_status <> 'APPROVED';
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET answer_text = NVL(answer_text, '') || ' This unavailable-object case must not fabricate a DUAL/NULL result row. Return no result rows and explain that no approved physical object is available for the resolved game.',
|
||||
inspection_note = 'Customer QA verified: unavailable game objects return no result rows; no synthetic DUAL result.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-01';
|
||||
|
||||
COMMIT;
|
||||
64
database/adb/107_sgmp_separate_customer_qa_from_fewshot.sql
Normal file
64
database/adb/107_sgmp_separate_customer_qa_from_fewshot.sql
Normal file
@@ -0,0 +1,64 @@
|
||||
-- Customer QA is evaluation data, never production Few-shot context.
|
||||
-- Preserve it for SG_AI_QA_* baseline/history audit while retiring its vector copies.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'RETIRED',
|
||||
inspection_note = 'Evaluation-only customer QA. Excluded from production Few-shot retrieval.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_EVALUATION_SEPARATION'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK';
|
||||
|
||||
COMMIT;
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_vector_search(
|
||||
p_question IN CLOB,
|
||||
p_top_k IN PLS_INTEGER DEFAULT 3,
|
||||
p_target_type IN VARCHAR2 DEFAULT 'ANY'
|
||||
) RETURN SYS_REFCURSOR
|
||||
AUTHID DEFINER
|
||||
IS
|
||||
v_query_vector VECTOR;
|
||||
v_results SYS_REFCURSOR;
|
||||
v_target_type VARCHAR2(16) := UPPER(TRIM(NVL(p_target_type, 'ANY')));
|
||||
BEGIN
|
||||
IF p_question IS NULL THEN
|
||||
RAISE_APPLICATION_ERROR(-20003, 'question is required.');
|
||||
END IF;
|
||||
IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
|
||||
RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
|
||||
END IF;
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
RAISE_APPLICATION_ERROR(-20005, 'target_type must be NONE, SINGLE, MULTI, ALL, or ANY.');
|
||||
END IF;
|
||||
|
||||
v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
p_question,
|
||||
JSON(sg_qa_vector_params('search_query'))
|
||||
);
|
||||
|
||||
OPEN v_results FOR
|
||||
SELECT example_id,
|
||||
question,
|
||||
answer_sql,
|
||||
answer_text,
|
||||
embedding_model,
|
||||
reference_kind,
|
||||
target_type,
|
||||
object_role,
|
||||
source_case_id,
|
||||
source_type,
|
||||
vector_distance(embedding, v_query_vector, COSINE) AS cosine_distance
|
||||
FROM sg_qa_vector_example
|
||||
WHERE reference_status = 'APPROVED'
|
||||
AND (source_type IS NULL OR source_type <> 'CUSTOMER_QA_BENCHMARK')
|
||||
AND (target_type = 'ANY' OR v_target_type = 'ANY' OR target_type = v_target_type)
|
||||
ORDER BY vector_distance(embedding, v_query_vector, COSINE), example_id
|
||||
FETCH FIRST p_top_k ROWS ONLY;
|
||||
RETURN v_results;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT source_type, reference_status, COUNT(*) AS example_count
|
||||
FROM sg_qa_vector_example
|
||||
GROUP BY source_type, reference_status
|
||||
ORDER BY source_type, reference_status;
|
||||
@@ -0,0 +1,165 @@
|
||||
-- Build one generalized runtime Few-shot pattern for every customer QA case.
|
||||
-- The source benchmark remains evaluation-only; this derived record contains
|
||||
-- no customer game name, date literal, expected result, or physical CZN object.
|
||||
|
||||
DECLARE
|
||||
v_pattern_question CLOB;
|
||||
v_pattern_sql CLOB;
|
||||
v_embedding_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
v_object_role VARCHAR2(64);
|
||||
v_exists NUMBER;
|
||||
|
||||
FUNCTION generalized_question(p_question CLOB) RETURN CLOB IS
|
||||
v_value CLOB := p_question;
|
||||
BEGIN
|
||||
-- Resolved names/aliases become a semantic game placeholder.
|
||||
FOR token IN (
|
||||
SELECT column_value AS value
|
||||
FROM TABLE(sys.odcivarchar2list(
|
||||
'카오스 제로 나이트메어', '카오스제로나이트메어', 'Chaos Zero Nightmare',
|
||||
'STOVE_CHAOSZERO', '카제나', 'CZN', 'Bubblyz', '버블리즈',
|
||||
'로드나인', '로나', '테스트게임', 'BUBBLYZ', 'LORDNINE'
|
||||
))
|
||||
) LOOP
|
||||
v_value := REPLACE(v_value, token.value, '<게임>');
|
||||
END LOOP;
|
||||
v_value := REGEXP_REPLACE(v_value, '[0-9]{4}년[[:space:]]*[0-9]{1,2}월[[:space:]]*[0-9]{1,2}일', '<기준일>');
|
||||
v_value := REGEXP_REPLACE(v_value, '[0-9]{4}-[0-9]{2}-[0-9]{2}', '<기준일>');
|
||||
RETURN v_value;
|
||||
END;
|
||||
|
||||
FUNCTION generalized_sql(p_sql CLOB) RETURN CLOB IS
|
||||
v_value CLOB := p_sql;
|
||||
BEGIN
|
||||
-- Physical game objects become logical roles. Common dimensions remain
|
||||
-- logical as well so the current metadata/plan selects real objects.
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_COMN_USER_MST"', '<RESOLVED_GAME_USER_MASTER>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_COMN_CHARACTER_MST"', '<RESOLVED_GAME_CHARACTER_MASTER>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_CUSTOM_GOODS_HAVE_TXN"', '<RESOLVED_GAME_GOODS_HOLDINGS>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_CUSTOM_GOODS_CHANGE_TXN"', '<RESOLVED_GAME_GOODS_CHANGE>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_CUSTOM_BIZ_USER_TXN"', '<RESOLVED_GAME_BUSINESS_USER>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_CUSTOM_USER_GOODS_TXN"', '<RESOLVED_GAME_USER_GOODS>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."COMN_SALES_TXN"', '<APPROVED_SALES_TRANSACTION>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."COMN_REFUND_TXN"', '<APPROVED_REFUND_TRANSACTION>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."COMN_GAME_ALIAS_BAS"', '<GAME_ALIAS_CATALOG>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."COMN_COUNTRY_BAS"', '<COUNTRY_DIMENSION>');
|
||||
v_value := REPLACE(v_value, '"SGMP_POC"."CZN_COMN_SVC_DIM_BAS"', '<RESOLVED_GAME_SERVICE_DIMENSION>');
|
||||
v_value := REPLACE(v_value, 'STOVE_CHAOSZERO', '<RESOLVED_GAME_ID>');
|
||||
v_value := REPLACE(v_value, '''카제나''', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, '''CZN''', '<RESOLVED_GAME_PREFIX>');
|
||||
v_value := REGEXP_REPLACE(v_value, 'CZN_[A-Z0-9_]+', '<RESOLVED_GAME_OBJECT>');
|
||||
v_value := REPLACE(v_value, '카제나', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, '카오스 제로 나이트메어', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, '카오스제로나이트메어', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, 'CZN', '<RESOLVED_GAME_PREFIX>');
|
||||
v_value := REPLACE(v_value, 'BUBBLYZ', '<RESOLVED_GAME_ID>');
|
||||
v_value := REPLACE(v_value, 'Bubblyz', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, '버블리즈', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, 'LORDNINE', '<RESOLVED_GAME_ID>');
|
||||
v_value := REPLACE(v_value, '로드나인', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REPLACE(v_value, '테스트게임', '<RESOLVED_GAME_NAME>');
|
||||
v_value := REGEXP_REPLACE(v_value, 'TO_DATE\(''[0-9]{4}-[0-9]{2}-[0-9]{2}'', ''YYYY-MM-DD''\)', '<BUSINESS_DATE>');
|
||||
v_value := REGEXP_REPLACE(v_value, 'TO_DATE\(''[0-9]{8}'', ''YYYYMMDD''\)', '<BUSINESS_DATE>');
|
||||
v_value := REGEXP_REPLACE(v_value, 'DATE ''[0-9]{4}-[0-9]{2}-[0-9]{2}''', '<BUSINESS_DATE>');
|
||||
RETURN v_value;
|
||||
END;
|
||||
|
||||
FUNCTION role_of(p_sql CLOB) RETURN VARCHAR2 IS
|
||||
BEGIN
|
||||
IF DBMS_LOB.INSTR(p_sql, 'CZN_COMN_CHARACTER_MST') > 0 THEN
|
||||
RETURN 'GAME_CHARACTER_MASTER';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'CZN_CUSTOM_GOODS_HAVE_TXN') > 0 THEN
|
||||
RETURN 'GAME_GOODS_HOLDINGS';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'CZN_CUSTOM_GOODS_CHANGE_TXN') > 0 THEN
|
||||
RETURN 'GAME_GOODS_CHANGE';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'CZN_CUSTOM_BIZ_USER_TXN') > 0 THEN
|
||||
RETURN 'GAME_BUSINESS_USER';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'COMN_SALES_TXN') > 0 THEN
|
||||
RETURN 'SALES_TRANSACTION';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'COMN_REFUND_TXN') > 0 THEN
|
||||
RETURN 'REFUND_TRANSACTION';
|
||||
ELSIF DBMS_LOB.INSTR(p_sql, 'CZN_COMN_USER_MST') > 0 THEN
|
||||
RETURN 'GAME_USER_MASTER';
|
||||
END IF;
|
||||
RETURN 'METADATA_OR_OPERATION';
|
||||
END;
|
||||
BEGIN
|
||||
FOR source_row IN (
|
||||
SELECT example_id, source_case_id, question, answer_sql
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
ORDER BY source_case_id
|
||||
) LOOP
|
||||
v_pattern_question := generalized_question(source_row.question);
|
||||
v_pattern_sql := generalized_sql(source_row.answer_sql);
|
||||
v_object_role := role_of(source_row.answer_sql);
|
||||
v_embedding_input := TO_CLOB('Generalized question pattern: ') || v_pattern_question
|
||||
|| CHR(10) || 'Logical object role: ' || v_object_role
|
||||
|| CHR(10) || 'Structural SQL template: ' || v_pattern_sql
|
||||
|| CHR(10) || 'Use only current game scope metadata and replace placeholders from the current request.';
|
||||
|
||||
-- A generalized runtime pattern must not contain known customer answer
|
||||
-- identifiers or fixed business-date literals.
|
||||
IF REGEXP_LIKE(v_pattern_question,
|
||||
'카제나|버블리즈|Bubblyz|로드나인|테스트게임|[0-9]{4}년|[0-9]{4}-[0-9]{2}-[0-9]{2}', 'i')
|
||||
OR REGEXP_LIKE(v_pattern_sql,
|
||||
'CZN_|STOVE_CHAOSZERO|카제나|버블리즈|Bubblyz|[0-9]{4}-[0-9]{2}-[0-9]{2}', 'i') THEN
|
||||
RAISE_APPLICATION_ERROR(-20061, 'Generalization leak in ' || source_row.source_case_id);
|
||||
END IF;
|
||||
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_embedding_input,
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_exists
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'GENERALIZED_QUESTION_PATTERN'
|
||||
AND source_case_id = 'PAT-' || source_row.source_case_id;
|
||||
|
||||
IF v_exists = 0 THEN
|
||||
INSERT INTO sg_qa_vector_example (
|
||||
question, answer_sql, answer_text, embedding_input, embedding, embedding_model,
|
||||
reference_status, reference_kind, target_type, object_role,
|
||||
inspection_status, inspection_note, verified_at, verified_by,
|
||||
source_case_id, source_type
|
||||
) VALUES (
|
||||
v_pattern_question,
|
||||
v_pattern_sql,
|
||||
'Question-specific generalized Few-shot. Structural only: it contains no customer game, date, result, or executable answer. First decide whether this pattern is applicable; then apply the authoritative NONE/SINGLE/MULTI/ALL game plan and replace placeholders from current metadata.',
|
||||
v_embedding_input,
|
||||
v_embedding,
|
||||
'cohere.embed-v4.0',
|
||||
'APPROVED', 'SQL_TEMPLATE', 'ANY', v_object_role,
|
||||
'VERIFIED',
|
||||
'Derived from a customer QA structure after game/date/result/object leakage validation; runtime uses this generalized pattern only.',
|
||||
SYSTIMESTAMP, 'SGMP_POC_PATTERN_REVIEW',
|
||||
'PAT-' || source_row.source_case_id, 'GENERALIZED_QUESTION_PATTERN'
|
||||
);
|
||||
ELSE
|
||||
UPDATE sg_qa_vector_example
|
||||
SET question = v_pattern_question,
|
||||
answer_sql = v_pattern_sql,
|
||||
answer_text = 'Question-specific generalized Few-shot. Structural only: it contains no customer game, date, result, or executable answer. First decide whether this pattern is applicable; then apply the authoritative NONE/SINGLE/MULTI/ALL game plan and replace placeholders from current metadata.',
|
||||
embedding_input = v_embedding_input,
|
||||
embedding = v_embedding,
|
||||
object_role = v_object_role,
|
||||
reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Derived from a customer QA structure after game/date/result/object leakage validation; runtime uses this generalized pattern only.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_PATTERN_REVIEW'
|
||||
WHERE source_type = 'GENERALIZED_QUESTION_PATTERN'
|
||||
AND source_case_id = 'PAT-' || source_row.source_case_id;
|
||||
END IF;
|
||||
END LOOP;
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT source_type, reference_status, COUNT(*) AS example_count
|
||||
FROM sg_qa_vector_example
|
||||
GROUP BY source_type, reference_status
|
||||
ORDER BY source_type, reference_status;
|
||||
@@ -0,0 +1,358 @@
|
||||
-- Generate one reusable, question-specific Few-shot pattern per customer QA
|
||||
-- benchmark without promoting the benchmark answer itself. Game identity is
|
||||
-- deliberately not inferred here: sg_game_query_plan owns that through OCI
|
||||
-- GenAI chat + the current game catalog.
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_genai_generalize_pattern(
|
||||
p_question IN CLOB,
|
||||
p_answer_sql IN CLOB,
|
||||
p_target_type IN VARCHAR2
|
||||
) RETURN CLOB AUTHID DEFINER
|
||||
IS
|
||||
v_prompt CLOB;
|
||||
v_result CLOB;
|
||||
BEGIN
|
||||
v_prompt :=
|
||||
'Create one reusable, question-specific Few-shot SQL pattern from the source example. '
|
||||
|| 'This is training guidance, never an answer key. Return exactly these tagged sections and nothing else: '
|
||||
|| '[[PATTERN_QUESTION]], [[STRUCTURAL_SQL_PATTERN]], [[OBJECT_ROLE]], [[TARGET_TYPE]], '
|
||||
|| '[[APPLICABILITY]], [[END]]. '
|
||||
|| 'Preserve only the query intent and structural operations such as aggregation, joins, '
|
||||
|| 'grouping, ordering, date semantics, and filters. Replace every game name, alias, game ID, '
|
||||
|| 'schema name, physical object name, column name, literal date, literal number, user ID, '
|
||||
|| 'currency amount, and expected output with semantic placeholders such as <GAME_SCOPE>, '
|
||||
|| '<LOGICAL_FACT>, <LOGICAL_DIMENSION>, <METRIC>, <AS_OF_DATE>, <FILTER>, and <GROUPING>. '
|
||||
|| 'In STRUCTURAL_SQL_PATTERN, every non-SQL identifier must be an angle-bracket placeholder: '
|
||||
|| 'do not retain any source column, alias, table, schema, literal, code, or business value. '
|
||||
|| 'Do not include executable SQL. Do not include a game name or a customer answer. '
|
||||
|| 'The current game scope is supplied separately at runtime by a database OCI GenAI chat '
|
||||
|| 'resolver, therefore never choose or imply a game. The TARGET_TYPE section must be one of NONE, '
|
||||
|| 'SINGLE, MULTI, ALL, ANY and must describe applicability, not a game identity. '
|
||||
|| 'Source target type from the current resolver: ' || NVL(p_target_type, 'ANY') || CHR(10)
|
||||
|| 'Source question:' || CHR(10) || DBMS_LOB.SUBSTR(p_question, 4000, 1) || CHR(10)
|
||||
|| 'Source SQL (structure only; do not copy identifiers or values):' || CHR(10)
|
||||
|| DBMS_LOB.SUBSTR(p_answer_sql, 12000, 1);
|
||||
v_result := DBMS_CLOUD_AI.GENERATE(
|
||||
prompt => v_prompt,
|
||||
profile_name => 'SGMP_POC_OCI_GPT54MINI',
|
||||
action => 'chat'
|
||||
);
|
||||
RETURN v_result;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_genai_validate_pattern(
|
||||
p_pattern_json IN CLOB
|
||||
) RETURN CLOB AUTHID DEFINER
|
||||
IS
|
||||
v_prompt CLOB;
|
||||
v_result CLOB;
|
||||
BEGIN
|
||||
v_prompt :=
|
||||
'Inspect only concrete-answer leakage in this reusable Few-shot pattern. Return exactly '
|
||||
|| '[[CONCRETE_LEAKAGE]] YES or NO, then [[REASON]] and a short reason, then [[END]]. '
|
||||
|| 'Return YES only when a customer answer, concrete game identity, physical schema/table/column '
|
||||
|| 'identifier, literal date, literal business result, or executable SQL against a real object remains. '
|
||||
|| 'Return NO when all such references are semantic angle-bracket placeholders. A pseudo-SQL pattern '
|
||||
|| 'using SELECT/FROM/JOIN/GROUP BY, generic game-scope checks, EXISTS, UNION, or equality with '
|
||||
|| 'angle-bracket placeholders is not concrete leakage and must return NO. Do not judge usefulness or '
|
||||
|| 'completeness; classify leakage only. '
|
||||
|| 'Candidate:' || CHR(10) || DBMS_LOB.SUBSTR(p_pattern_json, 16000, 1);
|
||||
v_result := DBMS_CLOUD_AI.GENERATE(
|
||||
prompt => v_prompt,
|
||||
profile_name => 'SGMP_POC_OCI_GPT54MINI',
|
||||
action => 'chat'
|
||||
);
|
||||
RETURN v_result;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_generate_generalized_patterns
|
||||
RETURN NUMBER AUTHID DEFINER
|
||||
IS
|
||||
PRAGMA AUTONOMOUS_TRANSACTION;
|
||||
v_plan_raw CLOB;
|
||||
v_plan JSON_OBJECT_T;
|
||||
v_target_type VARCHAR2(16);
|
||||
v_pattern_raw CLOB;
|
||||
v_validation_raw CLOB;
|
||||
v_status VARCHAR2(16);
|
||||
v_validation_note CLOB;
|
||||
v_question CLOB;
|
||||
v_sql_pattern CLOB;
|
||||
v_answer_text CLOB;
|
||||
v_object_role VARCHAR2(64);
|
||||
v_embedding_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
v_count NUMBER := 0;
|
||||
|
||||
FUNCTION parse_json_result(p_value CLOB) RETURN JSON_OBJECT_T IS
|
||||
v_text CLOB := TRIM(p_value);
|
||||
BEGIN
|
||||
IF DBMS_LOB.SUBSTR(v_text, 7, 1) = '```json' THEN
|
||||
v_text := REGEXP_REPLACE(v_text, '^```json[[:space:]]*', '');
|
||||
v_text := REGEXP_REPLACE(v_text, '[[:space:]]*```[[:space:]]*$', '');
|
||||
ELSIF DBMS_LOB.SUBSTR(v_text, 3, 1) = '```' THEN
|
||||
v_text := REGEXP_REPLACE(v_text, '^```[[:space:]]*', '');
|
||||
v_text := REGEXP_REPLACE(v_text, '[[:space:]]*```[[:space:]]*$', '');
|
||||
END IF;
|
||||
RETURN JSON_OBJECT_T.parse(v_text);
|
||||
END;
|
||||
|
||||
FUNCTION section_value(
|
||||
p_raw IN CLOB, p_start_tag IN VARCHAR2, p_end_tag IN VARCHAR2
|
||||
) RETURN CLOB IS
|
||||
v_start PLS_INTEGER;
|
||||
v_end PLS_INTEGER;
|
||||
BEGIN
|
||||
v_start := DBMS_LOB.INSTR(p_raw, p_start_tag, 1, 1);
|
||||
IF v_start = 0 THEN
|
||||
RAISE_APPLICATION_ERROR(-20071, 'OCI GenAI response is missing ' || p_start_tag);
|
||||
END IF;
|
||||
v_start := v_start + LENGTH(p_start_tag);
|
||||
v_end := DBMS_LOB.INSTR(p_raw, p_end_tag, v_start, 1);
|
||||
IF v_end = 0 OR v_end <= v_start THEN
|
||||
RAISE_APPLICATION_ERROR(-20072, 'OCI GenAI response is missing ' || p_end_tag);
|
||||
END IF;
|
||||
RETURN TRIM(DBMS_LOB.SUBSTR(p_raw, LEAST(v_end - v_start, 32767), v_start));
|
||||
END;
|
||||
|
||||
PROCEDURE upsert_pattern(
|
||||
p_case_id IN VARCHAR2,
|
||||
p_status IN VARCHAR2,
|
||||
p_note IN CLOB
|
||||
) IS
|
||||
BEGIN
|
||||
UPDATE sg_qa_vector_example
|
||||
SET question = v_question,
|
||||
answer_sql = v_sql_pattern,
|
||||
answer_text = v_answer_text,
|
||||
embedding_input = v_embedding_input,
|
||||
embedding = v_embedding,
|
||||
embedding_model = 'cohere.embed-v4.0',
|
||||
reference_status = p_status,
|
||||
reference_kind = 'SQL_PATTERN',
|
||||
target_type = v_target_type,
|
||||
object_role = v_object_role,
|
||||
inspection_status = CASE WHEN p_status = 'APPROVED' THEN 'GENAI_VERIFIED' ELSE 'GENAI_REJECTED' END,
|
||||
inspection_note = p_note,
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_OCI_GENAI_PATTERN'
|
||||
WHERE source_type = 'GENERALIZED_QUESTION_PATTERN'
|
||||
AND source_case_id = 'PAT-' || p_case_id;
|
||||
|
||||
IF SQL%ROWCOUNT = 0 THEN
|
||||
INSERT INTO sg_qa_vector_example (
|
||||
question, answer_sql, answer_text, embedding_input, embedding, embedding_model,
|
||||
reference_status, reference_kind, target_type, object_role, inspection_status,
|
||||
inspection_note, verified_at, verified_by, source_case_id, source_type
|
||||
) VALUES (
|
||||
v_question, v_sql_pattern, v_answer_text, v_embedding_input, v_embedding, 'cohere.embed-v4.0',
|
||||
p_status, 'SQL_PATTERN', v_target_type, v_object_role,
|
||||
CASE WHEN p_status = 'APPROVED' THEN 'GENAI_VERIFIED' ELSE 'GENAI_REJECTED' END,
|
||||
p_note, SYSTIMESTAMP, 'SGMP_POC_OCI_GENAI_PATTERN',
|
||||
'PAT-' || p_case_id, 'GENERALIZED_QUESTION_PATTERN'
|
||||
);
|
||||
END IF;
|
||||
END;
|
||||
BEGIN
|
||||
FOR source_row IN (
|
||||
SELECT source.source_case_id, source.question, source.answer_sql
|
||||
FROM sg_qa_vector_example source
|
||||
WHERE source.source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sg_qa_vector_example pattern
|
||||
WHERE pattern.source_type = 'GENERALIZED_QUESTION_PATTERN'
|
||||
AND pattern.source_case_id = 'PAT-' || source.source_case_id
|
||||
AND pattern.reference_status = 'APPROVED'
|
||||
)
|
||||
ORDER BY source_case_id
|
||||
) LOOP
|
||||
BEGIN
|
||||
-- The target category comes from the existing OCI GenAI game resolver;
|
||||
-- no alias, prefix, table, or name is transformed in this migration.
|
||||
v_plan_raw := sg_game_query_plan(source_row.question, 5);
|
||||
v_plan := parse_json_result(v_plan_raw);
|
||||
v_target_type := UPPER(NVL(v_plan.get_string('targetType'), 'ANY'));
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL') THEN
|
||||
v_target_type := 'ANY';
|
||||
END IF;
|
||||
|
||||
v_pattern_raw := sg_qa_genai_generalize_pattern(
|
||||
source_row.question, source_row.answer_sql, v_target_type
|
||||
);
|
||||
v_question := section_value(v_pattern_raw, '[[PATTERN_QUESTION]]', '[[STRUCTURAL_SQL_PATTERN]]');
|
||||
v_sql_pattern := section_value(v_pattern_raw, '[[STRUCTURAL_SQL_PATTERN]]', '[[OBJECT_ROLE]]');
|
||||
v_object_role := SUBSTR(section_value(v_pattern_raw, '[[OBJECT_ROLE]]', '[[TARGET_TYPE]]'), 1, 64);
|
||||
IF section_value(v_pattern_raw, '[[TARGET_TYPE]]', '[[APPLICABILITY]]')
|
||||
IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
v_target_type := section_value(v_pattern_raw, '[[TARGET_TYPE]]', '[[APPLICABILITY]]');
|
||||
END IF;
|
||||
v_answer_text := TO_CLOB('Generalized, question-specific structural pattern. '
|
||||
|| 'Current game scope must be supplied only by sg_game_query_plan. Applicability: ')
|
||||
|| section_value(v_pattern_raw, '[[APPLICABILITY]]', '[[END]]');
|
||||
v_embedding_input := TO_CLOB('Question-specific generalized Few-shot pattern:' || CHR(10))
|
||||
|| v_question || CHR(10) || 'Logical role: ' || v_object_role || CHR(10)
|
||||
|| 'Structural SQL pattern:' || CHR(10) || v_sql_pattern;
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_embedding_input, JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
v_validation_raw := sg_qa_genai_validate_pattern(v_pattern_raw);
|
||||
v_status := CASE
|
||||
WHEN REGEXP_SUBSTR(
|
||||
UPPER(section_value(v_validation_raw, '[[CONCRETE_LEAKAGE]]', '[[REASON]]')),
|
||||
'[A-Z]+'
|
||||
) = 'NO'
|
||||
THEN 'APPROVE'
|
||||
ELSE 'REJECT'
|
||||
END;
|
||||
v_validation_note := section_value(v_validation_raw, '[[REASON]]', '[[END]]');
|
||||
|
||||
IF v_status = 'APPROVE' THEN
|
||||
upsert_pattern(source_row.source_case_id, 'APPROVED',
|
||||
'ADB OCI GenAI generated and independently validated a generalized pattern. '
|
||||
|| 'The original customer QA remains evaluation-only. ' || v_validation_note);
|
||||
v_count := v_count + 1;
|
||||
ELSE
|
||||
upsert_pattern(source_row.source_case_id, 'DRAFT',
|
||||
'ADB OCI GenAI rejected the generalized pattern: ' || v_validation_note);
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
-- Persist an auditable non-runtime draft and continue with the other
|
||||
-- customer questions; one malformed LLM response must not block all 47.
|
||||
v_question := source_row.question;
|
||||
v_sql_pattern := TO_CLOB('<PATTERN_GENERATION_FAILED>');
|
||||
v_answer_text := TO_CLOB('No runtime Few-shot pattern: OCI GenAI generalization failed.');
|
||||
v_object_role := 'UNSPECIFIED';
|
||||
v_target_type := 'ANY';
|
||||
v_embedding_input := TO_CLOB('Failed generalized pattern: ') || source_row.question;
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_embedding_input, JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
upsert_pattern(source_row.source_case_id, 'DRAFT',
|
||||
'OCI GenAI pattern generation error: ' || SQLERRM);
|
||||
END;
|
||||
END LOOP;
|
||||
COMMIT;
|
||||
RETURN v_count;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
ROLLBACK;
|
||||
RAISE;
|
||||
END;
|
||||
/
|
||||
|
||||
-- Re-run only the independent OCI Chat safety review after its policy changes.
|
||||
-- It never reads a customer benchmark and never changes the generated pattern.
|
||||
CREATE OR REPLACE FUNCTION sg_qa_revalidate_generalized_patterns
|
||||
RETURN NUMBER AUTHID DEFINER
|
||||
IS
|
||||
PRAGMA AUTONOMOUS_TRANSACTION;
|
||||
v_raw CLOB;
|
||||
v_status VARCHAR2(16);
|
||||
v_reason CLOB;
|
||||
v_start PLS_INTEGER;
|
||||
v_end PLS_INTEGER;
|
||||
v_count NUMBER := 0;
|
||||
|
||||
FUNCTION section_value(
|
||||
p_raw IN CLOB, p_start_tag IN VARCHAR2, p_end_tag IN VARCHAR2
|
||||
) RETURN CLOB IS
|
||||
v_from PLS_INTEGER;
|
||||
v_to PLS_INTEGER;
|
||||
BEGIN
|
||||
v_from := DBMS_LOB.INSTR(p_raw, p_start_tag, 1, 1);
|
||||
IF v_from = 0 THEN RAISE_APPLICATION_ERROR(-20073, 'Missing ' || p_start_tag); END IF;
|
||||
v_from := v_from + LENGTH(p_start_tag);
|
||||
v_to := DBMS_LOB.INSTR(p_raw, p_end_tag, v_from, 1);
|
||||
IF v_to = 0 OR v_to <= v_from THEN RAISE_APPLICATION_ERROR(-20074, 'Missing ' || p_end_tag); END IF;
|
||||
RETURN TRIM(DBMS_LOB.SUBSTR(p_raw, LEAST(v_to - v_from, 32767), v_from));
|
||||
END;
|
||||
BEGIN
|
||||
FOR item IN (
|
||||
SELECT example_id, question, answer_sql, answer_text
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'GENERALIZED_QUESTION_PATTERN'
|
||||
ORDER BY source_case_id
|
||||
) LOOP
|
||||
BEGIN
|
||||
v_raw := sg_qa_genai_validate_pattern(
|
||||
TO_CLOB('[[PATTERN_QUESTION]]') || item.question
|
||||
|| TO_CLOB(CHR(10) || '[[STRUCTURAL_SQL_PATTERN]]') || item.answer_sql
|
||||
|| TO_CLOB(CHR(10) || '[[APPLICABILITY]]') || item.answer_text || CHR(10) || '[[END]]'
|
||||
);
|
||||
v_status := CASE
|
||||
WHEN REGEXP_SUBSTR(
|
||||
UPPER(section_value(v_raw, '[[CONCRETE_LEAKAGE]]', '[[REASON]]')),
|
||||
'[A-Z]+'
|
||||
) = 'NO'
|
||||
THEN 'APPROVE'
|
||||
ELSE 'REJECT'
|
||||
END;
|
||||
v_reason := section_value(v_raw, '[[REASON]]', '[[END]]');
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = CASE WHEN v_status = 'APPROVE' THEN 'APPROVED' ELSE 'DRAFT' END,
|
||||
inspection_status = CASE WHEN v_status = 'APPROVE' THEN 'GENAI_VERIFIED' ELSE 'GENAI_REJECTED' END,
|
||||
inspection_note = 'ADB OCI GenAI independent revalidation: ' || v_reason,
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_OCI_GENAI_PATTERN'
|
||||
WHERE example_id = item.example_id;
|
||||
IF v_status = 'APPROVE' THEN v_count := v_count + 1; END IF;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_reason := TO_CLOB('OCI GenAI revalidation error: ' || SQLERRM);
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'DRAFT',
|
||||
inspection_status = 'GENAI_REJECTED',
|
||||
inspection_note = v_reason,
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_OCI_GENAI_PATTERN'
|
||||
WHERE example_id = item.example_id;
|
||||
END;
|
||||
END LOOP;
|
||||
COMMIT;
|
||||
RETURN v_count;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
ROLLBACK;
|
||||
RAISE;
|
||||
END;
|
||||
/
|
||||
|
||||
-- Production retrieval accepts only independently generalized patterns or
|
||||
-- policy templates. Customer QA benchmarks remain evaluation-only forever.
|
||||
CREATE OR REPLACE FUNCTION sg_qa_vector_search(
|
||||
p_question IN CLOB,
|
||||
p_top_k IN PLS_INTEGER DEFAULT 3,
|
||||
p_target_type IN VARCHAR2 DEFAULT 'ANY'
|
||||
) RETURN SYS_REFCURSOR AUTHID DEFINER
|
||||
IS
|
||||
v_query_vector VECTOR;
|
||||
v_results SYS_REFCURSOR;
|
||||
v_target_type VARCHAR2(16) := UPPER(TRIM(NVL(p_target_type, 'ANY')));
|
||||
BEGIN
|
||||
IF p_question IS NULL THEN RAISE_APPLICATION_ERROR(-20003, 'question is required.'); END IF;
|
||||
IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
|
||||
RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
|
||||
END IF;
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
RAISE_APPLICATION_ERROR(-20005, 'invalid target type.');
|
||||
END IF;
|
||||
v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
p_question, JSON(sg_qa_vector_params('search_query'))
|
||||
);
|
||||
OPEN v_results FOR
|
||||
SELECT example_id, question, answer_sql, answer_text, embedding_model,
|
||||
reference_kind, target_type, object_role, source_case_id, source_type,
|
||||
vector_distance(embedding, v_query_vector, COSINE) AS cosine_distance
|
||||
FROM sg_qa_vector_example
|
||||
WHERE reference_status = 'APPROVED'
|
||||
AND source_type IN ('GENERALIZED_QUESTION_PATTERN', 'POLICY_TEMPLATE')
|
||||
AND (target_type = 'ANY' OR v_target_type = 'ANY' OR target_type = v_target_type)
|
||||
ORDER BY vector_distance(embedding, v_query_vector, COSINE), example_id
|
||||
FETCH FIRST p_top_k ROWS ONLY;
|
||||
RETURN v_results;
|
||||
END;
|
||||
/
|
||||
9
database/adb/110_sg_game_query_plan_admin_grants.sql
Normal file
9
database/adb/110_sg_game_query_plan_admin_grants.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
-- The MCP DB account owns the OCI GenAI planning functions while the game
|
||||
-- catalog is owned by the data schema. Definer-rights PL/SQL needs direct
|
||||
-- object grants; role grants are not sufficient at compile time.
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'GRANT SELECT ON SGMP_POC.SG_GAME_CATALOG TO ADMIN';
|
||||
EXECUTE IMMEDIATE 'GRANT SELECT ON SGMP_POC.COMN_GAME_ALIAS_BAS TO ADMIN';
|
||||
EXECUTE IMMEDIATE 'GRANT EXECUTE ON SGMP_POC.SG_GAME_CATALOG_SEARCH TO ADMIN';
|
||||
END;
|
||||
/
|
||||
148
database/adb/111_sg_game_daily_au_lookup.sql
Normal file
148
database/adb/111_sg_game_daily_au_lookup.sql
Normal file
@@ -0,0 +1,148 @@
|
||||
-- Deterministic daily-AU lookup for an already resolved game query plan.
|
||||
-- Physical user-master objects are selected only from SG_GAME_CATALOG.
|
||||
-- No game name, alias, prefix, or object name is embedded in this function.
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_game_daily_au_lookup(
|
||||
p_query_plan IN CLOB,
|
||||
p_base_date IN DATE DEFAULT NULL
|
||||
) RETURN CLOB AUTHID DEFINER IS
|
||||
v_plan JSON_OBJECT_T;
|
||||
v_targets JSON_ARRAY_T;
|
||||
v_target JSON_OBJECT_T;
|
||||
v_result JSON_OBJECT_T := JSON_OBJECT_T();
|
||||
v_items JSON_ARRAY_T := JSON_ARRAY_T();
|
||||
v_item JSON_OBJECT_T;
|
||||
v_game_key VARCHAR2(128);
|
||||
v_game_id VARCHAR2(128);
|
||||
v_game_name VARCHAR2(512);
|
||||
v_object_name VARCHAR2(128);
|
||||
v_safe_object_name VARCHAR2(128);
|
||||
v_effective_date DATE;
|
||||
v_au_count NUMBER;
|
||||
v_column_count PLS_INTEGER;
|
||||
v_object_count PLS_INTEGER;
|
||||
v_seen SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST();
|
||||
v_target_count PLS_INTEGER := 0;
|
||||
|
||||
FUNCTION is_seen(p_game_key IN VARCHAR2) RETURN BOOLEAN IS
|
||||
BEGIN
|
||||
FOR i IN 1 .. v_seen.COUNT LOOP
|
||||
IF v_seen(i) = p_game_key THEN
|
||||
RETURN TRUE;
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN FALSE;
|
||||
END;
|
||||
|
||||
PROCEDURE add_status(
|
||||
p_game_key IN VARCHAR2,
|
||||
p_status IN VARCHAR2,
|
||||
p_reason IN VARCHAR2
|
||||
) IS
|
||||
BEGIN
|
||||
v_item := JSON_OBJECT_T();
|
||||
v_item.put('gameKey', p_game_key);
|
||||
v_item.put('status', p_status);
|
||||
v_item.put('reason', p_reason);
|
||||
v_items.append(v_item);
|
||||
END;
|
||||
BEGIN
|
||||
IF p_query_plan IS NULL THEN
|
||||
RAISE_APPLICATION_ERROR(-20001, 'queryPlan is required');
|
||||
END IF;
|
||||
|
||||
v_plan := JSON_OBJECT_T.parse(p_query_plan);
|
||||
v_targets := v_plan.get_array('dataEligibleTargets');
|
||||
IF v_targets IS NULL THEN
|
||||
v_targets := v_plan.get_array('targets');
|
||||
END IF;
|
||||
|
||||
IF v_targets IS NOT NULL AND v_targets.get_size > 0 THEN
|
||||
FOR i IN 0 .. v_targets.get_size - 1 LOOP
|
||||
v_target := TREAT(v_targets.get(i) AS JSON_OBJECT_T);
|
||||
IF v_target IS NULL OR NOT v_target.has('gameKey') THEN
|
||||
CONTINUE;
|
||||
END IF;
|
||||
v_game_key := v_target.get_string('gameKey');
|
||||
IF v_game_key IS NULL OR is_seen(v_game_key) THEN
|
||||
CONTINUE;
|
||||
END IF;
|
||||
v_seen.EXTEND;
|
||||
v_seen(v_seen.COUNT) := v_game_key;
|
||||
v_target_count := v_target_count + 1;
|
||||
|
||||
BEGIN
|
||||
SELECT game_id, game_nm, user_master_object_name
|
||||
INTO v_game_id, v_game_name, v_object_name
|
||||
FROM sg_game_catalog
|
||||
WHERE game_key = v_game_key
|
||||
AND active_yn = 'Y';
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
add_status(v_game_key, 'UNAVAILABLE', 'Catalog target is not active.');
|
||||
CONTINUE;
|
||||
END;
|
||||
|
||||
IF v_object_name IS NULL THEN
|
||||
add_status(v_game_key, 'UNAVAILABLE', 'No approved user-master object is registered.');
|
||||
CONTINUE;
|
||||
END IF;
|
||||
|
||||
v_safe_object_name := DBMS_ASSERT.SIMPLE_SQL_NAME(UPPER(v_object_name));
|
||||
SELECT COUNT(*) INTO v_object_count
|
||||
FROM user_objects
|
||||
WHERE object_name = v_safe_object_name
|
||||
AND object_type IN ('TABLE', 'VIEW', 'MATERIALIZED VIEW')
|
||||
AND status = 'VALID';
|
||||
SELECT COUNT(*) INTO v_column_count
|
||||
FROM user_tab_columns
|
||||
WHERE table_name = v_safe_object_name
|
||||
AND column_name IN ('GUID', 'BASE_DT', 'AU_FLAG', 'EXPT_USER_YN');
|
||||
IF v_object_count = 0 OR v_column_count <> 4 THEN
|
||||
add_status(v_game_key, 'UNAVAILABLE', 'Approved user-master object is not query-ready.');
|
||||
CONTINUE;
|
||||
END IF;
|
||||
|
||||
IF p_base_date IS NULL THEN
|
||||
EXECUTE IMMEDIATE 'SELECT MAX(BASE_DT) FROM ' || v_safe_object_name
|
||||
INTO v_effective_date;
|
||||
ELSE
|
||||
v_effective_date := TRUNC(p_base_date);
|
||||
END IF;
|
||||
IF v_effective_date IS NULL THEN
|
||||
add_status(v_game_key, 'NO_DATA', 'No available base date in the selected object.');
|
||||
CONTINUE;
|
||||
END IF;
|
||||
|
||||
EXECUTE IMMEDIATE
|
||||
'SELECT COUNT(DISTINCT GUID) FROM ' || v_safe_object_name
|
||||
|| ' WHERE BASE_DT = :1 AND AU_FLAG = 1 AND EXPT_USER_YN = ''N'''
|
||||
INTO v_au_count USING v_effective_date;
|
||||
|
||||
v_item := JSON_OBJECT_T();
|
||||
v_item.put('gameKey', v_game_key);
|
||||
v_item.put('gameId', v_game_id);
|
||||
v_item.put('gameName', v_game_name);
|
||||
v_item.put('objectName', v_safe_object_name);
|
||||
v_item.put('baseDate', TO_CHAR(v_effective_date, 'YYYY-MM-DD'));
|
||||
v_item.put('auCount', v_au_count);
|
||||
v_item.put('status', 'READY');
|
||||
v_item.put('sqlTemplate',
|
||||
'SELECT COUNT(DISTINCT GUID) AS AU_COUNT FROM <catalog_user_master_object> '
|
||||
|| 'WHERE BASE_DT = :baseDate AND AU_FLAG = 1 AND EXPT_USER_YN = ''N''');
|
||||
v_items.append(v_item);
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
v_result.put('status', CASE WHEN v_target_count = 0 THEN 'NO_GAME_TARGET' ELSE 'GAME_AU_LOOKUP' END);
|
||||
v_result.put('targetType', NVL(v_plan.get_string('targetType'), 'NONE'));
|
||||
IF p_base_date IS NULL THEN
|
||||
v_result.put_null('requestedBaseDate');
|
||||
ELSE
|
||||
v_result.put('requestedBaseDate', TO_CHAR(TRUNC(p_base_date), 'YYYY-MM-DD'));
|
||||
END IF;
|
||||
v_result.put('targetCount', v_target_count);
|
||||
v_result.put('items', v_items);
|
||||
RETURN v_result.to_clob;
|
||||
END;
|
||||
/
|
||||
@@ -24,9 +24,33 @@ USING (
|
||||
CAST(NULL AS VARCHAR2(4000)) AS text_value,
|
||||
'Maximum cosine distance for accepting the closest independently embedded game alias.' AS description
|
||||
FROM dual
|
||||
UNION ALL
|
||||
SELECT 'SCOPE_GUIDANCE_NONE', NULL,
|
||||
'{"mode":"GAME_UNSPECIFIED","allowGameScopedObjects":false,"targetExecution":"COMMON_OBJECTS_OR_ZERO_ROW","instruction":"No game was selected. Do not use a game-scoped object. Use only a game-neutral common object when it answers the question; otherwise return a zero-row result."}',
|
||||
'Prompt guidance for a question without a selected game.'
|
||||
FROM dual
|
||||
UNION ALL
|
||||
SELECT 'SCOPE_GUIDANCE_SINGLE', NULL,
|
||||
'{"mode":"EXACT_TARGETS","allowGameScopedObjects":true,"targetExecution":"ONLY_RESOLVED_TARGETS","instruction":"Use only the resolved target in targets. Do not select another game-scoped object."}',
|
||||
'Prompt guidance for exactly one resolved game target.'
|
||||
FROM dual
|
||||
UNION ALL
|
||||
SELECT 'SCOPE_GUIDANCE_MULTI', NULL,
|
||||
'{"mode":"MULTIPLE_TARGETS","allowGameScopedObjects":true,"targetExecution":"ALL_RESOLVED_TARGETS","instruction":"Return results for all resolved available targets. Preserve unresolved targets as unavailable; do not replace them with another game."}',
|
||||
'Prompt guidance for multiple game targets.'
|
||||
FROM dual
|
||||
UNION ALL
|
||||
SELECT 'SCOPE_GUIDANCE_ALL', NULL,
|
||||
'{"mode":"ALL_CATALOG_TARGETS","allowGameScopedObjects":true,"targetExecution":"ALL_AVAILABLE_CATALOG_TARGETS","instruction":"Use all available catalog targets. Do not invent games or game-scoped objects outside the catalog."}',
|
||||
'Prompt guidance for every catalog game.'
|
||||
FROM dual
|
||||
) s
|
||||
ON (t.policy_key = s.policy_key)
|
||||
WHEN MATCHED THEN UPDATE SET
|
||||
t.text_value = CASE
|
||||
WHEN s.policy_key LIKE 'SCOPE_GUIDANCE_%' THEN s.text_value
|
||||
ELSE t.text_value
|
||||
END,
|
||||
t.description = s.description,
|
||||
t.active_yn = 'Y',
|
||||
t.updated_at = SYSTIMESTAMP
|
||||
|
||||
82
database/adb/118_sgmp_qa_vector_quality_threshold.sql
Normal file
82
database/adb/118_sgmp_qa_vector_quality_threshold.sql
Normal file
@@ -0,0 +1,82 @@
|
||||
-- Customer-managed quality floor for runtime Few-shot retrieval.
|
||||
-- Lower cosine distance is more similar. The value is data, not application code.
|
||||
MERGE INTO sg_game_scope_policy t
|
||||
USING (
|
||||
SELECT 'QA_VECTOR_MAX_COSINE_DISTANCE' AS policy_key,
|
||||
0.650000 AS number_value,
|
||||
'Maximum cosine distance accepted for a runtime approved Few-shot example.' AS description
|
||||
FROM dual
|
||||
) s
|
||||
ON (t.policy_key = s.policy_key)
|
||||
WHEN MATCHED THEN UPDATE SET
|
||||
t.number_value = s.number_value,
|
||||
t.description = s.description,
|
||||
t.active_yn = 'Y',
|
||||
t.updated_at = SYSTIMESTAMP
|
||||
WHEN NOT MATCHED THEN INSERT (
|
||||
policy_key, number_value, text_value, description, active_yn
|
||||
) VALUES (
|
||||
s.policy_key, s.number_value, NULL, s.description, 'Y'
|
||||
);
|
||||
/
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_vector_search(
|
||||
p_question IN CLOB,
|
||||
p_top_k IN PLS_INTEGER DEFAULT 3,
|
||||
p_target_type IN VARCHAR2 DEFAULT 'ANY'
|
||||
) RETURN SYS_REFCURSOR AUTHID DEFINER
|
||||
IS
|
||||
v_query_vector VECTOR;
|
||||
v_results SYS_REFCURSOR;
|
||||
v_target_type VARCHAR2(16) := UPPER(TRIM(NVL(p_target_type, 'ANY')));
|
||||
v_max_cosine_distance NUMBER;
|
||||
BEGIN
|
||||
IF p_question IS NULL THEN
|
||||
RAISE_APPLICATION_ERROR(-20003, 'question is required.');
|
||||
END IF;
|
||||
IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
|
||||
RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
|
||||
END IF;
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
RAISE_APPLICATION_ERROR(-20005, 'invalid target type.');
|
||||
END IF;
|
||||
|
||||
SELECT number_value
|
||||
INTO v_max_cosine_distance
|
||||
FROM sg_game_scope_policy
|
||||
WHERE policy_key = 'QA_VECTOR_MAX_COSINE_DISTANCE'
|
||||
AND active_yn = 'Y'
|
||||
AND number_value IS NOT NULL;
|
||||
|
||||
v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
p_question, JSON(sg_qa_vector_params('search_query'))
|
||||
);
|
||||
|
||||
OPEN v_results FOR
|
||||
SELECT example_id, question, answer_sql, answer_text, embedding_model,
|
||||
reference_kind, target_type, object_role, source_case_id, source_type,
|
||||
cosine_distance
|
||||
FROM (
|
||||
SELECT example_id, question, answer_sql, answer_text, embedding_model,
|
||||
reference_kind, target_type, object_role, source_case_id, source_type,
|
||||
VECTOR_DISTANCE(embedding, v_query_vector, COSINE) AS cosine_distance
|
||||
FROM sg_qa_vector_example
|
||||
WHERE reference_status = 'APPROVED'
|
||||
-- A generated structural pattern is review material, not a runtime
|
||||
-- Few-shot. Runtime examples must have human verification and an
|
||||
-- executable SQL body rather than unresolved logical placeholders.
|
||||
AND inspection_status = 'VERIFIED'
|
||||
AND answer_sql IS NOT NULL
|
||||
AND NOT REGEXP_LIKE(answer_sql, '<[A-Z][A-Z0-9_]*>', 'i')
|
||||
AND (target_type = 'ANY' OR v_target_type = 'ANY' OR target_type = v_target_type)
|
||||
)
|
||||
WHERE cosine_distance <= v_max_cosine_distance
|
||||
ORDER BY cosine_distance, example_id
|
||||
FETCH FIRST p_top_k ROWS ONLY;
|
||||
RETURN v_results;
|
||||
END;
|
||||
/
|
||||
|
||||
COMMENT ON TABLE sg_game_scope_policy IS
|
||||
'Customer-managed game scope and runtime retrieval policy values; changing a value requires no application deployment.';
|
||||
/
|
||||
38
database/adb/119_sgmp_remove_invalid_std12_fewshot.sql
Normal file
38
database/adb/119_sgmp_remove_invalid_std12_fewshot.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
-- STD-12 is a multi-target orchestration case, not a reusable SQL few-shot.
|
||||
-- Preserve SG_AI_QA_QUESTION as the customer benchmark; remove only its
|
||||
-- invalid vector-example row so it cannot be managed as a few-shot.
|
||||
|
||||
DECLARE
|
||||
v_count PLS_INTEGER;
|
||||
BEGIN
|
||||
SELECT COUNT(*)
|
||||
INTO v_count
|
||||
FROM sg_qa_vector_example
|
||||
WHERE example_id = 51
|
||||
AND source_case_id = 'STD-12'
|
||||
AND source_type = 'CUSTOMER_QA_BENCHMARK';
|
||||
|
||||
IF v_count <> 1 THEN
|
||||
RAISE_APPLICATION_ERROR(-20051, 'Expected exactly one invalid STD-12 few-shot row.');
|
||||
END IF;
|
||||
|
||||
DELETE FROM sg_qa_vector_example
|
||||
WHERE example_id = 51
|
||||
AND source_case_id = 'STD-12'
|
||||
AND source_type = 'CUSTOMER_QA_BENCHMARK';
|
||||
|
||||
IF SQL%ROWCOUNT <> 1 THEN
|
||||
RAISE_APPLICATION_ERROR(-20052, 'Invalid STD-12 few-shot row was not deleted.');
|
||||
END IF;
|
||||
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT COUNT(*) AS remaining_fewshot_rows
|
||||
FROM sg_qa_vector_example
|
||||
WHERE example_id = 51;
|
||||
|
||||
SELECT COUNT(*) AS preserved_question_rows
|
||||
FROM sg_ai_qa_question
|
||||
WHERE question_code = 'STD-12';
|
||||
84
database/adb/121_sg_game_catalog_identity_duality_view.sql
Normal file
84
database/adb/121_sg_game_catalog_identity_duality_view.sql
Normal file
@@ -0,0 +1,84 @@
|
||||
-- One DB-owned JSON identity document per game. No game value is hardcoded.
|
||||
-- The relational alias child makes aliases a nested Duality View array.
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE q'[
|
||||
CREATE TABLE sg_game_catalog_identity_alias (
|
||||
game_key VARCHAR2(128) NOT NULL,
|
||||
alias_value VARCHAR2(512) NOT NULL,
|
||||
CONSTRAINT sg_game_catalog_identity_alias_pk PRIMARY KEY (game_key, alias_value),
|
||||
CONSTRAINT sg_game_catalog_identity_alias_fk FOREIGN KEY (game_key)
|
||||
REFERENCES sg_game_catalog (game_key)
|
||||
)]';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -955 THEN RAISE; END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
MERGE INTO sg_game_catalog_identity_alias target
|
||||
USING (
|
||||
SELECT c.game_key, aliases.alias_value
|
||||
FROM sg_game_catalog c,
|
||||
JSON_TABLE(
|
||||
c.aliases_json,
|
||||
'$[*]' COLUMNS (alias_value VARCHAR2(512) PATH '$')
|
||||
) aliases
|
||||
WHERE c.active_yn = 'Y'
|
||||
) source
|
||||
ON (target.game_key = source.game_key AND target.alias_value = source.alias_value)
|
||||
WHEN NOT MATCHED THEN INSERT (game_key, alias_value)
|
||||
VALUES (source.game_key, source.alias_value);
|
||||
/
|
||||
|
||||
DELETE FROM sg_game_catalog_identity_alias target
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM sg_game_catalog c,
|
||||
JSON_TABLE(
|
||||
c.aliases_json,
|
||||
'$[*]' COLUMNS (alias_value VARCHAR2(512) PATH '$')
|
||||
) aliases
|
||||
WHERE c.game_key = target.game_key
|
||||
AND c.active_yn = 'Y'
|
||||
AND aliases.alias_value = target.alias_value
|
||||
);
|
||||
/
|
||||
|
||||
CREATE OR REPLACE JSON RELATIONAL DUALITY VIEW sg_game_catalog_identity_dv AS
|
||||
SELECT JSON {
|
||||
'_id' : c.game_key,
|
||||
'gameId' : c.game_id,
|
||||
'gamePrefix' : c.game_prefix,
|
||||
'gameName' : c.game_nm,
|
||||
'gameAliases' : [
|
||||
SELECT JSON {
|
||||
'_id' : { 'gameKey' : a.game_key, 'value' : a.alias_value }
|
||||
}
|
||||
FROM sg_game_catalog_identity_alias a
|
||||
WHERE a.game_key = c.game_key
|
||||
]
|
||||
}
|
||||
FROM sg_game_catalog c
|
||||
WHERE c.active_yn = 'Y'
|
||||
WITH CHECK OPTION;
|
||||
/
|
||||
|
||||
-- Serialize the DB JSON document itself before embedding. GAME_ID, GAME_PREFIX,
|
||||
-- names and every alias therefore share one vector search document.
|
||||
UPDATE sg_game_catalog c
|
||||
SET c.embedding = DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
(
|
||||
SELECT JSON_SERIALIZE(d.data RETURNING CLOB)
|
||||
FROM sg_game_catalog_identity_dv d
|
||||
WHERE JSON_VALUE(d.data, '$._id') = c.game_key
|
||||
),
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
),
|
||||
c.updated_at = SYSTIMESTAMP
|
||||
WHERE c.active_yn = 'Y';
|
||||
/
|
||||
|
||||
COMMENT ON TABLE sg_game_catalog_identity_dv IS
|
||||
'DB JSON identity document for each active game; the canonical embedding source for game-name, alias, GAME_ID and GAME_PREFIX resolution.';
|
||||
/
|
||||
144
database/adb/122_sgmp_std18_filtered_sales_aggregate_fewshot.sql
Normal file
144
database/adb/122_sgmp_std18_filtered_sales_aggregate_fewshot.sql
Normal file
@@ -0,0 +1,144 @@
|
||||
-- STD-18 asks for an aggregate over qualifying orders, not an individual
|
||||
-- transaction list. Remove the invalid customer-derived references and keep
|
||||
-- one reusable, data-neutral aggregate pattern for runtime retrieval.
|
||||
|
||||
DELETE FROM sg_qa_vector_example
|
||||
WHERE source_case_id IN ('STD-18', 'PAT-STD-18')
|
||||
AND source_type IN ('CUSTOMER_QA_BENCHMARK', 'GENERALIZED_QUESTION_PATTERN');
|
||||
/
|
||||
|
||||
DECLARE
|
||||
v_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
v_exists NUMBER;
|
||||
BEGIN
|
||||
v_input := TO_CLOB('질문 패턴: 전체 매출에서 금액 조건을 만족하는 주문을 집계해줘.')
|
||||
|| CHR(10) || 'Question pattern: summarize whole-scope sales after a payment amount filter.'
|
||||
|| CHR(10) || 'Logical object role: SALES_TRANSACTION'
|
||||
|| CHR(10) || 'Required result grain: one aggregate row with total sales amount, distinct buyer count, and order count.'
|
||||
|| CHR(10) || 'A reference to orders does not by itself request individual order detail.';
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_input,
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_exists
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'FILTERED_SALES_AGGREGATE';
|
||||
|
||||
IF v_exists = 0 THEN
|
||||
INSERT INTO sg_qa_vector_example (
|
||||
question, answer_sql, answer_text, embedding_input, embedding, embedding_model,
|
||||
reference_status, reference_kind, target_type, object_role,
|
||||
inspection_status, inspection_note, verified_at, verified_by,
|
||||
source_case_id, source_type
|
||||
) VALUES (
|
||||
'전체 매출에서 금액 조건을 만족하는 주문을 집계해줘.',
|
||||
TO_CLOB('SELECT SUM(CAST(s."PAYMT_AMT" AS NUMBER)) AS "TOTAL_SALES_AMOUNT",' || CHR(10)
|
||||
|| ' COUNT(DISTINCT s."GUID") AS "BUYER_COUNT",' || CHR(10)
|
||||
|| ' COUNT(*) AS "ORDER_COUNT"' || CHR(10)
|
||||
|| 'FROM "SGMP_POC"."COMN_SALES_TXN" s' || CHR(10)
|
||||
|| 'WHERE s."PAYMT_DTM" >= <BUSINESS_DATE_START>' || CHR(10)
|
||||
|| ' AND s."PAYMT_DTM" < <BUSINESS_DATE_END>' || CHR(10)
|
||||
|| ' AND CAST(s."PAYMT_AMT" AS NUMBER) <AMOUNT_CONDITION>' || CHR(10)
|
||||
|| ' AND s."EXPT_USER_YN" = ''N'''),
|
||||
'Structural Few-shot: return one aggregate row containing total sales amount, distinct buyer count, and order count after the requested payment-amount filter. Do not return individual orders unless the user explicitly asks for a list or detail rows.',
|
||||
v_input,
|
||||
v_embedding,
|
||||
'cohere.embed-v4.0',
|
||||
'APPROVED', 'SQL_TEMPLATE', 'NONE', 'SALES_TRANSACTION',
|
||||
'VERIFIED',
|
||||
'Reusable whole-scope filtered-sales aggregate. No customer date, amount, game, or expected result is stored.',
|
||||
SYSTIMESTAMP, 'SGMP_POC_METADATA_REVIEW',
|
||||
'FILTERED_SALES_AGGREGATE', 'POLICY_TEMPLATE'
|
||||
);
|
||||
ELSE
|
||||
UPDATE sg_qa_vector_example
|
||||
SET question = '전체 매출에서 금액 조건을 만족하는 주문을 집계해줘.',
|
||||
answer_sql = TO_CLOB('SELECT SUM(CAST(s."PAYMT_AMT" AS NUMBER)) AS "TOTAL_SALES_AMOUNT",' || CHR(10)
|
||||
|| ' COUNT(DISTINCT s."GUID") AS "BUYER_COUNT",' || CHR(10)
|
||||
|| ' COUNT(*) AS "ORDER_COUNT"' || CHR(10)
|
||||
|| 'FROM "SGMP_POC"."COMN_SALES_TXN" s' || CHR(10)
|
||||
|| 'WHERE s."PAYMT_DTM" >= <BUSINESS_DATE_START>' || CHR(10)
|
||||
|| ' AND s."PAYMT_DTM" < <BUSINESS_DATE_END>' || CHR(10)
|
||||
|| ' AND CAST(s."PAYMT_AMT" AS NUMBER) <AMOUNT_CONDITION>' || CHR(10)
|
||||
|| ' AND s."EXPT_USER_YN" = ''N'''),
|
||||
answer_text = 'Structural Few-shot: return one aggregate row containing total sales amount, distinct buyer count, and order count after the requested payment-amount filter. Do not return individual orders unless the user explicitly asks for a list or detail rows.',
|
||||
embedding_input = v_input,
|
||||
embedding = v_embedding,
|
||||
reference_status = 'APPROVED',
|
||||
reference_kind = 'SQL_TEMPLATE',
|
||||
target_type = 'NONE',
|
||||
object_role = 'SALES_TRANSACTION',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Reusable whole-scope filtered-sales aggregate. No customer date, amount, game, or expected result is stored.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'FILTERED_SALES_AGGREGATE';
|
||||
END IF;
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
-- A SQL template is prompt context, never an executable statement. Permit
|
||||
-- reviewed policy templates to retain logical placeholders while continuing
|
||||
-- to require executable SQL for automatically generalized patterns.
|
||||
CREATE OR REPLACE FUNCTION sg_qa_vector_search(
|
||||
p_question IN CLOB,
|
||||
p_top_k IN PLS_INTEGER DEFAULT 3,
|
||||
p_target_type IN VARCHAR2 DEFAULT 'ANY'
|
||||
) RETURN SYS_REFCURSOR AUTHID DEFINER
|
||||
IS
|
||||
v_query_vector VECTOR;
|
||||
v_results SYS_REFCURSOR;
|
||||
v_target_type VARCHAR2(16) := UPPER(TRIM(NVL(p_target_type, 'ANY')));
|
||||
v_max_cosine_distance NUMBER;
|
||||
BEGIN
|
||||
IF p_question IS NULL THEN RAISE_APPLICATION_ERROR(-20003, 'question is required.'); END IF;
|
||||
IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
|
||||
RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
|
||||
END IF;
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
RAISE_APPLICATION_ERROR(-20005, 'invalid target type.');
|
||||
END IF;
|
||||
|
||||
SELECT number_value INTO v_max_cosine_distance
|
||||
FROM sg_game_scope_policy
|
||||
WHERE policy_key = 'QA_VECTOR_MAX_COSINE_DISTANCE'
|
||||
AND active_yn = 'Y'
|
||||
AND number_value IS NOT NULL;
|
||||
|
||||
v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
p_question, JSON(sg_qa_vector_params('search_query'))
|
||||
);
|
||||
|
||||
OPEN v_results FOR
|
||||
SELECT example_id, question, answer_sql, answer_text, embedding_model,
|
||||
reference_kind, target_type, object_role, source_case_id, source_type,
|
||||
cosine_distance
|
||||
FROM (
|
||||
SELECT example_id, question, answer_sql, answer_text, embedding_model,
|
||||
reference_kind, target_type, object_role, source_case_id, source_type,
|
||||
VECTOR_DISTANCE(embedding, v_query_vector, COSINE) AS cosine_distance
|
||||
FROM sg_qa_vector_example
|
||||
WHERE reference_status = 'APPROVED'
|
||||
AND inspection_status = 'VERIFIED'
|
||||
AND answer_sql IS NOT NULL
|
||||
AND (source_type = 'POLICY_TEMPLATE'
|
||||
OR NOT REGEXP_LIKE(answer_sql, '<[A-Z][A-Z0-9_]*>', 'i'))
|
||||
AND (target_type = 'ANY' OR v_target_type = 'ANY' OR target_type = v_target_type)
|
||||
)
|
||||
WHERE cosine_distance <= v_max_cosine_distance
|
||||
ORDER BY cosine_distance, example_id
|
||||
FETCH FIRST p_top_k ROWS ONLY;
|
||||
RETURN v_results;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT example_id, source_case_id, source_type, reference_status, inspection_status
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_case_id IN ('STD-18', 'PAT-STD-18', 'FILTERED_SALES_AGGREGATE')
|
||||
ORDER BY example_id;
|
||||
33
database/adb/123_sgmp_filtered_sales_aggregate_any_scope.sql
Normal file
33
database/adb/123_sgmp_filtered_sales_aggregate_any_scope.sql
Normal file
@@ -0,0 +1,33 @@
|
||||
-- This customer question is game-unscoped. Keep the existing NONE-compatible
|
||||
-- Few-shot path; game_query_plan remains responsible for scope resolution.
|
||||
UPDATE sg_qa_vector_example
|
||||
SET question = '매출에서 금액 조건을 만족하는 주문의 총액, 구매자 수, 주문 수를 집계해줘.',
|
||||
answer_sql = TO_CLOB('SELECT' || CHR(10)
|
||||
|| ' SUM(CAST(s."PAYMT_AMT" AS NUMBER)) AS "TOTAL_SALES_AMOUNT",' || CHR(10)
|
||||
|| ' COUNT(DISTINCT s."GUID") AS "BUYER_COUNT",' || CHR(10)
|
||||
|| ' COUNT(*) AS "ORDER_COUNT"' || CHR(10)
|
||||
|| ' FROM <COMMON_SALES_TRANSACTION> s' || CHR(10)
|
||||
|| ' WHERE s."PAYMT_DTM" >= <BUSINESS_DATE_START>' || CHR(10)
|
||||
|| ' AND s."PAYMT_DTM" < <BUSINESS_DATE_END>' || CHR(10)
|
||||
|| ' AND CAST(s."PAYMT_AMT" AS NUMBER) <AMOUNT_CONDITION>' || CHR(10)
|
||||
|| ' AND s."EXPT_USER_YN" = ''N'''),
|
||||
answer_text = 'Aggregate result-shape reference: return one row with total sales amount, distinct buyer count, and order count. The game plan separately supplies any game scope; use this pattern only when the question is semantically similar.',
|
||||
embedding_input = TO_CLOB('Question pattern: summarize sales after a payment amount condition.' || CHR(10)
|
||||
|| 'Logical object role: SALES_TRANSACTION' || CHR(10)
|
||||
|| 'Result grain: one aggregate row with total sales amount, distinct buyer count, and order count.'),
|
||||
embedding = DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
TO_CLOB('Question pattern: summarize sales after a payment amount condition.' || CHR(10)
|
||||
|| 'Logical object role: SALES_TRANSACTION' || CHR(10)
|
||||
|| 'Result grain: one aggregate row with total sales amount, distinct buyer count, and order count.'),
|
||||
JSON(sg_qa_vector_params('search_document'))),
|
||||
target_type = 'NONE',
|
||||
source_case_id = 'PORTAL-STD-18',
|
||||
inspection_note = 'Generalized aggregate pattern for the current game-unscoped question; game_query_plan controls scope separately.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE example_id = 141
|
||||
AND source_type = 'POLICY_TEMPLATE';
|
||||
/
|
||||
|
||||
COMMIT;
|
||||
/
|
||||
23
database/adb/124_sgmp_std18_expected_answer_fewshot.sql
Normal file
23
database/adb/124_sgmp_std18_expected_answer_fewshot.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- The reviewed customer benchmark answer is part of this Few-shot guidance.
|
||||
-- It clarifies that the requested result is one aggregate row, not detail rows.
|
||||
UPDATE sg_qa_vector_example
|
||||
SET answer_text = TO_CLOB('Expected answer shape: return exactly one aggregate row, not individual order rows.' || CHR(10)
|
||||
|| 'Expected answer:' || CHR(10)
|
||||
|| 'TOTAL_SALES_AMOUNT BUYER_COUNT ORDER_COUNT' || CHR(10)
|
||||
|| '------------------ ----------- -----------' || CHR(10)
|
||||
|| ' 204720 6 6'),
|
||||
embedding_input = TO_CLOB('Question pattern: summarize sales after a payment amount condition.' || CHR(10)
|
||||
|| 'Expected output: TOTAL_SALES_AMOUNT, BUYER_COUNT, ORDER_COUNT as one aggregate row.' || CHR(10)
|
||||
|| 'Expected result example: 204720, 6, 6.'),
|
||||
embedding = DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
TO_CLOB('Question pattern: summarize sales after a payment amount condition.' || CHR(10)
|
||||
|| 'Expected output: TOTAL_SALES_AMOUNT, BUYER_COUNT, ORDER_COUNT as one aggregate row.' || CHR(10)
|
||||
|| 'Expected result example: 204720, 6, 6.'),
|
||||
JSON(sg_qa_vector_params('search_document'))),
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE example_id = 141
|
||||
AND source_type = 'POLICY_TEMPLATE';
|
||||
/
|
||||
COMMIT;
|
||||
/
|
||||
@@ -7,13 +7,14 @@ IS
|
||||
v_result CLOB;
|
||||
v_extract JSON_OBJECT_T;
|
||||
BEGIN
|
||||
v_prompt := 'Extract only game-name mentions from the user question. '
|
||||
|| 'Metrics, acronyms, dates, filters, and database object or column names are not game names unless they are themselves an explicit game title. '
|
||||
v_prompt := 'Extract only game identity mentions from the user question. '
|
||||
|| 'A registered game title, alias, GAME_ID, GAME_PREFIX, or catalog key is a game mention and must be preserved exactly as written. '
|
||||
|| 'Metrics, acronyms, dates, filters, and database object or column names are not game mentions unless they are themselves an explicit registered game identity. '
|
||||
|| 'When a title-like noun directly qualifies a game data request such as user master, character, sales, AU, NRU, server, or game log, preserve that noun as a game-name mention even when it is not in a catalog. '
|
||||
|| 'Do not discard an unknown title merely because it cannot be resolved. General scope words such as common, overall, all, total, or every are not game-name mentions unless they are part of an explicit title. '
|
||||
|| 'Return exactly one JSON object with keys game_mentions (array of strings) '
|
||||
|| 'and scope_hint (GLOBAL, SINGLE_GAME, MULTI_GAME, ALL_GAMES, UNKNOWN). '
|
||||
|| 'Do not resolve names to IDs and do not generate SQL. '
|
||||
|| 'Do not resolve one game identity to another and do not generate SQL. '
|
||||
|| 'Return raw JSON only: no prose, no Markdown, and no code fence. Question: '
|
||||
|| DBMS_LOB.SUBSTR(p_question, 4000, 1);
|
||||
|
||||
|
||||
@@ -93,8 +93,12 @@ IS
|
||||
v_unresolved JSON_ARRAY_T := JSON_ARRAY_T();
|
||||
v_unmatched JSON_ARRAY_T := JSON_ARRAY_T();
|
||||
v_mention_results JSON_ARRAY_T := JSON_ARRAY_T();
|
||||
v_execution_tasks JSON_ARRAY_T := JSON_ARRAY_T();
|
||||
v_seen_game_keys t_seen_game_keys;
|
||||
v_result JSON_OBJECT_T := JSON_OBJECT_T();
|
||||
v_reference_summary JSON_OBJECT_T := JSON_OBJECT_T();
|
||||
v_select_ai_reference CLOB;
|
||||
v_plan_status VARCHAR2(30);
|
||||
v_matched_count PLS_INTEGER := 0;
|
||||
v_data_eligible_count PLS_INTEGER := 0;
|
||||
v_unmatched_count PLS_INTEGER := 0;
|
||||
@@ -111,6 +115,14 @@ IS
|
||||
v_mention_result JSON_OBJECT_T;
|
||||
v_target JSON_OBJECT_T;
|
||||
v_unmatched_item JSON_OBJECT_T;
|
||||
v_execution_task JSON_OBJECT_T;
|
||||
v_worker_arguments JSON_OBJECT_T;
|
||||
v_fewshot_arguments JSON_OBJECT_T;
|
||||
v_task_plan JSON_OBJECT_T;
|
||||
v_task_reference JSON_OBJECT_T;
|
||||
v_task_targets JSON_ARRAY_T;
|
||||
v_excluded_mentions JSON_ARRAY_T;
|
||||
v_task_question CLOB;
|
||||
|
||||
v_cursor SYS_REFCURSOR;
|
||||
v_game_key VARCHAR2(128);
|
||||
@@ -345,21 +357,52 @@ BEGIN
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
v_result.put('contractVersion', '1.0');
|
||||
IF v_target_type = 'NONE' THEN
|
||||
v_plan_status := 'NO_TARGET';
|
||||
ELSIF v_matched_count = 0 THEN
|
||||
v_plan_status := 'UNMATCHED';
|
||||
ELSIF v_data_eligible_count = 0 THEN
|
||||
v_plan_status := 'UNAVAILABLE';
|
||||
ELSIF v_unmatched_count > 0 THEN
|
||||
v_plan_status := 'PARTIAL';
|
||||
ELSE
|
||||
v_plan_status := 'SUPPORTED';
|
||||
END IF;
|
||||
|
||||
-- This is the sole Select AI handoff contract. It is deliberately generic:
|
||||
-- game values and physical objects come only from the database lookup above.
|
||||
v_reference_summary.put('targetType', v_target_type);
|
||||
v_reference_summary.put('status', v_plan_status);
|
||||
v_reference_summary.put('gameTargets', v_supported);
|
||||
v_select_ai_reference := '[GAME QUERY REFERENCE]' || CHR(10) || CHR(10)
|
||||
|| v_reference_summary.to_clob()
|
||||
|| CHR(10) || CHR(10)
|
||||
|| 'Field meanings:' || CHR(10) || CHR(10)
|
||||
|| '* targetType:' || CHR(10)
|
||||
|| ' * NONE: No game was resolved.' || CHR(10)
|
||||
|| ' * SINGLE: Exactly one game was resolved.' || CHR(10)
|
||||
|| ' * MULTI: Multiple specific games were resolved.' || CHR(10)
|
||||
|| ' * ALL: The query applies to all supported games.' || CHR(10)
|
||||
|| '* status: The result of game-target resolution.' || CHR(10)
|
||||
|| '* gameTargets: The exact games resolved by the DB lookup. Each item may include:' || CHR(10)
|
||||
|| ' * gameKey: Canonical game identifier.' || CHR(10)
|
||||
|| ' * gamePrefix: Prefix used for game-scoped objects.' || CHR(10)
|
||||
|| ' * userMasterObjectName: Resolved user-master object for that game.' || CHR(10) || CHR(10)
|
||||
|| 'Object-selection guidance:' || CHR(10) || CHR(10)
|
||||
|| '* Use only the targets listed in gameTargets.' || CHR(10)
|
||||
|| '* For NONE, use a game-neutral common object when it directly answers the question.' || CHR(10)
|
||||
|| '* If no suitable common object exists, state that a game name is required.' || CHR(10)
|
||||
|| '* Do not infer an unlisted game or game-scoped object.';
|
||||
|
||||
v_result.put('contractVersion', '2.0');
|
||||
v_result.put('targetType', v_target_type);
|
||||
v_result.put('scopeType', v_target_type);
|
||||
v_result.put('selectAiReference', v_select_ai_reference);
|
||||
v_result.put('extractScopeHint', v_scope_type);
|
||||
IF v_target_type = 'NONE' THEN
|
||||
v_result.put('status', 'NO_TARGET');
|
||||
ELSIF v_matched_count = 0 THEN
|
||||
v_result.put('status', 'UNMATCHED');
|
||||
ELSIF v_data_eligible_count = 0 THEN
|
||||
v_result.put('status', 'UNAVAILABLE');
|
||||
ELSIF v_unmatched_count > 0 THEN
|
||||
v_result.put('status', 'PARTIAL');
|
||||
ELSE
|
||||
v_result.put('status', 'SUPPORTED');
|
||||
END IF;
|
||||
v_result.put('status', v_plan_status);
|
||||
-- `gameTargets` is the public downstream contract. The detailed `targets`
|
||||
-- collection remains diagnostic evidence only for the MCP response.
|
||||
v_result.put('gameTargets', v_supported);
|
||||
v_result.put('targets', v_targets);
|
||||
v_result.put('matchedGames', v_supported);
|
||||
v_result.put('mentionResults', v_mention_results);
|
||||
@@ -368,6 +411,66 @@ BEGIN
|
||||
v_result.put('unresolvedTargets', v_unresolved);
|
||||
v_result.put('dataIneligibleTargets', v_data_ineligible);
|
||||
v_result.put('unmatchedGames', v_unmatched);
|
||||
-- Dynamic ReAct work items. Every game identity and availability state comes
|
||||
-- from the catalog lookup above; clients must not infer their own targets.
|
||||
FOR i IN 0 .. v_targets.get_size - 1 LOOP
|
||||
v_target := TREAT(v_targets.get(i) AS JSON_OBJECT_T);
|
||||
IF v_target.get_string('gameKey') IS NOT NULL THEN
|
||||
v_execution_task := JSON_OBJECT_T();
|
||||
v_execution_task.put(
|
||||
'action',
|
||||
CASE
|
||||
WHEN v_target.get_string('dataStatus') = 'AVAILABLE'
|
||||
AND v_target.get_string('userMasterObjectName') IS NOT NULL
|
||||
THEN 'QUERY'
|
||||
ELSE 'REPORT_UNAVAILABLE'
|
||||
END
|
||||
);
|
||||
v_execution_task.put('scopeGameKey', v_target.get_string('gameKey'));
|
||||
v_execution_task.put('target', v_target);
|
||||
IF v_execution_task.get_string('action') = 'QUERY' THEN
|
||||
v_excluded_mentions := JSON_ARRAY_T();
|
||||
FOR j IN 0 .. v_targets.get_size - 1 LOOP
|
||||
v_candidate := TREAT(v_targets.get(j) AS JSON_OBJECT_T);
|
||||
IF v_candidate.get_string('gameKey') <> v_target.get_string('gameKey')
|
||||
AND v_candidate.get_string('mention') IS NOT NULL THEN
|
||||
v_excluded_mentions.append(v_candidate.get_string('mention'));
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
-- Preserve the original question verbatim. The target-specific
|
||||
-- queryPlan below is the separate, authoritative scope contract.
|
||||
v_task_question := p_question;
|
||||
v_task_reference := JSON_OBJECT_T();
|
||||
v_task_targets := JSON_ARRAY_T();
|
||||
v_task_targets.append(v_target);
|
||||
v_task_reference.put('targetType', 'SINGLE');
|
||||
v_task_reference.put('status', 'SUPPORTED');
|
||||
v_task_reference.put('gameTargets', v_task_targets);
|
||||
|
||||
v_task_plan := JSON_OBJECT_T();
|
||||
v_task_plan.put('contractVersion', '2.0');
|
||||
v_task_plan.put('targetType', 'SINGLE');
|
||||
v_task_plan.put('status', 'SUPPORTED');
|
||||
v_task_plan.put('gameTargets', v_task_targets);
|
||||
v_task_plan.put('selectAiReference',
|
||||
'[GAME QUERY REFERENCE]' || CHR(10) || CHR(10) || v_task_reference.to_clob());
|
||||
|
||||
v_worker_arguments := JSON_OBJECT_T();
|
||||
v_worker_arguments.put('prompt', v_task_question);
|
||||
v_worker_arguments.put('scopeGameKey', v_target.get_string('gameKey'));
|
||||
v_worker_arguments.put('queryPlan', v_task_plan);
|
||||
v_fewshot_arguments := JSON_OBJECT_T();
|
||||
v_fewshot_arguments.put('question', v_task_question);
|
||||
v_fewshot_arguments.put('topK', 3);
|
||||
v_execution_task.put('workerTool', 'oracle.select_ai.smilegate_fewshot_nl2sql');
|
||||
v_execution_task.put('workerArguments', v_worker_arguments);
|
||||
v_execution_task.put('fewShotArguments', v_fewshot_arguments);
|
||||
END IF;
|
||||
v_execution_tasks.append(v_execution_task);
|
||||
END IF;
|
||||
END LOOP;
|
||||
v_result.put('executionTasks', v_execution_tasks);
|
||||
v_result.put('nextAction', 'CALL_FEWSHOT');
|
||||
|
||||
CASE v_target_type
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
-- General target-contract guidance belongs to the Select AI profile, not application branches.
|
||||
-- It contains no current game, prefix, ID, or physical object name.
|
||||
-- Select AI profile instructions contain only common SQL-generation guidance.
|
||||
-- Game target routing and execution policy are supplied at runtime by
|
||||
-- SG_GAME_QUERY_PLAN; they do not belong in the profile-wide prompt.
|
||||
|
||||
BEGIN
|
||||
DBMS_CLOUD_AI.SET_ATTRIBUTE(
|
||||
@@ -7,7 +8,7 @@ BEGIN
|
||||
attribute_name => 'additional_instructions',
|
||||
attribute_value => q'~Generate Oracle SQL only for the listed approved objects. Do not reference external tables. Use English aliases only. Use database comments and annotations as the source of business rules.
|
||||
|
||||
When an authoritative game query plan is supplied in the user request, use its targets and statuses as the only game-scope source; do not independently rematch a game, infer a default game, or substitute one target's object for another. A plan with no selected game does not by itself prohibit a query: use an approved common object when it can answer the operation. If an operation inherently requires a game-scoped logical object and the relevant plan target is unresolved or its physical object is unavailable, return an appropriate zero-row result. A zero-row result is not a synthetic row containing a NULL value and is not an execution failure. For multiple or all resolved targets, use the supplied target identifiers to group a common object when applicable, or combine only the supplied available objects. When filtering an approved common object by game, derive the allowed game identifiers through the active approved game-alias catalog lookup; do not put a game identifier or prefix directly as a SQL literal predicate. Preserve an alias lookup with no matching data as an empty or aggregate-null result, never as a substituted game. Never invent identifiers, prefixes, or physical object names.~'
|
||||
~'
|
||||
);
|
||||
END;
|
||||
/
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
-- Benchmark correction: common-fact eligibility is determined by the active
|
||||
-- alias source. Registry-only games are reported separately while eligible
|
||||
-- targets continue through the common-fact query.
|
||||
-- Korean baseline text and SQL are reconstructed from UTF-8 base64 for SQLcl safety.
|
||||
|
||||
UPDATE sg_ai_qa_question
|
||||
SET expected_focus = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'7Jes65+sIOqyjOyehCDruYTqtZDsl5DshJwg7Lm07YOI66Gc6re466GcIO2ZleyduOuQnCDrjIDsg4HsnYAg67OE7LmtIOy5tO2TiOuhnOq3uOulvCDqtazrj5kg7KeR7ZWp7Jy866GcIO2VmOqzoCDqs7XthrUg7IKs7IukIO2FjOydtOu4lOydhCBMRUZUIEpPSU7tlZjsl6wg6rKM7J6E67OEIOynkeqzhO2VnOuLpC4g7IKs7IukIO2WieydtCDsl4bripQg64yA7IOB7J2AIDDsnLzroZwg67O07KG07ZWY6rOgLCDrp6Tsua3rkJwg64uk66W4IOuMgOyDgeydmCDqsrDqs7zrpbwg7IOd65617ZWY7KeAIOyViuuKlOuLpC4gRFVBTCBVTklPTuycvOuhnCDrjIDsg4HrqoXqs7wg6rCS7J2EIO2VqeyEse2VmOyngCDslYrripTri6Qu'
|
||||
)),
|
||||
'AL32UTF8'
|
||||
),
|
||||
baseline_answer = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'7Lm07YOI66Gc6re4IOunpOy5rSDrjIDsg4Hrs4Qg66ek7Lac7J2EIOuwmO2ZmO2VnOuLpC4g7IKs7IukIO2WieydtCDsl4bripQg64yA7IOB7J2AIDAsIOuLpOuluCDrp6Tsua0g64yA7IOB7J2AIO2VtOuLuSDsnbzsnpDsnZgg7KeR6rOE6rCS7J2EIOuwmO2ZmO2VnOuLpC4='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
),
|
||||
baseline_sql = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'V0lUSCByZXF1ZXN0ZWRfZ2FtZXMgQVMgKAogIFNFTEVDVCBESVNUSU5DVCBnLiJHQU1FX0lEIiwgZy4iR0FNRV9OTSIKICBGUk9NICJTR01QX1BPQyIuIkNPTU5fR0FNRV9BTElBU19CQVMiIGcKICBXSEVSRSBnLiJVU0VfWU4iID0gJ1knCiAgICBBTkQgKAogICAgICBVUFBFUihnLiJHQU1FX05NIikgTElLRSBVUFBFUignJUJ1YmJseXolJykKICAgICAgT1IgVVBQRVIoZy4iR0FNRV9BTElBU19OTSIpIExJS0UgVVBQRVIoJyVCdWJibHl6JScpCiAgICAgIE9SIFVQUEVSKGcuIkdBTUVfTk0iKSBMSUtFIFVQUEVSKCcl7Lm07KCc64KYJScpCiAgICAgIE9SIFVQUEVSKGcuIkdBTUVfQUxJQVNfTk0iKSBMSUtFIFVQUEVSKCcl7Lm07KCc64KYJScpCiAgICApCikKU0VMRUNUIHJnLiJHQU1FX05NIiBBUyAiR0FNRV9OQU1FIiwKICAgICAgIE5WTChTVU0oQ0FTRQogICAgICAgICBXSEVOIHMuIlBBWU1UX0RUTSIgPj0gVE9fREFURSgnMjAyNjA3MTUnLCAnWVlZWU1NREQnKQogICAgICAgICAgQU5EIHMuIlBBWU1UX0RUTSIgPCBUT19EQVRFKCcyMDI2MDcxNicsICdZWVlZTU1ERCcpCiAgICAgICAgICBBTkQgcy4iRVhQVF9VU0VSX1lOIiA9ICdOJwogICAgICAgICBUSEVOIENBU1Qocy4iUEFZTVRfQU1UIiBBUyBOVU1CRVIpIEVMU0UgMCBFTkQpLCAwKSBBUyAiU0FMRVNfQU1UIgpGUk9NIHJlcXVlc3RlZF9nYW1lcyByZwpMRUZUIEpPSU4gIlNHTVBfUE9DIi4iQ09NTl9TQUxFU19UWE4iIHMKICBPTiBzLiJHQU1FX0lEIiA9IHJnLiJHQU1FX0lEIgpHUk9VUCBCWSByZy4iR0FNRV9OTSIKT1JERVIgQlkgcmcuIkdBTUVfTk0iCg=='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
)
|
||||
WHERE question_code = 'STD-11';
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET inspection_status = 'REVIEW',
|
||||
inspection_note = 'Customer benchmark criterion updated: multi-target common-fact comparisons preserve catalog-resolved zero-fact targets through a catalog-driven left join.'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-11';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- Correct the earlier catalog-only interpretation in this same migration. A
|
||||
-- registry can identify a game to the operator, but does not by itself make it
|
||||
-- an approved source for a common fact query.
|
||||
UPDATE sg_ai_qa_question
|
||||
SET expected_focus = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'67O17IiYIOqyjOyehCDqs7XthrUg7IKs7IukIOuNsOydtO2EsCDsp4jsnZjripQg7Zmc7ISxIOqyjOyehCDrs4Tsua0g7JuQ7LKc7JeQ7IScIO2ZleyduOuQnCDrjIDsg4Hrp4wg7IKs7IukIOyhsO2ajCDrjIDsg4HsnLzroZwg7IKs7Jqp7ZWY6rOgLCDrs4Tsua0g7JuQ7LKc7J20IOyXhuuKlCDroIjsp4DsiqTtirjrpqwg7KCE7JqpIOuMgOyDgeydgCDsobDtmowg67aI6rCAIOyDge2DnOuhnCDrs4Trj4Qg7JWI64K07ZWc64ukLiDsobDtmowg6rCA64ql7ZWcIOuMgOyDgeydmCDqsrDqs7zripQg7Jyg7KeA7ZWY66mwIOyghOyytCDsmpTssq3snYQg7LCo64uo7ZWY7KeAIOyViuuKlOuLpC4gRFVBTCBVTklPTuycvOuhnCDrjIDsg4Eg7ZaJ7J2064KYIOqwkuydhCDrp4zrk6Tsp4Ag7JWK64qU64ukLg=='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
),
|
||||
baseline_answer = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'7Lm07KCc64KYIOunpOy2nOydgCAyMjcsNjgx7J6F64uI64ukLiBCdWJibHl664qUIO2ZnOyEsSDqsozsnoQg67OE7LmtIOybkOyynOydtCDsl4bslrQg66ek7LacIOyhsO2ajCDrjIDsg4HsnbQg7JWE64uZ64uI64ukLg=='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
)
|
||||
WHERE question_code = 'STD-11';
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET inspection_status = 'REVIEW',
|
||||
inspection_note = 'Customer benchmark criterion updated: common-fact comparison queries use active-alias eligible targets; registry-only targets are separately unavailable and do not become synthetic fact rows.'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-11';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT question_code, expected_focus, baseline_answer
|
||||
FROM sg_ai_qa_question
|
||||
WHERE question_code = 'STD-11';
|
||||
22
database/adb/89_sgmp_common_fact_multi_target_guidance.sql
Normal file
22
database/adb/89_sgmp_common_fact_multi_target_guidance.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
-- Object-specific, data-driven guidance for comparison queries on a common fact table.
|
||||
-- No game, prefix, ID, or physical per-game object is embedded in this annotation.
|
||||
|
||||
DECLARE
|
||||
v_result VARCHAR2(4000);
|
||||
BEGIN
|
||||
v_result := sgmp_set_annotation(
|
||||
'SGMP_POC',
|
||||
'TABLE',
|
||||
'COMN_SALES_TXN',
|
||||
NULL,
|
||||
'Game fact scope: query this table only for plan targets marked ACTIVE_ALIAS. Derive target GAME_ID values through active COMN_GAME_ALIAS_BAS aliases rather than direct identifier or prefix literals. For a mixed request, retain the eligible target results and report other plan statuses separately; do not substitute or manufacture a target result.',
|
||||
'MULTI_TARGET_COMPARISON'
|
||||
);
|
||||
DBMS_OUTPUT.PUT_LINE(v_result);
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT annotation_name, annotation_value
|
||||
FROM user_annotations_usage
|
||||
WHERE object_name = 'COMN_SALES_TXN'
|
||||
AND annotation_name = 'MULTI_TARGET_COMPARISON';
|
||||
92
database/adb/90_sgmp_multi_common_fact_fewshot_template.sql
Normal file
92
database/adb/90_sgmp_multi_common_fact_fewshot_template.sql
Normal file
@@ -0,0 +1,92 @@
|
||||
-- Generic Few-shot structure for multi-target comparisons on a common fact object.
|
||||
-- The template is intentionally logical: no current game, prefix, ID, date, or result value is embedded.
|
||||
|
||||
DECLARE
|
||||
v_exists NUMBER;
|
||||
v_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
BEGIN
|
||||
SELECT COUNT(*)
|
||||
INTO v_exists
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'MULTI_COMMON_FACT_LEFT_JOIN';
|
||||
|
||||
IF v_exists = 0 THEN
|
||||
v_input := TO_CLOB('Question pattern: Compare a common fact metric across multiple resolved games. Use only fact-query-eligible targets and separately report known registry-only or unavailable targets.')
|
||||
|| CHR(10) || 'Logical object role: SALES_TRANSACTION'
|
||||
|| CHR(10) || 'Required structure: active alias catalog distinct game set, left join fact, aggregate by catalog display identifier.';
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_input,
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
|
||||
INSERT INTO sg_qa_vector_example (
|
||||
question, answer_sql, answer_text, embedding_input, embedding, embedding_model,
|
||||
reference_status, reference_kind, target_type, object_role,
|
||||
inspection_status, inspection_note, verified_at, verified_by,
|
||||
source_case_id, source_type
|
||||
) VALUES (
|
||||
'Compare a common fact metric across multiple resolved games, including games with no fact rows.',
|
||||
TO_CLOB('WITH resolved_games AS (' || CHR(10)
|
||||
|| ' SELECT DISTINCT a."GAME_ID", a."GAME_NM"' || CHR(10)
|
||||
|| ' FROM "SGMP_POC"."COMN_GAME_ALIAS_BAS" a' || CHR(10)
|
||||
|| ' WHERE a."USE_YN" = ''Y''' || CHR(10)
|
||||
|| ' AND (<ACTIVE_ALIAS_MATCHES_FOR_EACH_REQUESTED_GAME_TERM>)' || CHR(10)
|
||||
|| ')' || CHR(10)
|
||||
|| 'SELECT g."GAME_NM" AS "GAME_NAME",' || CHR(10)
|
||||
|| ' NVL(SUM(CASE WHEN <FACT_DATE_AND_EXCLUSION_CONDITION>' || CHR(10)
|
||||
|| ' THEN CAST(f."<METRIC_COLUMN>" AS NUMBER) ELSE 0 END), 0) AS "METRIC_VALUE"' || CHR(10)
|
||||
|| 'FROM resolved_games g' || CHR(10)
|
||||
|| 'LEFT JOIN "SGMP_POC"."<APPROVED_COMMON_FACT_OBJECT>" f' || CHR(10)
|
||||
|| ' ON f."GAME_ID" = g."GAME_ID"' || CHR(10)
|
||||
|| 'GROUP BY g."GAME_NM"' || CHR(10)
|
||||
|| 'ORDER BY g."GAME_NM"'),
|
||||
'Structural Few-shot only. Replace every angle-bracket placeholder from the current approved object metadata, the current game query plan, and the original question. Only ACTIVE_ALIAS targets enter the alias-driven LEFT JOIN and grouping; report registry-only or unavailable targets from the plan without manufacturing fact rows with DUAL/UNION.',
|
||||
v_input,
|
||||
v_embedding,
|
||||
'cohere.embed-v4.0',
|
||||
'APPROVED', 'SQL_TEMPLATE', 'MULTI', 'SALES_TRANSACTION',
|
||||
'VERIFIED',
|
||||
'Generic, non-customer-specific comparison structure. Verified against the game-alias and common-fact metadata contract; not an executable answer key.',
|
||||
SYSTIMESTAMP, 'SGMP_POC_METADATA_REVIEW',
|
||||
'MULTI_COMMON_FACT_LEFT_JOIN', 'POLICY_TEMPLATE'
|
||||
);
|
||||
END IF;
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
-- Keep the approved template current when the policy text evolves. The vector
|
||||
-- is rebuilt from its generic retrieval text; no customer answer is embedded.
|
||||
DECLARE
|
||||
v_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
BEGIN
|
||||
v_input := TO_CLOB('Question pattern: Compare a common fact metric across multiple resolved games. Use only fact-query-eligible targets and separately report known registry-only or unavailable targets.')
|
||||
|| CHR(10) || 'Logical object role: SALES_TRANSACTION'
|
||||
|| CHR(10) || 'Required structure: active alias catalog distinct game set, left join fact, aggregate by catalog display identifier.';
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_input,
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET question = 'Compare a common fact metric across multiple resolved games, using only fact-query-eligible targets.',
|
||||
answer_text = 'Structural Few-shot only. Replace every angle-bracket placeholder from the current approved object metadata, the current game query plan, and the original question. Only ACTIVE_ALIAS targets enter the alias-driven LEFT JOIN and grouping; report registry-only or unavailable targets from the plan without manufacturing fact rows with DUAL/UNION.',
|
||||
embedding_input = v_input,
|
||||
embedding = v_embedding,
|
||||
inspection_note = 'Generic, non-customer-specific comparison structure. Active-alias targets are fact-query eligible; registry-only targets are reported separately. Not an executable answer key.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'MULTI_COMMON_FACT_LEFT_JOIN';
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT example_id, reference_status, reference_kind, target_type, object_role,
|
||||
source_case_id, source_type
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'MULTI_COMMON_FACT_LEFT_JOIN';
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Retire the overly specific no-target template. The profile and table
|
||||
-- metadata carry this general scope policy without a case-shaped example.
|
||||
|
||||
DELETE FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'NO_ELIGIBLE_FACT_TARGET';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT COUNT(*) AS remaining_template_count
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'NO_ELIGIBLE_FACT_TARGET';
|
||||
70
database/adb/92_sgmp_transaction_detail_fewshot_template.sql
Normal file
70
database/adb/92_sgmp_transaction_detail_fewshot_template.sql
Normal file
@@ -0,0 +1,70 @@
|
||||
-- Generic Few-shot structure for a filtered transaction/order detail request.
|
||||
-- It fixes the output grain through an approved object pattern, not a global
|
||||
-- instruction or a customer-specific answer.
|
||||
|
||||
DECLARE
|
||||
v_input CLOB;
|
||||
v_embedding VECTOR;
|
||||
v_exists NUMBER;
|
||||
BEGIN
|
||||
v_input := TO_CLOB('Question pattern: List individual payment orders that match a business date and an amount condition.')
|
||||
|| CHR(10) || 'Logical object role: SALES_TRANSACTION'
|
||||
|| CHR(10) || 'Required output: transaction identifiers, game, user, payment timestamp, and payment amount.';
|
||||
v_embedding := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
v_input,
|
||||
JSON(sg_qa_vector_params('search_document'))
|
||||
);
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO v_exists
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'FILTERED_TRANSACTION_DETAIL';
|
||||
|
||||
IF v_exists = 0 THEN
|
||||
INSERT INTO sg_qa_vector_example (
|
||||
question, answer_sql, answer_text, embedding_input, embedding, embedding_model,
|
||||
reference_status, reference_kind, target_type, object_role,
|
||||
inspection_status, inspection_note, verified_at, verified_by,
|
||||
source_case_id, source_type
|
||||
) VALUES (
|
||||
'List payment orders matching a date and amount condition.',
|
||||
TO_CLOB('SELECT t."PAYMT_TRANSAC_ID" AS "PAYMENT_TRANSACTION_ID",' || CHR(10)
|
||||
|| ' t."PAYMT_TRANSAC_DTL_ID" AS "PAYMENT_TRANSACTION_DETAIL_ID",' || CHR(10)
|
||||
|| ' t."GAME_ID" AS "GAME_ID",' || CHR(10)
|
||||
|| ' t."GUID" AS "USER_ID",' || CHR(10)
|
||||
|| ' t."PAYMT_DTM" AS "PAYMENT_DATETIME",' || CHR(10)
|
||||
|| ' t."PAYMT_AMT" AS "PAYMENT_AMOUNT"' || CHR(10)
|
||||
|| 'FROM "SGMP_POC"."COMN_SALES_TXN" t' || CHR(10)
|
||||
|| 'WHERE t."PAYMT_DTM" >= <BUSINESS_DATE_START>' || CHR(10)
|
||||
|| ' AND t."PAYMT_DTM" < <BUSINESS_DATE_END>' || CHR(10)
|
||||
|| ' AND CAST(t."PAYMT_AMT" AS NUMBER) <AMOUNT_CONDITION>' || CHR(10)
|
||||
|| ' AND t."EXPT_USER_YN" = ''N''' || CHR(10)
|
||||
|| 'ORDER BY t."PAYMT_DTM", t."PAYMT_TRANSAC_ID", t."PAYMT_TRANSAC_DTL_ID"'),
|
||||
'Structural Few-shot only. Replace placeholders using the original request and approved metadata. Use the business payment timestamp for a payment-date condition. This pattern is for individual transaction detail; do not substitute an aggregate-only result for a requested order list.',
|
||||
v_input,
|
||||
v_embedding,
|
||||
'cohere.embed-v4.0',
|
||||
'APPROVED', 'SQL_TEMPLATE', 'NONE', 'SALES_TRANSACTION',
|
||||
'VERIFIED',
|
||||
'Generic transaction-detail output shape with no customer date, amount, game, or result value; not an executable answer key.',
|
||||
SYSTIMESTAMP, 'SGMP_POC_METADATA_REVIEW',
|
||||
'FILTERED_TRANSACTION_DETAIL', 'POLICY_TEMPLATE'
|
||||
);
|
||||
ELSE
|
||||
UPDATE sg_qa_vector_example
|
||||
SET embedding_input = v_input,
|
||||
embedding = v_embedding,
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'FILTERED_TRANSACTION_DETAIL';
|
||||
END IF;
|
||||
COMMIT;
|
||||
END;
|
||||
/
|
||||
|
||||
SELECT example_id, reference_status, target_type, object_role, source_case_id
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'POLICY_TEMPLATE'
|
||||
AND source_case_id = 'FILTERED_TRANSACTION_DETAIL';
|
||||
@@ -0,0 +1,57 @@
|
||||
-- Customer question wording requests individual orders. Align the benchmark
|
||||
-- with the transaction-detail output pattern rather than forcing KPI summary.
|
||||
|
||||
UPDATE sg_ai_qa_question
|
||||
SET expected_focus = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'Q09NTl9TQUxFU19UWE7sl5DshJwgUEFZTVRfRFRNIOq4sOykgOydvCwgUEFZTVRfQU1UID4gMTAwMDAsIEVYUFRfVVNFUl9ZTj0nTicg7KGw6rG07J2YIOqwnOuzhCDso7zrrLgg7IOB7IS466W8IOyhsO2ajO2VnOuLpC4g7KO866y4IOyLneuzhOyekCwg6rKM7J6ELCDsgqzsmqnsnpAsIOqysOygnCDsnbzsi5zsmYAg6riI7JWh7J2EIOygnOqzte2VnOuLpC4='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
),
|
||||
baseline_sql = TO_CLOB('SELECT s."PAYMT_TRANSAC_ID" AS "PAYMENT_TRANSACTION_ID",' || CHR(10)
|
||||
|| ' s."PAYMT_TRANSAC_DTL_ID" AS "PAYMENT_TRANSACTION_DETAIL_ID",' || CHR(10)
|
||||
|| ' s."GAME_ID" AS "GAME_ID",' || CHR(10)
|
||||
|| ' s."GUID" AS "USER_ID",' || CHR(10)
|
||||
|| ' s."PAYMT_DTM" AS "PAYMENT_DATETIME",' || CHR(10)
|
||||
|| ' s."PAYMT_AMT" AS "PAYMENT_AMOUNT"' || CHR(10)
|
||||
|| 'FROM "SGMP_POC"."COMN_SALES_TXN" s' || CHR(10)
|
||||
|| 'WHERE s."PAYMT_DTM" >= DATE ''2026-07-15''' || CHR(10)
|
||||
|| ' AND s."PAYMT_DTM" < DATE ''2026-07-16''' || CHR(10)
|
||||
|| ' AND CAST(s."PAYMT_AMT" AS NUMBER) > 10000' || CHR(10)
|
||||
|| ' AND s."EXPT_USER_YN" = ''N''' || CHR(10)
|
||||
|| 'ORDER BY s."PAYMT_DTM", s."PAYMT_TRANSAC_ID", s."PAYMT_TRANSAC_DTL_ID"'),
|
||||
baseline_answer = utl_i18n.raw_to_char(
|
||||
utl_encode.base64_decode(utl_raw.cast_to_raw(
|
||||
'6rKw7KCc6riI7JWhIDHrp4zsm5Ag7LSI6rO8IOyjvOusuCA26rG07J2EIOyjvOusuCDsi53rs4TsnpAsIOqyjOyehCwg7IKs7Jqp7J6QLCDqsrDsoJwg7J287IucLCDqsrDsoJzquIjslaHqs7wg7ZWo6ruYIOuwmO2ZmO2VnOuLpC4='
|
||||
)),
|
||||
'AL32UTF8'
|
||||
)
|
||||
WHERE question_code = 'STD-18';
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET answer_sql = TO_CLOB('SELECT s."PAYMT_TRANSAC_ID" AS "PAYMENT_TRANSACTION_ID",' || CHR(10)
|
||||
|| ' s."PAYMT_TRANSAC_DTL_ID" AS "PAYMENT_TRANSACTION_DETAIL_ID",' || CHR(10)
|
||||
|| ' s."GAME_ID" AS "GAME_ID",' || CHR(10)
|
||||
|| ' s."GUID" AS "USER_ID",' || CHR(10)
|
||||
|| ' s."PAYMT_DTM" AS "PAYMENT_DATETIME",' || CHR(10)
|
||||
|| ' s."PAYMT_AMT" AS "PAYMENT_AMOUNT"' || CHR(10)
|
||||
|| 'FROM "SGMP_POC"."COMN_SALES_TXN" s' || CHR(10)
|
||||
|| 'WHERE s."PAYMT_DTM" >= DATE ''2026-07-15''' || CHR(10)
|
||||
|| ' AND s."PAYMT_DTM" < DATE ''2026-07-16''' || CHR(10)
|
||||
|| ' AND CAST(s."PAYMT_AMT" AS NUMBER) > 10000' || CHR(10)
|
||||
|| ' AND s."EXPT_USER_YN" = ''N''' || CHR(10)
|
||||
|| 'ORDER BY s."PAYMT_DTM", s."PAYMT_TRANSAC_ID", s."PAYMT_TRANSAC_DTL_ID"'),
|
||||
answer_text = 'Approved customer Few-shot: return individual qualifying payment orders with transaction identifiers, game, user, payment timestamp, and payment amount. Use PAYMT_DTM for the payment business date.',
|
||||
reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Customer benchmark aligned to detailed qualifying orders and the payment business timestamp.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-18';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT question_code, expected_focus, baseline_answer
|
||||
FROM sg_ai_qa_question
|
||||
WHERE question_code = 'STD-18';
|
||||
19
database/adb/94_sgmp_std21_country_continuous_fewshot.sql
Normal file
19
database/adb/94_sgmp_std21_country_continuous_fewshot.sql
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Customer benchmark evidence is retained for evaluation only. It is not a
|
||||
-- runtime Few-shot because the vector store must not become a collection of
|
||||
-- case-specific benchmark overrides.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'RETIRED',
|
||||
inspection_status = 'RETIRED',
|
||||
inspection_note = 'Retired from runtime Few-shot retrieval; retained as customer QA evaluation evidence.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-21';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, source_case_id
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-21';
|
||||
17
database/adb/95_sgmp_std22_nru_fewshot.sql
Normal file
17
database/adb/95_sgmp_std22_nru_fewshot.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- Promote the reviewed customer QA example for the NRU metric.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Customer QA reviewed: NRU is measured with NRU_FLAG, with the stated date and excluded-user condition.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-22';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, source_case_id
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'STD-22';
|
||||
17
database/adb/96_sgmp_czn02_standard_au_fewshot.sql
Normal file
17
database/adb/96_sgmp_czn02_standard_au_fewshot.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- Promote the reviewed customer QA example for the standard AU metric.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
inspection_note = 'Customer QA reviewed: standard AU is measured with AU_FLAG and excluded-user filtering.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-02';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, source_case_id
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-02';
|
||||
57
database/adb/97_sgmp_exact_qa_fewshot_priority.sql
Normal file
57
database/adb/97_sgmp_exact_qa_fewshot_priority.sql
Normal file
@@ -0,0 +1,57 @@
|
||||
-- Prefer an exact approved customer QA question over semantically adjacent
|
||||
-- vector neighbours. This is a general retrieval rule; it does not encode
|
||||
-- a game, metric, table, or customer-case-specific SQL policy.
|
||||
|
||||
CREATE OR REPLACE FUNCTION sg_qa_vector_search(
|
||||
p_question IN CLOB,
|
||||
p_top_k IN PLS_INTEGER DEFAULT 3,
|
||||
p_target_type IN VARCHAR2 DEFAULT 'ANY'
|
||||
) RETURN SYS_REFCURSOR
|
||||
AUTHID DEFINER
|
||||
IS
|
||||
v_query_vector VECTOR;
|
||||
v_results SYS_REFCURSOR;
|
||||
v_target_type VARCHAR2(16) := UPPER(TRIM(NVL(p_target_type, 'ANY')));
|
||||
BEGIN
|
||||
IF p_question IS NULL THEN
|
||||
RAISE_APPLICATION_ERROR(-20003, 'question is required.');
|
||||
END IF;
|
||||
IF p_top_k IS NULL OR p_top_k < 1 OR p_top_k > 20 THEN
|
||||
RAISE_APPLICATION_ERROR(-20004, 'top_k must be between 1 and 20.');
|
||||
END IF;
|
||||
IF v_target_type NOT IN ('NONE', 'SINGLE', 'MULTI', 'ALL', 'ANY') THEN
|
||||
RAISE_APPLICATION_ERROR(-20005, 'target_type must be NONE, SINGLE, MULTI, ALL, or ANY.');
|
||||
END IF;
|
||||
|
||||
v_query_vector := DBMS_VECTOR.UTL_TO_EMBEDDING(
|
||||
p_question,
|
||||
JSON(sg_qa_vector_params('search_query'))
|
||||
);
|
||||
|
||||
OPEN v_results FOR
|
||||
SELECT example_id,
|
||||
question,
|
||||
answer_sql,
|
||||
answer_text,
|
||||
embedding_model,
|
||||
reference_kind,
|
||||
target_type,
|
||||
object_role,
|
||||
source_case_id,
|
||||
source_type,
|
||||
vector_distance(embedding, v_query_vector, COSINE) AS cosine_distance
|
||||
FROM sg_qa_vector_example
|
||||
WHERE reference_status = 'APPROVED'
|
||||
AND (target_type = 'ANY' OR v_target_type = 'ANY' OR target_type = v_target_type)
|
||||
ORDER BY CASE
|
||||
WHEN DBMS_LOB.COMPARE(
|
||||
LOWER(TRIM(question)), LOWER(TRIM(p_question))
|
||||
) = 0 THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
vector_distance(embedding, v_query_vector, COSINE),
|
||||
example_id
|
||||
FETCH FIRST p_top_k ROWS ONLY;
|
||||
RETURN v_results;
|
||||
END;
|
||||
/
|
||||
20
database/adb/98_sgmp_czn02_standard_au_semantics.sql
Normal file
20
database/adb/98_sgmp_czn02_standard_au_semantics.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Strengthen the approved customer QA example itself. The wording belongs
|
||||
-- to the benchmark Few-shot record, not to a global Select AI profile rule.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET answer_text = 'Expected focus: CZN_COMN_USER_MST, BASE_DT=2026-07-15, AU_FLAG=1, EXPT_USER_YN=''N''. '
|
||||
|| 'The phrase standard AU is the report metric label; do not add STD_USER_YN unless the question separately asks for the standard-user cohort. '
|
||||
|| 'Historical answer: STD_AU_COUNT=0',
|
||||
inspection_note = 'Customer QA verified: standard AU uses the AU flag and excluded-user filtering; standard-user cohort is a separate request.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-02'
|
||||
AND reference_status = 'APPROVED';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, answer_text
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-02';
|
||||
23
database/adb/99_sgmp_czn03_standard_business_au_fewshot.sql
Normal file
23
database/adb/99_sgmp_czn03_standard_business_au_fewshot.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- Approve the reviewed customer QA comparison example. Metric definitions
|
||||
-- stay in the exact Few-shot example rather than becoming global profile text.
|
||||
|
||||
UPDATE sg_qa_vector_example
|
||||
SET reference_status = 'APPROVED',
|
||||
inspection_status = 'VERIFIED',
|
||||
answer_text = 'Expected focus: compare two independently aggregated metrics for the same resolved game and date. '
|
||||
|| 'Standard AU: CZN_COMN_USER_MST with AU_FLAG=1 and EXPT_USER_YN=''N''. '
|
||||
|| 'Business AU: CZN_CUSTOM_BIZ_USER_TXN with BIZ_AU_FLAG=1 and EXPT_USER_YN=''N''. '
|
||||
|| 'The labels standard AU and business AU do not imply STD_USER_YN. '
|
||||
|| 'Historical answer: STD_AU_COUNT=0, BIZ_AU_COUNT=1.',
|
||||
inspection_note = 'Customer QA verified: standard and business AU are separate aggregates with their respective AU flags.',
|
||||
verified_at = SYSTIMESTAMP,
|
||||
verified_by = 'SGMP_POC_METADATA_REVIEW'
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-03';
|
||||
|
||||
COMMIT;
|
||||
|
||||
SELECT example_id, reference_status, inspection_status, source_case_id, answer_text
|
||||
FROM sg_qa_vector_example
|
||||
WHERE source_type = 'CUSTOMER_QA_BENCHMARK'
|
||||
AND source_case_id = 'CZN-03';
|
||||
Reference in New Issue
Block a user