Ao vivo 18/11 · Turma 318 nov às 19:00 MSK — aula prática gratuita de agentes de IA · Turma 3 ao vivo começa 23/11Aula 18/11 →Turma 3 (23/11)
LançamentoAPI / Produto · Pronto p/ usoHabr AI→ original

Dois limites de conversa do bot para amoCRM não funcionavam desde o lançamento: a culpa era de um AND no lugar de OR e de uma ramificação defeituosa

O bot Octery para amoCRM tinha dois limites no painel administrativo: o número máximo de respostas e o limiar de mensagens sem sentido. Nenhum deles funcionava desde o início. A condição para transferir a conversa a um gerente foi montada com AND em vez de OR, enquanto a ramificação de transferência gravava valores em campos com nomes incorretos, fazendo com que as etapas seguintes lessem a resposta anterior do modelo.

Processado por IA de Habr AI; editado por Hamidun News
Dois limites de conversa do bot para amoCRM não funcionavam desde o lançamento: a culpa era de um AND no lugar de OR e de uma ramificação defeituosa
Fonte: Habr AI. Colagem: Hamidun News.
Ouvir artigo
Ficha técnica e números-chave
ParâmetroDados
Fonte originalHabr AI ↗
Editor-chefe
Dado-chave #1A lógica ficava na configuração do pipeline: sem testes unitários, sem CI e sem um diff legível
Dado-chave #2A solução foi transferida para uma função pura na API, que obtém os limites diretamente das configurações
Dado-chave #3Cada um dos 16 cenários da especificação virou um teste com um nome descritivo

Imagine: os números aparecem no painel administrativo, a configuração é salva e a interface parece estar correta. Na prática, porém, ela não faz nada. Foi exatamente assim que, em 30 de setembro, descobriram que nenhum dos dois limites de duração da conversa funcionava no bot Octery e que, ao que tudo indica, eles nunca haviam funcionado desde o início.

O Octery responde a leads nos chats do amoCRM e transfere a negociação para um gerente. Há dois limites. Max Messages define quantas respostas o bot dará antes de chamar uma pessoa. Hard Stop Threshold determina quantas mensagens consecutivas sem sentido ele tolerará: "aaa", "test", "???" ou até mesmo a saída de outro bot. Cada mensagem desse tipo custa uma chamada ao modelo, portanto não faz sentido responder a elas indefinidamente.

Dois erros que escondiam um ao outro

A decisão de transferir a conversa era tomada depois da resposta do modelo, dentro do pipeline de processamento. A condição reunia três verificações ligadas por AND. De acordo com o significado das configurações, os limites são independentes: a transferência deve ocorrer se o contador de respostas se esgotar ou se houver uma sequência de mensagens sem sentido. Com AND, o bot só chamava um gerente quando o cliente, ao mesmo tempo, esgotava o limite de mensagens e escrevia bobagens várias vezes seguidas. Isso nunca acontecia.

O segundo erro estava na ramificação que deveria ser executada quando a condição fosse atendida. Ela substituía a resposta por "transferindo para um gerente" e definia a intenção como manager. No entanto, os valores eram gravados em campos cujos nomes haviam sido substituídos por expressões: o valor era inserido no campo de nome e permanecia ali. Além disso, o envio da resposta e o registro liam os dados diretamente da análise da resposta do modelo, e não dessa ramificação. Mesmo que alguém tivesse trocado AND por OR, o cliente ainda receberia uma resposta normal e os logs não mostrariam qualquer vestígio da transferência.

A primeira execução manual teria encontrado qualquer um dos erros isoladamente. Juntos, eles tornaram os limites invisíveis.

Por que ninguém percebeu

A lógica ficava na configuração do pipeline, não no código. Não é possível escrever um teste unitário para essa configuração, executá-la no CI ou revisar a alteração como um diff legível: durante a revisão, ela parece apenas uma "correção da condição". Levar manualmente uma conversa real até o limite é demorado, por isso as verificações comuns nunca chegavam a esse ponto. A pergunta "os limites funcionam?" não tinha resposta positiva nem negativa.

