tva
← Insights

Passer de l'usage solo à l'équipe avec un assistant IA sur Telegram

Tu as construit un assistant IA Telegram dédié à un projet — Claude, GPT ou un autre LLM encapsulé derrière un bot Telegram, hébergé sur ton propre serveur. Ça marche très bien en solo. Tu veux maintenant le partager avec ton équipe : développeurs, conseillers ou spécialistes qui bénéficieraient d'un accès à la demande au même assistant. Le chemin d'un seul utilisateur vers une petite équipe comporte plus de pièces mobiles que la documentation ne l'indique habituellement.

Ce guide couvre chaque étape : collecter les Telegram ID des membres de l'équipe, étendre l'allow-list d'une façon qui résiste à la distinction restart/recreate de Docker, ouvrir le bon type de groupe, configurer la détection de triggers pour que le bot ne spamme pas, et résoudre le compromis vie-privée qui prend la plupart des équipes par surprise.

Ce dont tu as besoin

  • Un bot Telegram fonctionnel qui gère déjà les messages pour au moins un utilisateur (toi)
  • Un accès SSH ou shell au serveur qui héberge le container du bot
  • Les noms d'utilisateur Telegram des membres de l'équipe que tu veux ajouter
  • L'accès à BotFather (le même compte Telegram qui a créé le bot à l'origine)
  • Environ vingt minutes pour la partie technique, plus du temps de coordination asynchrone avec les membres de l'équipe

Ce que ce guide résout

  • Les membres de l'équipe ne peuvent pas déclencher ton bot — « ça marche chez moi, pas chez eux »
  • Les modifications de l'allow-list semblent s'appliquer, mais le bot ignore quand même les nouveaux utilisateurs après un restart
  • Le bot spamme dans les groupes — il répond à chaque message au lieu de ne répondre qu'aux pertinents
  • Comportement de trigger confus — quand le bot doit-il répondre ? Sur mention uniquement ? Sur mot-clé ? Sur réponse ?
  • Inquiétudes liées aux fuites de mémoire entre utilisateurs que tu n'avais pas anticipées

Étape 1 : Collecter l'identifiant Telegram numérique de chaque membre de l'équipe

L'allow-list de ton assistant IA Telegram est indexée par identifiants numériques d'utilisateur, pas par noms d'utilisateur ni noms d'affichage. Les noms d'utilisateur peuvent changer ; l'identifiant numérique est stable pour toute la durée de vie du compte. Tu as besoin de cet identifiant pour chaque membre de l'équipe que tu veux ajouter.

La solution la plus simple : demande à chaque membre de démarrer une conversation avec @userinfobot (un bot utilitaire public). Le premier message qu'il envoie en retour contient leur identifiant numérique — quelque chose comme 100000001. Demande-leur de copier l'identifiant et de te l'envoyer en DM.

Alternatives si @userinfobot est bloqué ou indisponible dans ta région :

  • Utilise les logs de ton propre bot. Ajoute temporairement une ligne « log toutes les tentatives » au middleware allow-list de ton bot, demande au membre de l'équipe d'envoyer un message à ton bot, et lis l'identifiant utilisateur dans les logs de ton container. Supprime la ligne de logging une fois l'identifiant récupéré.
  • Lis depuis un message de groupe. Si un utilisateur a déjà envoyé un message dans un groupe où ton bot est présent, le champ from.id du message contient son identifiant numérique — lisible via l'endpoint getUpdates du bot.

Garde les identifiants collectés dans un endroit sûr — une note, un gestionnaire de mots de passe, ou directement dans ton fichier .env. Traite-les comme des adresses e-mail : ils identifient un être humain précis et peuvent être croisés avec les profils Telegram publics.

Étape 2 : Étendre l'allow-list de ton bot

La plupart des frameworks de bot Telegram — aiogram, python-telegram-bot, Telegraf, grammY — implémentent les vérifications d'allow-list sous forme de middleware. Chaque update entrant est filtré par l'identifiant de l'expéditeur avant qu'un handler ne s'exécute. Les expéditeurs non autorisés sont silencieusement ignorés : ton bot reçoit leurs messages en interne mais ne répond jamais.

L'allow-list elle-même réside généralement dans une variable d'environnement, chargée dans le container via env_file: dans ton docker-compose.yml :

BOT_ALLOWED_USERS=100000001,100000002,100000003
BOT_OPERATOR_ID=100000001

Deux formats sont couramment utilisés :

  • Liste CSV : BOT_ALLOWED_USERS=111,222,333. Parsée par le code de configuration du bot sous forme de list[int].
  • Tableau JSON : BOT_ALLOWED_USERS=[111,222,333]. Utilisé quand le parser de configuration attend du JSON pour les types complexes.

