Ir para o conteúdo

13 · Escrevendo um guardrail a partir de uma regra em prosa

A Escrita de Guardrails (Guardrail Writing) transforma uma regra que você sabe dizer numa política que você pode publicar, com a evidência por trás dela. Você declara a regra com as suas próprias palavras e nomeia a obrigação que ela tem de cumprir; o serviço pede ao seu modelo, com a sua chave, que redija a política, compila o rascunho, verifica a obrigação nele e o repara onde ele vaza. Este capítulo diz como uma requisição é feita, o que volta, e o que uma política gerada é e não é.

A requisição

Uma requisição de guardrail leva generation no lugar de uma política. A obrigação é sua, em operands, e nunca cabe ao modelo escolhê-la:

result = client.generate_and_verify(
    "Funds may move only for a signed-in user whose account is not frozen.",
    "execute_transfer_funds",           # the action the rule is about
    "is_authenticated",                 # the context it must never fire without
    provider="anthropic", model="claude-sonnet-5-5",
    api_key_env="ANTHROPIC_API_KEY",    # your key, sent with this one request and never stored
    rounds=3,
)
print(result.outcome["verdict_produced"], result.status)
for checked in result.envelope["obligations_verified"]:   # a list, so its shortness is visible
    print(checked["round"], checked["action"], checked["context"], checked["status"])
print("ship it" if result.shipping_candidate else "nothing verified to ship")
Campo O que é
provider, model anthropic, gemini ou openai_compatible, e o nome do modelo como esse provedor o escreve
api_key a sua chave desse provedor. Obrigatória: o serviço não tem credencial de modelo própria, nem nenhuma a que recorrer
prompt a regra com as suas palavras, no máximo 8 KB
rounds de 1 a 3, e o seu plano pode permitir menos (capítulo 40): 1 redige e verifica uma vez; 2 ou 3 devolvem o reparo do solver ao seu modelo para uma nova redação enquanto a obrigação ainda falha
dialect o rascunho é escrito em Colang 2, a menos que você peça Colang 1
base_policy um arquivo existente ao qual a regra deve ser acrescentada
base_url para um provedor compatível com OpenAI, o seu próprio gateway, onde o seu plano inclui um e o host está na lista do seu tenant
cases no máximo 16 situações declaradas nos seus termos, cada uma com o que deve acontecer: bloqueada ou permitida. Cada uma é resolvida sobre a política a publicar

O que acontece, numa rodada

  1. Pede-se um rascunho ao seu modelo, com a sua chave, mantida só em memória durante a chamada.
  2. O rascunho é compilado. Um rascunho que o compilador não entendeu por inteiro não recebe veredito. Uma regra que falta parece uma aprovação, e um rascunho fluente é ao mesmo tempo o mais provável de esconder uma e o mais provável de ser aceito de confiança. Então um rascunho com qualquer diagnóstico de análise é nulo: outcome.verdict_produced é false, as linhas que o compilador não conseguiu ler são citadas com os seus números, e nenhuma resolução roda. O job ainda tem sucesso, porque a resposta é real: o seu rascunho não diz o que você pensa.
  3. Um rascunho que nunca menciona a ação ou o contexto falha como obligation_absent: um desvio por omissão.
  4. Caso contrário, a obrigação é verificada no rascunho, sob patch a menos que você nomeie um perfil, e uma obrigação que falha volta com o reparo do solver.

As rodadas dois e três só acontecem enquanto a obrigação ainda falha e o solver tem um reparo a devolver. O prompt então traz o rascunho anterior, o veredito e a proteção do solver, com os próprios nomes do rascunho, com a instrução de não mudar mais nada. A obrigação nunca muda entre as rodadas: verificar uma pergunta diferente seria o laço corrigindo a própria prova. Uma rodada que não compila interrompe o laço, e uma rodada pior é relatada como pior.

O que volta

