Osservabilità LLM nel 2026: Tracing, Valutazione e Monitoraggio con LangSmith e Langfuse

Implementa tracing, valutazione e monitoraggio LLM in produzione nel 2026 con LangSmith, Langfuse, Arize Phoenix e OpenTelemetry GenAI semantic conventions. Esempi di codice Python pronti per la produzione.

Osservabilità LLM 2026: Guida Langfuse

Aggiornato: 9 giugno 2026

L'osservabilità LLM è la pratica di tracciare, valutare e monitorare ogni chiamata a un modello linguistico in produzione (input, output, latenza, costo, qualità) per scoprire regressioni, allucinazioni e drift prima che colpiscano gli utenti. Nel 2026 lo stack di riferimento ruota attorno a tre pilastri: tracing distribuito con le semantic conventions GenAI di OpenTelemetry, valutazione continua con LLM-as-judge e ground truth, e monitoraggio di costi e latenza con strumenti come LangSmith, Langfuse e Arize Phoenix. In questa guida ti mostro come implementarli passo passo, con il codice esatto che usiamo nei progetti reali.

  • OpenTelemetry ha stabilizzato le GenAI semantic conventions nel 2026, rendendo i trace LLM portabili fra LangSmith, Langfuse, Phoenix e qualsiasi backend OTLP.
  • Per la maggior parte dei team open-source, Langfuse self-hosted offre il miglior rapporto costo/funzionalità; LangSmith è preferibile se sei già nell'ecosistema LangChain/LangGraph.
  • La valutazione in produzione richiede tre livelli: online evals (LLM-as-judge sul traffico reale), offline evals (dataset di regressione) e guardrail (controlli sincroni sulla risposta).
  • Tracciare token in/out, costo per request e time-to-first-token è obbligatorio: senza queste metriche non si possono ottimizzare prompt, cache o routing fra modelli.
  • Il pattern emergente è la session-level evaluation: si valutano conversazioni multi-turno e traiettorie di agenti, non singole chiamate isolate.
  • Integrare l'osservabilità fin dal primo prototipo evita di dover riscrivere lo strato di logging quando l'app passa in produzione (mi è capitato due volte, non lo consiglio).

Cosa significa osservabilità LLM e perché serve nel 2026

Un'applicazione LLM non è deterministica. Lo stesso prompt può produrre output diversi, e una modifica al system prompt che migliora il 70% dei casi può peggiorare silenziosamente il restante 30%. L'osservabilità LLM è la disciplina che rende visibile questo comportamento: non solo logs e metriche, ma trace strutturati che catturano la catena completa di chiamate dietro ogni risposta, insieme a un giudizio di qualità su quella risposta.

Nel 2026 il problema è amplificato da tre tendenze. Gli agenti multi-step generano traiettorie complesse con decine di tool call per singola richiesta utente, le pipeline RAG introducono retrieval che può fallire silenziosamente, e i router multi-modello (instradare a Claude Haiku 4.5 o Opus 4.8 in base al task) rendono il costo per request molto variabile. Senza osservabilità, queste architetture sono scatole nere.

Una definizione operativa che uso spesso in workshop: hai osservabilità LLM se puoi rispondere a queste cinque domande senza riprodurre il bug. (1) Qual è stato l'input esatto? (2) Quale modello, versione di prompt e parametri sono stati usati? (3) Quali tool sono stati chiamati, e in che ordine? (4) Quanto è costata e quanto è durata la request? (5) La risposta era buona, e secondo quale metrica?

I tre pilastri: tracing, valutazione, monitoraggio

Pensa all'osservabilità LLM come a tre livelli sovrapposti, ognuno con uno scopo diverso e strumenti distinti.

1. Tracing distribuito

Cattura la struttura ad albero di ogni request: span padre per la sessione utente, span figli per ogni chiamata LLM, retrieval vettoriale, tool execution. Ogni span porta attributi standardizzati: gen_ai.system, gen_ai.request.model, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens. Il tracing risponde a "cosa è successo?".

2. Valutazione

Assegna un punteggio di qualità alle risposte. Si divide in offline (dataset di regressione, eseguito in CI quando cambia un prompt) e online (LLM-as-judge che scora un campione del traffico produzione). Risponde a "era una buona risposta?".

3. Monitoraggio

Aggrega metriche in dashboard: p50/p95/p99 di latenza, costo per utente, tasso di errore, drift della distribuzione di input. Risponde a "sta funzionando bene nel complesso?".

