Segurança, guardrails e fitness functions para agentes
Este é o quinto artigo da série sobre arquitetura AI friendly. Já discutimos como agentes encontram contexto, usam skills e trabalham com conhecimento especializado.
Agora precisamos responder a duas perguntas:
o que o agente pode fazer;
como sabemos que a arquitetura continua respeitando esses limites?
Dar contexto a um agente não significa dar acesso irrestrito ao sistema.
Instruções não são controles de segurança
É comum começar com uma regra escrita no prompt ou na definição de uma skill:
Use a API de produção apenas para consultas de leitura.
Nunca altere dados.
Nunca acesse endpoints administrativos.
Essa orientação pode ser útil para guiar o comportamento do agente, mas não deve ser tratada como uma barreira de segurança.
O agente pode receber novos documentos, combinar informações de fontes diferentes e interpretar o código da aplicação. Um texto que ensina o agente a respeitar uma regra também pode trazer instruções conflitantes ou mostrar caminhos para contorná-la.
O mesmo vale para verificações feitas dentro de uma skill ou por uma integração via MCP. Se a própria camada que executa a ação decide se a ação é segura com base em contexto fornecido ao agente, esse contexto pode ser manipulado ou interpretado de forma inesperada.
MCP pode ajudar a conectar um agente a sistemas e ferramentas, mas a conexão não é, por si só, um limite de segurança. A autorização precisa existir no serviço que protege o recurso.
Mesmo leitura pode abrir uma brecha
Imagine que queremos ajudar um agente a investigar um incidente. Para isso, damos a ele um token que permite fazer requisições GET na API de produção.
À primeira vista, parece uma permissão segura. O agente não consegue alterar pedidos, reiniciar serviços ou modificar configurações.
Mas, ao consultar o código, a documentação e os contratos da aplicação, ele pode descobrir outros endpoints disponíveis. Pode encontrar rotas administrativas, parâmetros internos, relações entre recursos ou formas indiretas de obter dados que não deveriam estar no contexto da investigação.
O problema não está apenas no método HTTP usado pela requisição. O problema está no conjunto de recursos que o agente consegue alcançar, nos dados retornados e nas relações que ele pode deduzir.
Por isso, não basta dizer:
GET é permitido.
POST, PUT e DELETE não são permitidos.
Precisamos perguntar:
qual serviço pode ser acessado;
quais rotas estão disponíveis;
quais campos podem ser retornados;
quais registros podem ser consultados;
quais relações entre recursos podem ser inferidas;
por quanto tempo a credencial é válida;
como cada acesso será auditado.
Como oferecer contexto sem abrir produção
Existem formas mais seguras de disponibilizar informação para investigação.
Token com escopo limitado
Em vez de entregar uma credencial genérica da API, podemos criar uma credencial específica para o agente:
principal: incident-investigation-agent
resource: orders-observability-api
operations:
- read:incident-summary
- read:service-health
- read:dependency-latency
data_policy:
- exclude:customer.personal_data
- exclude:payment.card_data
expiration: 15 minutes
O serviço que recebe essa credencial deve validar o escopo. A descrição no prompt não substitui essa validação.
Dados derivados para investigação
Também podemos retirar o agente do caminho da aplicação de produção. Eventos, métricas, logs sanitizados e informações operacionais podem ser enviados para uma área própria de consulta, como uma réplica, um data lake ou um data warehouse.
Essa camada pode aplicar retenção, anonimização, filtragem de campos e atraso de propagação. O agente recebe contexto suficiente para investigar sem ganhar uma porta de entrada para a aplicação de produção.
Banco com menor privilégio possível
Quando o acesso direto ao banco for realmente necessário, ele deve ser criado para a tarefa, e não reaproveitar uma credencial de aplicação:
CREATE ROLE incident_reader LOGIN PASSWORD 'managed-externally';
GRANT CONNECT ON DATABASE operations TO incident_reader;
GRANT USAGE ON SCHEMA incident_data TO incident_reader;
GRANT SELECT ON incident_data.service_health TO incident_reader;
GRANT SELECT ON incident_data.request_summary TO incident_reader;
REVOKE ALL ON SCHEMA billing FROM incident_reader;
REVOKE ALL ON SCHEMA customers FROM incident_reader;
Além de ser somente leitura, esse usuário deve ter acesso apenas às tabelas, views ou schemas necessários. Views de investigação podem esconder dados sensíveis e limitar o volume de informação retornada.
O princípio é simples: não devemos confiar no agente para evitar tabelas perigosas. O banco precisa impedir o acesso mesmo que o agente tente fazer uma consulta fora do escopo.
Guardrails
Guardrails são mecanismos externos às intenções do agente que validam, limitam ou bloqueiam ações. Eles podem existir na identidade, na rede, na API, no banco, no sistema de arquivos ou no processo de aprovação.
Um exemplo mais realista de guardrail não é um if dentro do prompt. É uma política aplicada pelo serviço que recebe a requisição:
A política pode verificar a identidade, o recurso, a operação, os parâmetros, os campos solicitados, a quantidade de dados e o ambiente. Se qualquer condição não for atendida, a requisição é recusada antes de chegar ao recurso protegido.
Para alterações, podemos separar preparação e execução:
O agente não recebe a credencial de execução. Mesmo que ele produza uma instrução incorreta, a camada de execução ainda aplica suas próprias regras.
Exemplo: incidente de CPU
Durante um incidente, a investigação pode mostrar que os pods estão ficando sem CPU. O agente pode correlacionar os sinais, formular uma hipótese e preparar o ajuste no repositório de infraestrutura.
Ele também pode abrir o pull request e registrar a GMUD. A mudança, porém, continua dependendo de uma pessoa responsável, que revisa o impacto, aprova a GMUD e faz ou autoriza o merge. Depois disso, o pipeline aplica a alteração nos pods.
Guardrails também podem limitar caminhos de arquivos, destinos de rede, tamanho de consultas, tempo de execução, quantidade de registros e tipos de dados retornados.
Fitness functions determinísticas
Fitness functions vêm da arquitetura evolutiva. Elas transformam uma característica importante da arquitetura em uma verificação objetiva e contínua.
Uma fitness function não precisa de IA para decidir o resultado. Pode ser um teste de arquitetura, uma regra de pipeline, uma análise estática, uma consulta de metadados ou uma verificação periódica. Dado o mesmo estado de entrada, o resultado deve ser reproduzível.
O objetivo não é avaliar se a resposta do agente parece boa. É verificar se a arquitetura continua oferecendo as propriedades que consideramos importantes.
Exemplo com Deptrac
Um exemplo real é o Deptrac, uma ferramenta de análise estática para projetos PHP. Ela permite definir camadas arquiteturais e quais dependências são permitidas entre elas.
Imagine um sistema com dois contextos: Orders e Billing. Uma decisão arquitetural pode dizer que Orders não deve importar diretamente classes internas de Billing. A comunicação precisa acontecer por um contrato público.
Essa regra pode ser descrita em uma configuração do Deptrac:
deptrac:
paths:
- ./src
layers:
- name: Orders
collectors:
- type: classLike
value: .*\\Orders\\.*
- name: Billing
collectors:
- type: classLike
value: .*\\Billing\\.*
- name: Shared
collectors:
- type: classLike
value: .*\\Shared\\.*
ruleset:
Orders:
- Shared
Billing:
- Shared
Com essa regra, uma classe de Orders que importar diretamente uma classe de Billing gera uma violação. O pipeline pode executar:
vendor/bin/deptrac analyse --config-file=deptrac.yaml
O resultado é determinístico. O Deptrac não precisa entender a intenção do agente, avaliar a qualidade do código gerado ou interpretar um prompt. Ele apenas verifica as dependências que existem no código contra as regras definidas pela equipe.
Se um agente criar uma nova classe e introduzir uma dependência proibida, o pull request falha mesmo que o agente tenha recebido instruções para respeitar os limites. A fitness function protege a decisão arquitetural no momento em que o sistema evolui.
Conclusão
Uma arquitetura AI friendly não é apenas uma arquitetura que permite ao agente fazer mais. É uma arquitetura que oferece contexto sem transformar cada fonte de informação em uma nova superfície de ataque.
Prompts, skills e integrações ajudam a orientar o agente, mas não devem ser a última linha de defesa. Permissões precisam ser aplicadas pelos recursos protegidos, com identidade, menor privilégio, escopo, auditoria e possibilidade de revogação.
Guardrails limitam ações em tempo de execução. Fitness functions determinísticas verificam se essas proteções continuam presentes enquanto a arquitetura evolui.
Para aprofundar o conceito de fitness functions, vale ler Architectural Fitness Functions, da Yonder e Fitness Function Driven Development, da Thoughtworks.
No próximo artigo, vamos mostrar como dividir um grande bloco de conhecimento em contextos especializados, organizados por domínio, responsabilidade e finalidade.

