Desligamos o Agente de IA no meio do processo e o sistema não quebrou

skail · 2026-09-10 · 5 min

Um agente de IA de cobrança conversa com o cliente pelo WhatsApp, espera dias por uma resposta, consulta o ERP e chama o financeiro quando alguém jura que já pagou. Na demonstração, tudo funciona. Em produção, o container reinicia no meio da conversa, o cliente responde três dias depois e ninguém sabe dizer em que ponto o agente estava. Esse é o problema que a execução durável resolve para agentes de IA em produção.

Numa live com o Cris (Christophe Trevisani Chavey, cofundador da eNotas), montei um agente de cobrança integrado a um ERP legado e derrubei o container dele duas vezes enquanto uma cobrança estava em andamento. Nem o cliente nem o financeiro perceberam. Quando o agente voltou, registrou o pagamento e encerrou a cobrança a partir do ponto exato em que tinha parado.

A LLM é a parte fácil desse agente. O trabalho de verdade está em tudo que fica em volta dela: guardar contexto por semanas, esperar sem gastar máquina, impedir que uma ação execute duas vezes, deixar um humano decidir quando for preciso e explicar depois o que aconteceu. O código mostrado aqui é C# com o SDK da skail, conversando com um backend antigo em Node e TypeScript. A gravação completa da live está logo abaixo.

O que muda quando o agente de IA sai da demonstração

Antes de abrir o código, vale listar o que um agente precisa ter para rodar dentro de um software B2B. Nenhum desses itens depende do modelo de linguagem escolhido.

Todos esses itens são problemas clássicos de software, ligados a falha, espera, aprovação e auditoria. Um agente de produção precisa resolvê-los do mesmo jeito que qualquer sistema crítico resolve.

O harness do agente é o ERP que você já tem

Harness é o nome dado a tudo que fica em volta do modelo. A LLM, seja Gemini, GPT ou Claude, recebe texto e devolve texto. Quem guarda a memória, aplica as regras de segurança, diz quais ferramentas o modelo pode usar e de fato executa essas ferramentas é o harness.

Numa empresa que já tem um ERP ou um sistema B2B, boa parte desse harness já existe: cadastro de clientes, regras de cobrança, permissões, histórico. O que costuma faltar é a camada que deixa esse sistema sustentar um processo longo, com IA no meio, sem quebrar quando alguma peça cai. É essa camada que a skail cobre.

Por que o código do agente não tem try/catch

O método principal do agente de cobrança, Atender, cabe numa tela. Não há tratamento de exceção, retry, exponential backoff nem circuit breaker. O código descreve a regra de negócio e mais nada.

Essa simplicidade tem uma origem. O monolito era linear e fácil de ler, e qualquer pessoa entendia o fluxo abrindo um arquivo. A busca por escala levou a microsserviços, filas, gateways e rede entre um método e outro. O tempo do desenvolvedor migrou para a infraestrutura, uma camada que o cliente nunca vê e sem a qual o sistema nem roda.

A skail nasceu dessa dor. O time vinha de escalar a plataforma de nota fiscal da eNotas, com centenas de milhões de requisições por dia e mais de 2 mil integrações com sistemas instáveis pelo Brasil. A proposta é escrever como monolito e escalar como arquitetura distribuída: o código fica linear, e a plataforma cuida da distribuição, da persistência de estado e da recuperação de falha. Se uma chamada dá timeout, a execução se recupera sozinha e o código nem fica sabendo.

Um exemplo fora do agente mostra a ideia. Num cálculo de imposto, o fluxo aciona dois motores ao mesmo tempo, o do SAP e um de terceiro, e segue com a primeira resposta que chegar. Um WhenAny junta as duas chamadas com um timeout de 5 minutos, e enquanto espera a execução fica hibernada. Nada de fila, callback ou cron job para montar essa espera.

Como um backend legado aciona o agente com um POST

O ERP da demo é um backend antigo em Node com TypeScript. No método que cria a fatura, depois que ela é salva, uma única chamada dispara o agente: um POST na URL da skail com o ID da fatura, autenticado com bearer token.

Isso vale para qualquer stack. Na live apareceram perguntas sobre Delphi e ASP Classic, e a resposta é a mesma: se o sistema consegue fazer um POST, consegue acionar o agente. A partir desse POST, a execução já é durável. Para quem está em .NET ou TypeScript existe SDK, e aí basta chamar o método direto.

O agente foi escrito em C# de propósito, mesmo havendo SDK em TypeScript, para mostrar a interoperabilidade entre um Node antigo e um serviço .NET atual. A skail roda junto da aplicação, na infraestrutura do próprio cliente, então o mesmo modelo serve para instalação on-premise com SQL Server e para nuvem própria.

Hibernar por dias sem nenhum worker rodando

A régua de cobrança fica cadastrada no ERP. Na demo ela tem cinco marcos: um lembrete amigável 31 dias antes do vencimento, outro 3 dias antes, o próprio vencimento, uma cobrança no dia seguinte e a cobrança final 15 dias depois.

