8 min de leitura

Como agentes de IA concorrentes colidem em contas de produção

Agentes de IA concorrentes podem sobrescrever uns aos outros em produção. Defina limites de propriedade, rejeite gravações obsoletas, use leases com cuidado e audite cada ação.

Como agentes de IA concorrentes colidem em contas de produção

Duas execuções autônomas na mesma conta de produção não ficam seguras só porque cada uma recebeu uma descrição de tarefa diferente. Elas compartilham um sistema mutável, e cada plano pode ficar obsoleto antes da próxima chamada de API. Se ambas podem alterar o mesmo recurso, você precisa de um limite de propriedade que o próprio serviço imponha.

A falha mais comum é mais silenciosa do que uma grande indisponibilidade. Um agente adiciona um membro a um grupo enquanto outro substitui a lista completa de membros usando uma leitura antiga. As duas solicitações retornam sucesso. A solicitação posterior remove o membro que a primeira havia adicionado. Cada execução seguiu suas instruções. Foi a API que aceitou uma sequência inválida.

Trate a execução de um agente como um cliente concorrente não confiável, com credenciais reais e tempo de resposta imprevisível. Dê a ele uma área pequena para controlar, torne as gravações condicionais à versão lida e registre contexto suficiente para explicar mais tarde uma alteração aceita ou rejeitada. A revisão humana continua útil, mas não substitui um receptor capaz de detectar estado obsoleto.

Separe o limite da tarefa do limite de gravação

O limite da tarefa diz o que o agente foi instruído a realizar. O limite de gravação diz quais objetos mutáveis ele pode alterar. São coisas diferentes, e as equipes sofrem quando tratam os dois como equivalentes.

«Atualizar a implantação de staging» parece específico. Ainda assim, pode envolver uma tag de imagem compartilhada, um ponteiro de lançamento, uma regra de tráfego, um registro DNS, um livro-razão de migrações do banco de dados e um canal de notificações. O agente pode obedecer ao texto da tarefa e, ao mesmo tempo, colidir com uma execução de lançamento que controla um desses objetos.

Defina a propriedade em termos que o serviço receptor consiga verificar. Bons limites citam identificadores duráveis de recursos, não categorias vagas de trabalho:

  • um ambiente e um registro de implantação
  • um tenant ou uma conta de cliente
  • um pull request e sua branch
  • um ticket de incidente e os recursos nomeados no conjunto de alterações
  • uma janela de manutenção com uma lista explícita de destinos

Evite limites como «trabalho de backend» ou «limpeza de produção». Eles são rótulos para pessoas. Não dizem à API qual gravação deve falhar.

Um registro de propriedade útil contém o ID da execução, o ID do recurso, a operação permitida e a validade. Mantenha-o perto do serviço que controla o recurso. Se um controlador de implantação controla o ponteiro de lançamento, esse controlador deve validar quem pode avançá-lo. Uma planilha, uma mensagem no chat ou uma instrução no prompt não conseguem bloquear uma solicitação que chega depois que a pessoa que a escreveu já foi embora.

Crie um pequeno mapa de conflitos antes de conceder acesso de gravação

Para cada tarefa automatizada, liste os recursos que ela lê, grava, exclui e usa como padrão compartilhado. Depois marque cada par de tarefas que pode gravar o mesmo identificador ou em que a entrada de uma pode ser alterada pela outra. Isso não é burocracia. É uma forma de revelar colisões que as permissões baseadas em funções escondem.

Por exemplo, um agente que troca um token de serviço e outro que atualiza a configuração de uma integração talvez nunca chamem o mesmo endpoint. O agente que grava a configuração pode ler a referência do token atual e depois publicar o documento completo de configuração quando a troca já tiver alterado essa referência. O conflito está na versão do documento, não em um comando idêntico.

Se você não consegue descrever o conjunto de gravações de uma execução, não dê a ela permissão ampla de gravação em produção. Faça com que ela prepare uma proposta ou limite-a a um namespace de recursos até que o limite possa ser descrito.

Uma resposta de sucesso ainda pode apagar uma alteração correta

