Salta al contenuto principale

01 - System Design GenAI: Fondamenti e Architetture per Applicazioni in Produzione

System Design GenAI: Fondamenti e Architetture per Applicazioni in Produzione Stai cercando di integrare un LLM nella tua applicazione e ti chiedi se fare...

Cosa ne pensi di questo articolo?

01 - System Design GenAI: Fondamenti e Architetture per Applicazioni in Produzione
System Design GenAIFoto:Tara WinsteadPexels

In Breve

System Design GenAI: Fondamenti e Architetture per Applicazioni in Produzione Stai cercando di integrare un LLM nella tua applicazione e ti chiedi se fare...

System Design GenAI: Fondamenti e Architetture per Applicazioni in Produzione

Stai cercando di integrare un LLM nella tua applicazione e ti chiedi se fare RAG, fine-tuning o semplicemente migliorare i prompt? Non sei il solo: secondo un'analisi di 2024, il 73% dei deployment GenAI in enterprise fallisce entro sei mesi, principalmente per scelte architetturali sbagliate nelle fasi iniziali di progettazione. Il problema non e il modello: e che molti team scelgono la tecnologia prima di capire il problema.

Questa guida ti fornisce un framework decisionale pratico per progettare sistemi GenAI in produzione, coprendo le architetture fondamentali - RAG, fine-tuning, prompt engineering - e i criteri per scegliere l'approccio giusto in base al tuo caso d'uso specifico.

Cosa Imparerai

  • Le tre architetture fondamentali: RAG, fine-tuning e prompt engineering
  • Framework decisionale: quando usare ciascun approccio
  • Architetture di sistema per applicazioni GenAI in produzione
  • Stack tecnologico 2026: LangChain, LlamaIndex, vLLM
  • Pattern comuni e anti-pattern da evitare
  • Metriche di qualita per valutare un sistema RAG

Il Problema del 73%: Perche i Deployment GenAI Falliscono

Prima di entrare nelle architetture, e cruciale capire perche cosi tanti progetti falliscono. Le cause principali identificate nelle post-mortem di deployment enterprise sono:

  • Hallucination non gestita: il modello genera risposte plausibili ma false, e nessun sistema di validazione e stato implementato
  • Latenza inaccettabile: p99 oltre i 3-5 secondi su query che l'utente si aspetta veloci
  • Costi esplosivi: nessun calcolo del costo per query prima del go-live, poi il budget viene bruciato in settimane
  • Knowledge cutoff non gestito: il modello non conosce dati recenti o privati dell'azienda
  • Mancanza di tracciabilita: impossibile sapere su quali documenti si basa una risposta (critico in contesti regolamentati)

Ogni architettura che esamineremo affronta alcuni di questi problemi meglio di altri. Conoscere i trade-off ti permette di progettare sistemi robusti fin dall'inizio.

Le Tre Architetture Fondamentali

1. Prompt Engineering

Il punto di partenza per qualsiasi sistema GenAI: strutturare il prompt per guidare il modello verso l'output desiderato. Tecniche chiave nel 2026:

  • Few-shot prompting: fornire esempi input-output nel prompt
  • Chain-of-thought (CoT): chiedere al modello di ragionare step-by-step prima di rispondere
  • System prompt: definire il comportamento e il contesto del modello
  • Structured output: forzare l'output in formato JSON o XML per parsing affidabile
# Esempio: prompt engineering con structured output
import json
from openai import OpenAI

client = OpenAI()