Si ton bot utilise Python et pydantic-settings pour la configuration, la forme tableau JSON est le choix le plus sûr — même avec un seul utilisateur, préfère BOT_ALLOWED_USERS=[100000001] à BOT_ALLOWED_USERS=100000001. La raison est détaillée dans la sous-section pydantic plus bas, mais en résumé : la forme JSON contourne une ambiguïté du parser qui fait planter ton container au démarrage.

Étape 3 : Redémarrer ton container de la bonne façon

C'est là que la plupart des mises à jour d'allow-list échouent silencieusement. Tu modifies .env, tu exécutes docker compose restart ton-bot, tu regardes le container redémarrer — et les nouveaux utilisateurs ne peuvent toujours pas déclencher le bot. La modification « n'a pas été prise en compte ».

La raison : docker compose restart se contente d'arrêter et de relancer le container existant. Il ne le recrée pas. Les variables d'environnement — y compris tout ce qui vient de env_file: — sont injectées dans un container au moment de sa création, pas au moment de son démarrage. Un restart préserve le snapshot des variables d'environnement d'origine. Ton fichier .env modifié est sans effet sur un container simplement redémarré.

La bonne commande :

docker compose up -d --force-recreate --no-deps ton-nom-de-service-bot

Ce que fait chaque flag :

  • --force-recreate arrête l'ancien container, le supprime, et en crée un nouveau avec la spec Compose courante — y compris le contenu nouvellement modifié de env_file:.
  • --no-deps empêche Compose de recréer également les services dont ton bot dépend (bases de données, files de messages). Si ton bot n'a pas de depends_on, ce flag est sans effet mais inoffensif.
  • -d lance le container recréé en mode détaché, ce qui libère immédiatement ton terminal.

Vérifie que la recréation a réussi en contrôlant le temps de fonctionnement du container :

docker ps --filter name=ton-bot --format "{{.Status}}"
# Attendu : "Up 10 seconds" (pas "Up 4 hours")

Si le statut affiche le même temps de fonctionnement qu'avant, la recréation n'a pas eu lieu — vérifie les fautes de frappe dans le nom du service ou si tu as bien exécuté la commande depuis le bon répertoire.

Ce pattern s'applique à n'importe quel service Docker Compose dont la configuration est dans un env-file : API gateways, workers, scrapers, agents de monitoring. Le même piège se reproduit à chaque fois. Nous avons documenté des patterns plus larges pour gérer de nombreux containers de ce type dans notre guide de health-check routinier pour une infrastructure Dockerisée.

pydantic-settings : un piège de parser à connaître

Si la couche de configuration Python de ton bot utilise pydantic-settings — la bibliothèque standard pour les settings Pydantic v2 — et que tu déclares ton allow-list en list[int], tu vas rencontrer un problème de parser qui vaut la peine d'être compris avant qu'il te piège.

pydantic-settings traite les types complexes (list, dict, tuple) comme encodés en JSON par défaut. Quand il lit BOT_ALLOWED_USERS=111,222 depuis ton env-file, il tente d'abord json.loads("111,222"). Ça échoue avec JSONDecodeError: Extra data parce que le CSV brut n'est pas du JSON valide. Ton container plante au démarrage avec un SettingsError: error parsing value for field.

Si tu as un BeforeValidator personnalisé attaché au champ qui sait parser du CSV, tu pourrais supposer qu'il s'exécute en premier et intercepte la chaîne brute avant la tentative de décodage JSON. Ce n'est pas le cas. pydantic-settings applique l'étape de décodage JSON avant tout validateur au niveau du champ pour les types complexes.

Tu as deux solutions :

Solution rapide — syntaxe tableau JSON dans l'env-file :

BOT_ALLOWED_USERS=[100000001,100000002,100000003]

C'est du JSON valide. pydantic-settings le décode directement en liste d'entiers. Aucun validateur nécessaire. Le compromis est purement cosmétique : des crochets autour d'une liste.

Solution durable — annoter le champ avec 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 supprime entièrement l'étape de décodage JSON. Ton BeforeValidator reçoit la chaîne brute et la parse en CSV. C'est la solution la plus propre si tu contrôles le code de configuration.

Le problème sous-jacent est suivi dans l'issue #157 de pydantic-settings, avec des discussions connexes dans les issues #184 et #570. Le comportement est cohérent sur toutes les versions actuellement publiées de pydantic-settings (v2.x). Si tu ne contrôles pas le code de configuration — en utilisant un framework de bot tiers — utilise la solution de contournement avec la syntaxe tableau JSON.

Étape 4 : Créer un groupe Telegram avec ton bot et ton équipe

Telegram propose deux types de groupes pour ce cas d'usage :

  • Groupe standard : jusqu'à 200 membres, modèle d'administration simple, pas de fonctionnalités avancées. Adapté aux petites équipes.
  • Supergroupe : jusqu'à 200 000 membres, permissions d'administration fines, discussions en fil, persistance de l'historique des messages. Convertis un groupe standard plus tard si tu as besoin d'évoluer.

