tva
← Insights

Escalando um Assistente de IA no Telegram: do Uso Solo para a Equipe

Você construiu um assistente de IA específico para um projeto no Telegram — um Claude, GPT ou outro LLM empacotado por trás de um bot, rodando no seu próprio servidor. Funciona bem para uso solo. Agora você quer compartilhá-lo com sua equipe: desenvolvedores, consultores ou especialistas que se beneficiariam de acesso sob demanda ao mesmo assistente. O caminho de um único usuário para uma equipe pequena tem mais partes móveis do que a documentação costuma mencionar.

Este guia cobre cada etapa: coletar os IDs do Telegram dos membros da equipe, estender o allow-list de uma forma que sobreviva à distinção entre restart e recreate do Docker, abrir o tipo certo de grupo, configurar a detecção de trigger para o bot não fazer spam e resolver o trade-off de privacidade que pega a maioria das equipes de surpresa.

O Que Você Vai Precisar

  • Um bot no Telegram funcionando que já processa mensagens para pelo menos um usuário (você)
  • Acesso SSH ou shell ao servidor que roda o container do bot
  • Os usernames do Telegram dos membros da equipe que você quer adicionar
  • Acesso ao BotFather (a mesma conta do Telegram que criou o bot originalmente)
  • Cerca de vinte minutos para o trabalho técnico, mais tempo de coordenação assíncrona com os membros da equipe

O Que Este Guia Resolve

  • Membros da equipe não conseguem acionar o bot — "funciona pra mim, não funciona pra eles"
  • Alterações no allow-list parecem aplicadas, mas o bot ainda ignora novos usuários após um restart
  • Bot faz spam em grupos — responde a todas as mensagens em vez de apenas às relevantes
  • Comportamento de trigger confuso — quando o bot deve responder? Só quando mencionado? Por palavra-chave? Por reply?
  • Preocupações com vazamento de memória entre usuários que você não havia antecipado

Passo 1: Colete o ID Numérico do Telegram de Cada Membro da Equipe

O allow-list do seu assistente de IA no Telegram é baseado em IDs numéricos de usuário, não em usernames ou nomes de exibição. Usernames podem mudar; o ID numérico é estável durante toda a vida da conta. Você precisa desse ID para cada membro da equipe que quiser adicionar.

A maneira mais fácil: peça a cada membro que inicie uma conversa com @userinfobot (um bot utilitário público). A primeira mensagem de resposta contém o ID numérico — algo como 100000001. Peça que copiem o ID e enviem para você via DM.

Alternativas caso o @userinfobot esteja bloqueado ou indisponível na sua região:

  • Use os logs do seu próprio bot. Adicione temporariamente uma linha de "logar todas as tentativas" no middleware do allow-list do seu bot, peça ao membro da equipe que envie uma mensagem ao bot e leia o ID do usuário nos logs do container. Remova a linha de log após coletar o ID.
  • Leia a partir de uma mensagem em grupo. Se um usuário já enviou uma mensagem em um grupo onde seu bot está, o campo from.id da mensagem contém o ID numérico — acessível via o endpoint getUpdates do bot.

Guarde os IDs coletados em um lugar seguro — uma anotação, gerenciador de senhas ou diretamente no seu arquivo .env. Trate-os como endereços de e-mail: eles identificam uma pessoa específica e podem ser cruzados com perfis públicos do Telegram.

Passo 2: Estenda o Allow-List do Seu Bot

A maioria dos frameworks de bot para Telegram — aiogram, python-telegram-bot, Telegraf, grammY — implementa as verificações de allow-list como middleware. Cada update recebido é filtrado pelo ID do remetente antes de qualquer handler ser executado. Remetentes não autorizados são descartados silenciosamente: seu bot recebe as mensagens internamente, mas nunca responde.

O allow-list em si geralmente fica em uma variável de ambiente, carregada no container via env_file: no seu docker-compose.yml:

BOT_ALLOWED_USERS=100000001,100000002,100000003
BOT_OPERATOR_ID=100000001

Dois formatos são usados com frequência:

  • Lista CSV: BOT_ALLOWED_USERS=111,222,333. Interpretada pelo código de configurações do bot como list[int].
  • Array JSON: BOT_ALLOWED_USERS=[111,222,333]. Usado quando o parser de configurações espera JSON para tipos complexos.

Se o seu bot usa Python e pydantic-settings para configuração, o formato de array JSON é a escolha mais segura — mesmo com um único usuário, prefira BOT_ALLOWED_USERS=[100000001] em vez de BOT_ALLOWED_USERS=100000001. O motivo está detalhado na subseção sobre pydantic mais abaixo, mas a versão curta é que o formato JSON contorna uma ambiguidade do parser que derruba o container na inicialização.

