Storia Progetti Blog Consulenza Scrivimi →
Home › Blog › Come creare un bot Telegram con l'AI (codice Claude)
Tutorial

Come creare un bot Telegram con l'AI (codice Claude)

8 min lettura Pubblicato il
Come creare un bot Telegram con l'AI usando Claude — Raffaele Mele

In breve: per creare un bot Telegram con l'AI servono tre cose: un bot creato con @BotFather (ti dà un token), una chiave API di un modello come Claude e un piccolo programma che legge i messaggi da Telegram, li manda al modello e rimanda indietro la risposta. In questa guida trovi un bot completo in Node.js, circa 100 righe, con memoria della conversazione, lista di chat autorizzate e gestione degli errori. Il costo dipende dal modello: con messaggi brevi si parla di frazioni di centesimo a risposta.

Come funziona un bot Telegram con l'AI?

Un bot Telegram è un account speciale controllato da un programma tuo, non da una persona. Il programma parla con Telegram tramite le Bot API ufficiali. Quando qualcuno scrive al bot, il tuo programma riceve il messaggio, lo gira a un modello di linguaggio e rimanda la risposta nella stessa chat. L'AI quindi non sta dentro Telegram: sta nel tuo programma, che fa da ponte.

Un bot così è un chatbot: risponde ma non agisce. Se vuoi che esegua compiti da solo, con strumenti e più passaggi, entri nel territorio degli agenti AI. Conviene partire dal chatbot e aggiungere strumenti dopo.

Che cosa serve per iniziare?

  • Un account Telegram per creare il bot.
  • Node.js 20 o successivo sul computer o sul server dove farai girare il bot.
  • Una chiave API del modello (qui Claude, dalla console di Anthropic). L'API è a pagamento ed è separata dall'abbonamento a Claude.

Come si crea un bot con BotFather?

  1. Su Telegram cerca @BotFather, il bot ufficiale che crea gli altri bot.
  2. Scrivi /newbot e scegli un nome e uno username (deve finire con bot).
  3. BotFather ti risponde con il token, una stringa del tipo 123456:ABC.... Chi ha il token controlla il bot: non metterlo mai nel codice che pubblichi su GitHub.
  4. Se il token finisce in mani sbagliate, scrivi /token a BotFather per generarne uno nuovo.

Qual è il codice di un bot Telegram con Claude?

Prima di copiare, tre cose da sapere:

  • Usa una cartella nuova e vuota. Così npm init -y e npm install non toccano nessun altro progetto.
  • Il codice non modifica i file del tuo computer e non esegue comandi: legge i messaggi del bot e chiama l'API di Claude. Crea solo la cartella node_modules con l'SDK.
  • Si spende solo quando il bot risponde. Il bot parte in sicurezza: finché non scrivi il tuo ID in ALLOWED_CHAT_IDS non chiama mai Claude. Imposta anche un tetto di spesa nella console dell'API.

Il programma qui sotto usa solo l'SDK ufficiale di Anthropic e le funzioni di base di Node.js, senza librerie per Telegram. Crea una cartella, esegui npm init -y e npm install @anthropic-ai/sdk, poi salva il codice in bot.mjs.

// bot.mjs: bot Telegram con Claude (Node.js 20 o successivo)
import Anthropic from "@anthropic-ai/sdk";

const TOKEN = process.env.TELEGRAM_BOT_TOKEN;
const API_BASE = process.env.TELEGRAM_API_BASE || "https://api.telegram.org";
const MODEL = process.env.CLAUDE_MODEL || "claude-opus-5-5";
// Chat autorizzate (ID separati da virgola). Se la lista è vuota il bot non chiama mai Claude:
// risponde solo con l'ID della chat, così sai cosa scrivere qui.
const ALLOWED = new Set((process.env.ALLOWED_CHAT_IDS || "").split(",").filter(Boolean).map(Number));
const MAX_MESSAGES = 20; // cronologia: ultimi 20 messaggi (10 scambi)
const MIN_SECONDS = 2;   // anti-spam: un messaggio ogni 2 secondi per chat
const SYSTEM = "Sei un assistente gentile e preciso. Rispondi in italiano, in modo chiaro e breve. Se non sai una cosa, dillo.";

// Chiamata all'API dei bot di Telegram
export async function telegram(method, body) {
  const res = await fetch(`${API_BASE}/bot${TOKEN}/${method}`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(body),
  });
  const data = await res.json();
  if (!data.ok) throw new Error(`Telegram ${method}: ${data.description}`);
  return data.result;
}