O comportamento de «a última gravação vence» é uma política de perda de dados quando os clientes enviam representações completas. Ele parece inofensivo em demonstrações porque cada cliente lê e grava imediatamente. Agentes podem passar minutos examinando logs, criando um plano, pedindo aprovação e repetindo uma chamada depois de um timeout.

Considere um serviço com o recurso notification-policy. Ele devolve esta representação ao Agente A:

{
  "id": "prod-alerts",
  "version": 41,
  "destinations": ["[email protected]"],
  "severity": "high"
}

O Agente A planeja adicionar um destino de backup. Durante a revisão, o Agente B altera severity de high para critical e grava com sucesso a versão 42. Em seguida, o Agente A envia uma substituição completa baseada na versão 41:

{
  "destinations": ["[email protected]", "[email protected]"],
  "severity": "high"
}

Se o endpoint aceitar essa solicitação, ele desfaz silenciosamente a alteração de B. Nenhum dos agentes precisa ter um bug. A API permitiu que uma observação antiga substituísse um fato mais recente.

Atualizações parciais reduzem a área de risco, mas não eliminam o problema. Um patch que adiciona um destino ainda pode violar uma nova cota, uma política de roteamento atualizada ou uma exclusão ocorrida depois da leitura. O serviço precisa decidir se o patch continua válido diante do estado atual.

Por isso, «só permitimos que os agentes usem PATCH» não é um projeto de concorrência. É apenas uma forma menor de gravação. Ainda é necessária uma condição que conecte a gravação ao estado observado pelo agente.

Torne condicional toda solicitação que altera o estado

O controle otimista de concorrência costuma ser a primeira defesa correta para gravações feitas por agentes. O cliente lê uma versão, uma ETag, um número de geração ou um token de revisão. Depois envia esse valor junto da atualização pretendida. O serviço aceita a gravação apenas se o valor atual continuar igual.

A RFC 9110 define If-Match exatamente para esse tipo de solicitação. O servidor avalia a condição antes de aplicar o método. Se a ETag não corresponder mais, o servidor rejeita o método com 412 Precondition Failed. Isso não é um inconveniente da API. É o servidor se recusando a fingir que um plano desatualizado continua correto.

Uma atualização HTTP condicional pode ter esta aparência:

GET /v1/notification-policies/prod-alerts

HTTP/1.1 200 OK
ETag: "41"
Content-Type: application/json

{"destinations":["[email protected]"],"severity":"high"}

O agente leva essa ETag para a gravação:

PATCH /v1/notification-policies/prod-alerts
If-Match: "41"
Content-Type: application/json
Idempotency-Key: run-7f3c-add-backup

{"destinations":["[email protected]","[email protected]"]}

Se outro gravador tiver produzido a ETag "42", devolva uma rejeição clara:

HTTP/1.1 412 Precondition Failed
Content-Type: application/json

{
  "error": "stale_version",
  "resource": "notification-policy/prod-alerts",
  "expected_etag": "41",
  "current_etag": "42",
  "retryable": false
}

Não classifique esse erro como repetível se o agente puder reenviar o mesmo corpo sem pensar. Uma nova tentativa precisa começar com uma leitura atualizada e uma nova decisão. Ela pode descobrir que o resultado desejado já existe, que a política mais recente tornou a alteração inválida ou que uma pessoa precisa escolher entre dois resultados concorrentes.

Nos bancos de dados, use o predicado equivalente na própria mutação. Uma atualização típica verifica a versão na cláusula WHERE e trata zero linhas afetadas como conflito:

UPDATE notification_policy
SET destinations = :destinations,
    version = version + 1
WHERE id = :id
  AND version = :observed_version;

Nunca leia uma versão e depois faça uma atualização incondicional em uma segunda operação. A verificação e a alteração do estado precisam ocorrer juntas, na autoridade que armazena o estado.

A idempotência evita duplicatas, não divergências

É comum uma equipe colocar uma chave de idempotência em um endpoint e declarar que as gravações concorrentes estão resolvidas. A chave impede que a mesma solicitação lógica produza seu efeito duas vezes. Ela não diz ao serviço se duas solicitações diferentes são compatíveis.

