loading experience
Progettazione · Il motore · DesireeIA

CORE — Il motore d'inferenza proprietario: perché la sovranità del codice è la vera chiave dell'IA

Non una scatola nera: un motore che controlliamo.

Il nostro motore d'inferenza locale, scritto in C++17 con ABI C e wrapper .NET e Python: controllo totale dell'intera catena di esecuzione, dal file del modello al token.

Scorri per esplorare
Il principio

Consumatori di API o proprietari del motore?

In un panorama dominato da soluzioni "chiavi in mano" e framework preconfezionati, la maggior parte delle aziende si limita ad agire da mero consumatore di API. L'illusione di velocità iniziale si paga nel lungo periodo.

Per noi l'IA non può essere una scatola nera senza leve di ottimizzazione. Per questo abbiamo scelto la strada più complessa, ma l'unica sostenibile per il futuro enterprise: progettare e sviluppare il nostro motore d'inferenza locale, DesireeIA.

Consumatore di API
  • Perdita di controllo sul processo
  • Latenza imprevedibile
  • Dipendenza da runtime terzi opachi
  • Costi infrastrutturali fuori controllo
Motore proprietario
  • Controllo dell'intera catena di esecuzione
  • Profilo di latenza costante e prevedibile
  • Codice nostro, ottimizzabile a ogni livello
  • Dati e modelli sul tuo hardware
01 · La nostra visione

Perché creare un motore d'inferenza proprietario

Nasce da una precisa esigenza strategica e ingegneristica: il controllo totale dell'intera catena di esecuzione.

A Ottimizzazione hardware e portabilità estrema

CPU con istruzioni SIMD

Sfruttamento nativo di AVX2 e AVX-512 su x86_64, e di ARM NEON/SVE su Apple Silicon e sistemi edge.

GPU discrete ed embedded

Accelerazione diretta tramite API moderne (CUDA, Vulkan, Metal): schede enterprise, server cloud o dispositivi periferici a basso consumo.

Efficienza di rete

Dati scambiati ridotti al minimo con serializzazione binaria ottimizzata, per architetture distribuite e edge-computing.

B Niente garbage collection: determinismo

I framework in linguaggi con gestione automatica della memoria introducono pause imprevedibili durante l'inferenza e picchi di latenza incoerenti (jitter). Con il core in C++ nativo l'allocazione è deterministica: zero pause impreviste e un profilo di latenza costante.

02 · Come funziona

Che cos'è un motore d'inferenza

Il runtime che carica in memoria i parametri di un modello (pesi), riceve una sequenza di input (prompt) ed esegue le operazioni di algebra lineare necessarie a generare l'output token per token.

Testo di inputTokenizerToken IDsEmbedding + RoPE
Transformer · N layer
  1. RMSNorm / LayerNorm
  2. Self-Attention (Q, K, V)
  3. Connessione residua
  4. Feed-Forward (SwiGLU)
KV Cache letta e scritta a ogni layer
RMSNorm finaleOutput Head / LogitsSampler Temp · Top-PDetokenizer → testo

il token generato rientra come input del passo successivo

A

Cosa sono i pesi (weights)

Variabili matematiche apprese durante l'addestramento: la "conoscenza" memorizzata nelle matrici di attenzione e nei layer feed-forward. In FP16 ogni peso occupa 2 byte. La quantizzazione (GGUF in INT8, INT4 o K-quant) lo comprime a 8, 4 o persino 2 bit: meno memoria, più velocità sul bus.

Mpesi = P × b / 8
FP16
16,1 GB
INT8 (Q8_0)
8,5 GB
Q4_K_M
4,9 GB
Q2_K
2,6 GB

Esempio: Llama 3.1 8B (8,03 miliardi di parametri); bit effettivi per peso, scale incluse.

B

Il formato GGUF e la generazione dei token

GGUF è un contenitore binario che memorizza in un unico file sia i metadati dell'architettura (numero di layer, teste d'attenzione, dimensione del contesto) sia i pesi in blocchi quantizzati e allineati.

  1. Parsing & mmap il file è mappato nello spazio di indirizzamento virtuale.
  2. Tokenizzazione il testo diventa un vettore di Token IDs.
  3. Prefill tutti i token del prompt attraversano i layer in parallelo e popolano la KV Cache.
  4. Generazione autoregressiva il modello calcola i Logits; il Sampler (temperatura, Top-P, Top-K, Min-P) sceglie il token; il Detokenizer lo converte in testo e lo reimmette come input.
03 · Architettura

L'architettura di DesireeIA a tre livelli

Una rigorosa stratificazione per coniugare le prestazioni del codice nativo con la flessibilità dei linguaggi ad alto livello.

Applicazioni enterprise.NET / C# AppPython Script / Agent
Wrapper idiomatici.NET (binding nativo)Python
ABI / InteropC ABI · extern "C"
Core nativoC++17 Engine
  • GGUF Parser & mmap Loader
  • Memory & Tensor Manager
  • KV Cache Controller
  • Hardware Offloader (CUDA / CPU)