Pour des workflows d'équipe jusqu'à une douzaine de membres, un groupe standard suffit. Les étapes :

  • Dans ton application Telegram, appuie sur « Nouveau groupe » et sélectionne les membres de ton équipe depuis tes contacts
  • Donne au groupe un nom descriptif — « Projet X — Assistant IA », « Engineering Bot Workspace », etc.
  • Une fois créé, ouvre les paramètres du groupe, appuie sur « Ajouter un membre », recherche le nom d'utilisateur de ton bot (@ton_nom_de_bot) et ajoute-le
  • Promeus le bot en administrateur seulement s'il a besoin d'actions d'admin (supprimer des messages, épingler des messages). Pour un usage question-réponse pur, le statut de membre simple suffit

Si tu gères plusieurs bots dédiés à différents projets sur plusieurs équipes (nous en maintenons une poignée sur une infrastructure partagée), les patterns multi-tenant que nous utilisons sont documentés dans notre guide du stack de développement Docker multi-tenant.

Étape 5 : Configurer la détection des triggers

Par défaut, un bot Telegram dans un groupe ne reçoit que les messages qui le mentionnent explicitement (@ton_nom_de_bot), répondent à ses messages, ou utilisent une commande slash. Telegram appelle ça le « Privacy Mode », activé par défaut — un réglage sensé qui évite le spam accidentel.

Mais pour un assistant IA Telegram qui doit répondre à des questions naturelles (« Hé bot, quel est le statut du déploiement ? » sans mention explicite), le Privacy Mode est trop restrictif. Tu as deux options :

Option A : Garder le Privacy Mode activé, apprendre à l'équipe à utiliser @mention. Simple, aucun changement de configuration nécessaire. Le bot ne voit que ce à quoi il devrait répondre. Inconvénient : friction. Les membres de l'équipe oublient le @ et le bot reste silencieux.

Option B : Désactiver le Privacy Mode et implémenter ta propre logique de trigger. Ouvre BotFather, envoie /setprivacy, choisis ton bot, règle sur Disable. Le bot reçoit maintenant tous les messages du groupe. Tu implémentes toi-même la vérification « dois-je répondre ? ».

Un ensemble de triggers pratique que nous utilisons en production :

  • Message direct : toujours répondre — tu parles au bot en tête-à-tête
  • @mention dans un groupe : toujours répondre — invocation explicite
  • Réponse à l'un des messages du bot : toujours répondre — continuation d'un fil que le bot a initié
  • Message de groupe contenant le mot-trigger du bot : répondre. Le mot-trigger est généralement le surnom du bot ou le nom du projet, matché avec une regex à limite de mot pour que « conseiller » ne déclenche pas accidentellement sur « conseillère »
  • Tout le reste : journaliser silencieusement dans un fichier de conversation, sans réponse

La partie journalisation silencieuse est importante. Même quand le bot ne répond pas, il voit quand même le flux de conversation du groupe. Journaliser chaque message dans un fichier par chat donne au bot du contexte futur — quand quelqu'un le @mentionne finalement avec une question comme « qu'est-ce qu'on a décidé ? », le bot dispose de la conversation récente comme contexte pour raisonner.

L'implémentation dépend de ton framework. Dans aiogram, un seul handler de messages exécute les cinq vérifications avant de décider d'appeler ton LLM et de répondre. Dans Telegraf ou grammY, le pattern est identique — un handler bot.on('message') qui filtre explicitement avant de réagir.

Étape 6 : Résoudre le compromis vie-privée

Voici la question que la plupart des équipes ne se posent pas avant que ça devienne un problème : est-ce que ton bot maintient une mémoire séparée par utilisateur, par groupe, ou globalement sur toutes les conversations ?

Trois patterns sont courants :

  • Mémoire par chat : le bot démarre une session fraîche pour chaque conversation. Le DM avec l'utilisateur A est indépendant du DM avec l'utilisateur B, et les deux sont indépendants du groupe X. Vie privée maximale. Inconvénient : le bot ne se souvient pas du contexte entre les sessions, ce qui limite son utilité en tant qu'« assistant qui connaît notre projet »
  • Mémoire par utilisateur : le bot maintient des fils de mémoire séparés par utilisateur, mais les partage entre DMs et mentions dans un groupe du même utilisateur. Un juste milieu raisonnable
  • Mémoire globale : le bot a une seule session à laquelle toutes les conversations contribuent. Partage de contexte maximal — DMs et conversations de groupe enrichissent tous la même mémoire long-terme. Inconvénient : fuites de vie privée. Un élément confidentiel qu'un membre de l'équipe dit au bot en DM peut resurgir dans une réponse de groupe à la question d'un autre membre

