Upload files to "/"
This commit is contained in:
265
prc_26ai_nl2sql.sql
Normal file
265
prc_26ai_nl2sql.sql
Normal file
@@ -0,0 +1,265 @@
|
||||
create or replace procedure prc_26AI_NL2SQL (
|
||||
p_app_user in varchar2,
|
||||
p_prompt in clob,
|
||||
p_profile in varchar2,
|
||||
p_action in varchar2 default 'narrate',
|
||||
p_limit_rows in number default 100,
|
||||
p_force_runsql in varchar2 default 'N',
|
||||
p_result out clob
|
||||
)
|
||||
as
|
||||
/*
|
||||
|
||||
Criado por: fernando.leal@oracle.com
|
||||
Data: Oct/2025
|
||||
Objetivo: demonstrar casos de uso do Oracle AI Database 26ai
|
||||
|
||||
v1 - rotina para controle de regras ao SelectAI - leal
|
||||
|
||||
begin
|
||||
dbms_cloud_ai.create_profile(
|
||||
profile_name => 'PROF_CENSO_V1',
|
||||
attributes =>
|
||||
'{"provider": "oci",
|
||||
"credential_name": "OCI_CRED",
|
||||
"oci_compartment_id": "ocid1.compartment.oc1..xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||
"region": "us-chicago-1",
|
||||
"model": "meta.llama-4-maverick-17b-128e-instruct-fp8",
|
||||
"oci_apiformat": "GENERIC",
|
||||
"object_list_mode": "automated",
|
||||
"object_list": [
|
||||
{"owner": "AICHAT1", "name": "TB_26AI_CENSO"}
|
||||
],
|
||||
"enforce_object_list": true,
|
||||
"constraints":"true",
|
||||
"comments": true,
|
||||
"annotations": true,
|
||||
"temperature": 0.1
|
||||
}'
|
||||
);
|
||||
end;
|
||||
|
||||
|
||||
*/
|
||||
v_response clob;
|
||||
v_narrate clob;
|
||||
v_pre_prompt_geral clob;
|
||||
v_pre_prompt_contexto clob;
|
||||
v_contexto clob;
|
||||
|
||||
v_categoria varchar2(200);
|
||||
v_profile varchar2(200);
|
||||
|
||||
v_estimated_rows number;
|
||||
--
|
||||
-- Limite de linhas que pode ser narrado
|
||||
--
|
||||
v_limit_rows number := p_limit_rows;
|
||||
--
|
||||
-- caso numero de linhas seja muito alto (definido por v_limit_rows), a acao narrate sera alterada para runwsql automaticamente
|
||||
--
|
||||
v_force_runsql varchar2(1) := upper(p_force_runsql);
|
||||
v_dt_start TIMESTAMP ;
|
||||
v_runsql clob;
|
||||
begin
|
||||
|
||||
v_dt_start := current_timestamp;
|
||||
|
||||
v_pre_prompt_geral := 'Sempre utilize alias para referencias nome da tabela. Nunca cite owner.';
|
||||
|
||||
--
|
||||
-- Ajustar e definir as categorias existentes. As categorias irao definir pre prompts mais especificos
|
||||
--
|
||||
SELECT DBMS_CLOUD_AI.GENERATE(prompt => 'Com base na pergunta: "' || p_prompt || '", defina qual a melhor categoria para ela: "cidades","estados","população","censo","outros".
|
||||
A resposta deve ser em JSON, e deve seguir este exemplo: { "categoria": "exemplo" }. APENAS ESTE JSON DEVE SER RETORNADO.',
|
||||
profile_name => p_profile,
|
||||
action => 'chat') response
|
||||
INTO v_contexto;
|
||||
|
||||
begin
|
||||
SELECT jt.categoria
|
||||
INTO v_categoria
|
||||
FROM JSON_TABLE(
|
||||
replace(replace(v_contexto,'```',''),'json',''),
|
||||
'$[*]' COLUMNS (
|
||||
categoria VARCHAR2(50) PATH '$.categoria'
|
||||
)
|
||||
) jt;
|
||||
exception
|
||||
when others then
|
||||
p_result := v_contexto;
|
||||
end;
|
||||
|
||||
dbms_output.put_line('v_categoria: ' || v_categoria);
|
||||
|
||||
if v_categoria in ('cidades','estados','população','censo') then
|
||||
|
||||
v_pre_prompt_contexto := 'Filtros para nome de estados sempre devem ser com 2 caracteres em MAISUCULO. Exemplo: Minas Gerais como MG, Amazonas como AM, Pará como PA';
|
||||
|
||||
-- pode haver definicao de varios profiles, sendo que cada um estara associado a uma categoria especifica. Neste exemplo, herda da propria chamada
|
||||
v_profile := 'PROF_CENSO_V3';
|
||||
|
||||
else
|
||||
|
||||
p_result := 'O prompt informado não faz referência aos dados que podem ser retornados. Contexto: ' || v_categoria;
|
||||
|
||||
end if;
|
||||
|
||||
dbms_output.put_line('v_profile: ' || v_profile);
|
||||
|
||||
--
|
||||
-- deve ter havido uma categorizacao da questao com associacao a um profile do SelectAI
|
||||
--
|
||||
if v_profile is not null then
|
||||
|
||||
-- resposta do showsql para analise do comando
|
||||
SELECT DBMS_CLOUD_AI.GENERATE(prompt => v_pre_prompt_geral || ' ' || v_pre_prompt_contexto || ' ' || p_prompt,
|
||||
profile_name => v_profile,
|
||||
action => 'showsql') response
|
||||
INTO v_response;
|
||||
|
||||
if upper(v_response) like 'SELECT%' or upper(v_response) like 'WITH%' then
|
||||
|
||||
-- estimativa do numero de linahs retornadas
|
||||
-- baseado em estatisticas das tabelas e indices
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'EXPLAIN PLAN SET STATEMENT_ID = ''plan_selectai'' FOR ' || v_response;
|
||||
|
||||
SELECT MAX(cardinality)
|
||||
INTO v_estimated_rows
|
||||
FROM plan_table
|
||||
WHERE id = 0
|
||||
AND STATEMENT_ID = 'plan_selectai';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
v_estimated_rows := 0;
|
||||
END;
|
||||
|
||||
dbms_output.put_line('v_response: ' || v_response);
|
||||
dbms_output.put_line('v_estimated_rows: ' || v_estimated_rows);
|
||||
dbms_output.put_line('v_limit_rows: ' || v_limit_rows);
|
||||
dbms_output.put_line('v_force_runsql: ' || v_force_runsql);
|
||||
|
||||
-- validacoes
|
||||
-- if instr(upper(v_response),'WHERE') = 0 and instr(upper(v_response),'GROUP') = 0 then
|
||||
|
||||
--p_result := 'O prompt informado não tem nenhum tipo de filtro. Procure adicionar algum critério, como filtros por data, empresa, região, SKU, etc';
|
||||
|
||||
if v_estimated_rows > v_limit_rows then
|
||||
|
||||
--
|
||||
-- colocar recurso pra trazer dados parcisi (ate X linhas )
|
||||
--
|
||||
|
||||
if lower(p_action) = 'narrate' and v_force_runsql = 'Y' then
|
||||
|
||||
-- chamada principal do SelectAI
|
||||
BEGIN
|
||||
SELECT DBMS_CLOUD_AI.GENERATE(prompt => v_pre_prompt_geral || ' ' || v_pre_prompt_contexto || ' ' || p_prompt,
|
||||
profile_name => v_profile,
|
||||
action => 'runsql') response
|
||||
INTO v_narrate;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
v_narrate := 'Desculpe, mas não há informações específicas sobre "' || p_prompt || '". Há regras de acesso definidas em seu perfil.';
|
||||
END;
|
||||
|
||||
p_result := v_narrate;
|
||||
|
||||
else
|
||||
|
||||
p_result := 'Estimativa de linhas retornadas: ' || v_estimated_rows || '. Procure adicionar algum critério, como filtros por data, empresa, região, SKU, etc';
|
||||
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
if p_action <> 'showsql' then
|
||||
-- chamada principal do SelectAI
|
||||
BEGIN
|
||||
SELECT DBMS_CLOUD_AI.GENERATE(prompt => v_pre_prompt_geral || ' ' || v_pre_prompt_contexto || ' ' || p_prompt,
|
||||
profile_name => v_profile,
|
||||
action => p_action) response
|
||||
INTO v_narrate;
|
||||
|
||||
/*
|
||||
Feedback is available only on Oracle AI Database 26ai.
|
||||
You can use it alongside the existing Select AI actions: runsql, showsql, and explainsql.
|
||||
Ensure that your AI profile is configured for NL2SQL generation and not RAG.
|
||||
*/
|
||||
if p_action <> 'runsql' then
|
||||
SELECT DBMS_CLOUD_AI.GENERATE(prompt => v_pre_prompt_geral || ' ' || v_pre_prompt_contexto || ' ' || p_prompt,
|
||||
profile_name => v_profile,
|
||||
action => 'runsql') response
|
||||
INTO v_runsql;
|
||||
end if;
|
||||
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
v_narrate := 'Desculpe, mas não há informações específicas sobre "' || p_prompt || '". Há regras de acesso definidas em seu perfil.';
|
||||
END;
|
||||
|
||||
p_result := v_narrate;
|
||||
|
||||
else
|
||||
|
||||
p_result := v_response; -- sql ja gerado
|
||||
|
||||
|
||||
end if;
|
||||
|
||||
|
||||
end if;
|
||||
|
||||
else
|
||||
|
||||
p_result := 'Não foi possível gerar uma consulta para atender sua questão: ' || v_response;
|
||||
|
||||
end if; -- select
|
||||
|
||||
end if; -- v_profile
|
||||
|
||||
|
||||
|
||||
if p_result is not null then
|
||||
|
||||
--
|
||||
-- log
|
||||
--
|
||||
insert into TB_26AI_CENSO_HISTORY(USERNAME,
|
||||
DT,
|
||||
PROMPT,
|
||||
RESPONSE,
|
||||
PROFILE,
|
||||
NARRATE,
|
||||
DT_START,
|
||||
DT_END,
|
||||
PROMPT_CHARS,
|
||||
RESPONSE_CHARS
|
||||
)
|
||||
values( lower( p_app_user ) ,
|
||||
sysdate ,
|
||||
p_prompt ,
|
||||
v_response ,
|
||||
v_profile,
|
||||
--case
|
||||
-- when lower(p_action) = 'narrate' then
|
||||
p_result,
|
||||
-- end,
|
||||
v_dt_start,
|
||||
current_timestamp,
|
||||
DBMS_LOB.GETLENGTH(p_prompt),
|
||||
case
|
||||
when lower(p_action) = 'narrate' then
|
||||
DBMS_LOB.GETLENGTH(v_response) + DBMS_LOB.GETLENGTH(p_result)
|
||||
else
|
||||
DBMS_LOB.GETLENGTH(p_result)
|
||||
end
|
||||
) ;
|
||||
commit;
|
||||
end if; -- save do p_result
|
||||
|
||||
dbms_output.put_line('p_result: ' || p_result);
|
||||
|
||||
end;
|
||||
/
|
||||
Reference in New Issue
Block a user