Corso
Chainlit è un potente framework open-source in Python che ti permette di creare interfacce interattive per le tue applicazioni basate su LLM con pochissimo codice e senza complicazioni di front-end.
In questo tutorial ti mostrerò:
- Come installare e configurare Chainlit.
- I concetti chiave, come azioni, ciclo di vita della chat e configurazioni.
- La creazione di due app di esempio:
- Un chatbot statico “Sorprendimi” con pulsanti
- Un bot “Sorprendimi” alimentato da Ollama
Che cos'è Chainlit?
Chainlit ti aiuta a creare frontend per chatbot di AI, strumenti e workflow basati su LLM. Astrae la complessità del front-end e ti consente di concentrarti sulla logica in Python, offrendo al contempo il supporto per aggiungere pulsanti, slider, caricamento di file o perfino collegarti a strumenti usando il model context protocol (MCP).
Chainlit è ideale per:
- Prototipare app basate su LLM
- Creare strumenti interni
- Costruire demo didattiche
- Collegare i tuoi modelli a strumenti o API esterni
Componenti di Chainlit
Ogni app Chainlit si basa su alcune funzionalità essenziali:
- Hook del ciclo di vita della chat: ti permettono di controllare cosa accade nelle diverse fasi di una chat. Per esempio:
@cl.on_chat_startviene eseguito all'inizio della chat.@cl.on_messageviene eseguito quando l'utente invia un messaggio.@cl.on_chat_endviene eseguito quando la chat termina.- Azioni UI: Chainlit ti consente di aggiungere pulsanti con
cl.Actione gestirli con@cl.action_callback. Sono perfetti per creare UI pulite e interattive senza richiedere input testuale dell'utente. - Streaming dei messaggi: con LLM che supportano lo streaming di token, puoi trasmettere le risposte in tempo reale usando
stream=True, rendendo l'app più dinamica e reattiva. - Configurazione con
config.toml: questo file ti permette di abilitare funzioni come la persistenza della chat, il caricamento dei file, la personalizzazione del tema e migliorie di usabilità—il tutto senza modificare il codice Python.
Spiegherò ogni concetto con un esempio pratico di codice, così potrai vedere esattamente come funziona e come integrarlo nelle tue app Chainlit. Partiamo dal primo passo.
Prerequisiti
Assicurati di avere installato Python 3.8+, poi installa Chainlit usando pip. Useremo anche Langchain per la demo con Ollama, quindi assicurati di installarla. Esegui il seguente comando nel terminale:
pip install chainlit langchain langchain-community
Capire le basi di Chainlit attraverso esempi
In questa sezione tratteremo i mattoni fondamentali di Chainlit, che costituiranno il cuore di qualsiasi progetto.
Hook del ciclo di vita della chat
Ogni volta che un utente si collega alla tua app Chainlit, viene creata una sessione di chat. Puoi intervenire nelle diverse fasi di quella sessione usando i decorator forniti da Chainlit. Questi includono:
Sviluppare con @cl.on_chat_start
Questo hook viene eseguito quando inizia una nuova sessione di chat. Puoi usarlo per salutare l'utente, mostrare un messaggio di benvenuto o inizializzare lo stato della sessione.
import chainlit as cl
@cl.on_chat_start
def on_chat_start():
print("A new chat session has started!")

Sviluppare con @cl.on_message
Questo hook del messaggio viene eseguito quando l'utente invia un nuovo messaggio. Lo usiamo per elaborare l'input dell'utente, chiamare un LLM o restituire una risposta.
import chainlit as cl
@cl.on_message
async def on_message(msg: cl.Message):
print("The user sent:", msg.content)
await cl.Message(content=f"You said: {msg.content}").send()

