# Tutorial: NeMo Guardrails com Python, Proxy OpenAI-Compatible e Tracing ## 1. Objetivo Este tutorial orienta um time de desenvolvimento a implementar guardrails usando **NVIDIA NeMo Guardrails como biblioteca Python**, sem depender inicialmente do NeMo Server. A proposta é permitir uma adoção incremental: começar com rails determinísticos, rails LLM e regras Python dentro da aplicação, mantendo uma estrutura que possa evoluir futuramente para servidor, supervisor, judges batch e observabilidade completa. O projeto entregue junto com este tutorial foi gerado com base na planilha `Guardrails e Curadoria v3 - Consolidado.xlsx`, que define guardrails, curadoria, supervisores e LLM-as-a-judge. ## 2. Disclaimer de Uso e Responsabilidade Este material, incluindo códigos-fonte, exemplos, estruturas de projeto e definições de arquitetura, foi desenvolvido exclusivamente para fins educacionais, ilustrativos e de referência conceitual, com o objetivo de demonstrar possíveis abordagens para implementação de guardrails, supervisores e mecanismos de avaliação (judge) em sistemas baseados em inteligência artificial. >**Nota Importante:** O objetivo principal é ilustrar e exemplificar como estruturar um modelo de configuração para o uso do Nemo Guardrails. O conteúdo apresentado neste tutorial não constitui uma solução pronta para produção, nem deve ser interpretado como recomendação definitiva de arquitetura, implementação ou governança. ### 2.1 Natureza do código apresentado Os códigos fornecidos: Representam exemplos simplificados para ilustrar o funcionamento dos conceitos propostos; Incluem implementações determinísticas (regex, regras Python) e exemplos com uso de modelos de linguagem (LLM); Não contemplam todos os cenários reais de negócio, segurança, escalabilidade, resiliência ou compliance; Podem conter limitações, simplificações ou omissões intencionais, necessárias para fins didáticos. ### 2.2 Ausência de suporte e garantia Ao utilizar este material, o leitor declara estar ciente de que: Não há qualquer garantia de funcionamento, desempenho ou adequação para uso em ambientes produtivos; Não é oferecido suporte técnico, manutenção, correções ou atualizações para os códigos apresentados; Nem o autor, nem a empresa associada, assumem responsabilidade por: falhas de execução impactos financeiros problemas legais ou regulatórios incidentes de segurança ou vazamento de dados decisões tomadas com base nos exemplos fornecidos ### 2.3 Responsabilidade do leitor Cabe exclusivamente ao leitor: Avaliar criticamente a adequação dos exemplos ao seu contexto específico; Adaptar, evoluir e validar o código conforme: requisitos de negócio requisitos legais e regulatórios políticas de segurança da informação necessidades de desempenho e escalabilidade Realizar testes completos antes de qualquer uso em produção; Garantir conformidade com legislações aplicáveis (ex: LGPD, regulamentações setoriais, etc.). ### 2.4 Considerações sobre performance e latência O material inclui exemplos que utilizam: chamadas a modelos LLM validações semânticas múltiplas camadas de controle (guardrails, supervisor, judge) Esses elementos podem introduzir impactos significativos de latência e custo, especialmente em ambientes reais. Portanto: A arquitetura proposta deve ser criteriosamente avaliada quanto a: tempo de resposta custo por requisição volume de chamadas ao modelo Recomenda-se a adoção de estratégias como: priorização de regras determinísticas (Python/regex) execução assíncrona de avaliações (judge batch) cache e otimizações de fluxo ### 2.5 Sobre Supervisor e Judge Os componentes de Supervisor e LLM-as-a-Judge apresentados: São implementações meramente ilustrativas; Não representam modelos completos de auditoria, governança ou avaliação de qualidade; Devem ser tratados como pontos de partida conceituais, e não como soluções finais. ### 2.6 Uso em ambiente produtivo A utilização deste material em ambientes produtivos: É de inteira responsabilidade do leitor ou da organização que o adotar; Exige: revisão técnica aprofundada testes extensivos validação de segurança definição de SLAs e observabilidade governança adequada de IA ## 3. Conceitos principais ### 3.1 Guardrail Guardrail é uma proteção aplicada ao fluxo de IA. Pode bloquear, mascarar, rejeitar, reescrever, auditar ou medir uma interação. Neste projeto, os guardrails foram separados em quatro famílias: | Família | Uso | Exemplo da planilha | |---|---|---| | NeMo / LLM rail | Avaliação semântica com LLM | Toxicidade, Out-of-Scope, Groundedness | | Regex rail | Regra determinística rápida | PII Masking | | Python rail | Regra de negócio determinística | Alçada de Ajuste, Histórico | | Supervisor / Judge | Auditoria pós-fluxo ou batch | Supervisor VAS Avulso, Qualidade, Alucinação | ### 3.1.1 Tratamento de memória em caso de bloqueio Quando uma interação for bloqueada por qualquer guardrail, o conteúdo original bloqueado não deve ser armazenado diretamente na memória conversacional do agente. Essa regra se aplica a: - mensagens de entrada bloqueadas por Input Rails; - respostas bloqueadas por Output Rails; - trechos de RAG, KB, tickets ou documentos descartados; - decisões ou ações rejeitadas por regras Python. Esse cuidado evita que entradas maliciosas, dados sensíveis, instruções indevidas, respostas inseguras ou contexto contaminado permaneçam disponíveis em turnos futuros. Em caso de bloqueio, recomenda-se registrar apenas informações mínimas e seguras, como: - código do guardrail acionado; - timestamp; - identificador da sessão; - categoria da violação; - decisão tomada: bloqueado, mascarado, descartado, redirecionado ou reescrito. Quando houver necessidade de auditoria, o conteúdo deve ser armazenado apenas em trilha de segurança apropriada, com mascaramento, controle de acesso e política de retenção definida. A memória conversacional do agente deve receber, no máximo, um resumo seguro do evento, por exemplo: “Conteúdo bloqueado por política de segurança.” O conteúdo bloqueado não deve ser reutilizado como contexto para geração de respostas futuras. ### 3.2 Input Rail Executa antes do LLM. Serve para proteger o modelo contra entrada tóxica, fora de escopo, dados sensíveis, jailbreak ou pedidos indevidos. Na planilha: - PII Masking - Toxicidade - Out-of-Scope ### 3.3 Output Rail Executa depois que o LLM gera uma resposta, mas antes de devolver ao usuário ou executar uma ação. Na planilha: - Compliance Anatel - Verbalização Prematura - Groundedness ### 3.4 Python pré-execução Nem toda regra deve ir para o LLM. Regras financeiras, alçada, duplicidade de crédito e consistência histórica devem ficar em Python ou em serviço de negócio. Exemplo: ```python if valor_ajuste > limite: escalar_para_ath() ``` ### 3.5 Supervisor Supervisor é uma camada independente que audita o fluxo já executado. Ele não substitui guardrails. Ele verifica se a jornada foi correta. Na planilha: - Supervisor VAS Avulso - Avalia se o cancelamento foi feito corretamente - Retorna `CONFORME`, `SUSPEITO` ou `PROBLEMA` ### 3.6 LLM-as-a-judge É uma avaliação normalmente batch, pós-sessão, para medir qualidade, tom, alucinação, satisfação e aderência à rubrica. Na planilha: - Sentimento CSI - Taxa de Alucinação - Qualidade da Resposta - Tom de Voz ## 4. Arquitetura utilizada Este fluxo representa uma arquitetura estruturada para controle, validação e governança de sistemas baseados em LLM, combinando: Guardrails (proteção e controle em tempo real) Regras determinísticas (Python/regex) Supervisão de jornada Curadoria e métricas Execução integrada com sistemas reais (APIs/backend) O objetivo principal é ilustrar um sistema que: - opere dentro de limites seguros e definidos - evite riscos (jurídicos, financeiros, reputacionais) - mantenha qualidade e consistência nas respostas - seja observável e mensurável - possa evoluir de forma controlada O fluxo separa claramente responsabilidades entre: - bloqueio (guardrails) - execução (LLM + backend) - validação (supervisor) - medição (curadoria/judge) ```text User Input ↓ Input Rails ├─ Regex: PII Masking ├─ LLM: Toxicidade ├─ LLM: Out-of-Scope ├─ (Prompt Injection / Jailbreak Detection) ├─ (RAG Injection / Context Poisoning Detection) └─ (Data Leakage / Secret Exfiltration Pre-check) ↓ LLM principal via NeMo Guardrails ↓ Output Rails ├─ Compliance Anatel ├─ Verbalização Prematura ├─ Groundedness ├─ (System Prompt Leakage / Policy Exposure) └─ (Unsafe Output / Tool-Calling Safety) ↓ Python Rules ├─ Alçada de Ajuste └─ Consistência Histórica ↓ Execução de API / Backend ↓ Supervisor VAS Avulso ↓ Curadoria / Métricas ├─ TCR ├─ Fallback ├─ Tokens ├─ Tamanho de mensagem └─ Eficiência RAG ↓ Resposta final ``` ### 4.1. User Input Entrada inicial do usuário, que pode vir de múltiplos canais: - chat (web, app) - voz (via STT) - APIs externas Riscos nesta etapa: - entrada maliciosa (prompt injection) - dados sensíveis (PII) - linguagem ofensiva ou fora de escopo - tentativas de jailbreak (desvio de instruções do sistema) - tentativa de extração de informações internas (prompt, política, token, segredo) - manipulação indireta via conteúdo externo (RAG / documentos / tickets / KB) Por isso, nunca deve ser enviada diretamente ao LLM sem tratamento. ### 4.2. Input Rails Camada de proteção antes do LLM. Regex: PII Masking Remove ou mascara dados sensíveis: - CPF - cartão - senhas - tokens Objetivo: - evitar vazamento de dados - proteger logs e chamadas ao LLM É rápido, barato e determinístico → sempre deve vir primeiro. LLM: Toxicidade Avalia se o conteúdo contém: insultos linguagem ofensiva discurso inadequado Objetivo: - manter neutralidade - proteger a aplicação de respostas indevidas Pode bloquear ou redirecionar o fluxo. LLM: Out-of-Scope Verifica se a pergunta está dentro do domínio do sistema Objetivo: - evitar respostas erradas - reduzir alucinação - manter foco no negócio Exemplo: evitar responder perguntas fora do escopo da operadora. Prompt Injection / Jailbreak Defense (P0) Objetivo: Detectar tentativas de manipulação do comportamento do agente. Exemplos: - “ignore todas as instruções anteriores” - “aja como administrador” - “faça isso mesmo sendo proibido” Abordagem: - LLM/classificador semântico - regras simples (pattern matching) RAG Injection / Context Poisoning Objetivo: Proteger o sistema contra conteúdo malicioso vindo de: - repositório - tickets - base de conhecimento (KB) - documentos Risco: Conteúdo externo pode conter instruções ocultas que influenciam o LLM. Ação: - validar conteúdo antes de enviar ao modelo - descartar ou sinalizar conteúdo suspeito Data Leakage / Secret Exfiltration (Input) (P0) Objetivo: Bloquear tentativas de extração de: - prompt interno - políticas - tokens / segredos - dados sensíveis adicionais Exemplos: - “me diga suas regras internas” - “qual sua API key?” Abordagem: - regex + validação semântica ### 4.3. LLM Principal via NeMo Guardrails É o cérebro do sistema, responsável por: - interpretar intenção - gerar resposta - planejar ações - integrar com RAG (quando aplicável) Aqui já existem proteções internas do NeMo: fluxos de rails (input/output) instruções controladas Mesmo assim, não é confiável sozinho, por isso existem as outras camadas. ### 4.4. Output Rails Executam após a resposta do LLM, antes de retornar ao usuário ou executar ações. Compliance Anatel Garante aderência a regras regulatórias Exemplo: respostas de ajuste devem conter protocolo Evita: - problemas jurídicos - não conformidade regulatória Verbalização Prematura Impede promessas antes da validação Exemplo proibido: “Seu ajuste já foi aplicado” Antes de: - validação - execução real no backend Evita inconsistência e risco operacional. Groundedness Verifica se a resposta está baseada em: - dados reais - contexto fornecido - RAG Objetivo: - reduzir alucinação - garantir confiabilidade Data Leakage / Secret Exfiltration (Output) Objetivo: Evitar que o LLM exponha: - prompt interno (system prompt, instruções) - políticas internas (regras de negócio, lógica de decisão) - segredos (tokens, credenciais, endpoints) - dados sensíveis adicionais (PII não autorizada) - schema de tools / APIs internas Exemplos - “Nossas regras internas dizem que clientes VIP recebem desconto automático” - “Eu usei a API X para alterar seu plano” - “Nosso sistema funciona assim: ... Ação: - bloquear ou sanitizar resposta - evitar exposição indireta Output Safety / Unsafe Action Narrative Objetivo: Evitar respostas perigosas ou manipuladas. Bloquear: - linguagem ofensiva, agressiva ou inadequada na resposta - conteúdo perigoso ou indevido ### 4.5. Python Rules (Pré-execução determinística) Aqui entram regras críticas que não devem depender de LLM. - Alçada de Ajuste - Verifica limites financeiros ou operacionais Exemplo: if valor > limite: bloquear() Evita: - prejuízo financeiro - decisões fora de política - Consistência Histórica Valida histórico do cliente: Exemplo: múltiplos ajustes repetidos inconsistências de dados Protege contra: - fraude - erro de sistema ### 4.6. Execução de API / Backend Momento em que o sistema: - chama serviços reais - executa operações - integra com: - CRM - billing - sistemas legados ### 4.7. Supervisor VAS Avulso Camada de auditoria da jornada, após execução. Função: - verificar se tudo ocorreu corretamente Pode avaliar: - coerência da decisão - aderência às regras - consistência entre intenção e ação Retorna algo como: - CONFORME - SUSPEITO - PROBLEMA >**Importante:** Supervisor não bloqueia → ele audita e sinaliza ### 4.8. Curadoria / Métricas Camada de observabilidade e evolução do sistema. TCR (Task Completion Rate) - Mede se a tarefa foi concluída com sucesso Fallback - Quantas vezes o sistema falhou ou escalou Tokens - Consumo de tokens do LLM Impacta custo diretamente - Tamanho de mensagem - Controle de payload e eficiência - Eficiência RAG - Mede qualidade da recuperação de contexto Exemplo: respostas baseadas em conteúdo correto vs errado ## 5. Estrutura do projeto ```text nemo_guardrails_tracing_project/ ├── config/ │ ├── config.yml : Arquivo de configuração para o Nemo Guardrail (Modelos, definições de rails de input e output) │ ├── config.py : Registro das ações para os guardrails │ ├── guardrails.yaml : Arquivo de mapeamento dos rails conforme definição da Planilha inicial (não utilizado pelo código) │ ├── rails/ │ ├─────input.co : configuração de entrada dos fluxos Nemo │ ├─────output.co : configuração de saída dos fluxos Nemo │ └── guardrails_catalog.json ├── src/ │ ├── app.py : demo para consumir rails sem uso de Nemo Guardrails │ ├── app_nemo.py : demo para consumir rails com uso de Nemo Guardrails │ ├── actions.py : Arquivo de Actions expondo deterministic_rails e llm_rails │ ├── deterministic_rails.py : rails deterministicos para serem utilizados como modelo na estrutura │ ├── judges.py : estrutura demo para ilustrar judge │ ├── llm_client.py : mockup para demo llm │ ├── llm_rails.py : rails llm para serem utilizados como modelo na estrutura │ ├── models.py : classe do modelo de resposta dos rails │ ├── registry.py : modelo de registry do guardrail │ └── prompts/ : pasta com os prompts para rails que utilizam llm ├── tests/ │ └── test_guardrails.py : código utilizado para pytest ├── scripts/ │ └── run_tests.sh : bash script para testar os rails individualmente via pytest ├── requirements.txt : bibliotecas necessárias para o projeto ├── .env.example : variáveis de ambiente para configuração └── README.md ``` ## 6. Preparação do ambiente ### 6.1 Criar ambiente Python ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ### 6.2 Configurar variáveis ```bash cp .env.example .env ``` Variáveis principais: ```bash OPENAI_API_BASE=http://127.0.0.1:8051/v1 OPENAI_BASE_URL=http://127.0.0.1:8051/v1 OPENAI_API_KEY=dummy OPENAI_MODEL=gpt-4.1 OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006/v1/traces ENABLE_TRACING=true USE_MOCK_LLM=false ALCADA_MAX_AJUSTE=50 ``` >**Nota Importante:** O Nemo Guardrails possui compatibilidade apenas com a API da OpenAI. É possível utilizar-se de modelos que não tenham compatibilidade com API OpenAI, bastando para isso utilizar-se do proxy OCI OpenAI desta documentação: [https://github.com/hoshikawa2/nemo_guardrails_oci_generative_ai](https://github.com/hoshikawa2/nemo_guardrails_oci_generative_ai) ## 7. Configuração do NeMo Guardrails A camada de configuração no NeMo Guardrails é responsável por definir o comportamento do sistema sem alterar código Python. Ela é composta por três arquivos principais: | Arquivo | Função | |------------|----------------------------------------------------------------| | config.yml | Configuração estrutural (modelo, instruções, bindings) | | input.co | Definição de fluxos, regras e comportamento conversacional | | output.co | Definição de fluxos, regras e comportamento conversacional | ### Arquivo: `config/config.yml` ```yaml models: - type: main engine: openai model: ${OPENAI_MODEL} instructions: - type: general content: | Você é um assistente de atendimento de telecom. Responda em português, com clareza, sem prometer ajustes antes de validação, sem expor dados sensíveis e sem tratar temas fora do escopo. rails: input: flows: - self check input output: flows: - self check output ``` O config.yml é o arquivo central de configuração do NeMo Guardrails. Ele define: qual modelo será utilizado como o agente deve se comportar quais fluxos (rails) serão executados como o sistema se conecta ao motor de LLM >**Nota:** Em termos simples, o config.yml define a estrutura e as regras globais do agente, antes mesmo da execução dos fluxos do .co Dentro do seu fluxo: User Input ↓ config.yml ← (define regras globais) ↓ rails.co ← (define comportamento dinâmico) ↓ LLM / Python / Supervisor ### Arquivo: `config/guardrails.yaml` ```yaml guardrails: - {codigo: MSK, item: "PII Masking", mecanismo: regex} - {codigo: CMP, item: "Compliance Anatel", mecanismo: regex} - {codigo: ADJ, item: "Alçada de Ajuste", mecanismo: python} - {codigo: REVPREC_SUP, item: "Supervisor VAS Avulso", mecanismo: llm_supervisor} - {codigo: TCR, item: "Conclusão de Tarefa", mecanismo: python} - {codigo: REVPREC, item: "Verbalização Prematura", mecanismo: llm_rail} - {codigo: FALLBACK, item: "Fallback Não Entendi", mecanismo: python} - {codigo: VIOL, item: "Violação de Guardrails", mecanismo: python} - {codigo: TOX, item: "Toxicidade", mecanismo: llm_rail} - {codigo: OOS, item: "Out-of-Scope", mecanismo: llm_rail} - {codigo: GND, item: "Groundedness", mecanismo: llm_rail} - {codigo: HIST, item: "Consistência Histórica", mecanismo: python} - {codigo: PMPTK, item: "Prompt Tokens", mecanismo: python} - {codigo: EFIC, item: "Eficiência NLU", mecanismo: python} - {codigo: NO-M, item: "No-Match RAG", mecanismo: python} - {codigo: CSI, item: "Sentimento", mecanismo: llm_judge} - {codigo: ALUC, item: "Taxa de Alucinação", mecanismo: llm_judge} - {codigo: VLOOP, item: "Volume de Loops", mecanismo: python} - {codigo: MSIZE, item: "Tamanho de Mensagem", mecanismo: python} - {codigo: RQLT, item: "Qualidade da Resposta", mecanismo: llm_judge} - {codigo: VCTN, item: "Tom de Voz", mecanismo: llm_judge} - {codigo: REVPREC_METRIC, item: "Precisão e Revocação", mecanismo: python} - {codigo: SEMAC, item: "Acurácia Semântica STT", mecanismo: python} ``` ### Arquivo: `rails/input.co` ```yaml define bot refuse to respond "I apologize, but I cannot provide that information." define flow check_input_terms # 🔐 Segurança $ok_msk = execute mask_pii_action $ok_tox = execute detectar_toxicidade_action $ok_oos = execute detectar_out_of_scope_action # 💰 Regras de negócio $ok_adj = execute validar_alcada_action # 🧠 Contexto $ok_hist = execute validar_consistencia_historica_action # 🔁 Conversação $ok_loop = execute detectar_loop_action $ok_size = execute medir_tamanho_mensagem_action $ok_fbk = execute detectar_fallback_action # 🚨 HARD BLOCK if not ($ok_msk and $ok_tox and $ok_oos and $ok_adj and $ok_hist) bot refuse to respond stop # ⚠️ SOFT SIGNALS (não bloqueiam) # loop, tamanho e fallback são monitoramento ``` ### Arquivo: `rails/output.co` ```yaml define flow check_output_terms # 🧠 Qualidade da resposta $ok_revp = execute verbalizacao_prematura_action $ok_gnd = execute validar_groundedness_action $ok_sup = execute supervisor_vas_avulso_action # 📡 Compliance $ok_cmp = execute enforce_compliance_anatel_action # 📊 Métricas $ok_tcr = execute calcular_tcr_action $ok_tok = execute contabilizar_tokens_action $ok_efic = execute calcular_eficiencia_nlu_action $ok_nom = execute detectar_no_match_rag_action $ok_prec = execute calcular_precisao_revocacao_action $ok_sem = execute avaliar_acuracia_semantica_action # 🚨 Auditoria $ok_viol = execute registrar_violacao_action # 🚨 HARD BLOCK (só qualidade crítica) if not ($ok_revp and $ok_gnd and $ok_sup and $ok_cmp) bot refuse to respond stop # ⚠️ SOFT METRICS (não bloqueiam) # TCR, tokens, eficiência, precisão, STT etc ``` ## Definições ### define flow Cria um fluxo de execução. define flow self check input Representa: - um guardrail - uma sequência de validações ### Eventos Captura a entrada do usuário. - user input ### bot message Captura a resposta do LLM. - bot message ### Ações com LLM Avaliação semântica - bot evaluate toxicity Função: chamar LLM para classificar conteúdo Exemplo: - toxicidade - out-of-scope - groundedness ### Condições if not allowed bot refuse Função: - bloquear fluxo - redirecionar resposta ## 8. Exemplos de rails criados a partir da planilha Segue abaixo a estruturação dos exemplos para o entendimento do funcionamento da tecnologia. ### 8.1 MSK — PII Masking Implementação: `src/deterministic_rails.py` ```python CPF_RE = re.compile(r"\b\d{3}\.\d{3}\.\d{3}-\d{2}\b") CARD_RE = re.compile(r"\b(?:\d[ -]*?){13,16}\b") PASSWORD_RE = re.compile(r"(?i)(senha|password|token|api[_-]?key)\s*[:=]\s*\S+") ``` Objetivo: mascarar CPF, cartão, senha, token e credenciais antes de enviar ao LLM e antes de logar. ### 8.2 CMP — Compliance Anatel Implementação: `enforce_compliance_anatel()` Regra: respostas de ajuste precisam conter número de protocolo. ### 8.3 ADJ — Alçada de Ajuste Implementação: `validar_alcada()` Regra: se o valor do ajuste exceder `ALCADA_MAX_AJUSTE`, o fluxo é bloqueado e escalado para atendimento humano. ### 8.4 REVPREC — Verbalização Prematura Implementação: `verbalizacao_prematura()` Regra: o agente não pode prometer ajuste, crédito ou cancelamento antes de validação. ### 8.5 Supervisor VAS Avulso Implementação: `src/supervisor.py` Avalia cinco regras: 1. O VAS cancelado corresponde ao item solicitado. 2. Não houve promessa antes da validação. 3. Resposta de ajuste contém protocolo. 4. Não houve exposição de PII. 5. A decisão está coerente com os dados de contexto. ## 9. Integração com proxy OpenAI-Compatible A tecnologia Nemo Guardrails permite a integração com modelos LLM, porém apenas aqueles que sejam compatíveis com a estrutura OpenAI API. O projeto usa o cliente `openai` apontando para seu proxy: ```python client = OpenAI( api_key=settings.openai_api_key, base_url=settings.openai_api_base ) ``` Configuração: ```bash export OPENAI_API_BASE=http://127.0.0.1:8051/v1 export OPENAI_BASE_URL=http://127.0.0.1:8051/v1 export OPENAI_API_KEY=dummy export OPENAI_MODEL=gpt-4.1 ``` >**Nota:** Caso o projeto necessite utilizar modelos LLM não-compatíveis com OpenAI API, veja em referências como utilizar uma camada proxy para integrar com modelos locais ou Oracle Cloud Generative AI ## 10. Tracing com OpenTelemetry / Phoenix Segue aqui exemplo para integrar com plataforma de observabilidade utilizando o OpenTelemetry e Phoenix. Arquivo: `src/tracing.py` Cada etapa cria spans: - `rail.input.msk` - `rail.python.alcada` - `llm.nemo.generate` - `rail.output.verbalizacao_prematura` - `rail.output.compliance_anatel` - `supervisor.vas_avulso` Configuração: ```bash export ENABLE_TRACING=true export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006/v1/traces ``` ### 10. 1 Subindo OpenTelemetry + Phoenix para Tracing de LLM O Arize Phoenix é uma ferramenta de observabilidade focada em aplicações de IA. Neste tutorial, servirá apenas como modelo para se ter uma idéia de como integrar com uma plataforma de observabilidade. Instale: pip install arize-phoenix pip install opentelemetry-sdk pip install opentelemetry-exporter-otlp pip install opentelemetry-instrumentation Suba o servidor: phoenix serve Ele permite visualizar: - spans (cada etapa do fluxo) - latência por componente - entradas e saídas do LLM - erros e falhas - fluxo completo da execução UI disponível em: http://localhost:6006 Endpoint OTLP (para envio de traces): http://localhost:6006/v1/traces ![img_2.png](img_2.png) ### 10.2 Integração com Langfuse via OpenTelemetry O projeto já possui suporte a tracing utilizando OpenTelemetry (OTEL), o que permite integrar facilmente plataformas de observabilidade como: - Langfuse - Phoenix - Jaeger - Grafana Tempo - Elastic APM A arquitetura atual já está desacoplada do backend de observabilidade, portanto a adaptação para o Langfuse exige apenas pequenas alterações. --- #### Como funciona O fluxo será: ```text NeMo Guardrails ↓ OpenTelemetry ↓ OTLP Exporter ↓ Langfuse ``` --- #### Código Atual O projeto já possui um `tracing.py` semelhante a: ```python exporter = OTLPSpanExporter( endpoint=endpoint, timeout=5 ) ``` Atualmente ele publica para: ```python http://localhost:6006/v1/traces ``` que normalmente corresponde ao Phoenix. --- ### Modificações Necessárias #### 10.2.1 Adicionar autenticação do Langfuse >**Nota:** O Langfuse exige autenticação Basic Auth no exporter OTLP. Renomeie o **tracing_langfuse.py** para **tracing.py** caso deseje adotar o Langfuse como padrão. --- #### 10.2.2 Adicionar variáveis de ambiente Adicionar no `.env`: ```bash ENABLE_TRACING=true LANGFUSE_PUBLIC_KEY=pk-xxxxxxxx LANGFUSE_SECRET_KEY=sk-xxxxxxxx OTEL_EXPORTER_OTLP_ENDPOINT=https://cloud.langfuse.com/api/public/otel ``` --- #### 10.2.3 Explicação das Variáveis | Variável | Descrição | |---|---| | `ENABLE_TRACING` | Ativa ou desativa o tracing | | `LANGFUSE_PUBLIC_KEY` | Chave pública do projeto Langfuse | | `LANGFUSE_SECRET_KEY` | Chave secreta do projeto Langfuse | | `OTEL_EXPORTER_OTLP_ENDPOINT` | Endpoint OTLP do Langfuse | --- #### 10.2.4 Alteração no tracing.py **Código original** ```python exporter = OTLPSpanExporter( endpoint=endpoint, timeout=5 ) ``` --- #### 10.2.5 Código adaptado para Langfuse ```python import base64 public_key = os.getenv( "LANGFUSE_PUBLIC_KEY" ) secret_key = os.getenv( "LANGFUSE_SECRET_KEY" ) headers = {} if public_key and secret_key: auth = base64.b64encode( f"{public_key}:{secret_key}".encode() ).decode() headers["Authorization"] = ( f"Basic {auth}" ) exporter = OTLPSpanExporter( endpoint=endpoint, headers=headers, timeout=5 ) ``` --- #### 10.2.6 O que muda após isso O projeto passará a enviar automaticamente: - traces - spans - latência - execução de rails - execução de judges - tool calls - chamadas LLM - erros - retries para o Langfuse. --- #### 10.2.7 Exemplo de Trace Visualizado ```text TRACE ├── input_guardrail ├── supervisor ├── llm_router ├── mcp_tool ├── judge_groundedness └── final_response ``` #### 10.2.8 Adaptação para uso do Langfuse A implementação atual utiliza o **tracing.py** como padrão de observabilidade, porém existe outro código montado para autenticação com **Langfuse** chamado **tracing_langfuse.py**. Bastando utilizar a variáveis de memórias adicionais de autenticação como informado acima. Portanto a integração com Langfuse exige apenas: - alteração do endpoint - inclusão do Authorization header - configuração das variáveis de ambiente --- ## 11. Como executar o projeto ### 11.1 Teste demonstrável sem proxy ```bash export USE_MOCK_LLM=true export ENABLE_TRACING=false python -m src.app ``` Resultado esperado: ```json { "allowed": true, "input_sanitized": "Cancelar VAS. CPF [CPF_MASCARADO]", "output": "Cancelamento analisado. Ajuste elegível conforme validação. Protocolo nº 123456789.", "metrics": { "tcr": "CONCLUIDO" } } ``` ### 11.2 Executar testes automatizados ```bash pytest -q ``` Os testes comprovam: - CPF é mascarado. - Alçada bloqueia valor acima do limite. - Compliance Anatel bloqueia ajuste sem protocolo. - Verbalização prematura é bloqueada. - Fluxo completo funciona em modo mock. ### 11.3 Executar com proxy real ```bash export USE_MOCK_LLM=false export OPENAI_API_BASE=http://127.0.0.1:8051/v1 export OPENAI_BASE_URL=http://127.0.0.1:8051/v1 export OPENAI_API_KEY=dummy export OPENAI_MODEL=gpt-4.1 ``` ### 11.3.1 Teste dos guardrails ```bash bash scripts/run_tests.sh ``` Este script valida todos os exemplos de guardrails descritos no documento para facilitar o entendimento. ![img_1.png](img_1.png) ### 11.3.2 Teste sem uso do Nemo Guardrails ``` python -m src.app ``` O código **app.py** não utiliza o framework **Nemo Guardrails**. Ele apenas utiliza os guardrails criados de forma deterministica ou chamando a LLM. Como mostra o resultado abaixo. ![img.png](img.png) ### 11.3.3 Teste COM uso do Nemo Guardrails Já o código **app_nemo.py** utiliza o framework **Nemo Guardrails** para ilustrar as diferenças entre as 2 formas de implementar guardrails em seu código. python -m src.app_nemo ![img_4.png](img_4.png) ## 12. Mapeamento da planilha para implementação | Código | Item | Mecanismo | Implementação entregue | |---|---|---|---| | MSK | PII Masking | NeMo regex rail | Regex Python + pré-LLM | | CMP | Compliance Anatel | NeMo output rail | Output rail determinístico | | ADJ | Alçada de Ajuste | Python | Pré-execução Python | | REVPREC | Supervisor VAS Avulso | LLM Supervisor | `src/supervisor.py` | | TCR | Conclusão de Tarefa | Python | `src/curadoria.py` | | REVPREC | Verbalização Prematura | NeMo LLM rail | Output rail determinístico + expansível | | TOX | Toxicidade | NeMo LLM rail | `self_check_input` | | OOS | Out-of-Scope | NeMo LLM rail | `self_check_input` | | GND | Groundedness | NeMo LLM rail | `self_check_output`, com dependência de chunks RAG | | HIST | Consistência Histórica | Python | previsto como regra pré-execução | | CSI | Sentimento | LLM-as-a-judge | previsto como batch D-1 | | ALUC | Taxa de Alucinação | LLM-as-a-judge | previsto como batch D-1 | | RQLT | Qualidade da Resposta | LLM-as-a-judge | previsto como batch D-1 | | VCTN | Tom de Voz | LLM-as-a-judge | previsto como batch D-1 | ## 13. Recomendações para o time ### 13.1 Não colocar tudo no LLM Use Python para regras determinísticas e financeiras. Use LLM rails para semântica, linguagem, escopo e groundedness. ### 13.2 Separar bloqueio de medição Guardrail bloqueia. Curadoria mede. Supervisor audita. Judge avalia em lote. ### 13.3 Começar por P0 Primeira entrega sugerida: 1. PII Masking 2. Compliance Anatel 3. Alçada de Ajuste 4. Supervisor VAS Avulso 5. TCR 6. Verbalização Prematura 7. Prompt Injection / Jailbreak 8. RAG Injection / Context Poisoning 9. Data Leakage (Input) 10. Data Leakage (Output) ### 13.4 Evoluir para P1 Depois: 1. Toxicidade 2. Out-of-Scope 3. Groundedness 4. Histórico 5. Tokens 6. Eficiência NLU 7. No-Match RAG 8. Content Safety / Unsafe Output ## 14. Critérios de aceite O time deve comprovar: - Dados sensíveis não chegam ao LLM sem máscara. - Ajuste acima da alçada não é executado. - Resposta de ajuste sem protocolo é bloqueada. - Promessa antes da validação é bloqueada. - Supervisor retorna status estruturado. - Métricas de curadoria são geradas. - Spans aparecem no backend de tracing. - Tentativas de prompt injection e jailbreak são detectadas e bloqueadas antes da execução. - Conteúdo recuperado de RAG, KB, tickets ou documentos suspeitos é sinalizado ou descartado. - Tentativas de exfiltração de prompt, políticas, segredos ou dados sensíveis são bloqueadas na entrada e na saída. - Respostas ofensivas, agressivas, manipuladas ou inadequadas são bloqueadas ou reescritas antes de chegar ao usuário. ## 15. Gerando o pacote do NeMo Guardrails para uso no CI/CD Este projeto pode ser utilizado como uma **biblioteca Python versionada**, permitindo que múltiplos projetos de agentes de IA reutilizem os guardrails de forma padronizada e governada. Para facilitar o entendimento, a mesma estrutura deste tutorial foi reorganizada para produzir o package como artefato. Descompacte o arquivo zip: [final_nemo_package_ready.zip](./final_nemo_package_ready.zip) --- ## 🎯 Objetivo Transformar este repositório em um **package Python instalável**, que será: - publicado no pipeline do NeMo - consumido pelos pipelines dos agentes de IA - versionado (ex: `1.0.0`, `1.1.0`, etc.) --- ## 🧱 Pré-requisitos - Python **3.11+** - `pip` atualizado - Ambiente virtual (recomendado) --- ## ⚙️ Passo 1 — Criar ambiente Será necessário configurar as variáveis de ambiente e o arquivo config.yml para utilizar o componente Nemo Guardrails deste projeto. company_nemo_guardrails/config/config.yml ```bash models: - type: main engine: openai model: openai.gpt-4.1 api_key_env_var: OPENAI_API_KEY parameters: temperature: 0 base_url: https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/v1 max_tokens: 50 # 🔥 evita respostas longas do LLM # 🔥 usado apenas se você chamar explicitamente no flow - type: self_check_input engine: openai model: openai.gpt-4.1 api_key_env_var: OPENAI_API_KEY parameters: temperature: 0 base_url: https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/v1 rails: input: flows: - check_input_terms output: flows: - check_output_terms ``` Configurar o parâmetro base_url para apontar para seu endpoint OpenAI. Variáveis de Ambiente: ```text # Endpoint OpenAI-compatible export OPENAI_API_BASE=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/v1 export OPENAI_BASE_URL=https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/v1 export OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx export OPENAI_MODEL=openai.gpt-4.1 # Tracing / Phoenix / OpenTelemetry export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006/v1/traces export OTEL_SERVICE_NAME=nemo-guardrails-demo export ENABLE_TRACING=false # Modo demo: usa cliente fake se o proxy não estiver disponível export USE_MOCK_LLM=false export ALCADA_MAX_AJUSTE=50 ``` --- ## ⚙️ Passo 2 — Criar ambiente ```bash python -m venv .venv source .venv/bin/activate # Linux/Mac # ou .venv\Scripts\activate # Windows ``` --- ## 📦 Passo 3 — Gerar o pacote ```bash cd /final_pkg pip install -U pip pip install build python -m build ``` Serão gerados: ``` dist/ ├── company_nemo_guardrails-1.0.0.tar.gz └── company_nemo_guardrails-1.0.0-py3-none-any.whl ``` --- ## 📥 Passo 4 — Instalar dependências ```bash pip install --upgrade pip pip install -e ".[dev]" ``` Isso instala: - o package local (`-e`) - dependências do projeto - ferramentas de teste e build (`pytest`, `build`, etc.) --- ## 🧪 Passo 5 — Executar testes ```bash export OPENAI_API_KEY=sk-fake pytest -v ``` ✔️ Garante que: - os guardrails estão funcionando - o package está consistente - o CI/CD não irá quebrar --- ## 📤 Passo 6 — Publicar (ex: Azure Artifacts) ```bash python -m twine upload dist/* ``` No pipeline do Azure DevOps, isso é feito automaticamente via: ```yaml - task: TwineAuthenticate@1 - script: python -m twine upload ... ``` --- ## 📥 Como consumir no projeto de agente No projeto do agente de IA: ### requirements.txt ``` company-nemo-guardrails==1.0.0 ``` ### Código ```python from company_nemo_guardrails import create_rails rails = create_rails() ``` --- ## 🧠 Boas práticas - Nunca usar `./config` diretamente - Sempre usar `create_rails()` (config embutida no package) - Versionar mudanças (sem sobrescrever versões antigas) - Validar com `pytest` antes de publicar --- ## 🔁 Relação com CI/CD Este processo é executado no pipeline do NeMo: ``` Commit → Testes → Build → Publish Package ``` E o pipeline do agente: ``` Install package → Build → Deploy ``` --- ## 🚀 Resultado final ``` NeMo Guardrails (library versionada) ↓ Pipeline publica package ↓ Agentes consomem via pip ↓ Deploy único (agent + guardrails) ``` ## 16. Evolução futura A estrutura permite evoluir para: - NeMo Server. - LangGraph. - MCP tools. - RAG com groundedness por chunk. - Batch judges D-1. - Phoenix / Langfuse / OpenTelemetry. - Governança por catálogo de guardrails. ## 16. Referências ### NVIDIA NeMo Guardrails: documentação oficial. - [NeMo Guardrails Library Configuration Overview](https://docs.nvidia.com/nemo/guardrails/latest/configure-rails/overview.html) - [Tools Integration with the NeMo Guardrails Library](https://docs.nvidia.com/nemo/guardrails/latest/integration/tools-integration.html) - [Configuring Custom Actions](https://docs.nvidia.com/nemo/guardrails/latest/configure-rails/actions/index.html) - [Registering Actions](https://docs.nvidia.com/nemo/guardrails/latest/configure-rails/actions/registering-actions.html) - [Logging and Debugging Guardrails Generated Responses](https://docs.nvidia.com/nemo/guardrails/latest/observability/logging/index.html) ### OpenTelemetry: tracing distribuído por spans. - [Logging and Debugging Guardrails Generated Responses](https://docs.nvidia.com/nemo/guardrails/latest/observability/logging/index.html) - [Quick Start for Tracing Guardrails](https://docs.nvidia.com/nemo/guardrails/latest/observability/tracing/quick-start.html) ### Utilizando modelos não-compatíveis com OpenAI - [Integrating OpenClaw with Oracle Cloud Generative AI (OCI)](https://github.com/hoshikawa2/openclaw-oci) ## 17. Acknowledgments - **Author** - Cristiano Hoshikawa (Oracle LAD A-Team Solution Engineer)