A resposta começa com outcome: se um veredito foi produzido, uma frase dizendo o que aconteceu, os seus casos bloqueados e permitidos, e o shipping_candidate, o arquivo a publicar. Ele é escolhido nesta ordem:

  1. o primeiro rascunho de uma rodada que o verificador não conseguiu quebrar;
  2. senão, a própria política reparada pelo solver, da melhor rodada;
  3. senão, nada.

Essa ordem é o ponto da funcionalidade. Quando o seu modelo e o reparo do solver discordam, o reparo é publicado, porque é ele que tem uma prova anexada, e ele traz a verificação de bloqueio excessivo que uma nova redação não traz.

A evidência vem em seguida: obligations_verified (uma lista, para que a sua brevidade fique visível), o veredito, o certificado e o relato completo em generation: o rascunho de cada rodada como um artefato, o seu veredito e os seus diagnósticos, por que o laço parou, e as chamadas ao modelo feitas, com os tokens que o seu provedor relatou. Todo artefato registra qual lado o produziu (produced_by): o modelo ou o solver.

A sua chave e o seu prompt

O serviço não guarda nenhum dos dois. A sua chave e o seu prompt viajam da borda até o worker num único valor do armazenamento privado do serviço, lido e apagado numa única operação, e expiram com a fila do job. Eles nunca são escritos num banco de dados, num armazenamento de objetos, num log ou num evento, e, enquanto uma chamada está em andamento, a sua chave fica registrada no filtro de logs, que a substitui onde quer que apareça, inclusive num erro que um provedor repita. O job guarda o SHA-256 do prompt e o seu tamanho; nenhuma resposta bruta do modelo é guardada. O rascunho é guardado, como um arquivo de política sob a sua retenção, porque ele é o produto (capítulo 16).

Duas consequências que você vai encontrar:

  • Se um worker para no meio de um job e o job é refeito, a chave e o prompt já não existem: o job falha como generation_input_expired, não é cobrado, e você o envia de novo com uma nova chave de idempotência.
  • Uma requisição cujo armazenamento de passagem não pode ser alcançado é recusada com 503 e Retry-After, em vez de a chave ser guardada em algum lugar durável.

Uma política em Colang 2

Os rascunhos são escritos em Colang 2 por padrão, e a verificação lê um subconjunto declarado dele. Uma construção fora do subconjunto não é aproximada: um job sobre uma política que usa uma dentro do alcance da pergunta é recusado como colang2_construct_unsupported, nomeando a linha (capítulo 6). Para tudo o mais que o Colang consegue expressar, veja a documentação do NeMo Guardrails; este guia documenta o que o verificador compila.

O que uma política gerada é e não é

O rascunho é do modelo; o veredito, o certificado e o reparo são do solver. Toda resposta diz isso, na sua ressalva permanente draft_is_the_models, e todo artefato nomeia quem o produziu.

  • Ela não é uma política correta. Uma obrigação nomeada foi verificada sobre um rascunho, e obligations_verified lista exatamente isso. Toda resposta traz a ressalva verified_only_as_asked. Uma obrigação que a regra exige e que o rascunho nunca menciona não tem variável nem linha, e nada aqui a encontra.
  • Ela não é um guardrail que uma IA verificou. Um modelo escreveu um texto; o solver verificou uma proposição sobre esse texto. A resposta nunca chama um rascunho de verificado além das obrigações que lista.
  • Ela é um ponto de partida com evidência. Um rascunho verificado é uma política que cumpre a obrigação que você nomeou, com um certificado que qualquer pessoa pode conferir. Revise-o como revisaria a política de um colega, e acrescente o resto das suas regras como perguntas próprias (capítulo 4).

Se o seu modelo aceita uma regra escrita em outra língua, em português por exemplo, é assunto do seu modelo: o serviço repassa o seu prompt como você o escreveu, e não afirma nada sobre como um modelo o lê.

Os limites

  • Uma política gerada é verificada para as obrigações listadas em obligations_verified, e para nada mais.
  • A qualidade do rascunho é a do seu modelo. O serviço o confere e o repara; ele não torna o modelo certo.
  • Um rascunho nulo não tem veredito. Não o publique, e não cite para ele o veredito de uma rodada anterior.