Con la lezione precedente abbiamo addestrato la nostra RAG popolando il suo database vettoriale salvato su file. Ora finiamo di strutturare l'agente AI turistico e passiamo alla sua prova.
I passaggi saranno questi:
- richiamo del database: accederemo al suo file su disco utilizzando il medesimo embedder, passaggio necessario quest'ultimo affinché le distanze tra elementi vengano calcolate allo stesso modo;
- creazione dei tool: per prima cosa ci servono i due tool da utilizzare. Ne produrremo uno che avrà accesso alla RAG (mediante un oggetto
retriever) ed un altro che inoltrerà chiamate al servizio meteo; - definizione del modello: scegliamo il modello da utilizzare sfruttando la funzione
init_chat_model; - assemblaggio dell'agente: istanziamo il nostro agente integrando il modello, i tool e specificando eventuali altri attributi di nostro interesse.
Passiamo ora alla sua implementazione pratica.
I tool per l'Agente AI
I tool che abbiamo definito sono i seguenti:
from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool, ToolRuntime
from langgraph.checkpoint.memory import InMemorySaver
from langchain.agents.structured_output import ToolStrategy
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.tools.retriever import create_retriever_tool
import requests
# configurazione embeddings (stesso modello di RAG)
embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
api_key=api_key
)
# lettura del db da file
db = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings
)
# oggetto retriever
retriever = db.as_retriever(search_kwargs={"k": 3})
# il retriever diventa tool
tool_roma = create_retriever_tool(
retriever,
name="search_rome_art_history_culture",
description='''Consulta questa guida specializzata per rispondere a domande su Roma,
i suoi monumenti (Colosseo, San Pietro) e la sua storia.'''
)
@tool
def get_rome_weather() -> str:
"""Consulta questo tool per conoscere il meteo attuale a Roma.
Utile quando gli utenti chiedono informazioni climatiche per pianificare visite."""
# coordinate geografiche di Roma
lat, lon = 41.8919, 12.5113
url = f"https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lon}¤t_weather=true"
try:
response = requests.get(url)
data = response.json()
if "current_weather" in data:
temp = data["current_weather"]["temperature"]
wind = data["current_weather"]["windspeed"]
return f"A Roma ci sono attualmente {temp}°C con una velocità del vento di {wind} km/h."
else:
return "Non sono riuscito a recuperare i dati meteo al momento."
except Exception as e:
return f"Errore durante la chiamata API: {e}"
Si noti che abbiamo impostato il primo tool totalmente sull'oggetto retriever trasformandolo con la funzione create_retriever_tool. Avremmo potuto usare una normale ricerca sul database vettoriale ma un retriever applica uno strato di logica superiore che mette l'agente in condizioni migliori di lavoro.
Il secondo tool incapsula una logica di accesso ai dati via API e restituisce il risultato.
Molta importanza hanno le descrizioni dei tool che servono a specificare quando questo deve essere invocato. Si potrà agire su queste per l'ottimizzazione dell'esecuzione.
L'Agente AI
Ora che abbiamo i tool possiamo impostare il nostro agente AI:
model = init_chat_model(
"gpt-5.4-mini-2026-03-17",
temperature=0,
api_key=api_key
)
my_serde = JsonPlusSerializer(
allowed_msgpack_modules=[("__main__", "ResponseFormat")]
)
checkpointer = InMemorySaver(serde=my_serde)
PROMPT = """
Sei un assistente turistico specializzato su Roma.
Disponi di due tool:
- uno in grado di recuperare le informazioni sulla città. Se ti viene chiesto qualcosa sulla città di Roma ed i
suoi monumenti chiamalo.
- un altro tool è in grado di recuperare informazioni sul meteo a roma. Chiamalo solo se vi viene richiesta tempo,
temperatura o meteo di Roma.
Rispondi solo con informazioni recuperate tramite i tool. Se non trovi le informazioni nei tool o se non reputi di
dover chiamare uno dei tool, non
usare mai l'LLM a disposizione ma rispondi:
"Mi dispiace questo è un servizio turistico riguardante Roma.\n Chiedi informazioni che ti aiuteranno a passare
splendidi momenti nella Città Eterna"
"""
@dataclass
class ResponseFormat:
"""Struttura per la risposta dell'agente"""
risposta_finale: str
nome_suggerito: str | None = None
@dataclass
class Context:
"""identificativo dell'utente"""
user_id: str
# assemblaggio dell'agente
agent = create_agent(
model=model,
system_prompt=PROMPT,
tools=[tool_roma, get_rome_weather],
context_schema=Context,
response_format=ToolStrategy(ResponseFormat),
checkpointer=checkpointer
)
# identificatore dell'unica conversazione esistente
config = {"configurable": {"thread_id": "1"}}
# conversazione con l'agente
while(True):
query=input('\nTU: ')
if query.lower().startswith('basta'):
break
response=agent.invoke(
{"messages": [{"role": "user", "content": query}]},
config=config,
context=Context(user_id="1")
)
print(f'A.I.: {response['structured_response'].risposta_finale}')
print('='*30)
La sessione di test
La costruzione dell'agente ricalca quello che abbiamo fatto nella guida ma in questo caso ci siamo soffermati per lo più sulla definizione di un prompt che spiegasse bene gli scopi dell'agente, i ruoli dei tool e soprattutto che tutto ciò che non riguarda il lavoro dei tool non deve essere recuperato via LLM ma liquidato con una frase di impossibilità di proseguimento.
Lanciamo una sessione di test:
TU: Chi era Giuseppe Garibaldi?
A.I.: Mi dispiace questo è un servizio turistico riguardante Roma.
Chiedi informazioni che ti aiuteranno a passare splendidi momenti nella Città Eterna
==============================
TU: Quanto è alto il Colosseo?
A.I.: Il Colosseo raggiunge un’altezza attuale di 48 metri; originariamente arrivava a 52 metri.
==============================
TU: Che tempo fa oggi a Roma?
A.I.: A Roma ci sono attualmente 20.2°C con una velocità del vento di 9.0 km/h.
==============================
TU: Che tempo fa oggi a Firenze?
A.I.: Mi dispiace questo è un servizio turistico riguardante Roma.
Chiedi informazioni che ti aiuteranno a passare splendidi momenti nella Città Eterna
==============================
Come possiamo vedere abbiamo fatto quattro domande. Due sono palesemente fuori tema in quanto riguardano Giuseppe Garibaldi e la città di Firenze: a queste l'agente risponde dicendo che è specializzato solo su Roma. Le altre due invece non solo sono focalizzate sull'argomento giusto ma inquadrano perfettamente gli scopi dei tool: riceveremo infatti risposta proprio da questi ultimi due.
Se vuoi aggiornamenti su Agente AI turistico al lavoro inserisci la tua email nel box qui sotto: