{count, plural, one {Corso} other {Corsi}}
Gemini 3 Pro è il modello di IA all’avanguardia che stavamo aspettando: offre una finestra di contesto da un milione di token che gestisce senza sforzo dataset, documenti, video e codebase in un’unica passata. Fornisce capacità di ragionamento a livello PhD ed eccelle nell’elaborazione multimodale di testo, immagini, audio e video per workflow creativi senza interruzioni.
In questo tutorial basato su un progetto, ti mostrerò come usare l’API Gemini 3 per creare applicazioni multi‑agente che utilizzano un dataset CSV fornito dall’utente ed eseguono analisi dati approfondite.
In breve, l’app multi‑agente eseguirà:
- Analisi semplici: esplora rapidamente la struttura e le basi del dataset.
- Generazione di codice: usa Gemini 3 Pro per creare codice di analisi avanzato con visualizzazioni.
- Esecuzione sicura: esegui il codice in un ambiente sandbox e salva i risultati.
- Ragionamento intelligente: analizza e interpreta i risultati per ricavare insight chiave.
- Compilazione del report PDF: genera un PDF rifinito con visual e spiegazioni chiare, insight comprensibili in pochi secondi.
Se vuoi approfondire la creazione di workflow agentici di IA, ti consiglio di dare un’occhiata alla nostra guida a Google Antigravity, al tutorial su Gemini 3 Flash e allo skill track AI Agent Fundamentals.
1. Configurare l’ambiente dell’API Gemini 3
1. Esegui questo comando per installare tutti i pacchetti richiesti per la nostra app multi‑agente:
!pip install -q google-genai langgraph langsmith grandalf pydantic pandas matplotlib markdown2 weasyprint markdown-it-py mdit-py-plugins
Dettaglio dei pacchetti:
- google-generativeai: accedi a Gemini 3 Pro tramite l’API ufficiale.
- langgraph: orchestra workflow di IA multi‑agente con facilità.
- langsmith: traccia le esecuzioni, monitora le prestazioni e fai debug con dashboard interattive.
- grandalf: visualizza i grafi degli agenti come diagrammi ASCII puliti.
- pydantic: gestisci stati condivisi del grafo con validazione robusta dei dati.
- pandas: esegui un’esplorazione e analisi rapida del dataset.
- matplotlib: genera visualizzazioni dei dati sorprendenti.
- markdown2: converti Markdown in HTML per una formattazione ricca del report.
- weasyprint: trasforma HTML/CSS in report PDF professionali.
- markdown-it-py: parser Markdown avanzato per formattazioni complesse.
- mdit-py-plugins: estendi markdown-it-py con plugin per tabelle, note a piè di pagina e altro.
Nota: stiamo usando Jupyter Notebook per costruire questo progetto.
2. Vai su Google AI Studio e genera la tua chiave API. Assicurati di aver configurato la fatturazione nel tuo account, perché il modello Gemini 3 Pro non è disponibile nel piano gratuito.
3. Poi crea un account LangSmith gratuito e genera la chiave API.
4. Salva entrambe le chiavi API come variabili d’ambiente nel tuo sistema locale. Imposta LANGSMITH_API_KEY e GEMINI_API_KEY.
5. Importa tutti i pacchetti Python necessari nel tuo notebook:
from google import genai
from google.genai import types
from pydantic import BaseModel
from langgraph.graph import StateGraph, END
import os, json, textwrap, traceback
from pathlib import Path
import pandas as pd
import markdown2
import weasyprint
6. Imposta le variabili d’ambiente per specificare il nome del progetto LangSmith e abilitare il tracciamento LangSmith:
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = os.environ.get("LANGSMITH_API_KEY", "YOUR_LANGSMITH_KEY")
os.environ["LANGSMITH_PROJECT"] = os.environ.get("LANGSMITH_PROJECT", "autolab-gemini3pro")
7. Crea la cartella in cui verranno salvate tutte le immagini e i PDF:
ARTIFACTS_DIR = Path("artifacts")
ARTIFACTS_DIR.mkdir(exist_ok=True)
2. Come inizializzare il client dell’API Gemini 3
In questa sezione imposteremo un client dell’API Gemini e incapsuleremo le chiamate al modello in modo che possano essere tracciate e registrate in LangSmith. Inoltre, estrarremo i metadati sull’uso dei token e li restituiremo in un formato compatibile con LangSmith.
Per prima cosa, inizializzeremo il client Gemini GenAI fornendo la chiave API:
client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])
MODEL = "gemini-3-pro-preview"
Successivamente, scriveremo un piccolo wrapper attorno a una chiamata al modello Gemini per abilitare il tracciamento automatico da parte di LangSmith. Usando il decoratore @traceable registriamo la funzione come esecuzione LLM.
All’interno di questa funzione, il codice invierà il prompt a Gemini ed estrarrà i dettagli sull’uso dei token, essenziali per un tracciamento accurato in LangSmith, seguendo le linee guida di tracing.
Infine, la funzione restituirà l’output testuale del modello insieme alle statistiche sui token e alla risposta grezza nel formato previsto da LangSmith, assicurando che l’esecuzione sia visualizzata correttamente nell’interfaccia.
from langsmith import traceable
@traceable(name="gemini_generate_content", run_type="llm")
def gemini_call(prompt: str, thinking_level: str = "high"):
"""
Gemini wrapper che:
- usa lo schema corretto ThinkingConfig
- restituisce il formato LLM-run di LangSmith così l'uso token appare nell'UI
"""
resp = client.models.generate_content(
model=MODEL,
contents=prompt,
config=types.GenerateContentConfig(
thinking_config=types.ThinkingConfig(thinking_level=thinking_level)
),
)
usage = getattr(resp, "usage_metadata", None)
token_usage = None
if usage:
token_usage = {
"prompt_tokens": usage.prompt_token_count,
"completion_tokens": usage.candidates_token_count,
"total_tokens": usage.total_token_count,
"thoughts_tokens": getattr(usage, "thoughts_token_count", None),
}
return {
"generations": [{"text": resp.text}],
"llm_output": {
"model_name": MODEL,
"token_usage": token_usage,
},
"raw_response": resp,
}
3. Creare strumenti per il workflow multi‑agente di Gemini 3
Ora creeremo strumenti che forniscono ispezione del dataset, esecuzione sicura di Python e generazione di report da Markdown a PDF da usare all’interno di un workflow con agenti di IA.
Strumento 1: Carica dataset
Questo strumento prende un percorso file, legge il CSV in un DataFrame di pandas e poi crea un riepilogo contenente forma del dataset, nomi delle colonne, tipo di dato di ciascuna colonna, percentuali di valori mancanti, le prime cinque righe e statistiche descrittive complete. Restituisce questo riepilogo così un agente può comprendere rapidamente il dataset.
def load_dataset(path: str):
df = pd.read_csv(path)
summary = {
"shape": df.shape,
"columns": list(df.columns),
"dtypes": {c: str(t) for c, t in df.dtypes.items()},
"missing_pct": df.isna().mean().to_dict(),
"head": df.head(5).to_dict(orient="records"),
"describe": df.describe(include="all").fillna("").to_dict()
}
return summary
Strumento 2: Esegui codice Python in sicurezza (sandbox semplice)
Questo strumento esegue in sicurezza codice Python generato dinamicamente in un ambiente ristretto. Prepara un piccolo ambiente locale, quindi esegue il codice fornito con exec.
Il codice eseguito dovrebbe restituire percorsi di artifact (come i grafici salvati) e metadati.
def run_python(code: str):
"""
Il codice generato DEVE:
- salvare i grafici in ARTIFACTS_DIR
- raccogliere i percorsi in _artifacts (list[str])
- raccogliere i meta in _charts_meta (list[dict])
- opzionalmente impostare _stdout (string)
"""
local_env = {"ARTIFACTS_DIR": ARTIFACTS_DIR}
try:
exec(textwrap.dedent(code), {}, local_env)
return {
"ok": True,
"stdout": local_env.get("_stdout", ""),
"artifacts": local_env.get("_artifacts", []),
"charts_meta": local_env.get("_charts_meta", []),
}
except Exception:
return {"ok": False, "traceback": traceback.format_exc()}
Strumento 3: Renderizza PDF da Markdown
Questo strumento converte Markdown in un PDF ben formattato. Prima costruisce un parser markdown che supporta tabelle, liste, task list e note a piè di pagina.
Poi render_pdf converte il testo markdown in HTML, lo inserisce in un template con CSS personalizzato (controllando font, aspetto delle tabelle, dimensioni delle immagini, ecc.) e usa WeasyPrint per generare un file PDF.
Infine, salva il PDF nella cartella degli artifact e restituisce il percorso.
from markdown_it import MarkdownIt
from mdit_py_plugins.tasklists import tasklists_plugin
from mdit_py_plugins.footnote import footnote_plugin
# Crea una parser markdown potente una volta (supporta tabelle, liste, ecc.)
md = (
MarkdownIt("commonmark", {"breaks": True, "html": True})
.enable(["table", "strikethrough"])
.use(tasklists_plugin)
.use(footnote_plugin)
)
def render_pdf(markdown_text: str):
"""
Migliore Markdown -> HTML -> PDF:
- tabelle corrette
- liste stabili
- immagini centrate/piccole
- interruzioni di pagina pulite
"""
html_body = md.render(markdown_text)
html_template = f"""
<html>
<head>
<meta charset="utf-8">
<style>
body {{
font-family: Arial, sans-serif;
font-size: 12px;
line-height: 1.5;
color: #111;
}}
h1 {{ font-size: 20px; margin-bottom: 6px; }}
h2 {{ font-size: 16px; margin-top: 18px; margin-bottom: 6px; }}
h3 {{ font-size: 13px; margin-top: 12px; margin-bottom: 4px; }}
p {{ margin: 6px 0; }}
ul, ol {{
margin: 6px 0 6px 18px;
}}
li {{ margin: 2px 0; }}
table {{
width: 100%;
border-collapse: collapse;
margin: 8px 0 12px 0;
font-size: 11px;
}}
th, td {{
border: 1px solid #ccc;
padding: 6px;
text-align: left;
}}
th {{ background: #f2f2f2; }}
img {{
display: block;
margin: 8px auto 8px auto;
max-width: 70%;
height: auto;
page-break-inside: avoid;
}}
.chart-block {{
page-break-inside: avoid;
margin-bottom: 12px;
}}
code {{
background: #f6f6f6;
padding: 2px 4px;
border-radius: 4px;
font-size: 11px;
}}
pre code {{
display: block;
padding: 8px;
overflow-x: auto;
}}
</style>
</head>
<body>
{html_body}
</body>
</html>
"""
pdf_path = ARTIFACTS_DIR / "report.pdf"
weasyprint.HTML(
string=html_template,
base_url=str(ARTIFACTS_DIR.parent.resolve())
).write_pdf(str(pdf_path))
return str(pdf_path)
Questo registra semplicemente tutte e tre le funzioni come strumenti disponibili per l’agente.
TOOLS = [load_dataset, run_python, render_pdf]
4. Stato condiviso del grafo
Questa classe definisce un oggetto state condiviso che contiene tutto ciò che il workflow dell’agente produce: come il percorso del dataset, informazioni di profiling, piano generato, codice, risultati di esecuzione, insight e report finale, oltre a limiti di retry e messaggi di errore per prevenire loop infiniti.
class State(BaseModel):
dataset_path: str
profile: dict | None = None
plan: dict | None = None
code: str | None = None
exec_result: dict | None = None
charts_meta: list | None = None
insights: str | None = None
report_md: str | None = None
report_pdf: str | None = None
retry_count: int = 0 # NUOVO: ferma i loop infiniti
last_error: str | None = None # NUOVO: passa il traceback al coder
MAX_RETRIES = 2
5. Creare agenti API Gemini 3 per l’analisi dei dati
Ora creeremo agenti di IA che collaboreranno per profilare il dataset, scrivere ed eseguire codice di analisi, generare insight e produrre un report PDF finale.
Agente 1: Profiler dei dati e planner
Questo agente è responsabile di comprendere il dataset e creare un piano di analisi strutturato. Prima carica il dataset usando lo strumento load_dataset, che restituisce un riepilogo con shape, valori mancanti, tipi di colonna, statistiche descrittive ed esempi di righe.
Poi invia questo riepilogo del dataset all’LLM con istruzioni molto esplicite: identificare il tipo di task, selezionare una colonna target se applicabile, decidere quali passi esplorativi intraprendere, proporre i grafici da generare e delineare eventuali passi di modellazione se il dataset suggerisce classificazione o regressione.
L’LLM restituisce una struttura JSON che rappresenta questo piano e l’agente la analizza, ripiegando sul salvataggio di testo grezzo se l’analisi JSON fallisce.
Infine, salva sia il profilo del dataset sia il piano generato nello stato condiviso in modo che i prossimi agenti abbiano tutte le informazioni necessarie.
@traceable(name="profiler_agent")
def profiler_agent(state: State):
profile = load_dataset(state.dataset_path)
prompt = f"""
You are the Data Profiler Agent.
Produce a JSON analysis plan with:
- task_type: "classification"|"regression"|"eda_only"
- target_column (if any)
- eda_steps (list)
- charts_to_make (list) # 5-10 max, most informative
- baseline_model_steps (list if modeling)
- risks_or_data_issues (list)
Dataset profile:
{json.dumps(profile, indent=2)}
"""
resp = gemini_call(prompt, thinking_level="high")
text = resp["generations"][0]["text"]
try:
plan = json.loads(text)
except:
plan = {"raw_plan": text}
state.profile = profile
state.plan = plan
return state
Agente 2: Code writer
Questo agente converte il piano di analisi in codice Python eseguibile. Riceve il profilo del dataset, il piano e qualsiasi errore di esecuzione precedente. Usando tutto quel contesto, chiede all’LLM di produrre solo codice Python.
Il prompt include requisiti rigidi: caricare il dataset, seguire il piano alla lettera, generare ciascun grafico specificato, salvare i plot in ARTIFACTS_DIR, tracciare percorsi e metadati dei grafici, catturare l’output della console, chiudere le figure dopo il salvataggio e, opzionalmente, calcolare metriche di modellazione.
Questo garantisce che il codice sia riproducibile e sicuro nella sandbox. Il risultato viene salvato in state.code, pronto per l’esecuzione.
@traceable(name="code_writer_agent")
def code_writer_agent(state: State):
prompt = f"""
You are the Code Writer Agent.
Write Python code ONLY (no markdown).
Previous error to fix (if any):
{state.last_error}
HARD REQUIREMENTS:
1. Load dataset from: {state.dataset_path}
2. Follow the plan exactly.
3. Create ALL charts in charts_to_make.
4. Save every chart in ARTIFACTS_DIR with filenames like:
ARTIFACTS_DIR / "chart_01_<short_name>.png"
5. Track saved plot paths in _artifacts (list[str]).
6. Track chart metadata in _charts_meta (list[dict]) with:
{{
"title": "<human readable chart title>",
"filename": "artifacts/chart_01_x.png",
"description": "<what this plot shows (1-2 sentences)>",
"one_liner": "<ONE line insight from the chart>"
}}
The one_liner MUST be a single sentence, max ~20 words.
7. Store useful console output in _stdout.
IMPORTANT:
- import matplotlib.pyplot as plt
- plt.close() after saving each plot
- ensure _artifacts and _charts_meta exist even if empty
- if modeling, add baseline metrics to _stdout
Dataset profile:
{json.dumps(state.profile, indent=2)}
Analysis plan:
{json.dumps(state.plan, indent=2)}
Return ONLY executable python code.
"""
resp = gemini_call(prompt, thinking_level="high")
state.code = resp["generations"][0]["text"]
return state
Agente 3: Executor (con auto‑retry)
Questo agente esegue il codice Python prodotto dal Code Writer usando la sandbox isolata run_python. Cattura risultati di esecuzione, metadati dei grafici, output standard e qualsiasi artifact creato.
Se il codice gira con successo, i risultati vengono salvati e il workflow procede normalmente. Se fallisce, l’agente incrementa il contatore dei tentativi e salva il traceback così che l’agente Code Writer possa correggere l’errore al tentativo successivo.
Con MAX_RETRIES a limitare il loop, questo agente previene cicli infiniti e fornisce i segnali di feedback necessari per l’auto‑correzione.
@traceable(name="executor_agent")
def executor_agent(state: State):
result = run_python(state.code)
state.exec_result = result
state.charts_meta = result.get("charts_meta", [])
if not result["ok"]:
state.retry_count += 1
state.last_error = result.get("traceback", "Unknown error")
return state
Agente 4: Insights writer
Questo agente interpreta l’intera analisi. Prende il profilo del dataset, l’output di esecuzione e i metadati dei grafici e produce insight analitici leggibili.
Istruisce l’LLM a generare insight strutturati: per ogni grafico, due takeaway e un rischio, quindi un set limitato di insight complessivi.
L’agente deve garantire assenza di punti elenco vuoti, niente ripetizioni e insight specifici per il dataset, non generici.
Il report di insight risultante viene salvato in state.insights, diventando un input per la fase finale di reporting.
@traceable(name="insights_agent")
def insights_agent(state: State):
prompt = f"""
You are the Insights Agent.
HARD REQUIREMENTS:
- No empty bullets.
- No repeated bullets.
- Be specific to this dataset and these charts.
- Output format:
### Chart Insights
For each chart in charts_meta:
- **<title>**
- Takeaway 1 (one sentence)
- Takeaway 2 (one sentence)
- Caveat/Risk (one sentence)
### Overall Insights
- 3-5 bullets max, each one sentence.
Inputs:
Profile:
{json.dumps(state.profile, indent=2)}
Execution result:
{json.dumps(state.exec_result, indent=2)}
Charts meta:
{json.dumps(state.charts_meta, indent=2)}
"""
resp = gemini_call(prompt, thinking_level="high")
state.insights = resp["generations"][0]["text"]
return state
Agente 5: Costruttore del report → PDF
Questo è l’agente di sintesi finale. Usa gli output dell’intera pipeline: profilo, insight, metadati dei grafici, log di esecuzione e crea un report Markdown completo e pulito.
Il prompt impone regole di formattazione rigide: niente titoli ripetuti, spaziatura coerente, ogni grafico mostrato esattamente una volta in un blocco HTML standardizzato e integrazione pulita degli insight.
Una volta prodotto il Markdown, l’agente chiama render_pdf per convertirlo in un PDF rifinito usando WeasyPrint. Sia il Markdown sia il percorso del PDF vengono salvati nello stato condiviso, completando il workflow di analisi.
@traceable(name="report_agent")
def report_agent(state: State):
prompt = f"""
You are the Report Agent.
Create a neat Markdown report (HTML allowed).
HARD REQUIREMENTS:
- Do NOT repeat section titles or chart titles.
- Do NOT output empty bullet points. If a bullet would be empty, skip it.
- Keep spacing consistent: one blank line between sections.
- Use charts_meta as the ONLY source of charts.
- Include EVERY chart, exactly once, in the same order as charts_meta.
- For each chart output EXACTLY this block:
<div class="chart-block">
<h3>Chart {{i}}: {{title}}</h3>
<img src="{{filename}}" alt="{{title}}">
<p><b>What it shows:</b> {{one_liner}}</p>
</div>
Where:
- title, filename, one_liner come from charts_meta
- one_liner must be ONE sentence, max ~20 words.
Sections:
1. Dataset Overview (short)
2. Data Quality Notes (bullets)
3. Exploratory Analysis (chart-by-chart blocks only, no extra chart titles)
4. Modeling Results (if any; use a markdown table)
5. Key Insights (use insights text)
6. Recommendations / Next Steps (bullets)
Inputs:
Profile: {json.dumps(state.profile, indent=2)}
Exec stdout: {state.exec_result.get("stdout","")}
Exec ok: {state.exec_result.get("ok")}
Traceback (if any): {state.exec_result.get("traceback","")}
Charts meta:
{json.dumps(state.charts_meta, indent=2)}
Insights:
{state.insights}
Return ONLY the Markdown report.
"""
resp = gemini_call(prompt, thinking_level="low")
state.report_md = resp["generations"][0]["text"]
state.report_pdf = render_pdf(state.report_md)
return state
6. Costruire il grafo multi‑agente
Questo ultimo passaggio prevede la costruzione del workflow multi‑agente completo assemblando tutti gli agenti in un grafo guidato dallo stato.
Si crea uno StateGraph utilizzando un modello di Stato condiviso, garantendo che ogni agente interagisca con lo stesso oggetto di stato in evoluzione man mano che il workflow procede. Ogni componente, come profiler, code writer, executor, insights writer e report builder, viene aggiunto al grafo come nodo distinto, rappresentando una fase specifica della pipeline.
Il workflow inizia sempre con l’agente profiler, designato come punto di ingresso. Questo garantisce che il processo parta con una comprensione approfondita del dataset e la generazione di un piano di analisi.
Si definiscono gli edge per stabilire il flusso del processo. Dopo il profiling, l’output è indirizzato al code writer, che poi alimenta l’executor. La logica chiave risiede nell’instradamento condizionale dall’executor.
Una funzione di supporto, retry_or_continue, esamina il risultato dell’esecuzione. Se il codice viene eseguito con successo, il workflow procede all’agente degli insight.
Se fallisce ma ha ancora tentativi disponibili, torna al code writer per la correzione automatica.
Se non restano tentativi, salta ulteriori analisi e passa direttamente al generatore del report, assicurando che il sistema non entri in un loop infinito. Gli edge condizionali sono incorporati nel nodo executor così che il workflow possa adattarsi in base al successo o fallimento dell’esecuzione.
Infine, il grafo collega la fase di insight alla fase di report e dalla fase di report alla conclusione del workflow. Il grafo viene quindi compilato in una struttura eseguibile e viene generato un diagramma ASCII per visualizzare il flusso.
Questo grafo multi‑agente orchestra l’intera pipeline di analisi adattiva, abilitando il recupero dagli errori, il coordinamento passo‑passo e transizioni fluide tra agenti.
g = StateGraph(State)
g.add_node("profiler", profiler_agent)
g.add_node("code_writer", code_writer_agent)
g.add_node("executor", executor_agent)
g.add_node("insights", insights_agent)
g.add_node("report", report_agent)
g.set_entry_point("profiler")
g.add_edge("profiler", "code_writer")
g.add_edge("code_writer", "executor")
def retry_or_continue(state: State):
# success path
if state.exec_result and state.exec_result.get("ok"):
return "insights"
# stop retrying after MAX_RETRIES
if state.retry_count >= MAX_RETRIES:
return "report"
return "code_writer"
g.add_conditional_edges(
"executor",
retry_or_continue,
{"code_writer": "code_writer", "insights": "insights", "report": "report"}
)
g.add_edge("insights", "report")
g.add_edge("report", END)
graph = g.compile()
print(graph.get_graph().draw_ascii())
+-----------+
| __start__ |
+-----------+
*
*
*
+----------+
| profiler |
+----------+
*
*
*
+-------------+
| code_writer |
+-------------+
.
.
.
+----------+
| executor |
+----------+
.. ..
.. ..
. ..
+----------+ .
| insights | ..
+----------+ ..
** ..
** ..
* .
+--------+
| report |
+--------+
*
*
*
+---------+
| __end__ |
+---------+
7. Eseguire l’intera pipeline di analisi dati con l’API Gemini 3
Per eseguire l’intera pipeline, ti basta fornire un percorso del dataset, creare un oggetto State iniziale e invocare il grafo compilato. Nel nostro caso, gli passiamo il dataset Boston Housing.
DATASET_PATH = "/work/housing.csv" # <-- change this
state = State(dataset_path=DATASET_PATH)
out = graph.invoke(state)
Una volta invocato, il sistema multi‑agente esegue automaticamente l’intera analisi: profiling del dataset, generazione di un piano, scrittura ed esecuzione di codice Python, estrazione degli insight e produzione sia di un report Markdown sia di un PDF.
--- Modeling Baseline Results ---
Dataset Shape: (489, 4)
Linear Regression -> RMSE: 82,395.54, R2: 0.6911
Random Forest -> RMSE: 56,931.38, R2: 0.8525
Observations: Random Forest typically outperforms Linear Regression due to capturing non-linear relationships (e.g., LSTAT).
Al termine dell’esecuzione, puoi aprire la dashboard di LangSmith e andare al progetto “autolab-gemini3pro”. Ogni esecuzione degli agenti è visibile lì.