O que foi feito

A decisão foi transferida para a API como uma função pura independente. O pipeline fornece a ela a resposta do modelo e dois contadores do estado da conversa, enquanto a própria função obtém os limites nas configurações da empresa, impedindo que o chamador forneça valores diferentes. A saída é uma única decisão final: texto, intenção e motivo da transferência. Todas as etapas seguintes leem somente esse resultado.

As fórmulas têm duas armadilhas de diferença de uma unidade. O contador de respostas é calculado antes da mensagem atual: o bot fornece exatamente max_messages respostas e então transfere a conversa. A sequência de mensagens sem sentido inclui a mensagem atual, como informa a dica na interface. Se ambas as condições forem acionadas, o limite de mensagens é registrado como motivo. Se o modelo da frase estiver vazio, a frase padrão será enviada. Também foi removido um efeito colateral: a ramificação antiga classificava a mensagem como "sem sentido" e prejudicava as análises.

Testes derivados da especificação

Primeiro, o comportamento foi descrito por meio de cenários; depois, cada cenário virou um teste, totalizando 16. Os nomes falam por si: "hands off on the Nth non-meaningful message in a row, counting the current one" e "a meaningful message breaks the non-meaningful streak". O teste "old AND case" foi mantido de propósito: o único caso em que a condição antiga chegava a ser acionada agora é um caso particular do novo comportamento.

Risco da implantação e conclusão

O principal risco não é técnico. Empresas com limites baixos verão pela primeira vez o bot parar de responder e chamar um gerente. Para elas, isso parecerá um novo recurso, não uma correção. Por isso, elas serão avisadas antes da ativação, em um item separado do plano de implantação.

A conclusão prática para equipes que trabalham com pipelines no-code e low-code é simples: se um número está visível para o cliente na interface, seu comportamento deve ter um teste automatizado, e o nome do teste deve expressar a promessa feita ao cliente. É melhor transferir da configuração para o código a lógica de negócio da qual dependem a receita e a transferência do cliente para uma pessoa, para que ela possa ser lida em um diff e executada no CI.

História

Perguntas frequentes sobre a notícia

O que se sabe sobre Dois erros que escondiam um ao outro?

A decisão de transferir a conversa era tomada depois da resposta do modelo, dentro do pipeline de processamento. A condição reunia três verificações ligadas por AND. De acordo com o significado das configurações, os limites são independentes: a transferência deve ocorrer se o contador de respostas se esgotar ou se houver uma sequência de mensagens sem sentido. Com AND, o bot só chamava um gerente quando o cliente, ao mesmo tempo, esgotava o limite de mensagens e escrevia bobagens várias vezes seguidas.

Por que ninguém percebeu?

A lógica ficava na configuração do pipeline, não no código. Não é possível escrever um teste unitário para essa configuração, executá-la no CI ou revisar a alteração como um diff legível: durante a revisão, ela parece apenas uma "correção da condição". Levar manualmente uma conversa real até o limite é demorado, por isso as verificações comuns nunca chegavam a esse ponto. A pergunta "os limites funcionam?" não tinha resposta positiva nem negativa.

O que foi feito?

A decisão foi transferida para a API como uma função pura independente. O pipeline fornece a ela a resposta do modelo e dois contadores do estado da conversa, enquanto a própria função obtém os limites nas configurações da empresa, impedindo que o chamador forneça valores diferentes. A saída é uma única decisão final: texto, intenção e motivo da transferência. Todas as etapas seguintes leem somente esse resultado. As fórmulas têm duas armadilhas de diferença de uma unidade.

ZK
Zhemal Khamidun — CPO da Alpina Digital, gerente de produto do AlpinaGPT. Cria produtos de IA desde 2019. O Hamidun News é um projeto pessoal que virou um agregador em produção com mais de 6.000 leitores.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
O que você acha?
Carregando comentários…