Conectando
As mesmas verificações, onde quer que o seu agente rode. Em todos os casos, o seu código executa a ferramenta, nunca o guardrail, e só depois de o guardrail permitir.
Em Python puro
from stalwart_agents.guardrails import Guardrail
rail = Guardrail(tools=tools, rules="compiled", tool_kinds="tool_kinds.yaml")
verdict = rail.check_call(call, {"turns": turns, "results": results, "session": sid})
call pode ser o nosso formato ({"tool", "arguments"}), uma chamada de ferramenta da OpenAI, um bloco tool_use da
Anthropic ou um ToolCall do LangChain. Execute só onde verdict.proceed. Veja Construindo um
guardrail para a ida e volta da confirmação.
O contexto que as verificações leem:
| Chave | O que é |
|---|---|
turns |
os turnos da pessoa, o último por último: a rastreabilidade e as verificações do que foi dito os leem |
results |
o que as ferramentas devolveram, por chamada ou ferramenta, para que um valor numa escrita possa ser rastreado até elas |
session |
mantém o histórico de uma conversa separado: as regras de ordem e o registro da sessão o leem |
confirmation |
o token que approve deu para o sim da pessoa |
language |
o idioma dos turnos, en ou pt-BR, onde não é o do próprio guardrail (turns_in) |
labels, origins, plan, plan_token, usage |
rótulos de confiança, de onde vieram os valores, um plano aprovado e contagens de uso |
Na frente de ferramentas MCP: o gateway
O stalwart gateway fica entre o seu agente e os seus servidores MCP, e verifica cada tools/call antes de chegar a um
servidor. snippet("gateway", upstream=...) no stalwart mcp grava catalogue.json (as suas ferramentas, os tipos
delas e as regras sobrepostas) e um gateway.yaml para começar:
$ stalwart gateway --config gateway.yaml
Uma chamada que precisa de uma pessoa vira uma elicitação MCP com a frase da confirmação; um cliente que não pode ser perguntado recebe uma recusa, nunca uma escrita sem confirmação.
Dentro do Guardrails AI
$ pip install "stalwart-agents[guardrails]"
from guardrails import Guard
from stalwart_agents.guardrails import gai
guard = Guard().use(gai.ToolCall(tools=tools, rules="compiled", on_fail=gai.ask))
for call in response.tool_calls: # formato da OpenAI ou da Anthropic, do LangChain, ou um dict
outcome = guard.validate(gai.as_json(call), metadata={"stalwart": {"turns": turns, "results": results,
"session": sid}})
if outcome.validation_passed:
results[call.id] = run_tool(call)
elif (payload := gai.asked(guard)) is not None: # mostre payload["sentence"]; com o sim da pessoa:
outcome = guard.validate(gai.as_json(call), metadata={"stalwart": {
"turns": turns, "results": results, "session": sid, "confirmation": gai.approve(payload)}})
Valide cada chamada; não embrulhe o modelo. O Guardrails AI entrega aos validadores o texto que um modelo escreveu. Quando embrulha uma chamada ao modelo, um validador recebe só os argumentos da última chamada de ferramenta, sem o nome da ferramenta, em toda versão da faixa que suportamos (0.7 a 0.11). Por isso cada chamada que o modelo propõe é validada sozinha, antes de o seu código executá-la.
Os validadores:
| Validador | Nome | Roda |
|---|---|---|
ToolCall |
stalwart/tool_call |
todas as verificações |
GroundedArguments |
stalwart/grounded_arguments |
a rastreabilidade |
PolicyRules |
stalwart/policy_rules |
a sua planilha de regras |
AllowedTool |
stalwart/allowed_tool |
as ferramentas permitidas |
As verificações que não podem ser desligadas rodam em cada um, então uma escrita espera por uma pessoa em todos.
O que cada resposta faz:
- permitir:
PassResult;validation_passedé verdadeiro. - recusar:
FailResultcom a frase da regra, e o veredito (regra, id de decisão) emstalwart_verdictnos seus metadados; a sua ação on-fail se aplica:exceptionlevanta,refrainnão devolve nada,nooppassa e registra. - confirmar:
FailResultcujos metadados trazemstalwart_confirm, o que mostrar à pessoa. Comon_fail=gai.aska chamada é recusada até ela responder,gai.asked(guard)lê o conteúdo, egai.Ask(show)também o entrega ao seushow. Uma chamada alterada é perguntada de novo.
O contexto vem de metadata["stalwart"] (as chaves acima). Uma escrita verificada sem turns falha, nomeando a chave
que falta: fechado, nunca uma passagem silenciosa. Os nossos validadores nunca alteram uma chamada e nunca chamam um
modelo, então fix e reask não mudam nada: uma chamada recusada continua recusada.
Vários validadores num guard: Guard().use_many(deles, nosso) até a 0.10, Guard().use(deles, nosso) a partir da 0.11.
O próprio Guardrails AI envia métricas de uso, a menos que ~/.guardrailsrc diga enable_metrics=false. Nada nosso
envia.
No NeMo Guardrails
$ pip install "stalwart-agents[nemo]"
from nemoguardrails import LLMRails, RailsConfig
from stalwart_agents.guardrails import Guardrail
from stalwart_agents.guardrails.nemo import register, snippet
rails = LLMRails(RailsConfig.from_path("config"))
register(rails, Guardrail(tools=tools, rules="compiled"))
print(snippet("2.x")) # ou "1.0"
register acrescenta uma ação, stalwart_check_tool (StalwartCheckToolAction em Colang 2). O trecho é a forma de
guarda que o verificador prova: a ação da ferramenta só roda dentro do ramo onde a verificação a permitiu; uma chamada
que espera por uma pessoa pergunta a ela e, com o sim, é verificada de novo com o token; todo outro ramo termina na
frase de recusa. Troque a intenção e a ferramenta pelas suas; mantenha a forma.
O que a ação lê do contexto do NeMo, onde os próprios argumentos dela não o dão:
| Chave | Lida como |
|---|---|
stalwart_arguments |
os argumentos da chamada (defina-a a partir da ação que propõe a chamada) |
user_message, senão last_user_message |
o último turno da pessoa |
stalwart_turns |
os turnos da pessoa, o último por último, no lugar só do último |
stalwart_results |
o que as ferramentas devolveram |
stalwart_session |
a conversa (nemo onde não definida) |
stalwart_confirmation |
o token do sim da pessoa |
Uma escrita verificada sem turno é recusada, nunca permitida. Em Colang 2, bot say espera o seu cliente informar que
a fala terminou antes de o fluxo continuar, como um laço de chat faz.
A própria integração do NeMo com o Guardrails AI valida só as mensagens do usuário e do bot, nunca chamadas de
ferramenta, então os nossos validadores são usados por register acima, não por ela.