Um timeout de rede deixa essa diferença clara. Um agente envia uma solicitação para criar uma implantação, mas perde a resposta. Repetir a solicitação com a mesma chave de idempotência deve devolver o resultado original, em vez de criar uma segunda implantação. Isso é supressão de duplicatas.

Agora imagine dois agentes que escolhem candidatos de lançamento diferentes para o mesmo ambiente de produção. Eles enviam corpos diferentes e chaves de idempotência diferentes. As duas solicitações podem ser perfeitamente idempotentes e, ainda assim, uma deve perder porque o ponteiro de lançamento mudou.

Use os dois controles em endpoints de gravação importantes:

  • Uma chave de idempotência vincula novas tentativas e entregas duplicadas a uma única operação concluída.
  • Uma pré-condição de versão rejeita uma gravação cuja decisão depende de um estado obsoleto do recurso.
  • Uma invariante no servidor verifica regras que precisam valer até para uma gravação atual, como o número máximo de credenciais ativas.

Armazene a chave de idempotência com uma impressão digital da solicitação e a resposta concluída. Se o chamador reutilizar a chave com um corpo diferente, rejeite a solicitação. Devolver a primeira resposta para uma operação diferente cria uma confusão na depuração e pode esconder um bug do cliente.

Seja rigoroso com a validade. O serviço deve manter a chave por tempo suficiente para cobrir seu comportamento real de novas tentativas, mas um armazenamento de idempotência não é um histórico permanente de comandos. O histórico pertence ao registro de auditoria.

Use leases apenas para trabalhos que não podem se sobrepor

Coloque as chamadas dos agentes atrás de aprovação
Use o shim MCP incluído para colocar as ações do agente sob uma única camada local de aprovação.

Algumas ações demoram tanto que apenas verificações otimistas tornam a experiência ruim. Uma migração de banco de dados, um trabalho destrutivo de reconciliação ou uma virada de tráfego podem envolver muitas gravações dependentes. Nesses casos, dê a uma execução um lease curto no recurso.

Um lease precisa ter um proprietário, uma validade e um valor de fencing. O fencing é importante porque um worker cujo lease expirou pode acordar e continuar depois que outro worker adquiriu um novo lease. Toda gravação protegida precisa carregar o token monotonicamente crescente do lease, e o serviço deve rejeitar um token mais antigo do que o último aceito.

Sem fencing, um serviço de locks pode avisar ao Agente A que seu lease expirou, mas não consegue impedir que uma solicitação atrasada de A chegue ao banco de dados. O serviço de destino precisa rejeitá-la. Essa é a parte que as equipes esquecem quando dizem que têm um lock distribuído.

Mantenha os leases restritos e curtos. Não bloqueie «a produção» durante toda uma investigação autônoma. Bloqueie migration/customer-1842 ou release/prod-eu, e faça a execução renovar o lease apenas enquanto continuar progredindo. O lease deve expirar com segurança se o processo do agente, seu laptop ou sua rede desaparecer.

Não use um lease para cobrir edições normais de configuração que contam com verificações de versão. Locks longos transformam alterações rotineiras em filas, e as pessoas acabam aprendendo a contorná-los. Uma resposta 412 seguida de um plano atualizado custa menos do que uma indisponibilidade causada por um titular de lock obsoleto.

A identidade do agente precisa atravessar o gateway

Um token de produção compartilhado dá a todas as execuções o mesmo nome no serviço. Depois de uma colisão, você consegue ver que o token agiu, mas não sabe qual processo planejou a alteração, qual aprovação a autorizou ou qual execução deve ser interrompida. Isso torna a limpeza lenta e a revogação ampla.

Dê a cada processo de agente uma identidade de sessão distinta e passe um identificador estável de correlação para toda solicitação enviada ao destino. O serviço de destino deve registrar a identidade, o ID da execução, o ID da solicitação, o recurso-alvo, a versão observada, o resultado e sua própria versão resultante. Não esconda essas informações em prosa dentro de uma mensagem de commit.

O Sallyport mantém as credenciais de API e SSH fora do processo do agente enquanto executa a ação, o que ajuda a preservar a separação entre o contexto de planejamento do agente e o próprio segredo. Sua autorização por sessão pode identificar um processo de agente recém-iniciado antes que ele comece uma execução. Essa autorização controla quem pode agir, mas não substitui as pré-condições no destino.