Facendo clic sull’esecuzione più recente e passando alla vista Waterfall si visualizza la timeline di ogni passo: quanto tempo hanno impiegato gli agenti e quali strumenti hanno usato.

Puoi entrare nei dettagli di qualsiasi agente per ispezionare:
- Il prompt ricevuto
- L’esatta generazione del modello
- Dettagli di esecuzione degli strumenti
- Artifact restituiti, grafici e trace

LangSmith è stato fondamentale per migliorare l’intero workflow. Quello che vedi è la versione finale, ma ci sono voluti molti tentativi per far funzionare questo progetto, e LangSmith mi ha aiutato a fare debug dei problemi negli agenti.
8. Visualizzare Markdown e PDF del report
Una volta completato il workflow multi‑agente, puoi ispezionare direttamente il report Markdown generato all’interno del tuo notebook.
La versione Markdown è utile per rivedere rapidamente l’analisi, leggere gli insight ed esaminare la struttura del report senza lasciare l’ambiente di lavoro.
print(out["report_md"][:2000])
# Housing Price Analysis Report
## 1. Dataset Overview
The dataset consists of **489 records** and **4 features** focusing on housing metrics. The target variable is `MEDV` (Median Value of owner-occupied homes). The features include `RM` (average number of rooms), `LSTAT.............
Oltre al Markdown, il workflow produce anche un report PDF rifinito. Il PDF viene salvato automaticamente nella cartella degli artifact e puoi visualizzarne il percorso così:
print("PDF saved at:", out["report_pdf"])
PDF saved at: artifacts/report.pdf
Il PDF generato è perfetto e contiene tutti i componenti chiave dell’analisi: spiegazioni narrative, grafici resi visivamente, interpretazioni dei grafici, riepiloghi di modellazione e raccomandazioni finali.
È ideale da condividere con colleghi, responsabili o clienti, soprattutto quando vuoi una versione dei risultati pulita e pronta per la presentazione.

Considerazioni finali
Lavorare a questo progetto ha reso evidente quanto siano evoluti i modelli di IA moderni e i workflow di agenti basati su grafi. Non molto tempo fa, costruire anche un singolo agente con più strumenti richiedeva giorni di messa a punto, debug e gestione di comportamenti imprevedibili.
Oggi, con modelli come Gemini 3 Pro, il sistema può comprendere il dataset, generare codice accurato, eseguire analisi, interpretare visualizzazioni e assemblare un report rifinito con notevole affidabilità.
In questo progetto abbiamo costruito un’applicazione completa di analisi dati multi‑agente in grado di prendere qualsiasi dataset CSV, eseguire analisi esplorativa end‑to‑end, far girare modelli baseline, generare insight e produrre un report PDF completamente formattato.
Questo progetto usa cinque agenti coordinati: profiling & planning, generazione del codice, esecuzione con retry, generazione degli insight e reporting, e tre strumenti core per caricamento del dataset, esecuzione sicura del codice e rendering da Markdown a PDF.
Il risultato è un flusso di analisi pulito e automatico che produce un report professionale e narrativo supportato da visualizzazioni.
Gemini 3 API: Domande frequenti
Qual è la dimensione della finestra di contesto dell’API Gemini 3?
L’API Gemini 3 supporta una finestra di contesto fino a circa un milione di token, consentendo di elaborare in un’unica chiamata grandi dataset, documenti lunghi o intere codebase. Si raccomanda comunque di monitorare l’uso dei token per controllare i costi ed evitare troncamenti.
In che modo il parametro thinking_level influisce sulle prestazioni dell’API Gemini 3?
Il parametro thinking_level controlla la profondità del ragionamento rispetto a velocità e costo nell’API Gemini 3. Impostarlo su high attiva un ragionamento più approfondito (ideale per workflow complessi), mentre low privilegia risposte più rapide e un consumo di token inferiore.
Quali sono i dettagli di prezzo e rate limit dell’API Gemini 3?
Gemini 3 Pro utilizza una fatturazione basata sui token: paghi sia per i token in input sia per quelli in output. Prompt più grandi o input multimodali aumentano il numero di token e quindi il costo. I limiti di frequenza variano in base al livello dell’account, quindi tracciare l’uso e impostare avvisi è essenziale in ambienti di produzione.
Quali formati di input sono supportati dall’API Gemini 3?
L’API Gemini 3 supporta più formati di input—testo, immagini, audio e video—abilitando un vero ragionamento multimodale. Puoi mescolare i formati (per esempio, un dataset più l’immagine di un grafico), ma gli input non testuali in genere consumano più token, quindi pianifica di conseguenza.
Quali sono i principali limiti dell’API Gemini 3 e come gestirli?
Sebbene l’API Gemini 3 sia molto capace, presenta comunque limiti pratici: contesti ampi possono aumentare latenza e costi, e gli output del modello possono richiedere validazione umana. Non dovresti inviare dati sensibili senza verifiche di conformità, e il codice o le analisi generati andrebbero eseguiti in sandbox prima della messa in produzione.
In quanto data scientist certificato, sono appassionato di sfruttare tecnologie all’avanguardia per creare applicazioni di machine learning innovative. Con una solida esperienza in riconoscimento vocale, analisi e reportistica dei dati, MLOps, AI conversazionale e NLP, ho affinato le mie competenze nello sviluppo di sistemi intelligenti in grado di avere un impatto concreto. Oltre alla mia expertise tecnica, sono anche un comunicatore efficace, con il talento di rendere chiari e sintetici concetti complessi. Di conseguenza, sono diventato un blogger molto seguito in ambito data science, condividendo idee ed esperienze con una community in crescita di professionisti dei dati. Attualmente mi concentro sulla creazione e sull’editing di contenuti, lavorando con large language model per sviluppare contenuti potenti e coinvolgenti che possano aiutare aziende e singoli a valorizzare al meglio i propri dati.