Errore comune (l'ho commesso anch'io al primo progetto): implementare solo il primo pilastro. Avere trace senza valutazione significa avere registrazioni di problemi che non si sa di avere. Avere valutazione senza monitoraggio significa scoprire regressioni a campione invece che in aggregato.

LangSmith vs Langfuse vs Arize Phoenix: quale scegliere

I tre strumenti dominanti nel 2026 hanno filosofie diverse. Questa tabella sintetizza le differenze che contano davvero nella scelta.

Caratteristica LangSmith Langfuse Arize Phoenix
LicenzaSaaS proprietarioMIT (self-host) + cloudApache 2.0 + cloud
Integrazione nativaLangChain, LangGraphSDK Python/JS, OpenTelemetryOpenTelemetry-first
Self-hostingEnterprise onlySì, Docker ComposeSì, container singolo
Prompt managementOttimo (versioning + playground)Ottimo (versioning + A/B)Base
Dataset & evalsMaturo, integratoMaturo, integratoMaturo, focus ML
Costo (10M span/mese)~$500–1500$0 self-host / ~$199 cloud$0 self-host
Quando sceglierloStack 100% LangChainDefault open-sourceTeam già su Arize/OTel

La regola pratica che applichiamo in produzione: se il team lavora già con LangGraph e ha budget SaaS, LangSmith riduce il time-to-value. Per tutti gli altri, Langfuse self-hosted è il default: SDK stabile, prompt management eccellente, costo zero. Phoenix brilla nelle organizzazioni che hanno già un investimento in OpenTelemetry e vogliono uniformare tracing ML e LLM nello stesso backend (Grafana, Datadog, Honeycomb).

OpenTelemetry GenAI semantic conventions in pratica

Nel 2026 le GenAI semantic conventions di OpenTelemetry sono uscite dallo stato sperimentale per gli attributi core, e i trace LLM sono finalmente portabili. Tradotto: strumenti l'app una volta e cambi backend (da Langfuse a Phoenix a Datadog) senza riscrivere codice. Un'assicurazione utile, in un mercato che si muove veloce. La specifica definisce attributi standard come gen_ai.system, gen_ai.request.model, gen_ai.response.id e nomi di span tipo chat {model} ed execute_tool {name}.

Esempio minimale di strumentazione manuale con il Python SDK su una chiamata Claude:

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from anthropic import Anthropic

trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(
    BatchSpanProcessor(OTLPSpanExporter(endpoint="https://cloud.langfuse.com/api/public/otel/v1/traces"))
)
tracer = trace.get_tracer("ai-workflow-lab.demo")
client = Anthropic()

def answer(question: str) -> str:
    with tracer.start_as_current_span("chat claude-sonnet-4-6") as span:
        span.set_attribute("gen_ai.system", "anthropic")
        span.set_attribute("gen_ai.request.model", "claude-sonnet-4-6")
        span.set_attribute("gen_ai.request.temperature", 0.2)
        span.set_attribute("gen_ai.prompt.0.role", "user")
        span.set_attribute("gen_ai.prompt.0.content", question)

        resp = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            temperature=0.2,
            messages=[{"role": "user", "content": question}],
        )

        span.set_attribute("gen_ai.response.id", resp.id)
        span.set_attribute("gen_ai.usage.input_tokens", resp.usage.input_tokens)
        span.set_attribute("gen_ai.usage.output_tokens", resp.usage.output_tokens)
        return resp.content[0].text

Implementare tracing end-to-end con Langfuse

Vediamo il setup completo per una pipeline RAG con tracing nidificato. Una funzione utente chiama un retriever, poi un LLM, poi una post-elaborazione. Tutti gli step appaiono in un unico trace gerarchico, e Langfuse calcola automaticamente costo e durata cumulati.

from langfuse import Langfuse, observe
from langfuse.openai import openai  # wrapper auto-instrumentato

langfuse = Langfuse(
    public_key="pk-lf-...",
    secret_key="sk-lf-...",
    host="https://cloud.langfuse.com",
)

@observe(name="retrieve-context")
def retrieve(query: str, k: int = 5) -> list[str]:
    # qui chiamata al vector DB; il decoratore traccia input/output/durata
    results = vector_store.similarity_search(query, k=k)
    return [r.page_content for r in results]

@observe(name="generate-answer")
def generate(query: str, context: list[str]) -> str:
    system = "Rispondi solo usando il contesto fornito. Cita le fonti."
    user = f"Contesto:\n{chr(10).join(context)}\n\nDomanda: {query}"
    resp = openai.chat.completions.create(
        model="gpt-4.1",
        messages=[{"role": "system", "content": system},
                  {"role": "user", "content": user}],
        temperature=0.1,
    )
    return resp.choices[0].message.content