Não permita que o agente escolha sua própria identidade efetiva em um cabeçalho arbitrário. Faça o gateway ou o serviço de destino vincular a identidade a partir de uma sessão autenticada. Caso contrário, uma execução pode alegar depois que era o coordenador de implantação, e seus logs viram encenação.

Para SSH, o mesmo princípio vale, embora o protocolo de comunicação seja diferente. Use principals separados ou contas restritas para classes distintas de trabalho. Faça os logs dos comandos remotos incluírem um identificador de execução e evite uma única conta de shell compartilhada que possa editar todos os diretórios de aplicações.

O momento da aprovação não é o momento da transação

Preserve evidências contra adulteração
O registro de auditoria criptografado e encadeado por hash preserva evidências de sequências de ações aceitas e rejeitadas.

Uma pessoa pode aprovar a solicitação de um agente e, ainda assim, aprovar uma gravação que se torna errada dez segundos depois. Isso é normal em um sistema concorrente. A aprovação trata de autoridade e intenção no momento da revisão. Ela não congela o recurso.

O projeto perigoso pede que uma pessoa aprove uma frase ampla, como «atualizar a configuração de produção», e depois permite que o agente faça uma sequência de leituras e gravações quando conseguir executá-las. Um projeto mais seguro mostra o destino e o efeito pretendido, e então faz o serviço impor a versão ou o lease quando a gravação chegar.

Quando uma pré-condição falhar depois da aprovação, não reutilize automaticamente essa aprovação para um plano alterado. O agente deve relatar o conflito em termos concretos: qual recurso mudou, qual versão ele observou, qual campo mudou, se o serviço conseguir determinar isso, e se o resultado proposto ainda é necessário. Uma pessoa pode então aprovar uma nova ação, ou o agente pode fazer uma operação segura sem efeito depois de reler o estado.

A aprovação por chamada é adequada para operações em que cada uso apresenta risco significativo, como excluir uma credencial de produção ou alterar uma regra de roteamento visível externamente. Para lotes normais de gravações restritas e condicionais, a aprovação por execução costuma ser mais útil, pois permite ao operador verificar a identidade e o escopo sem criar o hábito de clicar automaticamente.

Não confunda uma pilha de aprovações com controle. Se os operadores não conseguem ver o ID do recurso, a operação e o resultado atual do conflito, estão aprovando uma frase enquanto o serviço faz o trabalho real em outro lugar.

Uma resposta de conflito precisa ter um responsável definido

Uma gravação obsoleta rejeitada é um resultado de segurança bem-sucedido, mas apenas se a execução souber o que fazer depois. «Tentar novamente em caso de erro» é o padrão errado. Ele transforma uma divergência em uma corrida automatizada.

Classifique cada caminho de gravação antes de permitir a execução autônoma. A classe determina quem resolve o conflito:

Tipo de alteraçãoEm caso de conflito de versãoResponsável
Adicionar um recurso independente com nome únicoReler e tentar novamente se o nome continuar disponívelAgente
Atualizar um campo calculado a partir dos dados atuaisReler, recalcular e tentar novamenteAgente
Avançar um ponteiro de lançamento compartilhadoParar e apresentar os dois candidatosResponsável pelo lançamento
Alterar membros ou permissões de acessoParar e solicitar revisãoResponsável pela conta
Excluir ou substituir um documento de configuração compartilhadoParar, a menos que um lease explícito o cubraOperador nomeado

A ideia não é tornar os agentes receosos. É distinguir recálculo de julgamento. Um agente pode repetir com segurança um relatório gerado a partir de entradas atuais. Ele não deve escolher entre duas versões de produção aprovadas, duas decisões de acesso ou dois planos de rollback diferentes apenas porque recebeu um 412.

Torne as respostas de conflito legíveis por máquina. Inclua a identidade do recurso, a versão atual, a categoria do conflito e a indicação de que o endpoint permite uma nova tentativa automática. Um 409 vago com uma página de erro HTML empurra o agente para o improviso.

