Luca Mele
Luca Mele

AI & Engineering

Costruire un chatbot IA per il mio portfolio — con Claude, in una sessione

Costruire un chatbot IA per il mio portfolio — con Claude, in una sessione
Torna a tutti gli articoli
·10 min di lettura
Ascolta il podcast generato dall'IA
Tutti i podcast →

La settimana scorsa ho aggiunto un chatbot IA a questo sito. Non un widget di supporto con risposte preconfezionate, ma un vero agente conversazionale che conosce il mio CV, i miei articoli del blog, le mie opinioni tech e i miei hobby — e può discuterne in qualsiasi lingua. Dall'idea alla produzione ci è voluta circa un'ora. Ecco esattamente come l'ho costruito, quali decisioni ho preso e cosa farei diversamente.

Il chatbot che vedi nell'angolo in basso a destra di questa pagina è alimentato da Claude Haiku, il modello più veloce ed economico di Anthropic. Funziona attraverso una singola API route Next.js, non ha database, nessuna dipendenza SDK, nessun vector store e nessun LangChain. Sono circa 140 righe di codice server e 230 righe di codice client. Tutto qui.

L'architettura: deliberatamente semplice

L'intero backend è un singolo file: una API route su /api/chat. Riceve la cronologia della conversazione dal client, antepone un system prompt con tutto ciò che il chatbot deve sapere, e lo inoltra all'API Messages di Claude tramite una chiamata fetch grezza. Nessun SDK, nessuna libreria wrapper, nessun livello di astrazione.

Perché nessun SDK? Perché l'API Messages di Anthropic è un singolo endpoint POST con un contratto JSON pulito. Aggiungere @anthropic-ai/sdk introdurrebbe dipendenze di cui non ho bisogno per quello che è essenzialmente una chiamata fetch con tre header. Questo è il Principio della Minima Potenza in pratica — usa la tecnologia più semplice che risolve il problema.

Il client è un componente React con useState per i messaggi e un form che posta alla API route. I messaggi sono salvati nello state del componente — nessun Redux, nessun context provider, nessuna libreria di gestione dello stato. Quando l'utente chiude la chat, la conversazione sparisce. Va bene per un chatbot di portfolio.

Il system prompt: il tuo chatbot è buono solo quanto il suo briefing

Qui è dove la maggior parte dei tutorial sui chatbot IA si fermano troppo presto. Ti mostrano come chiamare l'API e renderizzare la risposta. Ma il system prompt è il vero prodotto. È ciò che rende il tuo chatbot utile invece che generico.

Il mio system prompt è di circa 3.000 token. Contiene: la mia storia lavorativa completa (9 posizioni, cronologica), la mia formazione (MAS Software Engineering, CAS Frontend Engineering), le mie competenze tecniche, le mie teorie di management (finestra di Johari, 9 Box Grid, PAC), riassunti di tutti i 10 articoli del blog con i loro argomenti chiave, i miei hobby e regole di privacy rigorose.

Le regole di privacy sono critiche. Il system prompt dice esplicitamente: non rivelare mai il mio indirizzo di casa, numero di telefono, data di nascita o stato civile. Se richiesto, reindirizzare a email o LinkedIn. L'ho testato ampiamente — Claude rispetta questi limiti in modo affidabile. Ma dovresti testare le tue guardrails. I LLM possono essere creativi nel far trapelare informazioni se il prompt non è abbastanza esplicito.

Rate limiting: proteggere il portafoglio

Un chatbot IA senza rate limiting è una carta di credito attaccata a un endpoint pubblico. Ogni messaggio costa denaro — non molto con Haiku, ma si accumula se qualcuno decide di scriptare 10.000 richieste.

Ho implementato un semplice rate limiter in memoria: 800 messaggi per indirizzo IP per finestra di 12 ore. È una Map che memorizza contatori e timestamp di reset. Quando arriva una richiesta, controlla la map, incrementa il contatore e restituisce 429 se il limite è superato.

Il rate limiting in memoria è perfetto? No. Si resetta quando la funzione serverless parte a freddo, e non condivide lo stato tra istanze. Per un sito portfolio, è sufficiente. Se avessi bisogno di rate limiting a livello di produzione, userei Vercel KV o Upstash Redis. Ma questo aggiungerebbe una dipendenza e una connessione di servizio per un problema che non ho ancora. YAGNI.

Cronologia delle conversazioni: rendere la chat davvero conversazionale

La prima versione del chatbot era stateless — ogni messaggio veniva inviato a Claude in isolamento, senza memoria dei messaggi precedenti. Funzionava, ma sembrava rotto. «Cosa intendevi con quello?» otteneva una risposta confusa perché «quello» non aveva un referente.