@observe(name="rag-pipeline")
def answer_question(query: str, user_id: str) -> str:
    langfuse.update_current_trace(user_id=user_id, tags=["prod", "rag-v2"])
    context = retrieve(query)
    return generate(query, context)

# uso
answer_question("Qual è il piano gratuito?", user_id="user_42")
langfuse.flush()

Il risultato in Langfuse è un trace gerarchico: rag-pipeline come root, retrieve-context e generate-answer come figli, con la chiamata OpenAI annidata sotto generate-answer grazie al wrapper. Costo e token sono calcolati in automatico. Per integrare questo pattern in un'architettura di agenti IA con LangGraph e MCP, basta avvolgere ogni nodo del grafo nel decoratore @observe.

Valutazione automatica con LLM-as-judge

Una volta che i trace fluiscono, il passo successivo è assegnare loro un punteggio di qualità. La tecnica standard nel 2026 è LLM-as-judge: usare un modello forte (tipicamente Claude Opus 4.8 o GPT-4.1) per scorare l'output di un modello più economico secondo criteri espliciti. Funziona meglio di metriche statistiche come BLEU/ROUGE perché valuta semantica e fedeltà, non sovrapposizione di token.

Esempio di evaluator per fedeltà (faithfulness) di una risposta RAG rispetto al contesto recuperato:

FAITHFULNESS_PROMPT = """Sei un valutatore. Dato un CONTESTO e una RISPOSTA,
determina se la risposta è completamente supportata dal contesto.
Rispondi SOLO con JSON: {"score": 0|1, "reasoning": "..."}.
Score 1 = ogni affermazione è supportata. Score 0 = c'è almeno un'allucinazione.

CONTESTO:
{context}

RISPOSTA:
{answer}
"""

@observe(name="eval-faithfulness")
def score_faithfulness(trace_id: str, context: str, answer: str) -> dict:
    judge = openai.chat.completions.create(
        model="claude-opus-4-8",  # via gateway OpenAI-compatible
        messages=[{"role": "user",
                   "content": FAITHFULNESS_PROMPT.format(context=context, answer=answer)}],
        response_format={"type": "json_object"},
        temperature=0,
    )
    result = json.loads(judge.choices[0].message.content)
    langfuse.score(
        trace_id=trace_id,
        name="faithfulness",
        value=result["score"],
        comment=result["reasoning"],
    )
    return result

Esegui questo evaluator su un campione del 5–10% del traffico produzione (online eval) e sul 100% di un dataset di regressione (offline eval) ad ogni cambio di prompt. Le tecniche di prompt engineering avanzato con DSPy e output strutturati sono particolarmente utili per costruire judge affidabili, perché lo schema JSON forzato riduce drasticamente il rumore nel punteggio.

Monitorare costi, latenza e token in produzione

I trace e i punteggi popolano le dashboard. Le metriche minime da tenere sotto controllo settimanalmente sono queste:

  • Costo per request p50/p95: identifica regressioni quando un prompt cresce o un modello costoso viene usato per task semplici.
  • Token di output medio per intent: spesso si scopre che il 90% del costo viene da risposte troppo verbose, risolvibile con un'istruzione di sintesi.
  • Time to first token (TTFT) e tokens per second: critici per UX di streaming. Un TTFT > 2s su mobile fa abbandonare gli utenti.
  • Tasso di errore diviso per tipo: rate limit, timeout, validation error sui tool, refusal del modello.
  • Distribuzione dei modelli: se il router decide quale modello usare, monitora la percentuale di richieste che finiscono sul modello premium. Un drift verso l'alto indica un cambio nella distribuzione di input o un bug nel routing.
  • Score di qualità nel tempo: il dato più importante. Una flessione dello score medio a fronte di latenza e costo stabili è una regressione di qualità silenziosa, esattamente il tipo di problema che senza osservabilità scopri solo dai reclami utente.

Configura alert su deviazioni p95 da baseline a 7 giorni, non su soglie assolute. Le soglie assolute generano falsi positivi quando il traffico cambia, e quando i falsi positivi diventano la norma il team smette di guardare gli alert. Onestamente, è uno dei modi più rapidi per rendere inutile una dashboard.

Osservabilità per agenti multi-step e pipeline RAG

Gli agenti rompono il modello "una request = una chiamata LLM". Un singolo turno utente può generare 10–30 chiamate LLM, 5 tool call e 3 retrieval. Il pattern di osservabilità giusto è la session-level evaluation: invece di valutare singole chiamate, si valuta l'intera traiettoria (la domanda originale, gli step intermedi, la risposta finale) come unità.