Teste a colisão que você espera que aconteça

Não espere o tráfego de produção provar que suas verificações funcionam. Crie um teste que pause uma execução entre a leitura e a gravação, permita que uma segunda execução altere o mesmo recurso e depois libere a primeira. Verifique quatro resultados:

  1. A primeira gravação falha sem alterar o recurso.
  2. A resposta identifica uma versão obsoleta, em vez de um erro genérico do servidor.
  3. O agente não reenvia automaticamente o corpo antigo.
  4. Seus registros conseguem relacionar as duas tentativas às respectivas identidades e aprovações.

Faça o mesmo teste com timeout e nova tentativa para provar que o comportamento de idempotência é separado. São caminhos de falha diferentes e precisam de resultados esperados diferentes.

Audite tanto a ação tentada quanto o estado resultante

Separe o planejamento das credenciais
O Sallyport executa chamadas HTTP autenticadas e devolve os resultados sem expor o segredo ao agente.

Uma conta de produção precisa de dois registros depois de uma colisão entre agentes: o caminho do comando e o histórico autoritativo do recurso. Os logs do gateway explicam quem solicitou uma ação e por qual sessão aprovada. Os logs do serviço explicam se o estado mudou, qual versão venceu e por que uma solicitação falhou.

Não se contente com um registro de atividade que diga «PATCH concluído». Registre o identificador do recurso, o método, o ID de correlação da solicitação, a pré-condição enviada pelo cliente, a chave de idempotência ou uma referência segura a ela, o status da resposta e a ETag resultante. Se o serviço mantiver histórico em nível de campo, registre ali os campos alterados, em vez de tentar deduzi-los do transcript do agente.

O Sallyport projeta seus registros Sessions e Activity a partir de um log de auditoria criptografado e encadeado por hash. Se você o usa para ações de agentes, execute esta verificação ao investigar uma sequência contestada:

sp audit verify

O comando verifica a cadeia offline sobre o texto cifrado e não precisa da chave do cofre. Ele pode confirmar se o registro local permaneceu intacto. Antes de afirmar que sabe o que aconteceu, compare-o com os logs de solicitações do serviço de destino.

As regras de retenção e acesso também importam. Um transcript de agente pode conter raciocínios falhos ou detalhes operacionais copiados, enquanto um registro de solicitações deve ser um relato factual e compacto. Mantenha as evidências necessárias para reconstruir a autoridade e as transições de estado, e limite quem pode consultá-las.

O paralelismo deve ficar em conjuntos de recursos independentes

Você não precisa de uma fila global única para todas as execuções autônomas. Precisa de uma regra que permita o trabalho independente e torne explícita a mutação compartilhada. Particione por tenant, ambiente, branch do repositório, serviço ou outro namespace de recursos que o serviço consiga verificar.

Um projeto prático de produção tem um coordenador que atribui a cada execução um conjunto de gravações e concede credenciais ou acesso ao gateway somente para esse conjunto. O coordenador não decide se toda alteração é boa. Ele impede que dois workers recebam autoridade sobreposta por acidente. Os serviços receptores ainda impõem versões e invariantes, porque coordenadores falham, atribuições mudam e pessoas iniciam trabalhos emergenciais fora do caminho normal.

Quando uma ação abrange vários recursos, resista à tentação de chamá-la de alteração atômica se os serviços não conseguem realmente transacionar juntos. Registre o estado pretendido, ordene as gravações para que as etapas posteriores validem as anteriores e defina a compensação antes da execução. Uma ação de compensação também precisa verificar o estado atual. Voltar a um snapshot antigo pode apagar uma alteração legítima ocorrida depois da execução original.

O primeiro teste de produção deve ser deliberadamente simples: escolha um recurso de configuração compartilhado, inicie duas execuções de agentes a partir da mesma versão e faça com que proponham alterações incompatíveis. Se o serviço aceitar as duas, corrija esse endpoint antes de dar a qualquer execução uma responsabilidade maior. A autonomia fica menos interessante depois de uma colisão, e é exatamente por isso que você deve forçar a colisão primeiro em um teste controlado.

FAQ

O que caracteriza agentes de IA concorrentes?

