Vai al contenuto principale

Creare chatbot sensibili al contesto: sfruttare il framework LangChain per ChatGPT

Scopri come creare chatbot sensibili al contesto usando ChatGPT e il framework LangChain.
Aggiornato 29 set 2026  · 15 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

Nel frenetico panorama digitale di oggi, con l’ascesa dei Large Language Model (LLM), le applicazioni conversazionali hanno guadagnato un’enorme popolarità. I chatbot hanno trasformato il modo in cui interagiamo con applicazioni, siti web e perfino con i canali di assistenza clienti nella vita di tutti i giorni.

La possibilità di creare il tuo chatbot è diventata un punto di svolta, permettendo a aziende e privati di realizzare interfacce conversazionali personalizzate, efficienti e coinvolgenti, su misura per le proprie esigenze.

Questo articolo punta a spiegare in modo semplice come costruire un chatbot in Python sfruttando la potenza degli LLM. Vedremo come creare un chatbot con ChatGPT e come ottimizzarlo ulteriormente usando il popolare framework LangChain.

Se sei alle prime armi con ChatGPT e LangChain, dai un’occhiata al nostro Introduzione ai Large Language Model con GPT e LangChain - code-along qui sotto: 

Questo articolo copre tutti gli aspetti fondamentali per sviluppare un chatbot ottimizzato che utilizza ChatGPT come modello di base. Useremo un Jupyter Notebook con le librerie openai e langchain installate. Puoi seguire passo passo in questo workbook DataLab.

Nelle sezioni seguenti, vedremo come usare l’API di OpenAI per effettuare chiamate di base a ChatGPT come blocchi costitutivi della nostra conversazione. Inoltre, implementeremo la consapevolezza del contesto per il nostro chatbot usando semplici strutture Python. Infine, ottimizzeremo sia l’implementazione del chatbot sia la cronologia della conversazione con LangChain ed esploreremo le sue funzionalità di memoria.

Chiamate API di base a ChatGPT

Useremo ChatGPT come modello alla base del nostro chatbot. Per questo, il nostro primo compito pratico sarà scrivere una chiamata API semplice ma completa a ChatGPT, così da stabilire una prima interazione.

La funzione Python seguente incapsula la chiamata API desiderata a ChatGPT usando solo la libreria openai.

import os
import openai

openai_api_key = os.environ["OPENAI_API_KEY"]

def chatgpt_call(prompt, model="gpt-3.5-turbo"):
   response = openai.ChatCompletion.create(
       model=model,
       messages=[{"role": "user", "content": prompt}]
   )
   return response.choices[0].message["content"]

Nota che in questo caso usiamo il modello gpt-3.5-turbo perché è il più capace tra i GPT-3.5 ed è ottimizzato per la chat, oltre a essere uno dei più economici. Puoi trovare maggiori informazioni sui diversi modelli disponibili nella documentazione di OpenAI.

Ti serve aiuto per ottenere le chiavi API di OpenAI? Allora fa per te il training Getting Started with the OpenAI API and ChatGPT.

Analizziamo l’implementazione passo dopo passo!

La funzione chatgpt_call() è un wrapper attorno alla chiamata originale di OpenAI ChatCompletion.create, che crea una richiesta di completamento chat.

Dato il prompt desiderato, la funzione restituisce il completamento corrispondente di ChatGPT. Per una chiamata andata a buon fine, è sufficiente fornire l’ID del modello da usare (model) e il prompt desiderato (prompt).

Il completamento restituito da ChatGPT contiene metadati insieme alla risposta vera e propria. Tuttavia, la risposta è sempre presente nel campo response.choices[0].message[“content”]. Maggiori dettagli sul contenuto completo del completamento sono disponibili nella documentazione di OpenAI.

Con questa implementazione, possiamo inviare un prompt a ChatGPT in una sola riga:

prompt = "My name is Andrea"
response = chatgpt_call(prompt)
print(response)

# Output: Nice to meet you, Andrea! How can I assist you today?

La chiamata come interazione isolata

Noti qualche insidia nell’implementazione sopra?

Per darti un indizio, facciamo un’interazione di follow-up:

prompt = "Do you remember my name?"
response = chatgpt_call(prompt)
print(response)

# Output: I'm sorry, as an AI language model, I don't have the ability to remember specific information about individual users.

Giusto, come possiamo osservare, ogni chiamata API è un’interazione isolata. Significa che il modello non ha memoria dei prompt precedenti né dei completamenti già forniti. Ogni volta che chiamiamo la funzione chatgpt_call(), iniziamo una conversazione completamente nuova.