Passo 3: Reinicie o Container da Forma Correta

É aqui que a maioria das atualizações de allow-list dá errado silenciosamente. Você edita o .env, executa docker compose restart seu-bot, observa o container subir — e os novos usuários ainda não conseguem acionar o bot. A mudança "não surtiu efeito".

O motivo: docker compose restart apenas para e inicia o container existente. Ele não o recria. As variáveis de ambiente — incluindo tudo do env_file: — são injetadas no container no momento da criação, não na inicialização. Um restart preserva o snapshot original das variáveis de ambiente. O arquivo .env editado é irrelevante para um container apenas reiniciado.

O comando correto:

docker compose up -d --force-recreate --no-deps nome-do-seu-servico-bot

O que cada flag faz:

  • --force-recreate para o container antigo, remove-o e cria um novo com a spec atual do Compose — incluindo o conteúdo recém-editado do env_file:.
  • --no-deps evita que o Compose recrie também os serviços dos quais o bot depende (bancos de dados, filas de mensagens). Se o bot não tem depends_on, esta flag não faz nada, mas é inofensiva.
  • -d executa o container recriado em modo detached, para que o terminal retorne imediatamente.

Verifique se o recreate funcionou checando o uptime do container:

docker ps --filter name=seu-bot --format "{{.Status}}"
# Esperado: "Up 10 seconds" (não "Up 4 hours")

Se o status mostrar o mesmo longo uptime de antes, o recreate não ocorreu — verifique se há erros de digitação no nome do serviço ou se você executou o comando no diretório correto.

Esse padrão se aplica a qualquer serviço Docker Compose cuja configuração fica em um env-file: API gateways, workers, scrapers, agentes de monitoramento. A mesma armadilha te pega toda vez. Documentamos padrões mais amplos para gerenciar vários containers desse tipo no nosso guia de health-check rotineiro para infraestrutura Dockerizada.

Pydantic-Settings: Uma Armadilha do Parser para Conhecer

Se a camada de configurações Python do seu bot usa pydantic-settings — a biblioteca padrão para configurações do Pydantic v2 — e você declara o allow-list como list[int], você vai se deparar com um problema de parser que vale entender antes que ele te prejudique.

O pydantic-settings trata tipos complexos (list, dict, tuple) como codificados em JSON por padrão. Quando ele lê BOT_ALLOWED_USERS=111,222 do seu env-file, primeiro tenta json.loads("111,222"). Isso falha com JSONDecodeError: Extra data porque CSV puro não é JSON válido. Seu container falha na inicialização com SettingsError: error parsing value for field.

Se você tem um BeforeValidator personalizado anexado ao campo que sabe como interpretar CSV, pode assumir que ele roda primeiro e intercepta a string bruta antes da tentativa de decodificação JSON. Não roda. O pydantic-settings aplica o passo de decodificação JSON antes de qualquer validador em nível de campo para tipos complexos.

Você tem duas soluções alternativas:

Solução rápida — sintaxe de array JSON no env-file:

BOT_ALLOWED_USERS=[100000001,100000002,100000003]

Isso é JSON válido. O pydantic-settings decodifica diretamente numa lista de ints. Nenhum validador necessário. O trade-off é puramente cosmético: colchetes ao redor da lista.

Solução definitiva — anote o campo com NoDecode:

from pydantic_settings import NoDecode
from pydantic import BeforeValidator
from typing import Annotated

def parse_csv(v):
    if isinstance(v, str):
        return [int(x.strip()) for x in v.split(",")]
    return v

class Settings(BaseSettings):
    bot_allowed_users: Annotated[list[int], NoDecode, BeforeValidator(parse_csv)]

NoDecode suprime completamente o passo de decodificação JSON. O seu BeforeValidator recebe a string bruta e a interpreta como CSV. Essa é a solução mais limpa se você controla o código de configurações.

O problema subjacente é rastreado na issue #157 do pydantic-settings, com discussões relacionadas nas issues #184 e #570. O comportamento é consistente em todas as versões lançadas atualmente do pydantic-settings (v2.x). Se você não controla o código de configurações — usando um framework de bot de terceiros — use a solução alternativa com sintaxe de array JSON.

Passo 4: Crie um Grupo no Telegram com o Bot e a Equipe