Core nativo C++17

Il motore matematico ed esecutivo: memoria, caricamento dei GGUF, calcolo tensoriale, vettorizzazione SIMD e controllo hardware diretto.

Interfaccia C ABI

Un'interfaccia C pura (extern "C") elimina il name mangling del C++ e garantisce stabilità binaria tra compilatori e runtime, con interoperabilità a zero overhead.

Wrapper .NET e Python

API orientate agli oggetti, asincrone e idiomatiche sopra l'ABI C, senza sacrificare la velocità di esecuzione sottostante.

04 · Risorse hardware

Disco, RAM e VRAM

Uno degli aspetti più critici di un motore locale è la ripartizione strategica delle risorse tra disco, RAM di sistema e VRAM della scheda video.

  1. File GGUF su discommap zero-copy
  2. RAM di sistemalayer CPU · contesto
  3. Offloading dinamicoPCIe
  4. VRAM GPUlayer GPU · KV cache
A

Disco e mappatura di memoria (mmap)

Invece di leggere il GGUF e copiarlo sequenzialmente in RAM con I/O tradizionale (spreco di memoria e di tempo), il motore usa mmap: il sistema operativo mappa i blocchi del file nello spazio di memoria virtuale e li legge zero-copy solo quando servono. L'avvio è quasi istantaneo.

B

RAM di sistema (host memory)

  • Struttura del contesto e metadati del modello
  • Layer che non entrano nella VRAM
  • Backup della KV Cache con contesti molto lunghi
C

VRAM e layer offloading

La VRAM offre una banda di memoria enormemente superiore a quella della RAM di sistema. Il motore può dividere i layer: con 8 GB di VRAM e un modello da 12 GB, ne carica ad esempio 20 sulla GPU e lascia gli altri 12 sulla CPU.

La CPU elabora i primi layer, passa lo stato intermedio alla VRAM via PCIe e la GPU completa il forward pass. Modello da 12 GB su 32 layer = 0,375 GB per layer.

VRAM
~1.000 GB/s
RAM di sistema
60-100 GB/s
05 · Contesto e prestazioni

Contesto, KV Cache e dinamica delle prestazioni

Per capire perché le prestazioni cambiano durante l'esecuzione servono due concetti: la finestra di contesto e la KV Cache.

A

La finestra di contesto

La lunghezza massima della sequenza (prompt + risposte precedenti) che il modello elabora in un singolo passo. Poiché la Self-Attention mette in relazione ogni token con tutti i precedenti, la complessità teorica è quadratica:

O(N2)

N = lunghezza del contesto.

B

KV Cache

Per non ricalcolare l'attenzione di tutti i token passati a ogni passo, i vettori Key e Value di ogni layer vengono salvati in memoria: per il token N+1 il motore calcola K e V solo del nuovo token e recupera gli altri dalla cache. Il costo in memoria cresce linearmente col contesto:

MKV = 2 × L × hkv × d × N × b

Llama 3.1 8B: L = 32, h_kv = 8, d = 128, b = 2 byte (FP16) → 128 KiB / token

KV Cache contro pesi del modello (GB)

Pesi Q4_K_M
4,9 GB
KV · 4k token
0,5 GB
KV · 32k token
4,3 GB
KV · 128k token
17,2 GB

Oltre circa 37.141 token la KV Cache supera la dimensione dei pesi stessi.

Perché le prestazioni cambiano: compute-bound contro memory-bound

Fase 1 · Prefill

Compute-bound

Lettura del prompt: centinaia o migliaia di token elaborati in parallelo (moltiplicazione matrice-matrice, GEMM). Servono enormi quantità di operazioni in virgola mobile: il limite è la potenza di calcolo. Determina il Time To First Token (TTFT).

Core di calcolo100%
Bus di memorialibero
Fase 2 · Generazione

Memory-bandwidth bound

Un token alla volta (moltiplicazione matrice-vettore, GEMV): per ogni token il motore legge l'intera matrice dei pesi, gigabyte di dati, dalla VRAM/RAM. I core aspettano i dati dal bus. Determina la velocità continua, in Tokens Per Second (TPS).

Core di calcoloin attesa
Bus di memoria100%
Limite superiore della velocità di generazione
TPSmax ≈ BW / (Mpesi + MKV(N))
N = 0
205
16
N = 8k
168
13
N = 32k
109
9
N = 128k
45
4
VRAM 1.000 GB/sRAM 80 GB/s

Token al secondo teorici per Llama 3.1 8B in Q4_K_M: è un limite fisico di banda, non una misura. Più il contesto cresce, più la KV Cache aumenta i dati da leggere per token e i TPS scendono, mentre l'occupazione di VRAM/RAM sale.

DesireeIA

Intervenire su ogni variabile del ciclo.

Dall'allocazione della KV Cache alla gestione millimetrica degli stream di calcolo: prestazioni di livello enterprise, sicurezza dei dati ed efficienza.