Questo è chiaramente un problema quando cerchiamo di costruire un chatbot, perché è impossibile avere una conversazione se il modello non ricorda cosa abbiamo discusso finora. Per questo, il prossimo passo è rendere il modello consapevole delle interazioni precedenti.

Consapevolezza del contesto

La consapevolezza del contesto permette ai chatbot di comprendere e rispondere in modo appropriato sulla base di una conversazione in corso.

Costruendo un contesto, le interazioni future possono essere personalizzate in base a quelle passate, mantenendo la continuità del dialogo ed evitando ripetizioni. Inoltre, con chatbot sensibili al contesto, l’utente può porre domande di chiarimento in modo proattivo o fornire suggerimenti per correggere fraintendimenti.

Nel complesso, la consapevolezza del contesto migliora naturalezza, efficacia ed esperienza d’uso dei chatbot. D’ora in poi, chiameremo l’insieme delle interazioni precedenti cronologia della conversazione o memoria.

L’API originale di OpenAI per ChatGPT fornisce già un modo per inviare al modello la cronologia della conversazione insieme a ogni nuovo prompt. Inoltre, il framework LangChain offre anche un modo per gestire la memoria di ChatGPT in modo più efficace e con un occhio ai costi.

Capire messaggi di sistema, assistente e utente

La struttura della cronologia conversazionale di ChatGPT

A questo punto, possiamo usare il metodo chatgpt_call() direttamente, fornendo solo il prompt desiderato. Se guardiamo da vicino l’implementazione, il prompt in ingresso è formattato come parte della lista messages. Questa lista serve in realtà a tenere traccia della cronologia della conversazione, ed è per questo che deve essere formattata in un modo molto particolare.

Diamo un’occhiata più da vicino!

Finora abbiamo formattato la lista dei messaggi in chatgpt_call() così:

messages = [{"role": "user", "content": prompt}]

La lista messages memorizza la cronologia della conversazione come una raccolta di dizionari. Ogni dizionario nella lista rappresenta un messaggio della conversazione con due coppie chiave-valore.

  • La chiave role con valore user indica che il messaggio è stato inviato dall’utente.
  • La chiave content con valore prompt contiene il prompt effettivo dell’utente.

Questo è un esempio molto semplice che contiene una sola interazione. Anche se la chiave content conterrà sempre il prompt dell’utente o il completamento del chatbot, la chiave role è molto più versatile.

Ruoli di sistema, assistente e utente

La chiave role indica il proprietario del messaggio in content. Con ChatGPT, possiamo avere fino a tre ruoli:

  • User. Come già detto, il ruolo user corrisponde all’utente che interagisce con il chatbot.
  • Assistant. Il ruolo assistant corrisponde al chatbot.
  • System. Il ruolo system serve a fornire istruzioni, linee guida e contesto al chatbot. I messaggi di sistema aiutano a guidare le interazioni con l’utente, impostare il comportamento del chatbot, offrire informazioni contestuali e gestire interazioni specifiche nella conversazione. Possono essere visti come istruzioni di alto livello per il chatbot, trasparenti per l’utente.

Immagine autoprodotta. Interazione dei diversi ruoli nella catena conversazionale quando si costruisce un chatbot con chatGPT.

Immagine autoprodotta. Interazione dei diversi ruoli nella catena conversazionale quando si costruisce un chatbot con chatGPT.

Costruire una cronologia della conversazione

Possiamo procedere a costruire la nostra cronologia della conversazione usando i tre ruoli user, assistant e system nella lista messages.

Date le nostre interazioni di prova, una cronologia formattata correttamente che usa i tre ruoli sopra menzionati potrebbe essere la seguente:

messages =  [ 
{'role':'system', 'content':'You are friendly chatbot.'},
{'role':'user', 'content':'Hi, my name is Andrea'},
{'role':'assistant', 'content': "Nice to meet you, Andrea! How can I assist you today?"},
{'role':'user', 'content':'Do you remember my name?'}  ]

Possiamo modificare leggermente la nostra funzione call_chatgpt() per includere la cronologia della conversazione come parametro di input:

def call_chatgpt_with_memory(messages, model="gpt-3.5-turbo"):
   response = openai.ChatCompletion.create(
       model=model,
       messages=messages,
   )
   return response.choices[0].message["content"]

Proviamo questa nuova implementazione!

messages =  [ 
{'role':'system', 'content':'You are friendly chatbot.'},
{'role':'user', 'content':'Hi, my name is Andrea'},
{'role':'assistant', 'content': "Nice to meet you, Andrea! How can I assist you today?"},
{'role':'user', 'content':'Do you remember my name?'}  ]

response = call_chatgpt_with_memory(messages)
print(response)

# Output: Yes, your name is Andrea.

