Mini progetto didattico che implementa un mini-agente con “tool calling”:
a partire da un prompt testuale, un modello OpenAI (configurato nel codice) decide se usare uno dei tool disponibili e con quali parametri. La scelta avviene chiedendo al modello di rispondere in JSON con uno schema fisso; se viene selezionato un tool valido, il tool viene eseguito e l’azione viene loggata su file.
- ToolRegistry: registro dei tool disponibili (nome → funzione + descrizione).
- MiniAgent: router basato su LLM che decide
tooleparams. - 4 tool (in
app/tools.py):get_weather(city)→ meteo mock per una cittàcalculate_discount(price, discount)→ calcolo sconto percentualecount_words(text)→ conteggio paroleget_current_time(timezone='UTC')→ orario corrente (timezone è una label)
- Logging su
agent_activity.logquando viene eseguito un tool. - Test con
pytestche mockano l’API OpenAI (esecuzione deterministica).
- Python 3.9+ (consigliato 3.10+)
pip- Una OpenAI API Key (solo per eseguire
main.pyin modalità reale)
- Clona/copìa il progetto ed entra nella cartella:
cd mini-agent-toolkit- (Consigliato) Crea e attiva un virtual environment:
python -m venv .venv
# Linux/Mac
source .venv/bin/activate
# Windows
.venv\\Scripts\\activate- Installa le dipendenze:
pip install -r requirements.txtPer eseguire la demo reale serve OPENAI_API_KEY. Crea un file .env nella root del progetto:
OPENAI_API_KEY=la_tua_chiaveIl file .env viene caricato da main.py tramite python-dotenv.
Suggerimento sicurezza:
- aggiungi
.enva.gitignore - non committare mai chiavi o segreti
Esegui la demo (usa la lista di prompt “golden set” già pronta in main.py):
python main.pyOutput atteso:
- per i prompt che attivano un tool, la risposta ha il formato
"[TOOL <nome>] <risultato>" - per prompt generici, l’agente restituisce una risposta diretta del modello (senza tool)
Al termine, controlla il file agent_activity.log (viene aggiornato solo quando un tool viene eseguito).
Di seguito esempi coerenti con i prompt presenti in main.py.
Input
Che tempo fa a Roma?
Output (tool)
[TOOL get_weather] Il meteo a Roma è di 22°C, cielo sereno e vento debole.
Nota:
get_weatherè un mock (non chiama servizi meteo esterni).
Input
Quanto costa un prodotto da 150€ con lo sconto del 20%?
Output (tool)
[TOOL calculate_discount] Il prezzo originale di 150.00€, scontato del 20.0%, diventa 120.00€.
Input
conta queste parole: l'agente funziona molto bene
Output (tool)
[TOOL count_words] L'analisi è completata: la stringa contiene esattamente 7 parole.
Input
Che ore sono adesso?
Output (tool)
[TOOL get_current_time] L'orario attuale (UTC) è 14:22:09.
L’orario varia a runtime.
Input
Chi ha scritto la Divina Commedia?
Output (risposta diretta LLM)
La Divina Commedia è stata scritta da Dante Alighieri.
Le risposte dirette del modello possono variare (non sono “hard-coded”).
I test non richiedono la chiave API perché mockano il client OpenAI.
pytest -qmini_agent_toolkit/
├─ app/
│ ├─ agent.py # MiniAgent: chiama l’LLM e interpreta la risposta JSON
│ ├─ registry.py # ToolRegistry: registro tool (nome → func + description)
│ ├─ tools.py # Implementazioni dei 4 tool
│ ├─ logger.py # log_action: scrive su agent_activity.log
│ └─ __init__.py
├─ tests/
│ ├─ test_agent.py # unit test (mock OpenAI)
│ └─ __init__.py
├─ main.py # demo di consegna (golden set)
├─ requirements.txt
└─ agent_activity.log # file di log (append) generato/aggiornato a runtime
L’architettura separa due responsabilità:
- Decisione (routing / planning): il modello decide se serve un tool e quali parametri usare.
- Esecuzione (acting): i tool sono funzioni Python deterministiche che producono un risultato.
Questo pattern è tipico dei sistemi agentici: il modello pianifica, il codice esegue.
ToolRegistry centralizza le capability disponibili:
- aggiungere un tool richiede solo: implementazione + registrazione (nome, descrizione)
- l’agente non dipende dai dettagli dei tool (disaccoppiamento)
- il catalogo è riutilizzabile (es. UI, docs, “tool list” nel prompt di sistema)
In app/agent.py il modello riceve un system prompt che impone un output JSON con chiavi:
tool: nome del tool oppurenullparams: dizionario dei parametri da passare al toolanswer: testo di risposta diretta se non serve un tool
Questo rende il routing parsabile e riduce l’ambiguità rispetto a testo libero.
Quando un tool viene eseguito, log_action(...) registra:
- timestamp
- tool invocato
- prompt originale
- output del tool
Esempio di riga log:
[2026-02-11 14:22:09] ACTION: get_weather | IN: Che tempo fa a Roma? | OUT: Il meteo a Roma è di 22°C, cielo sereno e vento debole.
I test in tests/test_agent.py:
- patchano
OpenAIper evitare chiamate reali - forzano la “risposta del modello” (JSON) per verificare:
- happy path (tool corretto + params corretti)
- gestione input incompleto (risposta diretta)
- limiti/validazione (es. sconto > 100%)
- resistenza base a prompt injection (via risposta diretta)
Intermedio (Beginner+)
- Python: funzioni, moduli, classi semplici
- comprensione base di: environment variables, logging, test mocking
- introduzione pratica a “agentic pattern” (routing + tools)
- chi sta studiando AI Agents e vuole un esempio minimale ma realistico
- studenti/junior dev che vogliono vedere un flusso completo: registry → LLM routing → tool → log → test
- chi vuole una base da estendere verso tool più “veri” (API esterne, DB, RAG, ecc.)