export function createBot({ tg, claude, now = () => Date.now(), allowed = ALLOWED }) {
  const history = new Map();  // chatId -> messaggi della conversazione
  const lastSeen = new Map(); // chatId -> ultimo messaggio gestito

  // Telegram accetta fino a 4096 caratteri per messaggio: spezziamo le risposte lunghe
  async function reply(chatId, text) {
    for (let i = 0; i < text.length; i += 4000) {
      await tg("sendMessage", { chat_id: chatId, text: text.slice(i, i + 4000) });
    }
  }

  async function onMessage(msg) {
    const chatId = msg.chat.id;
    if (!msg.text) return;                              // ignora foto, vocali, ecc.
    if (!allowed.size) {                                // modalità di configurazione: nessun costo
      return reply(chatId, `Il tuo ID chat è ${chatId}. Scrivilo in ALLOWED_CHAT_IDS e riavvia il bot.`);
    }
    if (!allowed.has(chatId)) return;                   // chat non autorizzata: silenzio

    if (msg.text === "/start") return reply(chatId, "Ciao! Scrivimi una domanda. Con /reset azzeri la conversazione.");
    if (msg.text === "/reset") { history.delete(chatId); return reply(chatId, "Conversazione azzerata."); }

    const t = now();
    if (t - (lastSeen.get(chatId) ?? 0) < MIN_SECONDS * 1000) return; // troppo veloce
    lastSeen.set(chatId, t);

    const messages = history.get(chatId) ?? [];
    messages.push({ role: "user", content: msg.text });
    await tg("sendChatAction", { chat_id: chatId, action: "typing" });

    try {
      const res = await claude.messages.create({
        model: MODEL,
        max_tokens: 4096,
        system: SYSTEM,
        output_config: { effort: "low" }, // risposte veloci e meno costose
        messages,
      });
      if (res.stop_reason === "refusal") throw Object.assign(new Error("rifiuto"), { refusal: true });
      const text = res.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
      if (!text) throw new Error("risposta vuota");

      messages.push({ role: "assistant", content: text });
      while (messages.length > MAX_MESSAGES) messages.splice(0, 2); // toglie lo scambio più vecchio
      history.set(chatId, messages);
      await reply(chatId, text);
    } catch (err) {
      messages.pop(); // rimuove la domanda: la cronologia resta coerente
      console.error("Errore Claude:", err.status ?? "", err.message);
      const rateLimited = err instanceof Anthropic.RateLimitError;
      await reply(chatId, err.refusal ? "Non posso aiutarti su questa richiesta."
        : rateLimited ? "Ci sono troppe richieste, riprova tra poco."
        : "Ho avuto un problema tecnico, riprova tra poco.");
    }
  }

  return { onMessage, history };
}

async function run() {
  for (const name of ["TELEGRAM_BOT_TOKEN", "ANTHROPIC_API_KEY"]) {
    if (!process.env[name]) { console.error(`Manca la variabile ${name}.`); process.exit(1); }
  }
  if (!ALLOWED.size) console.log("ALLOWED_CHAT_IDS è vuota: scrivi al bot per vedere l'ID della tua chat.");
  const bot = createBot({ tg: telegram, claude: new Anthropic() }); // legge ANTHROPIC_API_KEY
  let offset = 0;
  for (;;) {
    try {
      const updates = await telegram("getUpdates", { offset, timeout: 30, allowed_updates: ["message"] });
      for (const u of updates) {
        offset = u.update_id + 1;
        if (u.message) await bot.onMessage(u.message).catch((e) => console.error(e.message));
      }
    } catch (e) {
      console.error(e.message);
      await new Promise((r) => setTimeout(r, 5000)); // pausa prima di riprovare
    }
  }
}

if (import.meta.url === `file://${process.argv[1]}`) run();

L'avvio si fa in due passaggi, così nessuno a parte te può usare il bot. Prima imposta token e chiave, senza la lista delle chat, e avvia il bot:

export TELEGRAM_BOT_TOKEN="il-token-di-botfather"
export ANTHROPIC_API_KEY="la-tua-chiave"
node bot.mjs

Scrivi un messaggio al bot: ti risponde con l'ID della tua chat (senza consumare nulla). Fermalo con Ctrl+C, poi riavvialo con il tuo ID:

export ALLOWED_CHAT_IDS="123456789"
node bot.mjs