Eles são concorrentes quando suas janelas de autoridade se sobrepõem e ambos podem emitir uma gravação que afeta o mesmo estado do mundo real. Threads de conversa separados, máquinas diferentes e credenciais distintas não mudam isso. Se uma execução pode agir sobre um estado que a outra observou antes, trate-as como concorrentes.

Dois agentes podem entrar em conflito se trabalharem em repositórios diferentes?

Sim. Uma conta de produção costuma conter padrões compartilhados, cotas, vínculos de IAM, nomes DNS, configurações de cobrança e ponteiros de implantação que fazem trabalhos aparentemente independentes se cruzarem. A propriedade no nível do recurso é mais segura do que presumir que projetos separados tenham áreas de impacto separadas.

A aprovação humana basta para evitar conflitos entre agentes?

Não. A aprovação comprova que uma pessoa autorizou uma solicitação em determinado momento, mas não prova que ela continua correta depois que outro processo altera o estado. O serviço que recebe a solicitação precisa rejeitar gravações obsoletas usando versões, pré-condições, leases ou um controle equivalente.

Quando devo usar uma chave de idempotência em vez de uma verificação de versão?

Use uma chave de idempotência quando o risco for uma solicitação repetida por causa de uma nova tentativa, timeout ou entrega duplicada. Use uma pré-condição de versão quando o risco for uma atualização aparentemente válida baseada em uma representação antiga. APIs de gravação maduras costumam precisar das duas.

Locks distribuídos resolvem gravações concorrentes de agentes?

Um lock distribuído só ajuda quando todos os gravadores respeitam o lock e quando sua expiração, propriedade e comportamento em caso de falha estão bem definidos. Ele não corrige um endpoint que aceita atualizações obsoletas. Comece com pré-condições no serviço e, se necessário, acrescente leases curtos para trabalhos exclusivos e longos.

Cada agente de IA deve ter sua própria credencial de produção?

Dê a cada execução autônoma uma identidade e um conjunto de permissões separados, mesmo que ambas atuem em nome da mesma equipe. Credenciais administrativas compartilhadas apagam a atribuição e tornam a revogação indiscriminada. A identidade do agente deve aparecer tanto no gateway de ações quanto nos registros do serviço de destino.

O que deve acontecer durante uma alteração emergencial em produção?

Uma execução de emergência ainda precisa da mesma proteção contra conflitos no serviço, porque a urgência não torna correto um estado obsoleto. Dê ao operador um caminho documentado de break-glass, com escopo restrito, validade curta e uma revisão mais rigorosa depois. Não crie um desvio permanente porque um agente precisou agir rapidamente uma vez.

O que um registro de auditoria deve guardar sobre as ações dos agentes?

Um registro de gravação precisa guardar o recurso de destino, a identidade do autor, o identificador da solicitação, a versão anterior, a transição solicitada, o resultado e a versão devolvida pelo serviço. Um transcript que diz que um agente «atualizou a produção» é vago demais para investigar uma colisão. Mantenha o mesmo ID de correlação entre as novas tentativas.

Agentes autônomos podem fazer implantações em paralelo com segurança?

Somente quando cada alteração tratar de um recurso separado e o serviço verificar esse limite. Por exemplo, pull requests independentes podem ser executados em paralelo, enquanto dois trabalhos que alteram o ponteiro de lançamento de um mesmo ambiente devem ser serializados. O trabalho paralelo é útil; autoridade paralela sobre um objeto mutável costuma ser descuido.

Como verificar um registro de auditoria do Sallyport?

sp audit verify verifica a integridade do registro de auditoria criptografado e encadeado por hash do Sallyport sem precisar da chave do cofre. Ele mostra se esse registro local de ações foi alterado, mas não substitui os próprios registros de solicitações e recursos do serviço de destino. Compare os dois ao investigar uma gravação contestada.

Sallyport

O Sallyport executa chamadas de API e comandos SSH pelo seu agente de IA. As chaves ficam em um cofre local no seu Mac; você aprova cada execução e toda ação vai para um registro selado.

© 2026 Sallyport · Código aberto sob Apache-2.0 · Oleg Sotnikov