def analyze_ticket(ticket_text: str) -> dict:
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": """Sei un sistema di triage per ticket di supporto.
Analizza il ticket e restituisci JSON con:
- priority: "high" | "medium" | "low"
- category: "bug" | "feature" | "question"
- sentiment: "frustrated" | "neutral" | "positive"
- estimated_resolution_hours: numero intero"""
            },
            {
                "role": "user",
                "content": f"Ticket: {ticket_text}"
            }
        ],
        response_format={"type": "json_object"}
    )
    return json.loads(response.choices[0].message.content)

# Uso
result = analyze_ticket("Il mio account e bloccato da ieri, non riesco ad accedere!")
# {"priority": "high", "category": "bug", "sentiment": "frustrated", ...}

Quando usarlo: casi semplici e ben definiti, prototipazione rapida, quando non hai dati privati da integrare e il modello base gia conosce il dominio.

Limiti: non funziona con dati recenti o proprietari, hallucination su fatti specifici, costo proporzionale alla lunghezza del contesto.

2. RAG - Retrieval-Augmented Generation

RAG risolve il problema del knowledge cutoff e dei dati privati: invece di affidarsi solo alla conoscenza del modello, recupera documenti rilevanti da un database e li inserisce nel contesto prima della generazione.

L'architettura base di un sistema RAG ha quattro fasi:

  1. Indexing: i documenti vengono suddivisi in chunk, convertiti in vettori embedding e salvati in un vector database
  2. Retrieval: la query dell'utente viene convertita nello stesso spazio embedding e si recuperano i chunk piu simili
  3. Augmentation: i chunk recuperati vengono inseriti nel prompt come contesto
  4. Generation: il LLM genera la risposta basandosi sul contesto fornito
# RAG minimo funzionante con LangChain e Qdrant
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_qdrant import QdrantVectorStore
from langchain.chains import RetrievalQA
from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

# 1. Carica e chunka i documenti
loader = PyPDFLoader("manuale_prodotto.pdf")
docs = loader.load()

splitter = RecursiveCharacterTextSplitter(
    chunk_size=512,
    chunk_overlap=64
)
chunks = splitter.split_documents(docs)

# 2. Crea il vector store
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = QdrantVectorStore.from_documents(
    documents=chunks,
    embedding=embeddings,
    url="http://localhost:6333",
    collection_name="manuale_prodotto"
)

# 3. Crea la chain RAG
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
retriever = vectorstore.as_retriever(search_kwargs={"k": 5})

rag_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=retriever,
    return_source_documents=True
)

# 4. Query
result = rag_chain.invoke({"query": "Come configuro le notifiche email?"})
print(result["result"])
# La risposta cita i documenti recuperati, non inventa

Quando usarlo: knowledge base aziendale, documentazione tecnica, FAQ, qualsiasi caso dove la risposta deve basarsi su documenti specifici e tracciabili.

Limiti: qualita dipendente dalla qualita del retrieval, latenza aggiuntiva, overhead di infrastruttura.

3. Fine-tuning

Il fine-tuning adatta il comportamento del modello attraverso addestramento aggiuntivo su dati specifici del dominio. Nel 2026, il paradigma dominante e il Parameter-Efficient Fine-tuning (PEFT) con tecniche come LoRA e QLoRA che permettono di addestrare su hardware consumer.

# Fine-tuning con LoRA usando transformers e PEFT
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import LoraConfig, get_peft_model, TaskType
import torch

model_name = "meta-llama/Llama-3.1-8B-Instruct"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(
    model_name,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)

# Configurazione LoRA: adatta solo il 0.1% dei parametri
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=16,           # rank della matrice di adattamento
    lora_alpha=32,  # scaling factor
    lora_dropout=0.1,
    target_modules=["q_proj", "v_proj", "k_proj", "o_proj"]
)

model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 6,815,744 || all params: 8,037,191,680
# trainable%: 0.0848%

Quando usarlo: quando hai migliaia di esempi di addestramento, serve un formato di output molto specifico e consistente, o vuoi ridurre la lunghezza del prompt eliminando esempi few-shot.

Anti-pattern critico: non fare fine-tuning per iniettare conoscenza fattuale (date, numeri, fatti specifici). Il modello "memorizza" senza comprensione e hallucinera comunque. Per la conoscenza usa RAG.

Il Framework Decisionale

La domanda piu importante non e "quale tecnologia usare" ma "qual e il mio problema reale". Questo decision tree copre il 90% dei casi d'uso:

Hai dati privati o recenti che il modello non conosce?
  SI  --> Considera RAG come base
  NO  --> Prompt engineering puo essere sufficiente

Il tuo knowledge base e aggiornato frequentemente?
  SI  --> RAG (indicizza i nuovi documenti, non ri-addestra)
  NO  --> Fine-tuning puo essere considerato

Hai 1000+ esempi di coppie input-output di alta qualita?
  SI  --> Fine-tuning e un'opzione valida
  NO  --> Stai nei limiti di RAG + few-shot

Hai bisogno di tracciabilita (citare le fonti)?
  SI  --> RAG obbligatorio
  NO  --> Piu flessibilita

Latenza critica (sotto 500ms)?
  SI  --> Fine-tuning (elimina retrieval overhead) o caching aggressivo
  NO  --> RAG funziona bene

Conclusione tipica 2026:
  Start with RAG + prompt engineering
  Add fine-tuning solo se RAG non raggiunge qualita richiesta

Architettura di Sistema per Produzione

Un sistema GenAI production-grade va ben oltre il semplice "LLM + vector database". I componenti necessari per un deployment serio:

# Stack minimo per RAG in produzione (Docker Compose)
services:
  api:
    image: your-genai-api:latest
    environment:
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      QDRANT_URL: http://qdrant:6333
      REDIS_URL: redis://redis:6379
    depends_on:
      - qdrant
      - redis

  qdrant:
    image: qdrant/qdrant:v1.9.0
    volumes:
      - qdrant_storage:/qdrant/storage
    ports:
      - "6333:6333"

  redis:
    image: redis:7-alpine
    # Semantic cache: evita LLM calls per query simili
    volumes:
      - redis_data:/data

  prometheus:
    image: prom/prometheus:latest
    # Monitora: latency p50/p95/p99, costo per query, quality score

  grafana:
    image: grafana/grafana:latest
    # Dashboard: LLM performance, retrieval quality, cost tracking

I componenti critici che separano un prototipo da un sistema in produzione:

  • Semantic caching (Redis + libreria come GPTCache): riduce i costi del 30-60% per applicazioni con query simili ricorrenti
  • Observability: traccia ogni chiamata LLM con latenza, tokens usati, costo e quality score - senza questi dati non puoi ottimizzare
  • Fallback strategy: cosa succede quando OpenAI e down? Hai un modello locale come backup?
  • Rate limiting e quota management: proteggi il tuo budget dalle query anomale
  • PII detection: prima di mandare dati al LLM, rileva e oscura dati personali sensibili

Lo Stack Tecnologico del 2026

L'ecosistema GenAI si e stabilizzato intorno a pochi player dominanti:

Stack Consigliato 2026

  • Orchestrazione: LangChain v0.3+ o LlamaIndex v0.10+ per pipeline RAG complesse; LangGraph per workflow agentici
  • Vector Database: Qdrant (self-hosted, eccellente performance), pgvector (gia in PostgreSQL, sotto 1M vettori), Pinecone (managed, latenza garantita)
  • Inference: vLLM o TensorRT-LLM per modelli open source self-hosted; OpenAI/Anthropic per API cloud
  • Embeddings: text-embedding-3-small di OpenAI (1536 dim, $0.02/1M token) o all-MiniLM-L6-v2 per self-hosting gratuito
  • Observability: LangSmith, Weights & Biases Weave, o Phoenix per tracing delle chain
  • Evaluation: RAGAS per metriche RAG automatizzate (faithfulness, answer relevancy, context recall)

Metriche di Qualita per Sistemi RAG

Come sapere se il tuo sistema RAG funziona bene? Il framework RAGAS definisce metriche misurabili:

# Valutazione automatica con RAGAS
from ragas import evaluate
from ragas.metrics import (
    faithfulness,        # la risposta e supportata dai documenti recuperati?
    answer_relevancy,    # la risposta risponde alla domanda?
    context_recall,      # i documenti recuperati contengono le info necessarie?
    context_precision    # i documenti recuperati sono tutti rilevanti?
)
from datasets import Dataset

# Dataset di test (ground truth necessario)
test_data = {
    "question": ["Come configuro l'autenticazione 2FA?"],
    "answer": ["Per configurare 2FA, vai in Impostazioni > Sicurezza..."],
    "contexts": [["Documentazione 2FA: ...", "Guida sicurezza: ..."]],
    "ground_truth": ["La 2FA si configura tramite l'app mobile nelle impostazioni sicurezza"]
}

dataset = Dataset.from_dict(test_data)
result = evaluate(dataset, metrics=[
    faithfulness,
    answer_relevancy,
    context_recall,
    context_precision
])

print(result)
# faithfulness: 0.95     (la risposta non inventa)
# answer_relevancy: 0.88 (la risposta e pertinente)
# context_recall: 0.82   (i doc recuperati coprono la risposta)
# context_precision: 0.91 (i doc recuperati sono rilevanti)

Target realistici per un sistema in produzione: faithfulness > 0.85 (critico: sotto questo soglia le hallucinations sono frequenti), answer_relevancy > 0.80, context_recall > 0.75.

Anti-pattern da Evitare

  • Chunk size fisso per tutti i documenti: documenti strutturati (FAQ, API docs) richiedono chunking diverso da testo narrativo
  • Solo retrieval semantico: fallisce su termini tecnici esatti; usa hybrid search (BM25 + semantico)
  • Nessun reranking: i top-k vettori non sono necessariamente i piu utili; un cross-encoder migliora la precision del 15-20%
  • RAG senza evaluation continua: la qualita si degrada quando i documenti cambiano; monitora faithfulness in produzione
  • Fine-tuning come prima scelta: e costoso e lento; RAG e quasi sempre la mossa giusta per iniziare

Conclusioni e Next Steps

Il sistema design per applicazioni GenAI richiede scelte architetturali che vanno ben oltre la selezione del modello. La regola pratica del 2026: inizia sempre con RAG + prompt engineering, misura la qualita con RAGAS, e aggiungi fine-tuning solo se il gap di qualita persiste dopo l'ottimizzazione del retrieval.

Nei prossimi articoli di questa serie esploreremo ogni componente in dettaglio: la selezione del vector database giusto, le strategie di chunking, l'hybrid search e l'architettura agentica con LangGraph.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti