Mapa da aula
Aula 03 publicada. Mapa, exemplo, EX007.
flowchart TD
N0["3.1 Programas em torno dos modelos"]
N1["3.2 A saída do modelo não é confiável"]
N2["3.3 Valide a saída estruturada"]
N3["3.5 Lendo o laboratório"]
N4["Síntese"]
N0 --> N1 --> N2 --> N3 --> N4
N4 --> EX["Exemplo resolvido"]
EX --> Q["Exercício EX007"]
Desenho lógico
flowchart LR
N0["3.1 Programas em torno dos modelos"]
N1["3.2 A saída do modelo não é confiável"]
N2["3.3 Valide a saída estruturada"]
N3["3.5 Lendo o laboratório"]
N4["Síntese"]
N0 --> N1 --> N2 --> N3 --> N4 --> Q["EX007"]
[3.1 Programas em torno dos modelos]
|
v
[3.2 A saída do modelo não é confiável]
|
v
[3.3 Valide a saída estruturada]
|
v
[3.5 Lendo o laboratório]
|
v
[Síntese]
|
v
[Exemplo resolvido] --> [Exercício EX007]
Objetivos de aprendizagem
Você vai (1) escrever Python simples para chamar e testar serviços de IA com segurança; (2) validar entradas não confiáveis e saídas de modelos; (3) tratar erros e segredos corretamente; e (4) explicar por que a saída de um modelo deve ser tratada como dado não confiável.
3.1 Programas em torno dos modelos
A maior parte do trabalho de segurança de IA é programação comum: montar prompts, interpretar respostas, chamar ferramentas, escrever testes. A biblioteca padrão do Python basta para muitas tarefas: json para interpretar saídas estruturadas, re para padrões, hashlib para verificações de integridade, unittest para testes. O trabalho de Jonas no Ask Brightwell é quase todo desse tipo: escapar a saída no console da equipe, validar o JSON da ferramenta de devoluções e escrever testes que falham quando uma consulta entre usuários diferentes dá certo. Nada disso exige mudar o modelo. Cada item é Python simples, que um revisor consegue ler em minutos e conferir contra a ameaça que ele trata.
3.2 A saída do modelo não é confiável
A resposta de um modelo pode conter texto que um atacante plantou por meio de um documento. Se o código insere esse texto em HTML, SQL ou num comando de shell sem escapá-lo, o atacante consegue injeção nesses sistemas — OWASP LLM05 Tratamento Inadequado da Saída (Improper Output Handling). Trate a saída exatamente como uma entrada do usuário: escape-a para HTML, use consultas parametrizadas, nunca a passe a um shell. A avaliação plantada por Jonas no console da equipe mostrou isso diretamente: o assistente citou uma etiqueta de imagem de uma avaliação, e o console a renderizou, executando o script no navegador de um funcionário. A correção foi o escape, não um modelo melhor.
3.3 Valide a saída estruturada
Quando um modelo precisa devolver uma ação, peça JSON e valide-o com rigor: interprete-o, verifique se existem apenas as chaves esperadas, verifique os tipos, verifique os valores permitidos (por exemplo, action em {"lookup", "return"}) e rejeite todo o resto. Nunca "conserte" uma saída inválida por adivinhação. No Ask Brightwell, o orquestrador aceita apenas lookup e return como ações e verifica se o número do pedido é uma sequência de dígitos. Qualquer outra coisa, inclusive chaves extras que o modelo invente, faz a requisição ser rejeitada e registrada, de modo que uma proposta malformada nunca chega à ferramenta de devoluções. Em seguida, o serviço de políticas faz sua própria verificação sobre a ação validada.
3.4 Erros e segredos
Falhe de forma fechada: se a validação falhar ou uma ferramenta der erro, não execute a ação. Guarde as chaves de API em variáveis de ambiente ou num gerenciador de segredos, nunca no código nem nos registros.
"""Lab E: evasion of a toy linear classifier (synthetic data, stdlib only).
Trains logistic regression on two synthetic clusters, then applies a
fast-gradient-sign (FGSM-style) perturbation of size eps to every test point
and reports clean vs adversarial accuracy. Teaching model only."""
import math, random
rng = random.Random(7)
def point(label):
cx = 1.0 if label else -1.0
return [rng.gauss(cx, 0.7), rng.gauss(cx, 0.7)], label
train = [point(i % 2) for i in range(400)]
test = [point(i % 2) for i in range(200)]
w, b = [0.0, 0.0], 0.0
sig = lambda z: 1 / (1 + math.exp(-z))
for epoch in range(200):
gw, gb = [0.0, 0.0], 0.0
for x, y in train:
p = sig(w[0]*x[0] + w[1]*x[1] + b)
gw[0] += (p - y)*x[0]; gw[1] += (p - y)*x[1]; gb += p - y
w = [w[i] - 0.1*gw[i]/len(train) for i in range(2)]; b -= 0.1*gb/len(train)
def acc(data, eps):
ok = 0
for x, y in data:
# gradient of the loss w.r.t. x is (p - y) * w; FGSM steps along its sign
p = sig(w[0]*x[0] + w[1]*x[1] + b)
xa = [x[i] + eps*math.copysign(1, (p - y)*w[i]) for i in range(2)]
ok += (sig(w[0]*xa[0] + w[1]*xa[1] + b) >= 0.5) == bool(y)
return ok / len(data)
print(f"weights w=({w[0]:.3f}, {w[1]:.3f}) b={b:.3f}")
for eps in (0.0, 0.25, 0.5, 0.75, 1.0):
print(f"eps={eps:.2f} accuracy={acc(test, eps):.3f}")
Saída esperada:
weights w=(1.795, 1.756) b=-0.080
eps=0.00 accuracy=0.985
eps=0.25 accuracy=0.950
eps=0.50 accuracy=0.840
eps=0.75 accuracy=0.660
eps=1.00 accuracy=0.505
No Ask Brightwell, se a ferramenta de pedidos excede o tempo-limite, o assistente diz ao cliente que não consegue consultar o pedido agora, em vez de adivinhar. A chave de API do fornecedor fica no gerenciador de segredos, e o filtro de registros do orquestrador a remove de qualquer mensagem de erro antes de gravá-la. Jonas acrescentou um teste que falha se uma sequência com formato de chave aparecer numa linha de registro, de modo que a regra é verificada a cada compilação.
3.5 Lendo o laboratório
O laboratório treina um classificador linear minúsculo e mostra sua acurácia caindo à medida que as entradas são empurradas por eps na pior direção: 0,985 sem perturbação, 0,505 com eps 1,0. É um lembrete de que a decisão de um modelo pode ser dirigida por mudanças pequenas e deliberadas na entrada; o código em torno dos modelos não deve supor que suas saídas estejam corretas. Para a Brightwell, o laboratório sustenta uma escolha de projeto, e não um fato sobre o ReturnGuard: decisões importantes não devem depender de uma única pontuação sem verificações. No laboratório, as perturbações são escolhidas pelo atacante; atacantes reais enfrentam limites sobre o que podem mudar, e é por isso que o laboratório é um lembrete, não uma medição.
3.6 Exemplo resolvido (caso sintético da Brightwell)
O console da equipe do Ask Brightwell exibia as respostas do modelo como HTML bruto. Jonas planta numa cópia de teste uma avaliação de produto contendo <img src=x onerror=...>; o assistente a cita e o script roda no navegador da equipe. Ele altera o console para escapar a saída e acrescenta um teste de unidade. A correção fica onde os dados saem do sistema, no console, e por isso vale para qualquer coisa que o modelo diga. O teste de unidade planta a mesma etiqueta de imagem e falha se o console voltar a renderizá-la como HTML, o que protege contra uma mudança futura que reintroduza a falha.
3.7 Erros e limites
Três erros são comuns: inserir texto do modelo em HTML, SQL ou shell; consertar JSON inválido por adivinhação; e segredos no código-fonte. Cada um desses erros transforma o texto de um modelo numa ação em outro sistema. O console do Ask Brightwell mostrou o primeiro; a validação rigorosa do JSON da ferramenta de devoluções evita o segundo; e manter a chave do fornecedor no gerenciador de segredos evita o terceiro. Testes para cada um garantem que uma mudança futura não traga a fraqueza de volta em silêncio, e é justamente para isso que eles são escritos como código.
Exercícios
- EX007 — Validador. Escreva um pseudocódigo para validar
{"action":..., "order_id":...}. Rubrica: 3 = interpretar, chaves exatas, tipos, valores permitidos, falha fechada; 2 = quatro itens; 1 = dois; 0 = nenhum. - EX008 — Tratamento da saída. Cite três destinos em que a saída do modelo precisa de codificação e a técnica certa para cada um. Rubrica: 3 = escape de HTML, SQL parametrizado, nada de shell/lista de argumentos; 2 = dois; 1 = um; 0 = nenhum.
- EX009 — Laboratório. O que significa a queda para 0,505 com eps 1,0? Rubrica: 3 = perto do acaso, pequenas mudanças elaboradas invertem decisões, ressalva de modelo de brinquedo; 2 = parcial; 1 = vago; 0 = errado.
Síntese
Programar em torno de modelos significa validar e codificar tudo o que passa para outros sistemas — sobretudo a saída do modelo — e falhar de forma fechada.
Continue estudando — capítulo 03 de 30
← Capítulo 02 (rascunho) · Índice de capítulos do curso · Capítulo 04 (rascunho) →