Sviluppare con @cl.on_stop
L'hook on_stop viene eseguito quando l'utente clicca il pulsante stop (⏹) durante un'attività in corso. Serve per annullare operazioni di lunga durata o ripulire sessioni interrotte.
import chainlit as cl
import asyncio
@cl.on_chat_start
async def start():
await cl.Message("Type anything and I'll pretend to work on it.").send()
@cl.on_message
async def on_message(msg: cl.Message):
await cl.Message("Working on it... you can press Stop").send()
try:
# Simulate a long task
await asyncio.sleep(10)
await cl.Message("Task complete!").send()
except asyncio.CancelledError:
print("Task was interrupted!")
# This is optional, just logs in the server
raise
@cl.on_stop
async def on_stop():
print("The user clicked Stop!")
Quando l'utente invia un messaggio, Chainlit simula un'attività con asyncio.sleep(10). Se l'utente clicca il pulsante stop (⏹), l'attività viene annullata e @cl.on_stop viene attivato per registrare l'interruzione.

Sviluppare con @cl.on_chat_end
Questo hook si attiva quando la sessione termina—se l'utente aggiorna, chiude la scheda o avvia una nuova sessione. Di solito si usa per registrare le disconnessioni o salvare lo stato.
import chainlit as cl
@cl.on_chat_start
async def on_chat_start():
await cl.Message("Welcome! Feel free to leave anytime").send()
@cl.on_chat_end
async def on_chat_end():
print("The user disconnected!")
Una volta aperto il localhost, puoi interagirci. Quando chiudi la scheda o la finestra del localhost, il terminale mostrerà quanto segue:

Azioni UI (pulsanti)
Chainlit ti consente di aggiungere pulsanti interattivi direttamente nell'interfaccia del tuo chatbot. Ogni pulsante è definito come un'azione e collegato a una funzione di callback in Python. Invii i pulsanti come parte di un Messaggio usando l'argomento actions:
import chainlit as cl
@cl.on_chat_start
async def start():
actions = [
cl.Action(
name="hello",
label="👋 Say Hello",
icon="smile",
payload={"value": "hi"}
)
]
await cl.Message("Click a button!", actions=actions).send()
Ecco come puoi gestire il click su un pulsante:
@cl.action_callback("hello")
async def on_hello(action: cl.Action):
await cl.Message("Hello there! 👋").send()
Il decorator @cl.action_callback("hello") dice a Chainlit di ascoltare i click su un pulsante con nome "hello". Al click, invia un messaggio amichevole all'utente nell'interfaccia della chat.