O Telegram tem dois tipos de grupos para este caso de uso:

  • Grupo comum: até 200 membros, modelo de admin simples, sem recursos avançados. Bom para equipes pequenas.
  • Supergrupo: até 200.000 membros, permissões de admin granulares, discussões em threads, persistência de histórico de mensagens. Converta um grupo comum em supergrupo se crescer.

Para fluxos de trabalho de equipes de até uma dúzia de membros, um grupo comum é suficiente. Passos:

  • No app do Telegram, toque em "Novo Grupo" e selecione os membros da equipe nos seus contatos
  • Dê ao grupo um nome descritivo — "Projeto X — Assistente de IA", "Workspace de Bot para Engenharia", etc.
  • Após criado, abra as configurações do grupo, toque em "Adicionar Membro", pesquise pelo username do bot (@nome_do_seu_bot) e adicione-o
  • Promova o bot a admin apenas se ele precisar de ações de administrador (apagar mensagens, fixar mensagens). Para uso de perguntas e respostas, o status de membro comum é suficiente

Se você gerencia múltiplos bots específicos para projetos em várias equipes (mantemos alguns desses em infraestrutura compartilhada), os padrões multi-tenant que usamos estão documentados no nosso guia de stack Docker para desenvolvimento multi-tenant.

Passo 5: Configure a Detecção de Trigger

Por padrão, um bot do Telegram em um grupo só recebe mensagens que o mencionam explicitamente (@nome_do_seu_bot), que são replies às suas mensagens ou que usam um slash-command. O Telegram chama isso de "Privacy Mode", e está habilitado por padrão — um padrão sensato que evita spam acidental do bot.

Mas para um assistente de IA no Telegram que deve responder a perguntas naturais ("Ei bot, qual é o status do deploy?" sem uma menção explícita), o Privacy Mode é restritivo demais. Você tem dois caminhos:

Caminho A: Manter o Privacy Mode ativo e treinar a equipe para usar @mention. Simples, sem alteração de configuração. O bot só vê o que deve responder. Desvantagem: fricção. Os membros da equipe esquecem o @ e o bot fica em silêncio.

Caminho B: Desabilitar o Privacy Mode e implementar sua própria lógica de trigger. Abra o BotFather, envie /setprivacy, escolha seu bot, defina como Disable. O bot agora recebe todas as mensagens do grupo. Você implementa a verificação "devo responder?" por conta própria.

Um conjunto de triggers prático que usamos em produção:

  • Mensagem direta: sempre responder — você está falando com o bot individualmente
  • @mention em grupo: sempre responder — invocação explícita
  • Reply a uma mensagem do bot: sempre responder — continuação de uma thread que o bot iniciou
  • Mensagem no grupo contendo a palavra-gatilho do bot: responder. A palavra-gatilho é tipicamente o apelido do bot ou o nome do projeto, verificada com regex de word-boundary para que "consultor" não acione acidentalmente em "consultora"
  • Todo o resto: registrar silenciosamente em um arquivo de conversa, sem resposta

A parte do log silencioso importa. Mesmo quando o bot não responde, ele ainda vê o fluxo de conversa do grupo. Registrar cada mensagem em um arquivo por chat dá ao bot contexto futuro — quando alguém finalmente fizer uma @mention com uma pergunta como "o que decidimos?", o bot tem a conversa recente disponível como contexto para raciocinar.

A implementação depende do seu framework. No aiogram, um único message handler executa todas as cinco verificações antes de decidir se deve chamar o LLM e responder. No Telegraf ou grammY, o padrão é idêntico — um handler bot.on('message') que filtra explicitamente antes de reagir.

Passo 6: Resolva o Trade-Off de Privacidade

Aqui está a pergunta que a maioria das equipes não pensa até virar um problema: seu bot mantém memória separada por usuário, por grupo ou globalmente em todas as conversas?

Três padrões são comuns:

  • Memória por chat: o bot inicia uma sessão nova para cada conversa. DM com o usuário A é independente do DM com o usuário B, e ambos são independentes do grupo X. Privacidade máxima. Desvantagem: o bot não lembra o contexto entre sessões, o que limita sua utilidade como "assistente que conhece nosso projeto"
  • Memória por usuário: o bot mantém threads de memória separados por usuário, mas os compartilha entre DMs e menções em grupo desse mesmo usuário. Um meio-termo razoável
  • Memória global: o bot tem uma sessão única para a qual todas as conversas contribuem. Compartilhamento máximo de contexto — DMs e conversas em grupo constroem a mesma memória de longo prazo. Desvantagem: vazamento de privacidade. Uma coisa confidencial que um membro da equipe conta ao bot em DM pode aparecer na resposta a uma pergunta de outro membro no grupo