Chaque pattern est défendable. Chacun a des compromis sur lesquels ton équipe doit se mettre d'accord avant de passer en multi-utilisateur.

Si tu choisis la mémoire globale — c'est notre choix pour les équipes soudées où le partage de contexte fait partie de la valeur ajoutée — sois explicite avec ton équipe avant qu'elle commence à utiliser le bot : « Tout ce que tu dis à ce bot peut resurgir dans des réponses visibles par tout le groupe. Traite-le comme un espace de travail partagé, pas comme un confident privé. »

Si tu choisis la mémoire par chat, tu renonces au raisonnement inter-contexte (« qu'est-ce qu'on a décidé la semaine dernière sur X ? ») mais tu évites totalement le risque de fuite.

C'est un choix de conception avec de vraies conséquences sociales, pas un simple réglage technique que tu peux modifier plus tard sans alignement de toute l'équipe. Nous abordons des compromis similaires dans notre article plus large sur les compétences d'agents IA pour des workflows spécialisés, où les configurations à contexte partagé apparaissent dans chaque engagement client que nous menons.

Faire évoluer ton assistant IA Telegram au-delà d'une petite équipe

Le pattern allow-list en env-file fonctionne bien pour des équipes allant jusqu'à une vingtaine ou trentaine d'utilisateurs. Au-delà, les entrées codées en dur deviennent pénibles — chaque onboarding nécessite un commit git (si ton env est versionné via SOPS ou une couche similaire de gestion des secrets), un déploiement, et une recréation du container.

Les patterns qui passent mieux à l'échelle :

  • Allow-list en base de données : les utilisateurs vivent dans une table SQL, le bot lit et met en cache la liste au démarrage, puis la rafraîchit périodiquement (ou via un webhook sur les changements d'utilisateurs). Intégrer un utilisateur devient un simple INSERT — pas de déploiement nécessaire
  • Accès basé sur l'appartenance à un groupe : au lieu d'autoriser des utilisateurs individuels, autorise tout utilisateur membre d'un groupe Telegram spécifique (ou d'un petit ensemble de groupes). L'appartenance au groupe devient la frontière d'accès. L'API getChatMember de Telegram confirme l'appartenance avant chaque invocation
  • Basé sur un channel : pour les assistants en lecture seule (résumés quotidiens, alertes, digests de monitoring), utilise un channel Telegram plutôt qu'un groupe. Les channels ont un modèle de permissions différent — seuls les admins publient, les autres lisent. Utile quand il y a un fan-out en un-vers-plusieurs plutôt qu'une conversation aller-retour

Pour les workflows de petites équipes — développeurs, conseillers, spécialistes occasionnels — le pattern allow-list en env-file est suffisant. Nous l'utilisons dans la plupart de notre infrastructure interne et traitons la variante basée sur une base de données comme un refactoring que nous faisons dès qu'un projet dépasse clairement la forme plus simple.

Checklist de clôture

Avant que ton équipe commence à utiliser le bot, vérifie :

  • Tous les identifiants Telegram numériques des membres de l'équipe collectés et ajoutés à l'allow-list
  • Le format de l'allow-list correspond à ce qu'attend ton parser de configuration — tableau JSON si pydantic-settings est dans la stack
  • Le container a bien été recréé (pas juste redémarré) pour que les nouvelles variables d'environnement soient chargées dans un container frais
  • Le groupe Telegram créé avec le bot ajouté comme membre (et promu admin s'il a besoin d'actions d'administration)
  • Le Privacy Mode de BotFather configuré en accord avec ta stratégie de trigger — désactivé seulement si tu as implémenté ta propre logique de filtrage
  • La logique de trigger dans le code de ton bot alignée avec le Privacy Mode (ne désactive pas le Privacy sans filtrage, sinon le bot spammera chaque message de groupe)
  • Le modèle de mémoire (par chat / par utilisateur / global) choisi et communiqué à l'équipe
  • Les attentes en matière de vie privée explicitement définies avec les membres de l'équipe avant qu'ils commencent à utiliser le bot

Si tu construis un assistant dédié à un projet de zéro et que tu veux comprendre comment l'infrastructure bot sous-jacente s'assemble, notre article complémentaire sur la construction d'un assistant IA dédié via Telegram couvre les fondations. Pour l'infrastructure e-mail qui accompagne souvent ces setups — notifications, chemins d'escalade, pistes d'audit — consulte notre article sur la configuration d'une boîte mail dédiée avec DKIM et DMARC.

Si tu gères ce type d'infrastructure d'assistant IA Telegram multi-utilisateur pour des clients ou pour ta propre équipe et que tu as besoin d'aide pour le déploiement, contacte-nous. Nous construisons et opérons ce type de setup dans le cadre de nos missions.


Insights connexes

Articles connexes