mirror of
https://github.com/hoshikawa2/nemo_guardrails_configuration.git
synced 2026-07-09 17:04:20 +00:00
First Commit
This commit is contained in:
@@ -1,43 +1,11 @@
|
|||||||
models:
|
models:
|
||||||
- type: main
|
- type: main
|
||||||
engine: openai
|
engine: openai
|
||||||
model: gpt-4.1
|
model: gpt-5
|
||||||
parameters:
|
|
||||||
temperature: 0.2
|
|
||||||
max_tokens: 800
|
|
||||||
|
|
||||||
# 🔧 MUITO IMPORTANTE
|
colang_version: "1.0"
|
||||||
actions:
|
|
||||||
- name: mask_pii
|
|
||||||
function: config.actions.action_mask_pii
|
|
||||||
|
|
||||||
- name: detectar_toxicidade
|
|
||||||
function: config.actions.action_detectar_toxicidade
|
|
||||||
|
|
||||||
- name: detectar_out_of_scope
|
|
||||||
function: config.actions.action_detectar_out_of_scope
|
|
||||||
|
|
||||||
- name: validar_alcada
|
|
||||||
function: config.actions.action_validar_alcada
|
|
||||||
|
|
||||||
- name: validar_groundedness
|
|
||||||
function: config.actions.action_validar_groundedness
|
|
||||||
|
|
||||||
- name: verbalizacao_prematura
|
|
||||||
function: config.actions.action_verbalizacao_prematura
|
|
||||||
|
|
||||||
- name: cmp
|
|
||||||
function: config.actions.action_cmp
|
|
||||||
|
|
||||||
# 🧠 Organização dos rails
|
|
||||||
rails:
|
rails:
|
||||||
input:
|
dialog:
|
||||||
flows:
|
flows:
|
||||||
- input_check_toxicidade
|
- main
|
||||||
- input_check_out_of_scope
|
|
||||||
|
|
||||||
output:
|
|
||||||
flows:
|
|
||||||
- output_check_verbalizacao_prematura
|
|
||||||
- output_check_groundedness
|
|
||||||
- output_check_cmp
|
|
||||||
7
nemo_guardrails_tracing_project/config/rails/flows.co
Normal file
7
nemo_guardrails_tracing_project/config/rails/flows.co
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
define user express input
|
||||||
|
$input_text
|
||||||
|
|
||||||
|
define flow main
|
||||||
|
user express input
|
||||||
|
execute executar_pipeline_validacoes
|
||||||
|
bot say $nemo_response
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
define flow input_check_toxicidade
|
|
||||||
user input
|
|
||||||
$r = execute detectar_toxicidade(text=$user_input)
|
|
||||||
if $r.allowed == False
|
|
||||||
bot respond "BLOCKED:TOX"
|
|
||||||
|
|
||||||
|
|
||||||
define flow input_check_out_of_scope
|
|
||||||
user input
|
|
||||||
$r = execute detectar_out_of_scope(text=$user_input)
|
|
||||||
if $r.allowed == False
|
|
||||||
bot respond "BLOCKED:OOS"
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
define flow output_check_cmp
|
|
||||||
|
|
||||||
$r = execute cmp(resposta="dummy")
|
|
||||||
|
|
||||||
if $r.allowed == False
|
|
||||||
bot respond "BLOCKED:CMP"
|
|
||||||
|
|
||||||
bot respond "OK"
|
|
||||||
|
|
||||||
|
|
||||||
define flow output_check_verbalizacao_prematura
|
|
||||||
|
|
||||||
$r = execute verbalizacao_prematura(resposta="dummy")
|
|
||||||
|
|
||||||
if $r.allowed == False
|
|
||||||
bot respond "BLOCKED:REVPREC"
|
|
||||||
|
|
||||||
bot respond "OK"
|
|
||||||
|
|
||||||
define flow output_check_groundedness
|
|
||||||
|
|
||||||
$r = execute validar_groundedness(resposta="dummy")
|
|
||||||
|
|
||||||
if $r.allowed == False
|
|
||||||
bot respond "BLOCKED:GND"
|
|
||||||
|
|
||||||
bot respond "OK"
|
|
||||||
149
nemo_guardrails_tracing_project/src/actions.py
Normal file
149
nemo_guardrails_tracing_project/src/actions.py
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
# src/actions.py
|
||||||
|
|
||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from .llm_rails import (
|
||||||
|
detectar_toxicidade,
|
||||||
|
detectar_out_of_scope,
|
||||||
|
verbalizacao_prematura,
|
||||||
|
validar_groundedness,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .deterministic_rails import validar_alcada
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .judges import avaliar_qualidade_resposta
|
||||||
|
except Exception:
|
||||||
|
avaliar_qualidade_resposta = None
|
||||||
|
|
||||||
|
|
||||||
|
PIPELINE_RESULTS = {}
|
||||||
|
|
||||||
|
|
||||||
|
def extrair_payload(context: dict) -> dict:
|
||||||
|
try:
|
||||||
|
messages = context.get("messages", [])
|
||||||
|
content = messages[-1]["content"]
|
||||||
|
return json.loads(content)
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def add_trace(trace, label, result):
|
||||||
|
trace.append({
|
||||||
|
"rail": label,
|
||||||
|
"allowed": result.allowed,
|
||||||
|
"reason": result.reason,
|
||||||
|
"code": getattr(result, "code", label),
|
||||||
|
"mechanism": getattr(result, "mechanism", ""),
|
||||||
|
"data": getattr(result, "data", {}),
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def executar_pipeline_validacoes(context: dict):
|
||||||
|
payload = extrair_payload(context)
|
||||||
|
|
||||||
|
request_id = payload.get("request_id") or str(uuid.uuid4())
|
||||||
|
input_text = payload.get("input_text", "")
|
||||||
|
ctx = payload.get("context", {}) or {}
|
||||||
|
|
||||||
|
trace = []
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# INPUT RAILS - LLM
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
r_tox = detectar_toxicidade(input_text)
|
||||||
|
add_trace(trace, "TOX", r_tox)
|
||||||
|
if not r_tox.allowed:
|
||||||
|
failures.append(("TOX", r_tox.reason))
|
||||||
|
|
||||||
|
r_oos = detectar_out_of_scope(input_text)
|
||||||
|
add_trace(trace, "OOS", r_oos)
|
||||||
|
if not r_oos.allowed:
|
||||||
|
failures.append(("OOS", r_oos.reason))
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# BUSINESS RAIL - DETERMINISTIC
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
valor = ctx.get("ajuste_valor")
|
||||||
|
r_adj = validar_alcada(valor)
|
||||||
|
add_trace(trace, "ADJ", r_adj)
|
||||||
|
if not r_adj.allowed:
|
||||||
|
failures.append(("ADJ", r_adj.reason))
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# LLM RESPONSE
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
final_response = ctx.get("resposta_llm", "")
|
||||||
|
|
||||||
|
trace.append({
|
||||||
|
"step": "LLM",
|
||||||
|
"allowed": True,
|
||||||
|
"input": input_text,
|
||||||
|
"output_preview": final_response[:200],
|
||||||
|
"mechanism": "provided_response_or_proxy",
|
||||||
|
})
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# OUTPUT RAILS - LLM
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
r_revprec = verbalizacao_prematura(final_response, ctx)
|
||||||
|
add_trace(trace, "REVPREC", r_revprec)
|
||||||
|
if not r_revprec.allowed:
|
||||||
|
failures.append(("REVPREC", r_revprec.reason))
|
||||||
|
|
||||||
|
r_gnd = validar_groundedness(final_response, ctx)
|
||||||
|
add_trace(trace, "GND", r_gnd)
|
||||||
|
if not r_gnd.allowed:
|
||||||
|
failures.append(("GND", r_gnd.reason))
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# OPTIONAL JUDGE / CMP
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
if avaliar_qualidade_resposta is not None:
|
||||||
|
r_cmp = avaliar_qualidade_resposta(final_response)
|
||||||
|
add_trace(trace, "CMP", r_cmp)
|
||||||
|
if not r_cmp.allowed:
|
||||||
|
failures.append(("CMP", r_cmp.reason))
|
||||||
|
else:
|
||||||
|
trace.append({
|
||||||
|
"rail": "CMP",
|
||||||
|
"allowed": True,
|
||||||
|
"reason": "CMP não configurado",
|
||||||
|
"mechanism": "skipped",
|
||||||
|
"data": {},
|
||||||
|
})
|
||||||
|
|
||||||
|
# =========================
|
||||||
|
# FINAL DECISION
|
||||||
|
# =========================
|
||||||
|
|
||||||
|
blocked = len(failures) > 0
|
||||||
|
|
||||||
|
if blocked:
|
||||||
|
first_code, first_reason = failures[0]
|
||||||
|
nemo_response = f"BLOCKED:{first_code} - {first_reason}"
|
||||||
|
else:
|
||||||
|
nemo_response = final_response
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"allowed": not blocked,
|
||||||
|
"label": "CONFORME" if not blocked else "PROBLEMA",
|
||||||
|
"response": final_response,
|
||||||
|
"reason": nemo_response if blocked else "",
|
||||||
|
"failures": failures,
|
||||||
|
"trace": trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
PIPELINE_RESULTS[request_id] = result
|
||||||
|
|
||||||
|
return {
|
||||||
|
"nemo_response": nemo_response
|
||||||
|
}
|
||||||
64
nemo_guardrails_tracing_project/src/app_nemo.py
Normal file
64
nemo_guardrails_tracing_project/src/app_nemo.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import json
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from nemoguardrails import LLMRails, RailsConfig
|
||||||
|
|
||||||
|
from src.actions import executar_pipeline_validacoes, PIPELINE_RESULTS
|
||||||
|
|
||||||
|
|
||||||
|
def build_rails():
|
||||||
|
config = RailsConfig.from_path("./config")
|
||||||
|
rails = LLMRails(config)
|
||||||
|
|
||||||
|
rails.register_action(
|
||||||
|
executar_pipeline_validacoes,
|
||||||
|
"executar_pipeline_validacoes"
|
||||||
|
)
|
||||||
|
|
||||||
|
return rails
|
||||||
|
|
||||||
|
|
||||||
|
rails = build_rails()
|
||||||
|
|
||||||
|
|
||||||
|
def executar_atendimento(user_input: str, context: dict):
|
||||||
|
request_id = str(uuid.uuid4())
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"request_id": request_id,
|
||||||
|
"input_text": user_input,
|
||||||
|
"context": context or {},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = rails.generate(
|
||||||
|
messages=[
|
||||||
|
{
|
||||||
|
"role": "user",
|
||||||
|
"content": json.dumps(payload, ensure_ascii=False),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
result = PIPELINE_RESULTS.pop(request_id, None)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return result
|
||||||
|
|
||||||
|
return {
|
||||||
|
"allowed": False,
|
||||||
|
"label": "PROBLEMA",
|
||||||
|
"reason": "Pipeline não retornou resultado estruturado",
|
||||||
|
"response": response,
|
||||||
|
"trace": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
user_input = "quero cancelar VAS"
|
||||||
|
|
||||||
|
context = {
|
||||||
|
"ajuste_valor": 2000,
|
||||||
|
"resposta_llm": "Cancelamento realizado",
|
||||||
|
}
|
||||||
|
|
||||||
|
print(executar_atendimento(user_input, context))
|
||||||
@@ -187,4 +187,5 @@ def test_fluxo_completo_sucesso():
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["allowed"] is True
|
assert result["allowed"] is False
|
||||||
|
assert result["blocked_by"] == "CMP"
|
||||||
|
|||||||
Reference in New Issue
Block a user