Se manca il token o la chiave, il bot non parte e te lo dice.

Ho provato la logica del bot con una suite di undici test automatici che simulano Telegram e il modello: risposte, memoria, limite di velocità, messaggi lunghi, errori, rifiuti e blocco delle chat non autorizzate. Il collegamento con l'API reale di Claude dipende dalla tua chiave, quindi la prima prova vera la fai tu scrivendo al bot.

Che cosa fa il codice, passo per passo?

  • Long polling: il bot chiede a Telegram i nuovi messaggi con getUpdates e resta in attesa fino a 30 secondi. Non serve un indirizzo pubblico né un certificato HTTPS.
  • Chat autorizzate: il bot risponde con Claude solo alle chat nella lista ALLOWED_CHAT_IDS e ignora tutte le altre. Se la lista è vuota non chiama mai il modello e mostra solo l'ID della chat. È la difesa più semplice contro chi trova il tuo bot e ti consuma credito.
  • Memoria: per ogni chat tiene gli ultimi 20 messaggi e li rimanda al modello a ogni richiesta, perché l'API non ricorda nulla da sola. /reset azzera la conversazione.
  • Anti-spam: un messaggio ogni due secondi per chat, per evitare raffiche che costano.
  • Risposte lunghe: Telegram accetta messaggi fino a 4096 caratteri, quindi il bot spezza i testi in blocchi da 4000.
  • Errori: se il modello è sovraccarico o rifiuta una richiesta, l'utente riceve una frase chiara e la cronologia resta coerente.
  • Effort basso: nel codice trovi output_config: { effort: "low" }. Sui modelli come Opus 5.5 il ragionamento non si può spegnere del tutto, e il livello predefinito è medio: per una chat conviene abbassarlo, così le risposte arrivano prima e costano meno.

Quanto costa far rispondere un bot con l'AI?

Si paga a token, in input e in output. I prezzi ufficiali per milione di token sono questi:

ModelloInputOutputCosto indicativo di una risposta*
Claude Opus 5.5$4$20circa $0,008
Claude Sonnet 5.5$2$10circa $0,004
Claude Haiku 4.5$1$5circa $0,002

*Stima mia, non un prezzo ufficiale: 500 token in input e 300 in output. Con la memoria attiva l'input cresce a ogni scambio, e il ragionamento conta come output, quindi il costo reale può essere più alto. Per il bot di tutti i giorni Sonnet 5.5 è spesso un buon compromesso; per cambiare modello basta impostare CLAUDE_MODEL. Per capire le differenze tra i modelli leggi Claude Opus 5.5 e Fable 5.1: cosa cambia. Prima di fidarti delle cifre controlla sempre la pagina dei prezzi di Anthropic.

Come si usa il bot in un gruppo?

Nei gruppi i bot hanno di default la modalità privacy attiva: ricevono solo i comandi rivolti a loro e le risposte ai loro messaggi. Per fargli leggere tutti i messaggi puoi disattivarla con /setprivacy in BotFather (poi il bot va riaggiunto al gruppo) oppure nominarlo amministratore, perché gli amministratori ricevono tutto. Fallo solo se serve davvero: un bot che legge e manda al modello ogni messaggio del gruppo costa molto di più. Il codice di questa guida risponde a qualsiasi messaggio di testo nelle chat autorizzate, quindi per un gruppo aggiungi un controllo, per esempio rispondere solo ai comandi o alle risposte dirette al bot, prima di chiamare il modello.

E se non vuoi copiare il codice?

Puoi farlo scrivere a Claude Code in una cartella nuova, e vedere i file prima di avviare qualcosa. Apri una cartella vuota, avvia Claude Code e incolla una richiesta come questa:

