mirror of
https://github.com/hoshikawa2/nemo_guardrails_configuration.git
synced 2026-07-09 17:04:20 +00:00
178 lines
4.7 KiB
Python
178 lines
4.7 KiB
Python
from .deterministic_rails import mask_pii, validar_alcada, enforce_compliance_anatel
|
|
from .llm_rails import (
|
|
detectar_toxicidade,
|
|
detectar_out_of_scope,
|
|
validar_groundedness,
|
|
verbalizacao_prematura,
|
|
supervisor_vas_avulso
|
|
)
|
|
from .judges import avaliar_qualidade_resposta
|
|
import json
|
|
|
|
|
|
def executar_atendimento(user_input: str, context: dict):
|
|
steps = []
|
|
|
|
# =========================
|
|
# 🔹 INPUT RAILS
|
|
# =========================
|
|
r = mask_pii(user_input)
|
|
steps.append(r)
|
|
text = r.sanitized_text or user_input
|
|
|
|
for rail in [detectar_toxicidade, detectar_out_of_scope]:
|
|
r = rail(text)
|
|
steps.append(r)
|
|
|
|
if not r.allowed:
|
|
return {
|
|
"allowed": False,
|
|
"blocked_by": r.code,
|
|
"response": None,
|
|
"steps": steps
|
|
}
|
|
|
|
# =========================
|
|
# 🔹 PYTHON RULE (CRÍTICA)
|
|
# =========================
|
|
if "ajuste_valor" in context:
|
|
r = validar_alcada(context["ajuste_valor"])
|
|
steps.append(r)
|
|
|
|
if not r.allowed:
|
|
return {
|
|
"allowed": False,
|
|
"blocked_by": r.code,
|
|
"response": None,
|
|
"steps": steps
|
|
}
|
|
|
|
# =========================
|
|
# 🔹 LLM RESPONSE
|
|
# =========================
|
|
resposta = context.get(
|
|
"resposta_llm",
|
|
"Resposta simulada do agente."
|
|
)
|
|
|
|
# =========================
|
|
# 🔹 OUTPUT RAILS (BLOQUEANTES)
|
|
# =========================
|
|
output_rails = [
|
|
enforce_compliance_anatel(resposta, context),
|
|
verbalizacao_prematura(resposta, context),
|
|
validar_groundedness(resposta, context),
|
|
]
|
|
|
|
for r in output_rails:
|
|
steps.append(r)
|
|
|
|
# 🔥 NÃO bloquear groundedness automaticamente
|
|
if not r.allowed and r.code != "GND":
|
|
return {
|
|
"allowed": False,
|
|
"blocked_by": r.code,
|
|
"response": None,
|
|
"steps": steps
|
|
}
|
|
|
|
# =========================
|
|
# 🔹 JUDGE (NÃO BLOQUEIA)
|
|
# =========================
|
|
r_quality = avaliar_qualidade_resposta(user_input, resposta)
|
|
steps.append(r_quality)
|
|
|
|
# =========================
|
|
# 🔹 SUPERVISOR (AUDITORIA)
|
|
# =========================
|
|
r_supervisor = supervisor_vas_avulso(
|
|
context.get("supervisor_payload", {})
|
|
)
|
|
steps.append(r_supervisor)
|
|
|
|
# =========================
|
|
# 🔹 RESULTADO FINAL
|
|
# =========================
|
|
BLOCKING_CODES = {"CMP", "ADJ", "REVPREC"}
|
|
|
|
allowed = all(
|
|
s.allowed for s in steps
|
|
if s.code in BLOCKING_CODES
|
|
)
|
|
|
|
|
|
return {
|
|
"allowed": allowed,
|
|
"response": resposta,
|
|
"steps": steps
|
|
}
|
|
|
|
|
|
# =========================
|
|
# 🔥 PRINT FORMATADO
|
|
# =========================
|
|
def print_result(result):
|
|
print("\n" + "=" * 80)
|
|
print("📊 RESULTADO FINAL")
|
|
print("=" * 80)
|
|
|
|
print(f"✔ Allowed: {result['allowed']}")
|
|
print(f"💬 Response: {result.get('response')}")
|
|
|
|
if not result["allowed"]:
|
|
print(f"🚫 Bloqueado por: {result.get('blocked_by')}")
|
|
|
|
print("\n🔎 STEPS:")
|
|
for s in result["steps"]:
|
|
print("-" * 60)
|
|
print(f"🧩 Code: {s.code}")
|
|
print(f"⚙️ Mechanism: {s.mechanism}")
|
|
print(f"✔ Allowed: {s.allowed}")
|
|
print(f"📝 Reason: {s.reason}")
|
|
if s.sanitized_text:
|
|
print(f"🔐 Sanitized: {s.sanitized_text}")
|
|
if s.data:
|
|
print(f"📦 Data: {s.data}")
|
|
|
|
print("=" * 80)
|
|
|
|
print("\n📦 JSON OUTPUT:")
|
|
print(json.dumps({
|
|
"allowed": result["allowed"],
|
|
"response": result.get("response"),
|
|
"steps": [
|
|
{
|
|
"code": s.code,
|
|
"allowed": s.allowed,
|
|
"reason": s.reason,
|
|
"mechanism": s.mechanism,
|
|
"data": s.data
|
|
}
|
|
for s in result["steps"]
|
|
]
|
|
}, indent=2, ensure_ascii=False))
|
|
|
|
|
|
# =========================
|
|
# 🔥 EXECUÇÃO DIRETA
|
|
# =========================
|
|
if __name__ == "__main__":
|
|
|
|
user_input = "Meu CPF é 123.456.789-00 e quero ajuste de 20 reais"
|
|
|
|
context = {
|
|
"ajuste_valor": 20,
|
|
"ajuste_validado": True,
|
|
"tipo_fluxo": "ajuste",
|
|
"requer_protocolo": True,
|
|
"resposta_llm": "Ajuste realizado. Protocolo: 202604270001.",
|
|
"chunks_rag": ["serviço fatura cobrança ajuste realizado protocolo"],
|
|
"supervisor_payload": {
|
|
"cancelamento_correto": True,
|
|
"servico_cancelado": "VAS Avulso",
|
|
"servico_solicitado": "VAS Avulso"
|
|
}
|
|
}
|
|
|
|
result = executar_atendimento(user_input, context)
|
|
print_result(result) |