Suggerimento: puoi personalizzare il payload con qualsiasi dato tu voglia inviare al server.
Streaming dei messaggi
Chainlit supporta lo streaming in tempo reale delle risposte degli LLM. Ciò significa che puoi inviare contenuti all'utente in modo incrementale man mano che vengono generati.
@cl.on_message
async def on_message(message: cl.Message):
await cl.Message(content="Thinking...").send()
async for chunk in llm.astream(message.content):
await cl.Message(content=chunk, author="LLM", stream=True).send()
Vediamolo nel dettaglio:
- Per prima cosa, mostra subito un messaggio "Thinking..." così l'utente sa che l'app sta lavorando.
- Poi invia il messaggio dell'utente a un LLM compatibile con lo streaming.
- Man mano che il modello genera l'output, trasmette ogni pezzo (chunk) all'interfaccia in tempo reale.
- Il parametro
stream=Truefa sì che ogni chunk appaia progressivamente invece di attendere l'intera risposta.
Nota: funziona al meglio con modelli che supportano lo streaming.
Configurazione di Chainlit (config.toml)
Per sbloccare funzionalità potenti come persistenza della chat, caricamento dei file, theming e altro, puoi personalizzare la tua app Chainlit usando il file config.toml. Questo file si trova nella root della directory del progetto (nella cartella .chainlit) e ti permette di regolare il comportamento a runtime senza modificare il codice.
Persistenza
Questo parametro permette a Chainlit di mantenere la cronologia della chat e lo stato della sessione. Attiva l'hook @cl.on_chat_resume, risultando ideale per app in cui gli utenti potrebbero disconnettersi e tornare più tardi.
[persistence]
enabled = true
Caricamento dei file
Questa impostazione consente agli utenti di caricare file nell'interfaccia della chat. Puoi limitare i tipi di file consentiti e le dimensioni per garantire sicurezza e prestazioni.
[features.spontaneous_file_upload]
enabled = true
accept = ["*/*"]
max_files = 5
max_size_mb = 500
Ecco alcuni tipi di file accettati da Chainlit.
# 1. Per tipi di file specifici:
# accept = ["image/jpeg", "image/png", "application/pdf"]
# 2. Per tutti i file di un certo tipo:
# accept = ["image/*", "audio/*", "video/*"]
# 3. Per estensioni specifiche:
# accept = { "application/octet-stream" = [".xyz", ".pdb"] }
Questo ti consente di adattare gli upload per sicurezza, prestazioni o casi d'uso specifici del dominio.
Personalizzazione UI
Questa personalizzazione cambia il nome dell'assistente nel parametro UI e abilita la Chain of Thought (CoT) nella modalità di rendering, utile per ragionamenti step-by-step o debugging.
[UI]
name = "Assistant"
cot = "full"
Migliorie di usabilità
Queste migliorano l'esperienza utente facendo scorrere automaticamente in vista i nuovi messaggi e consentendo la modifica dei messaggi.
[features]
user_message_autoscroll = true
edit_message = true
Le migliorie di usabilità sopra permettono all'utente di abilitare l'autoscroll e la modifica dei messaggi nell'interfaccia.
Progetto: bot “Sorprendimi” (senza LLM)
Ora che conosciamo i componenti di base di Chainlit, realizziamo una semplice app basata su UI che usa pulsanti per mostrare curiosità predefinite o messaggi motivazionali per sviluppatori.
import chainlit as cl
import random
FUN_FACTS = [
"💡 Did you know? Chainlit supports file uploads and custom themes!",
"💡 You can add buttons, sliders, and images directly in your chatbot UI!",
"💡 Chainlit supports real-time tool execution with LangChain and LLMs!",
"💡 You can customize the look of your chatbot with just a CSS file!",
"💡 Chainlit lets you connect to tools using Model Context Protocol (MCP)!"
]
SUPRISES = [
"🎉 Surprise! You're doing great!",
"🚀 Keep it up, you're making awesome progress!",
"🌟 Fun fact: Someone out there just smiled because of you. Why not make it two?",
"👏 Bravo! You just unlocked +10 imaginary developer XP!",
"💪 Remember: Even bugs fear your debugging skills!"
]
@cl.on_chat_start
async def start():
actions = [
cl.Action(
name="surprise_button",
label="🎁 Surprise Me",
icon="gift",
payload={"value": "surprise"}
),
cl.Action(
name="fact_button",
label="💡 Did You Know?",
icon="lightbulb",
payload={"value": "fact"}
)
]
await cl.Message(content="Choose an action:", actions=actions).send()
@cl.action_callback("surprise_button")
async def on_surprise(action: cl.Action):
suprise = random.choice(SUPRISES)
await cl.Message(content=suprise).send()
@cl.action_callback("fact_button")
async def on_fact(action: cl.Action):
fact = random.choice(FUN_FACTS)
await cl.Message(content=fact).send()
Il codice qui sopra definisce due liste: “FUN_FACTS” con consigli interessanti su Chainlit e “SUPRISES” con messaggi motivazionali.
- Quando inizia una nuova chat, vengono mostrati due pulsanti: "Surprise Me" e "Did You Know?"—usando
cl.Action. ' - Cliccando "Surprise Me" si attiva @cl.action_callback("surprise_button")
, che invia un messaggio sorpresa casuale. - Cliccando "Did You Know?" si attiva @cl.action_callback("fact_button")`, che invia una curiosità casuale.
Questo crea un semplice chatbot interattivo basato su pulsanti che non richiede LLM, perfetto per imparare come funzionano azioni e callback in Chainlit.
Per eseguire questa applicazione, lancia semplicemente il seguente comando nel terminale:
chainlit run main.py
Vedrai pulsanti interattivi nella UI che attivano curiosità o messaggi divertenti!

Progetto: bot “Sorprendimi” alimentato da Ollama
Ora automatizziamo il processo e generiamo i messaggi di sorpresa e curiosità usando un LLM locale tramite Ollama.
import chainlit as cl
from langchain_community.llms import Ollama
import random
llm = Ollama(model="mistral", temperature=0.7) # Use any lightweight local model
# Reusable action buttons
def get_action_buttons():
return [
cl.Action(
name="surprise_button",
label="🎁 Surprise Me",
icon="gift",
payload={"value": "surprise"}
),
cl.Action(
name="fact_button",
label="💡 Did You Know?",
icon="lightbulb",
payload={"value": "fact"}
)
]
@cl.on_chat_start
async def start():
await cl.Message(content="Choose an action below to see something fun:").send()
await cl.Message(content="", actions=get_action_buttons()).send()
@cl.action_callback("surprise_button")
async def on_surprise(action: cl.Action):
prompt = "Give a short, uplifting surprise message to a developer. Make it fun."
try:
surprise = llm.invoke(prompt).strip()
except Exception:
surprise = "🎉 Surprise! You're doing great!"
await cl.Message(content=surprise).send()
await cl.Message(content="", actions=get_action_buttons()).send()
@cl.action_callback("fact_button")
async def on_fact(action: cl.Action):
prompt = "Give a fun and helpful fact about LLMs or Chainlit."
try:
fact = llm.invoke(prompt).strip()
except Exception:
fact = "💡 Did you know? You can add sliders and buttons to Chainlit with just a few lines of code!"
await cl.Message(content=fact).send()
await cl.Message(content="", actions=get_action_buttons()).send()
Questa app Chainlit integra un LLM locale (tramite Ollama con il modello Mistral) per generare dinamicamente risposte basate sulle interazioni dell'utente.
- Definisce due pulsanti
cl.Action—"Surprise Me" e "Did You Know?" usando una funzione riutilizzabileget_action_buttons(). - All'inizializzazione della chat (
@cl.on_chat_start) invia un messaggio con questi pulsanti interattivi. - Quando l'utente clicca il pulsante "Surprise Me", l'handler
@cl.action_callbackinvia al LLM un prompt per un breve messaggio motivante per sviluppatori. La risposta viene ripulita con la funzione.strip()e rimandata in chat. - Allo stesso modo, cliccando "Did You Know?" il LLM viene invocato con un prompt che richiede una curiosità informativa su Chainlit o sugli LLM.
- Se il LLM fallisce, vengono restituiti messaggi statici di fallback.
- Dopo ogni interazione, i pulsanti vengono reinviati per mantenere il loop conversazionale.
Questo dimostra come combinare la UI di Chainlit con la generazione di contenuti basati su LLM, offrendo una base modulare ed estensibile per app di chat AI locali.
Esegui i seguenti comandi nel terminale:
ollama run mistral
chainlit run main.py
Ora hai un assistente AI locale e attivo che genera messaggi automatici.

Conclusione
Chainlit ha un grande potenziale per prototipare strumenti basati su chat, costruire assistenti e integrare output in tempo reale da LLM—il tutto senza toccare JavaScript. Per casi d'uso avanzati, dai un'occhiata al Chainlit Cookbook.
Per ampliare l'apprendimento con nuovi strumenti di AI, dai un'occhiata ai seguenti blog:
Sono una Google Developers Expert in ML (Gen AI), una Kaggle 3x Expert e una Women Techmakers Ambassador con oltre 3 anni di esperienza nel tech. Ho co-fondato una startup health-tech nel 2020 e sto conseguendo un master in informatica al Georgia Tech, con specializzazione in machine learning.