La soluzione era semplice: inviare l'intera cronologia della conversazione con ogni richiesta. Il client mantiene un array di messaggi, e ad ogni invio, manda l'array completo alla API route, che lo inoltra a Claude. La finestra di contesto di Claude fa il resto.

Ho limitato la cronologia a 50 messaggi per richiesta per prevenire abusi. In pratica, nessuno ha una conversazione di 50 messaggi con un chatbot di portfolio, ma il limite impedisce a qualcuno di inviare un payload con migliaia di messaggi fabbricati.

Rendering markdown: blocchi di codice, syntax highlighting, pulsante copia

Quando le persone fanno domande tecniche al chatbot, Claude risponde con blocchi di codice. Il rendering in testo semplice li rendeva illeggibili — solo un muro di testo monospace senza struttura visiva.

Ho costruito un renderer markdown leggero direttamente nel componente — nessun react-markdown, nessun remark, nessun rehype. Gestisce blocchi di codice fenced con rilevamento del linguaggio, codice inline e testo grassetto. Per il syntax highlighting, ho scritto un tokenizer a singolo passaggio che identifica keyword, stringhe, commenti e numeri per JavaScript/TypeScript, CSS e HTML.

La lezione chiave qui: non usare sostituzioni regex concatenate per il syntax highlighting. Il mio primo tentativo usava chiamate .replace() sequenziali, e le regex successive matchavano i tag <span class="..."> generati dalle precedenti. La soluzione era un approccio a singolo passaggio dove ogni match regex viene processato esattamente una volta.

Ho anche aggiunto un pulsante copia a ogni blocco di codice. Usa la Clipboard API (navigator.clipboard.writeText) con uno stato di conferma «Copiato». Piccolo dettaglio, grande miglioramento di usabilità.

L'interfaccia: farla sembrare una persona

La prima versione usava una generica bolla di chat viola con un'icona di fumetto. Funzionava, ma sembrava come ogni altro widget di supporto SaaS. Volevo che sembrasse di parlare davvero con me.

La versione attuale usa la mia foto come bolla di chat con un overlay viola IA e un badge «AI» — rendendo immediatamente chiaro che questa è una versione IA di me, non un bot nascosto che finge di essere umano. L'header della chat mostra il mio nome con «AI Agent» e un indicatore verde online. I messaggi dell'assistente mostrano un piccolo avatar accanto. La schermata di benvenuto ha una foto più grande con «Hey, I'm Luca!»

Ho anche aggiunto una modalità schermo intero. Il piccolo widget 360×480 funziona per domande veloci, ma per conversazioni ricche di codice, serve più spazio. Un pulsante di espansione nell'header passa a un layout a schermo intero con contenuto centrato limitato a max-w-3xl.

Quanto è costato

Claude Haiku è notevolmente economico. Con il mio system prompt (~3.000 token) e lunghezze di conversazione tipiche, ogni messaggio costa circa $0.001-0.003. Anche con un uso generoso, il costo mensile è di pochi dollari. Il rate limiter è per la prevenzione degli abusi, non per la gestione dei costi.

Il costo di sviluppo è stato essenzialmente zero in termini di dipendenze. Nessun nuovo pacchetto npm è stato aggiunto. L'intera funzionalità è costruita con le API route di Next.js, la Fetch API, lo state di React e Tailwind CSS — strumenti già nel progetto.

Cosa farei diversamente

Risposte in streaming. Attualmente, l'utente vede i puntini «...» fino a quando la risposta completa arriva. Con l'API streaming di Claude, potrei renderizzare i token man mano che arrivano, facendo sembrare il chatbot molto più reattivo.

Conversazioni persistenti. Al momento, chiudere la chat perde la conversazione. LocalStorage risolverebbe questo banalmente. Non l'ho aggiunto perché non sono sicuro che le persone vogliano che le loro conversazioni col chatbot vengano salvate — ma sarebbe una UX migliore per i visitatori di ritorno.

Migliore gestione degli errori per i casi limite. L'implementazione attuale gestisce errori di rete e rate limiting, ma non gestisce elegantemente casi come il filtraggio dei contenuti di Claude o risposte molto lunghe che raggiungono il limite di token a metà frase.

Il punto chiave

Costruire un chatbot IA nel 2026 non è un progetto infrastrutturale complesso. Con una buona API di modello, una route lato server e competenze frontend di base, puoi passare dal nulla a un chatbot in produzione in un pomeriggio. La parte difficile non è la tecnologia — è creare un system prompt che renda il chatbot genuinamente utile invece che genericamente chiacchierone.

L'implementazione totale: ~140 righe di codice server, ~230 righe di codice client, zero nuove dipendenze, una variabile d'ambiente. Se hai un sito portfolio e vuoi che i visitatori possano fare domande sul tuo lavoro, questa è probabilmente la funzionalità a più alto impatto che puoi aggiungere.