O agente declara dois eventos com WaitForEvent: o pagamento da fatura e a resposta do cliente. Depois de enviar o lembrete pelo WhatsApp e por e-mail, ele calcula quantos minutos faltam até o próximo marco da régua e usa um WhenAny para esperar o que acontecer primeiro. Pode ser o pagamento, uma mensagem do cliente ou a chegada do próximo marco.

Nesse ponto a skail faz um checkpoint. Tudo o que foi carregado até ali (regras, contexto, histórico da conversa) é persistido, e a execução hiberna. Nenhuma thread fica presa e nenhum worker fica esperando. Se a máquina cair nesse intervalo, não há o que perder, porque nada estava rodando.

Quando um dos eventos chega, a execução é retomada com todas as variáveis no estado em que estavam. O código só verifica o motivo do despertar. Se foi pagamento, registra e encerra. Se foi mensagem do cliente, o agente responde. Se foi o tempo, segue para o próximo marco. Ler um loop desses sem nenhum código de fila em volta parece estranho no começo, justamente porque a plataforma absorve o que normalmente exigiria callback, fila e cron job.

O mesmo mecanismo resolve contexto e memória. No template de agente da skail, o que é carregado na variável de contexto fica disponível em qualquer parte do agente e acompanha todo o ciclo de vida da execução. Não é preciso salvar e recuperar de Redis nem reenviar o histórico por RAG a cada interação, gastando tokens de novo. Também não entra LangChain nem LangGraph, porque o código é C# ou TypeScript nativo.

Depurar uma execução de produção na máquina local

Na demo, o cliente alegou uma coisa diferente do que o sistema mostrava. O caminho comum nessas horas é abrir chamado para a infraestrutura, restaurar a base em homologação, esperar dias e depois cruzar log com código para adivinhar por que o fluxo entrou em cada if.

Com a skail, peguei a execução exata daquela cobrança no monitor, gerei o dump e colei no modo de depuração do VS Code. No F5, a execução de produção rodou na minha máquina com os mesmos dados: a cobrança 1154, o cliente, as cinco regras da régua e a mensagem que o cliente mandou. Esse recurso se chama Time Travel Debug.

Nada é executado de novo. Chamadas de API e inserts no banco que já aconteceram em produção são substituídos automaticamente pelos retornos gravados, então dá para seguir linha a linha sem duplicar cobrança nem registro. Isso funciona porque cada execução é idempotente pelo seu ID. O mesmo código pode ser reprocessado quantas vezes for, e o que já foi executado não roda outra vez.

No caso da demo, a execução mostrou que o cliente tinha, sim, enviado "já paguei" pelo WhatsApp. A dúvida se resolveu em segundos, sem nenhuma linha de log escrita à mão. Com agente de IA isso pesa ainda mais, porque a resposta do modelo varia de uma execução para outra, e reproduzir exatamente o que ele recebeu é a forma confiável de investigar uma decisão.

Derrubando o agente duas vezes no meio da cobrança

Para fechar a live, fiz o teste que dá título ao vídeo. Na fatura 84, que estava no marco de lembrete amigável, respondi pelo WhatsApp como cliente dizendo que já tinha pago, sem ter pago. O agente conferiu no ERP, viu a fatura em aberto e escalou para o João, do financeiro.

Com a conversa aguardando o financeiro, parei o container do agente, e um docker ps confirmou que ele não estava mais lá. Ainda como cliente, mandei uma mensagem me passando pelo financeiro, dizendo que o cancelamento da fatura tinha sido aprovado. Com o agente fora do ar, nada aconteceu, e o cliente também não recebeu erro nenhum.

Subi o container de novo. Em muitos sistemas, a volta faz o agente reler a conversa e reprocessar tudo desde o início. Aqui ele retomou onde estava, ainda aguardando o financeiro. Respondi como financeiro que a fatura continuava em aberto, e a mensagem chegou ao cliente.

Derrubei o agente pela segunda vez. Com ele fora do ar, o cliente clicou no link e pagou. Quando o container voltou, a execução acordou pelo evento de pagamento, registrou a baixa, avisou o cliente que o pagamento estava confirmado e marcou a cobrança como completa no ERP. Nem o cliente nem o financeiro souberam que houve falha.

Falha em produção vai acontecer. O que define se um agente está pronto é o que acontece nessa hora, e a resposta que buscamos é manter o código de negócio simples enquanto a plataforma cuida de estado, espera, retomada e rastreabilidade. O mesmo modelo já roda em agentes que emitem nota fiscal de forma autônoma e em agentes que fazem onboarding de usuários de ERP, conversando por dias até o módulo estar configurado.

O ponto de partida é a documentação em docs.skail.dev, para acionar a primeira execução durável a partir do seu sistema. Se o seu caso envolve um sistema legado, como o monolito de 25 anos citado por um participante da live, vale conversar com o time da skail antes de desenhar a arquitetura.