Cada padrão é defensável. Cada um tem trade-offs com os quais sua equipe precisa concordar antes de abrir o acesso para múltiplos usuários.

Se você escolher memória global — como fazemos para equipes coesas onde o compartilhamento de contexto faz parte da proposta de valor — seja explícito com sua equipe antes de começarem a usar o bot: "Qualquer coisa que você disser a este bot pode aparecer em respostas visíveis para o grupo todo. Trate-o como um workspace compartilhado, não como um confidente privado."

Se você escolher memória por chat, abre mão do raciocínio com contexto cruzado ("o que decidimos na semana passada sobre X?"), mas evita completamente o risco de vazamento.

Esta é uma escolha de design com consequências sociais reais, não um botão técnico que você pode mudar depois sem alinhamento de toda a equipe. Discutimos trade-offs semelhantes no nosso texto mais amplo sobre skills de agentes de IA para fluxos de trabalho específicos de domínio, onde configurações de contexto compartilhado aparecem em cada engajamento com clientes que conduzimos.

Escalando o Assistente de IA no Telegram Além de uma Equipe Pequena

O padrão de allow-list via env-file funciona bem para equipes de até vinte ou trinta usuários. Além disso, as entradas hardcoded ficam trabalhosas — cada onboarding exige um commit no git (se o env está versionado via SOPS ou uma camada de gerenciamento de secrets semelhante), um deploy e um recreate do container.

Padrões que escalam além disso:

  • Allow-list baseado em banco de dados: os usuários ficam em uma tabela SQL, o bot lê e faz cache da lista na inicialização e depois atualiza periodicamente (ou via webhook em mudanças de usuário). Fazer o onboarding de um usuário torna-se um INSERT — sem necessidade de deploy
  • Acesso baseado em membership de grupo: em vez de autorizar usuários individuais, autorize qualquer usuário que seja membro de um grupo específico no Telegram (ou um conjunto pequeno de grupos). A participação no grupo torna-se o limite de acesso. A API getChatMember do Telegram confirma a participação antes de cada invocação
  • Baseado em canal: para assistentes somente leitura (resumos diários, alertas, digests de monitoramento), use um canal do Telegram em vez de um grupo. Os canais têm um modelo de permissões diferente — só admins publicam, outros apenas leem. Útil quando há um fan-out de um para muitos em vez de conversa bidirecional

Para fluxos de trabalho de equipes pequenas — desenvolvedores, consultores, especialistas ocasionais — o padrão de allow-list via env-file é suficiente. Usamos isso em grande parte da nossa infraestrutura interna e tratamos a variante baseada em banco de dados como uma refatoração que fazemos quando um projeto claramente supera a forma mais simples.

Checklist Final

Antes de sua equipe começar a usar o bot, verifique:

  • IDs numéricos do Telegram de todos os membros da equipe coletados e adicionados ao allow-list
  • Formato do allow-list compatível com o que o parser de configurações espera — array JSON se pydantic-settings estiver na stack
  • Container recriado (não apenas reiniciado) para que as novas variáveis de ambiente sejam carregadas em um container novo
  • Grupo no Telegram criado com o bot adicionado como membro (e promovido a admin se precisar de ações de administrador)
  • Privacy Mode do BotFather configurado para corresponder à sua estratégia de trigger — desabilitado somente se você implementou sua própria lógica de filtro
  • Lógica de trigger no código do bot alinhada com o Privacy Mode (não desabilite o Privacy sem filtrar, ou o bot vai responder a todas as mensagens do grupo)
  • Modelo de memória (por chat / por usuário / global) escolhido e comunicado à equipe
  • Expectativas de privacidade definidas explicitamente com os membros da equipe antes de começarem a usar o bot

Se você está construindo um assistente específico para um projeto do zero e quer entender como a infraestrutura do bot se encaixa, nosso texto complementar sobre construir um assistente de IA específico para projeto via Telegram cobre a base. Para infraestrutura de e-mail que frequentemente acompanha essas configurações — notificações, caminhos de escalada, trilhas de auditoria — veja nosso texto sobre configuração de mailbox específica para projeto com DKIM e DMARC.

Se você está gerenciando esse tipo de infraestrutura de assistente de IA multi-usuário no Telegram para clientes ou para a própria equipe e quer ajuda com o rollout, entre em contato. Construímos e operamos esse tipo de configuração como parte do nosso trabalho em projetos.


Insights Relacionados

Artigos relacionados