@@ -1,32 +1,57 @@
|
||||
-- OCI GenAI candidate selection. Vector distance only orders candidates; the
|
||||
-- model may select one supplied game_key or explicitly reject all candidates.
|
||||
-- Vector-score candidate selection. The closest catalog vector is accepted
|
||||
-- only when it is within the customer-managed policy threshold.
|
||||
CREATE OR REPLACE FUNCTION sg_game_match_candidate(
|
||||
p_mention IN CLOB,
|
||||
p_candidates_json IN CLOB
|
||||
) RETURN CLOB AUTHID DEFINER
|
||||
IS
|
||||
v_prompt CLOB;
|
||||
v_result CLOB;
|
||||
v_candidates JSON_ARRAY_T;
|
||||
v_candidate JSON_OBJECT_T;
|
||||
v_result JSON_OBJECT_T := JSON_OBJECT_T();
|
||||
v_threshold NUMBER;
|
||||
v_distance NUMBER;
|
||||
v_game_key VARCHAR2(128);
|
||||
BEGIN
|
||||
v_prompt := 'Decide whether the extracted game-name mention refers to exactly '
|
||||
|| 'one game in the supplied candidate array. Candidate vector distance is '
|
||||
|| 'retrieval evidence only and must not establish identity. Compare the '
|
||||
|| 'mention with candidate gameName, aliases, gameId, and gamePrefix. '
|
||||
|| 'If one candidate clearly identifies the same game, return exactly '
|
||||
|| '{"status":"MATCHED","game_key":"candidate key","reason":"short reason"}. '
|
||||
|| 'If none clearly identifies the same game, return exactly '
|
||||
|| '{"status":"UNMATCHED","game_key":null,"reason":"short reason"}. '
|
||||
|| 'Never invent a game_key and never return a key absent from the supplied '
|
||||
|| 'candidate array. Mention: '
|
||||
|| DBMS_LOB.SUBSTR(p_mention, 1000, 1)
|
||||
|| ' Candidates: '
|
||||
|| DBMS_LOB.SUBSTR(p_candidates_json, 12000, 1);
|
||||
v_result := DBMS_CLOUD_AI.GENERATE(
|
||||
prompt => v_prompt,
|
||||
profile_name => 'SGMP_POC_OCI_GPT54MINI',
|
||||
action => 'chat'
|
||||
);
|
||||
RETURN v_result;
|
||||
SELECT number_value
|
||||
INTO v_threshold
|
||||
FROM sg_game_scope_policy
|
||||
WHERE policy_key = 'GAME_ALIAS_MAX_COSINE_DISTANCE'
|
||||
AND active_yn = 'Y';
|
||||
|
||||
v_candidates := JSON_ARRAY_T.parse(p_candidates_json);
|
||||
IF v_candidates.get_size = 0 THEN
|
||||
v_result.put('status', 'UNMATCHED');
|
||||
v_result.put_null('game_key');
|
||||
v_result.put('reason', 'No active game catalog vector candidate was returned.');
|
||||
RETURN v_result.to_clob;
|
||||
END IF;
|
||||
|
||||
v_candidate := TREAT(v_candidates.get(0) AS JSON_OBJECT_T);
|
||||
v_distance := v_candidate.get_number('cosineDistance');
|
||||
v_game_key := v_candidate.get_string('gameKey');
|
||||
|
||||
IF v_distance <= v_threshold THEN
|
||||
v_result.put('status', 'MATCHED');
|
||||
v_result.put('game_key', v_game_key);
|
||||
v_result.put(
|
||||
'reason',
|
||||
'Closest catalog vector distance '
|
||||
|| TO_CHAR(v_distance, 'FM0D000000')
|
||||
|| ' is within configured maximum '
|
||||
|| TO_CHAR(v_threshold, 'FM0D000000') || '.'
|
||||
);
|
||||
ELSE
|
||||
v_result.put('status', 'UNMATCHED');
|
||||
v_result.put_null('game_key');
|
||||
v_result.put(
|
||||
'reason',
|
||||
'Closest catalog vector distance '
|
||||
|| TO_CHAR(v_distance, 'FM0D000000')
|
||||
|| ' exceeds configured maximum '
|
||||
|| TO_CHAR(v_threshold, 'FM0D000000') || '.'
|
||||
);
|
||||
END IF;
|
||||
RETURN v_result.to_clob;
|
||||
END;
|
||||
/
|
||||
|
||||
@@ -255,14 +280,14 @@ BEGIN
|
||||
|
||||
IF v_matched_candidate IS NOT NULL THEN
|
||||
v_mention_result.put('status', 'MATCHED');
|
||||
v_mention_result.put('reasonCode', 'LLM_CANDIDATE_MATCH');
|
||||
v_mention_result.put('reasonCode', 'VECTOR_SCORE_MATCH');
|
||||
v_mention_result.put('matchedGameKey', v_selected_key);
|
||||
|
||||
v_target := JSON_OBJECT_T.parse(v_matched_candidate.to_clob);
|
||||
v_target.put('mention', v_mention);
|
||||
v_target.put('status', 'MATCHED');
|
||||
v_target.put('matchStatus', 'MATCHED');
|
||||
v_target.put('reasonCode', 'LLM_CANDIDATE_MATCH');
|
||||
v_target.put('reasonCode', 'VECTOR_SCORE_MATCH');
|
||||
v_target.put('reason', v_reason);
|
||||
v_matched_count := v_matched_count + 1;
|
||||
|
||||
@@ -282,14 +307,7 @@ BEGIN
|
||||
END IF;
|
||||
ELSE
|
||||
v_mention_result.put('status', 'UNMATCHED');
|
||||
IF v_decision_status = 'MATCHED' THEN
|
||||
v_mention_result.put(
|
||||
'reasonCode',
|
||||
'LLM_SELECTED_UNKNOWN_CANDIDATE'
|
||||
);
|
||||
ELSE
|
||||
v_mention_result.put('reasonCode', 'LLM_NO_CANDIDATE_MATCH');
|
||||
END IF;
|
||||
v_mention_result.put('reasonCode', 'VECTOR_SCORE_OVER_THRESHOLD');
|
||||
|
||||
v_target := JSON_OBJECT_T();
|
||||
v_target.put('mention', v_mention);
|
||||
|
||||
Reference in New Issue
Block a user