11 KiB
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. Conceitos principais
2.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 |
2.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
2.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
2.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:
if valor_ajuste > limite:
escalar_para_ath()
2.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,SUSPEITOouPROBLEMA
2.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
3. Arquitetura recomendada
User Input
↓
Input Rails
├─ Regex: PII Masking
├─ LLM: Toxicidade
└─ LLM: Out-of-Scope
↓
LLM principal via NeMo Guardrails
↓
Output Rails
├─ Compliance Anatel
├─ Verbalização Prematura
└─ Groundedness
↓
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. Estrutura do projeto
nemo_guardrails_tracing_project/
├── config/
│ ├── config.yml
│ ├── rails.co
│ └── guardrails_catalog.json
├── src/
│ ├── app.py
│ ├── deterministic_rails.py
│ ├── supervisor.py
│ ├── curadoria.py
│ ├── tracing.py
│ └── settings.py
├── tests/
│ └── test_guardrails.py
├── scripts/
│ ├── run_demo.sh
│ └── run_tests.sh
├── requirements.txt
├── .env.example
└── README.md
5. Preparação do ambiente
5.1 Criar ambiente Python
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
5.2 Configurar variáveis
cp .env.example .env
Variáveis principais:
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
6. Configuração do NeMo Guardrails
Arquivo: config/config.yml
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
7. Rails criados a partir da planilha
7.1 MSK — PII Masking
Implementação: src/deterministic_rails.py
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.
7.2 CMP — Compliance Anatel
Implementação: enforce_compliance_anatel()
Regra: respostas de ajuste precisam conter número de protocolo.
7.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.
7.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.
7.5 Supervisor VAS Avulso
Implementação: src/supervisor.py
Avalia cinco regras:
- O VAS cancelado corresponde ao item solicitado.
- Não houve promessa antes da validação.
- Resposta de ajuste contém protocolo.
- Não houve exposição de PII.
- A decisão está coerente com os dados de contexto.
8. Integração com proxy OpenAI-Compatible
O projeto usa o cliente openai apontando para seu proxy:
client = OpenAI(
api_key=settings.openai_api_key,
base_url=settings.openai_api_base
)
Configuração:
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
9. Tracing com OpenTelemetry / Phoenix
Arquivo: src/tracing.py
Cada etapa cria spans:
rail.input.mskrail.python.alcadallm.nemo.generaterail.output.verbalizacao_prematurarail.output.compliance_anatelsupervisor.vas_avulso
Configuração:
export ENABLE_TRACING=true
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:6006/v1/traces
10. Como executar o projeto
10.1 Teste demonstrável sem proxy
export USE_MOCK_LLM=true
export ENABLE_TRACING=false
python -m src.app
Resultado esperado:
{
"allowed": true,
"input_sanitized": "Cancelar VAS. CPF [CPF_MASCARADO]",
"output": "Cancelamento analisado. Ajuste elegível conforme validação. Protocolo nº 123456789.",
"metrics": {
"tcr": "CONCLUIDO"
}
}
10.2 Executar testes automatizados
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.
10.3 Executar com proxy real
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
python -m src.app
bash scripts/run_tests.sh
11. 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 |
12. Recomendações para o time
12.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.
12.2 Separar bloqueio de medição
Guardrail bloqueia. Curadoria mede. Supervisor audita. Judge avalia em lote.
12.3 Começar por P0
Primeira entrega sugerida:
- PII Masking
- Compliance Anatel
- Alçada de Ajuste
- Supervisor VAS Avulso
- TCR
- Verbalização Prematura
12.4 Evoluir para P1
Depois:
- Toxicidade
- Out-of-Scope
- Groundedness
- Histórico
- Tokens
- Eficiência NLU
- No-Match RAG
13. 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.
14. 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.
15. Referências
- NVIDIA NeMo Guardrails: documentação oficial.
- Python SDK:
RailsConfig.from_path()eLLMRails.generate(). - Colang: linguagem para definir fluxos de guardrails.
- OpenTelemetry: tracing distribuído por spans.