Tre metriche specifiche per agenti che vale la pena tracciare:

  1. Step count: numero di iterazioni del ciclo ReAct/planner. Se cresce nel tempo, l'agente sta diventando indeciso (spesso un sintomo di prompt o tool description peggiorati).
  2. Tool success rate: percentuale di tool call che ritornano senza errore. Un calo indica drift dello schema di un tool o un servizio esterno degradato.
  3. Goal completion rate: valutato da un judge che riceve la domanda originale e la risposta finale. È la metrica nord-stella di un agente.

Per pipeline RAG, le metriche analoghe sono context precision (quanti dei chunk recuperati erano effettivamente rilevanti), context recall (quanto dell'informazione necessaria era presente nei chunk) e answer faithfulness. Sono lo stesso framework di valutazione descritto nella nostra guida completa alle pipeline RAG di produzione 2026, e si integrano nativamente con Langfuse e LangSmith tramite SDK come RAGAS. Se gestisci anche il deploy degli strumenti che chiamano questi modelli, vale la pena dare un'occhiata alla guida MCP in produzione con OAuth 2.1: le sue convenzioni di tracing combaciano con quelle viste qui.

Errori comuni da evitare

Cinque pattern che vediamo ripetersi nei progetti che iniziano l'osservabilità in ritardo:

  1. Loggare prompt e completion in log testuali invece che in trace strutturati. Rende impossibile filtrare, aggregare e correlare. Usa sempre uno strumento di tracing dedicato.
  2. Tracciare solo le chiamate LLM ignorando retrieval e tool. La maggior parte dei bug RAG vive nel retrieval, non nel modello.
  3. Confondere logs e evals. Avere i trace non significa sapere se le risposte sono buone. Servono entrambi.
  4. Salvare PII in chiaro. Configura masking lato SDK (Langfuse e LangSmith lo supportano) prima del primo deploy produzione, non dopo.
  5. Non versionare i prompt. Senza versioning non puoi correlare una regressione di score a un cambio specifico. Usa il prompt management integrato (LangSmith Hub, Langfuse Prompts) o git, ma scegli e applica una disciplina.

Per approfondire le specifiche tecniche, consulta la documentazione ufficiale OpenTelemetry GenAI semantic conventions, la documentazione Langfuse e la guida LangSmith.

Domande Frequenti

Qual è la differenza tra osservabilità LLM e logging tradizionale?

Il logging tradizionale produce stringhe testuali immutabili e non correlate. L'osservabilità LLM produce trace strutturati gerarchici, con attributi standardizzati (token, costo, modello), correlazione automatica fra step e la possibilità di assegnare punteggi di qualità a posteriori. È una superset, non un'alternativa.

Quanto costa fare osservabilità LLM in produzione?

Con Langfuse o Phoenix self-hosted il costo infrastrutturale è basso: ~$50–200/mese per Postgres e qualche worker fino a 10M span/mese. Il SaaS LangSmith parte da circa $39/utente al mese e scala con il volume; Langfuse cloud Pro è ~$199 forfettario. Il costo dominante è quasi sempre il modello judge, non il backend di tracing.

Posso usare OpenTelemetry per LLM senza un backend specializzato?

Sì: gli attributi GenAI vanno in qualsiasi backend OTLP (Datadog, Honeycomb, Grafana Tempo, Jaeger). Perdi però le viste UI specifiche per LLM, come diff di prompt, playground per replay e dataset di eval. Pattern ibrido: invia gli stessi span a entrambi i backend, uno per APM generale, uno per analisi LLM dedicata.

Quanto traffico devo campionare per la valutazione LLM-as-judge?

Per dashboard di trend bastano il 5–10% delle richieste. Per debugging di edge case alza al 100% temporaneamente su segmenti specifici (utente, intent, modello). Calcola il costo: judge a $15/M token su risposte medie di 500 token significa circa $0.01 a valutazione, sostenibile fino a centinaia di migliaia di chiamate al giorno.

Come gestisco i dati sensibili (PII) nei trace?

Configura il masking lato SDK prima dell'invio: Langfuse offre un parametro mask sul client, LangSmith ha hide_inputs/hide_outputs. Per regex PII affidabili affidati a librerie come Microsoft Presidio. In alternativa, self-host il backend nello stesso perimetro di rete del modello: i dati non lasciano mai l'infrastruttura.

Editorial Team
Sull'Autore Editorial Team

Our team of expert writers and editors.