Ottimo! Siamo riusciti a far sì che il modello tenga conto delle interazioni passate, così da poter effettivamente conversare con lui. Tuttavia, dobbiamo trovare un modo per aggiornare automaticamente la lista messages.

Cronologia della conversazione automatica

Possiamo ottenere la raccolta automatica dei messaggi elaborando un po’ di più la nostra funzione di chiamata API:

def chatgpt_conversation(prompt):
   context.append({'role':'user', 'content':f"{prompt}"})
   response = call_chatgpt_with_memory(context)
   context.append({'role':'assistant',
   'content':f"{response}"})
   return response

Proviamo ora!

chatgpt_conversation("Hello, my name is Andrea")

# Output: 'Nice to meet you, Andrea! How can I assist you today?'

E un’interazione di follow-up:

chatgpt_conversation("Do you remember my name?")

# Output: 'Yes, your name is Andrea.'

Ora la cronologia della conversazione si aggiorna automaticamente. Infine, nota che puoi ispezionarla — e vederne la struttura — in qualsiasi momento stampando la lista messages.

print(messages)

# Output:
[{'role': 'user', 'content': 'Hello, my name is Andrea'},
{'role': 'assistant', 'content': 'Nice to meet you, Andrea! How can I assist you today?'},
{'role': 'user', 'content': 'Do you remember my name?'},
{'role': 'assistant', 'content': 'Yes, your name is Andrea.'}]

Il framework LangChain

Fin qui, possiamo concordare che la nostra implementazione produce un chatbot utile, ma non necessariamente nella sua versione più ottimizzata.

Continuare a fornire ogni singolo prompt e messaggio precedente può portare rapidamente a una grande quantità di token, che ChatGPT dovrà elaborare tutti prima di restituire l’ultimo completamento.

Finora abbiamo usato operazioni di .append per raggruppare le interazioni passate così che il chatbot avesse una sorta di memoria. Tuttavia, la gestione della memoria potrebbe essere fatta in modo più efficace usando pacchetti dedicati come LangChain.

LangChain è un framework per sviluppare applicazioni basate su modelli linguistici. Dato che oggi i chatbot sono tra le applicazioni più popolari, LangChain offre un’implementazione più pulita per costruire la cronologia conversazionale del chatbot e altre alternative per gestirla in modo più efficiente.

Per maggiori informazioni su LangChain in sé, consiglio l’articolo introduttivo Introduction to LangChain for Data Engineering & Data Applications.

Cronologia semplice con LangChain

In questa sezione, vedremo come usare il framework LangChain per costruire un chatbot.

La libreria langchain sostituisce la libreria openai usata sopra, poiché il modulo langchain.llms ti consente già di interagire con ChatGPT in due semplici righe di codice:

# OpenAI key from environment
from langchain.llms import OpenAI
llm = OpenAI()

Una volta caricato il modello llm, importiamo l’oggetto memory che memorizzerà la cronologia della conversazione. Per salvare ogni interazione passata con il chatbot, LangChain fornisce la cosiddetta ConversationBufferMemory:

from langchain.memory import ConversationBufferMemory
memory = ConversationBufferMemory()

È il momento di importare la cosiddetta ConversationChain, un wrapper che utilizzerà llm e memory per passare il prompt dell’utente a ChatGPT e restituire i suoi completamenti:

from langchain.chains import ConversationChain

conversation = ConversationChain(
   llm=llm,
   memory=memory
)

Infine, per inviare un prompt a ChatGPT, possiamo usare il metodo .predict come segue:

conversation.predict(input="Hello, my name is Andrea")

# Output: "Hi Andrea, I'm an AI created to help you with whatever you may need. What can I do for you today?"

Impostiamo verbose=True per osservare le informazioni che il modello considera per fornire un completamento. Proviamolo in un’interazione di follow-up:

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Infine, verifichiamo che ricordi perfettamente le interazioni precedenti:

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Arricchire la cronologia della conversazione

Possiamo fornire ulteriore contesto al chatbot usando il metodo memory.save_context(). In questo modo, possiamo rendere il chatbot consapevole di qualsiasi contenuto desiderato senza doverlo introdurre in una conversazione. In LangChain, le parole chiave a questo scopo sono input e output. Per esempio,