Crea in questa cartella un bot Telegram in Node.js che risponde con Claude (SDK @anthropic-ai/sdk).
Usa il long polling, token e chiave API da variabili d'ambiente, una lista di chat autorizzate
(se è vuota il bot deve solo mostrare l'ID della chat e non chiamare mai il modello),
memoria degli ultimi 20 messaggi, un messaggio ogni 2 secondi per chat e risposte spezzate a 4000 caratteri.
Non toccare file fuori da questa cartella e non avviare nulla senza dirmelo.

Così hai lo stesso risultato e un assistente che ti spiega ogni riga. Controlla comunque il codice che ti propone prima di avviarlo: vale per questo come per qualsiasi altro.

Dove far girare il bot?

Sul tuo computer funziona finché è acceso. Per tenerlo sempre attivo serve un server: un piccolo VPS va benissimo, e il bot consuma pochissimo. Su un server Linux puoi usare PM2 (pm2 start bot.mjs) o un servizio systemd, così il bot riparte da solo dopo un riavvio. Con il long polling non devi aprire porte. I webhook sono l'alternativa: Telegram ti manda i messaggi a un indirizzo HTTPS tuo, e le due modalità non si usano insieme.

Quali precauzioni servono su sicurezza e privacy?

  • Chiavi fuori dal codice: token e chiave API stanno in variabili d'ambiente, mai su GitHub.
  • Limite di spesa: imposta un tetto mensile nella console dell'API, così un errore o un abuso non diventano una bolletta.
  • Dati degli utenti: i messaggi passano da Telegram e dall'API del modello. Se il bot è pubblico, dillo nella descrizione e non chiedere dati sensibili. Se tratti dati di persone nell'Unione Europea, valuta gli obblighi del GDPR.
  • Memoria in RAM: in questo esempio la cronologia sparisce al riavvio. Per conservarla serve un database.

Com'è la mia esperienza con i bot Telegram?

Per me è un'esperienza decisamente positiva. Uso Telegram per gestire da remoto i miei agenti, quelli collegati a Claude Code, Hermes Agent e altri, e posso farli lavorare in autonomia senza restare incollato al computer. Scrivo da telefono quello che serve, l'agente lavora e mi risponde nella stessa chat. È il motivo per cui consiglio di partire da un bot semplice come quello di questa guida: poi lo si può far crescere fino a diventare un vero collaboratore.

Come si può migliorare il bot?

Il passo successivo più utile è cambiare il testo di SYSTEM per dargli un ruolo preciso, per esempio assistente di un negozio o ripetitore di studio. Poi puoi collegarlo a strumenti esterni, ad esempio un calendario o un database, tramite MCP: a quel punto il chatbot diventa un agente. Se vuoi scrivere il codice con l'aiuto dell'AI, Claude Code è fatto per questo.

Fonti ufficiali

Risorsa gratuita

Vuoi iniziare con l'AI?

Scarica la guida AI da Zero — PDF gratuito, pratico, senza tecnicismi.

Domande frequenti
Come si crea un bot Telegram con l'AI?
Crei il bot con @BotFather su Telegram e ottieni un token, prendi una chiave API di un modello come Claude e scrivi un programma che legge i messaggi da Telegram con getUpdates, li manda al modello e invia la risposta con sendMessage. In questa guida c'è un esempio completo in Node.js.
Serve saper programmare per fare un bot Telegram con l'AI?
Un po' di base aiuta, ma il codice dell'esempio è già pronto: copi il file, imposti token e chiave e lo avvii con Node.js. Per modificarlo, per esempio cambiando il ruolo del bot, basta cambiare un testo.
Quanto costa un bot Telegram con l'AI?
Telegram non fa pagare i bot. Paghi solo l'API del modello, a token: con messaggi brevi una risposta costa indicativamente tra 0,2 e 0,8 centesimi di dollaro a seconda del modello, ma la cifra sale con la cronologia e con il ragionamento. Imposta un tetto di spesa nella console.
Il bot può funzionare nei gruppi?
Sì. Di default in un gruppo il bot vede solo i comandi rivolti a lui e le risposte ai suoi messaggi, per la modalità privacy. Puoi disattivarla con /setprivacy in BotFather (poi va riaggiunto al gruppo) o farlo amministratore, ma il costo cresce perché ogni messaggio del gruppo può arrivare al modello.
Meglio long polling o webhook?
Per iniziare il long polling: non servono dominio, HTTPS né porte aperte. I webhook sono utili su server pubblici con molto traffico. Le due modalità non si usano insieme sullo stesso bot.
Come evito che altri usino il mio bot e mi consumino il credito?
Il bot dell'esempio risponde solo alle chat nella lista ALLOWED_CHAT_IDS: se la lista è vuota non chiama mai il modello e ti mostra solo l'ID della tua chat. In più c'è un limite di velocità per chat, e ti conviene impostare un tetto di spesa mensile nella console dell'API.
Il codice può danneggiare il mio computer?
No: il bot non legge né scrive file e non esegue comandi, legge i messaggi di Telegram e chiama l'API di Claude. L'unica cosa che crea è la cartella node_modules con l'SDK. Per stare tranquillo usa una cartella nuova e vuota.