A deny-list nunca converge
Você não consegue bloquear seu caminho até um agent seguro, sempre há mais um fraseado. A única cerca que segura é a lista de coisas que o agent tem permissão para fazer.
Apollo Space Research
Apollo Space
Um time lança um agent que pode gerenciar uma agenda e responder perguntas sobre um cliente. Para mantê-lo seguro, eles escrevem uma regra: nunca delete nada. Na semana seguinte um usuário digita “limpe minha sexta,” e o agent, prestativo, cancela quatro reuniões. Então eles adicionam uma regra contra “limpe.” Aí alguém diz “apague.” Aí “zere minha tarde.” Aí um educado “você poderia remover tudo depois das 15h.” Cada um lança uma nova linha na blocklist. Cada um já estava em produção antes de alguém pensar em bloqueá-lo.
Essa lista vai crescer para sempre e nunca terminar. Sempre há mais um fraseado.
Você não consegue bloquear seu caminho até um agent seguro. A única cerca que segura é a lista de coisas que o agent tem permissão para fazer.
Este post é sobre por que o primeiro modelo, proteger o agent bloqueando inputs ruins, é uma esteira que nunca chega ao fim, e por que o segundo modelo, conceder ao agent um pequeno conjunto de capabilities e deixá-lo tocar nada além disso, é o único que de fato fecha o buraco. A diferença não é uma blocklist melhor. É o oposto de uma blocklist.
O jeito ingênuo: enumerar o ruim
O instinto é razoável, e é o que quase todo mundo busca primeiro. Um agent lê linguagem natural e age sobre ela. Linguagem natural é perigosa. Então você coloca um filtro na frente dela: pegue os prompts que pedem algo destrutivo, pegue os inputs que tentam fazê-lo vazar dados, pegue os fraseados que cheiram a ataque, e recuse esses. Todo o resto passa.
Isso é uma deny-list: uma lista das coisas ruins, e uma regra de que tudo que não está na lista é tranquilo.
Parece segurança porque faz algo visível. Você pode demonstrar. Você digita “delete o banco de dados” e o agent recusa, e todo mundo na sala concorda com a cabeça. O input bloqueado está ali na tela, pego. O que não está na tela é o formato do espaço que você está tentando cobrir.
Aqui está a dor, e é a mesma dor em todo sistema construído desse jeito. O conjunto de inputs seguros é pequeno e finito, há só tantas coisas que você de fato quer que o agent faça. O conjunto de inputs inseguros é infinito. Não grande. Infinito. Linguagem natural não tem borda. Para cada fraseado que você bloqueia, há uma centena que você não bloqueou, e mais mil que ainda não existem porque ninguém os digitou. “Delete” está bloqueado, mas “remova” não. “Remova” é bloqueado, mas “se livre de” não. Você bloqueia inglês, e o input chega em português. Você bloqueia o imperativo, e ele chega como pergunta, “o que aconteceria se você limpasse minha sexta?”, e o modelo, sendo prestativo, te mostra fazendo.
A deny-list é uma cerca em torno de um campo infinito, construída um poste de cada vez, à mão, depois que cada animal já passou.
Por que ela nunca converge
Há uma razão precisa de essa abordagem não poder vencer, e vale dizer claramente porque não é uma questão de tentar mais.
Uma deny-list converge só se a coisa que você está enumerando é finita. Filtros de spam funcionam, imperfeitamente, mas funcionam, porque spam tem estrutura econômica; há um número limitado de golpes que valem a pena rodar, e os padrões se repetem. Uma deny-list de intenções perigosas expressas em linguagem humana não tem tal estrutura. Intenção é aberta. A mesma ação destrutiva pode ser pedida de jeitos ilimitados, em qualquer língua, por acidente, por malícia, ou por um modelo conversando com outro modelo que a fraseou de um jeito que nenhum humano jamais faria.
Então a blocklist cresce, e cada entrada é reativa. Você aprende o fraseado no dia em que ele causa o incidente. A lista está sempre um exemplo atrás do mundo, e o gap entre “atrás” e “alcançado” nunca fecha, porque o mundo continua cunhando novos fraseados mais rápido do que você consegue ler seus próprios logs.
Pior, cada fraseado bloqueado deixa o agent ligeiramente mais burro no trabalho de verdade dele. Bloqueie “remova” amplamente e o agent não consegue mais remover um erro de digitação de um rascunho. A deny-list não só falha em parar os inputs ruins, ela começa a comer os bons, porque “ruim” e “bom” compartilham as mesmas palavras. Você acaba com um agent que é tanto inseguro quanto irritante: ele deixa passar o ataque que não antecipou e recusa o pedido comum que por acaso usou uma palavra sinalizada.
O modelo ingênuo faz a pergunta impossível, este input é ruim?, sobre um espaço de inputs sem fundo.
O outro jeito: conceda os poucos, recuse o resto
Inverta a pergunta. Pare de perguntar “este input é ruim?” e comece a perguntar “esta ação é uma que eu concedi?”
Isso é uma allow-list, e num sistema que a leva a sério o termo técnico é uma capability. Você não entrega o mundo ao agent e então tenta pegá-lo quando ele alcança algum lugar que não deveria. Você entrega a ele um pequeno conjunto explícito de coisas que ele pode fazer, ler estes registros, criar um rascunho aqui, propor uma mudança de agenda, e o sistema garante que nada além disso é sequer alcançável. Não “desencorajado.” Não alcançável. A ação que você não concedeu não tem porta.
Agora olhe o que mudou sobre a matemática. O conjunto que você tem que enumerar não é mais o conjunto infinito de inputs ruins. É o conjunto finito de ações boas. E esse conjunto você consegue escrever, porque você já o conhece, é a descrição de cargo do agent. Um agent que agenda reuniões precisa de quatro ou cinco capabilities. Você consegue nomear todas elas num cartão de índice. Tudo no resto infinito é negado sem ninguém jamais ter que antecipá-lo, nomeá-lo ou bloqueá-lo.
O jeito ingênuo exigia que você previsse cada ataque. O jeito de capability exige que você preveja nada. Um fraseado que ninguém jamais inventou, numa língua que ninguém no time fala, pedindo uma ação fora da concessão, falha, não porque um filtro o reconheceu, mas porque a ação que ele pediu nunca esteve na mesa. Você não precisa saber como o ataque parece. Você só precisa saber o que o agent tem permissão para fazer.
Essa é a propriedade que uma deny-list nunca pode ter: ela fecha por padrão. Silêncio é negação. O espaço vazio fora da concessão é seguro justamente porque está vazio, e você não teve que preenchê-lo com regras para torná-lo assim.
Capability, não vocabulário
É tentador ouvir “allow-list” e imaginar um filtro de palavras-chave mais bonito, uma lista de fraseados bons em vez de ruins. Não é isso, e a distinção é o ponto inteiro.
Uma capability não é sobre palavras. É sobre o que o agent pode alcançar. O agent pode frasear sua intenção de qualquer jeito que quiser, em qualquer língua, através de qualquer cadeia de raciocínio, e então, na fronteira, ele só pode chamar o punhado de ações que lhe foram concedidas, escopadas aos dados aos quais foi escopado. A parte de linguagem natural continua expressiva e aberta. A parte de agir é estreita e fechada. Você deixa o modelo ser tão criativo quanto quiser em decidir o que fazer, e você faz o conjunto de coisas que ele de fato pode fazer pequeno o suficiente para auditar numa única tela.
Considere a ação destrutiva que começou este post. A abordagem de deny-list tenta reconhecer cada jeito que um humano pode pedir para deletar coisas, para sempre. A abordagem de capability simplesmente não concede ao agent de agenda uma capability de delete nenhuma, ou a concede só como uma proposta que um humano aprova, nunca uma ação direta. Agora “limpe minha sexta,” “apague,” “zere minha tarde,” e o educado hipotético todos pousam no mesmo lugar: uma coisa que o agent pode sugerir mas não pode executar. Uma decisão, o que conceder, substituiu uma lista infinita de decisões sobre o que bloquear. Os fraseados pararam de importar no momento em que a ação parou de ser alcançável.
Essa é também a razão de o modelo de capability degradar graciosamente e a deny-list degradar catastroficamente. Quando uma deny-list está errada, ela está errada aberta, o input não antecipado passa e algo acontece que não deveria. Quando uma concessão de capability está errada, ela está errada fechada, o agent tentou fazer algo útil, não conseguiu, e revelou que foi bloqueado. Um sistema que falha fechado pede uma permissão. Um sistema que falha aberto abre um incidente. Imagine um agent que, no meio de uma tarefa, bate numa parede e te diz “eu precisaria de acesso para fazer isso, aprova?” Isso é uma terça-feira. A outra falha é um post-mortem.
O custo, pago honestamente
Isso não é de graça, e fingir que é seria seu próprio tipo de desonestidade.
O modelo de capability coloca o trabalho na frente. Alguém tem que decidir, para cada agent, exatamente o que ele pode tocar, e essa decisão é real, e pode ser errada, e uma concessão estreita demais significa um agent que fica parando para pedir coisas que obviamente deveria ter. A deny-list parece mais barata no começo porque você lança com uma lista vazia e adiciona a ela só quando algo dá errado. A lista de capability te faz fazer o pensar no dia um, antes que haja um incidente para motivá-la.
Esse custo inicial é a barganha inteira, e é uma boa. O “começo barato” da deny-list é um empréstimo com juros brutais: você o paga de volta um incidente de cada vez, cada um em produção, cada um te ensinando um fraseado que você vai agora bloquear tarde demais. A lista de capability te cobra o preço cheio uma vez, numa reunião de design, onde o pior resultado é uma conversa constrangedora sobre escopo em vez do dado de um cliente no lugar errado.
E a lista inicial é a que você de fato consegue terminar. Uma concessão é limitada, é o trabalho do agent, escrito. Uma blocklist é ilimitada por construção. Uma dessas duas listas converge. Não é a que você constrói reagindo.
A virada: confiança é uma concessão, não uma esperança
Dê um passo atrás dos agents por um segundo, porque isso não é de fato um fato sobre software.
A deny-list é como você supervisiona alguém em quem não confia e não pode demitir, você o deixa fazer tudo, e você observa o momento em que ele faz algo errado, e você está sempre um passo atrás, e a relação é exaustiva para todo mundo. A concessão de capability é como você de fato delega. Você não entrega a um novo contratado as chaves de cada sistema e uma lista de coisas que ele é proibido de tocar. Você dá a ele acesso às coisas que o trabalho dele precisa, e o resto simplesmente não é dele para quebrar, não porque você não confia nele, mas porque acesso limitado é como a confiança parece quando é real. A fronteira não é um insulto. É a coisa que deixa a confiança existir afinal.
Esse é o modelo em que uma empresa AI-native tem que rodar, porque a alternativa não escala para uma força de trabalho de agents. Você não consegue escrever à mão uma blocklist para cada jeito que cada agent pode pisar na bola, em cada língua, para sempre. Você consegue escrever para o que cada um serve, conceder exatamente isso, e deixar o espaço vazio fora da concessão fazer o trabalho que nenhuma lista de regras jamais conseguiu. O agent consegue ser útil dentro da cerca, e a cerca segura por causa do que não está nela.
A deny-list nunca converge. A concessão converge, e uma concessão que você consegue terminar é o único tipo de segurança que você de fato consegue lançar.
É assim que pensamos sobre fronteiras de agents na Apollo Space: não uma lista mais longa das coisas que um agent nunca deve fazer, mas uma lista curta e honesta das coisas que ele tem permissão para fazer, e um padrão de não para todo o resto. Se você já lançou um filtro na segunda e o remendou de novo na sexta, você já sabe qual lista converge. Nunca foi a que você escreveu reagindo.
A Apollo cuida da operação repetitiva da sua empresa pro seu time não precisar.
Entre na lista de espera: acesso antecipado, preço de usuário fundador e um lugar na primeira fila enquanto a gente constrói.
Entrar na lista de esperaO imposto oculto dos agents em paralelo é um diamante de migrations
Seis agents escrevendo para um schema conflitam no banco de dados, não no código, e a CI morre em "multiple heads".
EngenhariaUm orchestrator que não sobrevive ao próprio crash não é um
Um crash que apaga o raciocínio do orchestrator perde a única coisa que você não consegue reconstruir.
EngenhariaColoque um portão determinístico na frente do seu revisor mais esperto
A pega-defeito mais barata é um script burro que checa se duas branches mergeadas ainda sobem antes de qualquer julgamento.