memory.save_context({"input": "Hi"},
                   {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"},
                   {"output": "Cool"})

Inoltre, possiamo consultare il contenuto della memoria in qualsiasi momento eseguendo print(memory.buffer) o memory.load_memory_variables({}).

Tipi di memoria in LangChain

LangChain implementa diversi tipi di memoria per ChatGPT. La ConversationBufferMemory usata sopra tiene traccia di ogni singola interazione con ChatGPT. Tuttavia, abbiamo già detto che fornire a ChatGPT l’intera cronologia a ogni nuova interazione può rapidamente far salire il numero di token da elaborare.

Ricorda che, oltre al limite di token per interazione di ChatGPT, i costi d’uso dipendono anche dal numero di token. Elaborare tutta la cronologia della conversazione a ogni nuova interazione rischia di essere costoso nel tempo.

Per evitare l’elaborazione continua della cronologia, LangChain implementa altri modi ottimizzati per gestire la memoria di ChatGPT. Nel paragrafo successivo esploreremo uno dei tipi più avanzati.

Cronologia avanzata con LangChain

Un modo avanzato per gestire la memoria evitando di salvare ogni interazione passata consiste nello memorizzarne invece un riassunto.

Questo tipo di memoria è il mio preferito perché può davvero portare a una gestione ottimizzata senza sacrificare alcuna interazione passata.

Andiamo!

# OpenAI key from environment
from langchain.llms import OpenAI
llm = OpenAI()

from langchain.memory import ConversationSummaryBufferMemory
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)

Nota solo che questo tipo di memoria usa l’llm definito per generare il riepilogo delle interazioni precedenti.

Inoltre, questa memoria può conservare interazioni complete fino a un numero massimo di token (max_token_limit). Oltre tale limite, incorpora le informazioni di quei messaggi nel riepilogo.

Per provarla, creiamo un’interazione con un numero elevato di token. Considera il seguente schedule:

schedule = "There is a meeting at 8am with your product team. \
You will need your powerpoint presentation prepared. \
9am-12pm have time to work on your LangChain \
project which will go quickly because Langchain is such a powerful tool. \
At Noon, lunch at the italian resturant with a customer who is driving \
from over an hour away to meet you to understand the latest in AI. \
Be sure to bring your laptop to show the latest LLM demo."

memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=100)
memory.save_context({"input": "Hello"}, {"output": "What's up"})
memory.save_context({"input": "Not much, just hanging"}, {"output": "Cool"})
memory.save_context({"input": "What is on the schedule today?"}, {"output": f"{schedule}"})

Ora ci basta dichiarare una nuova conversation chain dati llm e memory, come negli esempi precedenti.

conversation = ConversationChain(
   llm=llm,
   memory=memory,
   verbose=True
)

Possiamo usare .predict per inviare un prompt a ChatGPT:

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Screenshot del contesto a disposizione di ChatGPT quando crea un completamento. Output verboso in verde.

Come possiamo osservare, il chatbot mantiene un riepilogo della cronologia originale, riducendo il numero di token elaborati da ChatGPT in ogni interazione successiva.

È tutto! Ora possiamo continuare a parlare per ore con il nostro chatbot ottimizzato!

Imposta verbose=False per un’esperienza di domanda e risposta più piacevole nel tuo notebook.

Conclusione

In questo articolo abbiamo visto come costruire un chatbot sensibile al contesto utilizzando il noto modello ChatGPT.

Abbiamo visto come creare un chatbot sensibile al contesto possa portare a interazioni continue. Questo approccio iterativo favorisce un ciclo di feedback costante, permettendoti di mantenere bisogni e preferenze dell’utente lungo la conversazione.

Abbiamo visto due approcci principali per gestire la cronologia conversazionale del chatbot. Primo, usando l’API nativa di ChatGPT per ottenere un chatbot funzionale. Secondo, usando il framework dedicato LangChain e un’implementazione di memoria ottimizzata.

Ora tocca a te! È il momento di usare i mattoncini presentati in questo articolo per personalizzare un chatbot su misura per il tuo caso d’uso!

If you are interested in building other applications using both LangChain and ChatGPT, the webinar Building AI Applications with LangChain and GPT is for you. Looking to get up to speed with NLP? Then check out the modules on Natural Language Processing in Python instead!


Andrea Valenzuela's photo
Author
Andrea Valenzuela
LinkedIn
Twitter

Andrea Valenzuela lavora attualmente all’esperimento CMS presso l’acceleratore di particelle (CERN) a Ginevra, Svizzera. Con un’esperienza di sei anni in data engineering e analisi, si occupa di analisi dei dati e sviluppo software. Oggi si dedica a democratizzare l’apprendimento delle tecnologie legate ai dati tramite la pubblicazione su Medium ForCode'Sake.

Ha conseguito una laurea in Ingegneria Fisica presso l’Università Politecnica della Catalogna e un master in Sistemi Interattivi Intelligenti presso l’Università Pompeu Fabra. La sua esperienza di ricerca include lavori professionali con precedenti algoritmi OpenAI per la generazione di immagini, come i Normalizing Flows.

Argomenti
Intelligenza artificiale
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

Mostra AltroMostra Altro