Come creare un gateway LLM self-hosted con LiteLLM
Configura LiteLLM su un VPS come endpoint compatibile con OpenAI: chiavi virtuali, budget per chiave, fallback tra provider e immagini bloccate.
Cosa fa un gateway LLM self-hosted
LiteLLM è un gateway LLM open source che ospiti autonomamente: un unico endpoint HTTP che tutte le applicazioni utilizzano e che inoltra ogni richiesta al provider responsabile della risposta. LLM significa large language model, ovvero modello linguistico di grandi dimensioni. Il gateway utilizza l'API OpenAI Chat Completions (application programming interface), quindi qualsiasi libreria client che comunica già con OpenAI può utilizzarlo dopo due modifiche: l'URL di base e la chiave.
Questo livello di indirezione è il punto centrale. Le applicazioni non devono più contenere le credenziali dei provider. Per cambiare modello basta modificare una riga nel file di configurazione sul server, invece di cambiare il codice in cinque servizi. Inoltre, poiché ogni chiamata passa dallo stesso processo, hai un punto in cui impostare un budget e registrare quanto è stato speso.
Dopo l'avvio, hai a disposizione:
- Un endpoint unico. Le applicazioni utilizzano
https://gateway.example.com/v1e richiedono un nome modello definito da te, ad esempiobulkostrong. - Chiavi virtuali. Ogni applicazione riceve una chiave separata, con il proprio elenco di modelli consentiti e il proprio limite di spesa. Puoi revocare una chiave senza modificare le altre.
- Fallback. Una chiamata non riuscita o un prompt troppo grande viene ritentato automaticamente con un altro modello.
- Un record nei log. Ogni richiesta scrive una riga con il relativo costo, quindi è possibile sapere quale applicazione ha sostenuto quella spesa.
Perché eseguire autonomamente il gateway
Un router gestito ha la stessa architettura, ma ogni richiesta passa attraverso il processo di un soggetto esterno. Eseguirlo autonomamente consente di mantenere le chiavi del provider e il testo dei prompt su un sistema sotto il proprio controllo. Il costo operativo è reale: ora è necessario gestire il componente da cui dipendono tutte le applicazioni. L’ultima sezione di questa guida tratta proprio questo costo, perché è l’aspetto che la maggior parte delle guide omette.
Requisiti
- Un VPS (virtual private server) con Ubuntu 24.04, Docker e il plugin Compose installati.
- Un nome di dominio che punti al VPS, se macchine esterne devono raggiungere il gateway tramite TLS (transport layer security).
- Almeno una API key del provider.
Il gateway non esegue inferenza. Inoltra le richieste e restituisce le risposte in streaming, quindi il carico della CPU dipende dal volume delle richieste e non dalle dimensioni del modello. Un server con 1 vCPU gestisce senza problemi alcune applicazioni interne. A crescere è il database, perché il gateway registra una riga di spesa per ogni richiesta.
Scrivere prima config.yaml
Il file di configurazione stabilisce quali modelli un client può richiedere. Sono importanti quattro sezioni di primo livello: model_list, litellm_settings, router_settings e general_settings.
model_list:
- model_name: bulk
litellm_params:
model: anthropic/claude-haiku-4-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: anthropic/claude-sonnet-5
api_key: os.environ/ANTHROPIC_API_KEY
- model_name: strong
litellm_params:
model: openai/gpt-5.5
api_key: os.environ/OPENAI_API_KEY
litellm_settings:
num_retries: 2
request_timeout: 120
json_logs: true
set_verbose: false
router_settings:
allowed_fails: 3
cooldown_time: 30
fallbacks: [{"bulk": ["strong"]}]
context_window_fallbacks: [{"bulk": ["strong"]}]
general_settings:
background_health_checks: true
health_check_interval: 300model_name è il nome che i client inviano. litellm_params.model è il modello reale, indicato come provider/model. Assegnare ai modelli un nome basato sul ruolo, non sul fornitore. Un'applicazione che richiede bulk continuerà a funzionare anche se il mese prossimo si decide che bulk debba usare un modello diverso.
api_key: os.environ/ANTHROPIC_API_KEY indica a LiteLLM di leggere quella variabile durante l'esecuzione. La chiave letterale non compare mai nel file. Questo è importante perché config.yaml è il file sottoposto a commit.
Due voci condividono intenzionalmente il nome strong. Quando più deployment hanno lo stesso model_name, il router li tratta come intercambiabili e distribuisce tra loro le richieste per quel nome. In questo modo strong continua a funzionare se un provider attraversa un periodo di problemi: quando un deployment entra in cooldown (come descritto sotto), le nuove richieste per strong vengono inviate all'altro.
num_retries: 2 riprova un errore ritentabile fino a due volte. I retry possono selezionare un altro deployment disponibile nello stesso gruppo di modelli: la documentazione sull'architettura di LiteLLM, verificata il 2026-10-29, descrive i retry all'interno del gruppo e i fallback tra gruppi come passaggi separati. Un retry per strong può quindi raggiungere l'altro provider senza abilitare il failover con pesatura. Un fallback viene attivato solo dopo aver esaurito questi retry.
allowed_fails e cooldown_time sono opzioni del router, quindi devono trovarsi sotto router_settings. Il proxy crea il router a partire da quella sezione e, nella v1.95.0, un cooldown_time scritto sotto litellm_settings non lo raggiunge mai. Di conseguenza, i cooldown restano silenziosamente al valore predefinito di 5 secondi. cooldown_time: 30 imposta per quanto tempo un deployment resta escluso dalla rotazione dopo essere entrato in cooldown. Il riferimento della configurazione descrive allowed_fails come il numero di errori che un deployment deve superare entro cooldown_time prima di entrare in cooldown. Nel codice sorgente della v1.95.0, allowed_fails: 3 è il valore predefinito. Con il valore predefinito, il router usa i trigger integrati; il conteggio degli errori entra in vigore solo quando si imposta un numero diverso. Questi trigger includono un cooldown immediato per una risposta 429 in un gruppo con più di un deployment, oltre il 50% di errori nel minuto corrente dopo almeno 5 richieste per un gruppo di questo tipo e gli errori che il router non ritenta, come un 401 dovuto a una chiave errata. Un trigger distinto attiva inoltre il cooldown di un deployment singolo quando tutte le richieste del minuto corrente falliscono e il traffico raggiunge SINGLE_DEPLOYMENT_TRAFFIC_FAILURE_THRESHOLD, che per impostazione predefinita è di 1000 richieste. Un provider che restituisce 500 in una raffica di richieste smette di essere utilizzato per ogni singola richiesta, mentre un 500 isolato ogni pochi minuti non attiva il cooldown.
fallbacks e context_window_fallbacks hanno trigger diversi. Il secondo è quello utile che spesso viene ignorato.
fallbacksviene attivato quando la chiamata primaria fallisce.context_window_fallbacksviene attivato quando il provider rifiuta la richiesta perché supera la finestra di contesto del modello. In questo modo un prompt troppo grande viene inviato a un modello con spazio sufficiente, invece di restituire un errore al chiamante.
È disponibile anche content_policy_fallbacks, per i casi in cui un provider rifiuta la richiesta per motivi legati alle policy sui contenuti. Impostarlo solo se esiste una destinazione appropriata per queste chiamate.
Implementare LiteLLM su un VPS con Docker Compose
Creare una directory contenente tre file: config.yaml, docker-compose.yml e .env. La guida rapida upstream usa il tag latest. Impostare invece un tag di release, così docker compose up -d il mese prossimo fornirà lo stesso gateway disponibile oggi e un rollback richiederà una sola riga.
services:
litellm:
image: ghcr.io/berriai/litellm:v1.95.0
restart: unless-stopped
command: ["--config", "/app/config.yaml", "--num_workers", "1"]
ports:
- "127.0.0.1:4000:4000"
volumes:
- ./config.yaml:/app/config.yaml:ro
env_file: .env
depends_on:
db:
condition: service_healthy
db:
image: postgres:16
restart: unless-stopped
environment:
POSTGRES_USER: litellm
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
POSTGRES_DB: litellm
healthcheck:
test: ["CMD-SHELL", "pg_isready -U litellm"]
interval: 5s
timeout: 5s
retries: 10
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:Compose legge .env due volte in questo caso. La prima volta per sostituire ${POSTGRES_PASSWORD} direttamente nel file Compose, la seconda tramite env_file per passare ogni variabile al container.
v1.95.0 era la release corrente nell'agosto 2026. Controllare la pagina delle release del progetto e impostare il tag della versione corrente al momento del deployment. Ogni release pubblica una firma, quindi è possibile verificare l'immagine prima di considerarla attendibile:
cosign verify --key https://raw.githubusercontent.com/BerriAI/litellm/v1.95.0/cosign.pub ghcr.io/berriai/litellm:v1.95.0La riga della porta è 127.0.0.1:4000:4000 e pubblica la porta soltanto sull'interfaccia di loopback. Scrivere invece 4000:4000 rende il gateway raggiungibile da tutta Internet, perché Docker aggiunge regole proprie nella catena FORWARD di iptables, che vengono valutate prima di quelle di ufw; di conseguenza, ufw deny 4000 non lo blocca. Questo è il modo più comune in cui un gateway self-hosted finisce per essere esposto: vedere come Docker pubblica direttamente una porta del container oltre ufw. Il traffico dall'esterno arriva invece tramite il reverse proxy.
Mantieni le chiavi dei provider fuori dall’immagine
Il file .env contiene tutti i secret. Viene passato come variabile d’ambiente in fase di esecuzione, quindi non viene mai incluso nell’immagine e non viene mai sottoposto a commit.
LITELLM_MASTER_KEY=sk-REPLACE_ME
LITELLM_SALT_KEY=sk-REPLACE_ME_TOO
POSTGRES_PASSWORD=REPLACE_ME_AS_WELL
DATABASE_URL=postgresql://litellm:REPLACE_ME_AS_WELL@db:5432/litellm
STORE_MODEL_IN_DB=True
LITELLM_MODE=PRODUCTION
LITELLM_LOG=ERROR
ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-proj-...Genera le due chiavi LiteLLM usando casualità reale, quindi limita i permessi del file:
printf 'sk-%s\n' "$(openssl rand -hex 32)"
chmod 600 .envLITELLM_MASTER_KEY è la credenziale amministrativa. Autentica l’API di gestione ed è la password per la Admin UI all’indirizzo /ui. Nessuna applicazione deve mai conservarla.
LITELLM_SALT_KEY cifra le credenziali dei provider archiviate nel database. Impostala una volta e non modificarla. Se la cambi in seguito, le credenziali già archiviate non possono essere decifrate. Il gateway si avvia normalmente, ma ogni chiamata a quei provider fallisce per un errore di autenticazione.
STORE_MODEL_IN_DB=True consente di aggiungere e modificare i modelli dalla Admin UI senza modificare config.yaml. È comodo, ma divide la fonte autorevole in due. Decidi quale deve essere la fonte autorevole e annota la decisione accanto alla configurazione.
Il motivo per cui le chiavi devono restare fuori dal file di configurazione è lo stesso per cui devono restare fuori dagli strumenti che fornisci a un agente. Mantieni i secret dei provider fuori dagli agenti AI descrive questo approccio, mentre file env e secret in Docker Compose ne illustra gli aspetti operativi.
Avvia il servizio e monitora il primo avvio:
docker compose up -d
docker compose logs -f litellmVerificare che il servizio funzioni effettivamente
Sono disponibili due probe senza autenticazione e uno autenticato. Possono fallire per motivi diversi.
curl -s http://127.0.0.1:4000/health/liveliness
curl -s http://127.0.0.1:4000/health/readiness/health/liveliness non richiede autenticazione e risponde "I'm alive!" quando il processo è in esecuzione. Anche /health/readiness non richiede autenticazione. Restituisce un oggetto JSON con "status": "healthy" e un campo db, oppure 503 quando il database non è raggiungibile. Configura il monitoraggio sulla readiness, perché la liveliness può rimanere verde su un gateway che non riesce a cercare nemmeno una chiave virtuale.
Il controllo autenticato è quello che comunica con i provider:
curl -s http://127.0.0.1:4000/health \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"Risponde con gli array healthy_endpoints e unhealthy_endpoints. Un modello presente in unhealthy_endpoints con un errore di autenticazione indica che la chiave del provider in .env è errata o mancante. È esattamente il problema da individuare in questa fase. Poiché è impostato background_health_checks: true, il proxy esegue automaticamente queste probe ogni health_check_interval secondi e /health restituisce l'ultimo risultato. Il polling non invia quindi ogni volta una richiesta di test ai provider.
Chiavi virtuali e budget per chiave
Ogni applicazione riceve una chiave propria, generata a partire dalla chiave master.
curl -s http://127.0.0.1:4000/key/generate \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{
"key_alias": "nightly-summariser",
"models": ["bulk"],
"max_budget": 5,
"budget_duration": "30d",
"rpm_limit": 60,
"tpm_limit": 200000
}'La risposta contiene un campo key che inizia con sk-. Quella stringa è ciò che riceve l'applicazione ed è l'unico dato che l'applicazione riceve.
modelsè una allowlist delle richieste che questa chiave può effettuare. La chiave precedente può richiederebulke nient'altro.max_budget: 5conbudget_duration: "30d"è pari a cinque dollari statunitensi per mese solare. LiteLLM reimposta il budget30dil primo giorno di ogni mese a mezzanotte, in UTC, a meno che non si impostitimezoneinlitellm_settings. Il periodo non è quindi una finestra mobile di 30 giorni: una volta spesi cinque dollari, la chiave smette di funzionare fino al primo giorno del mese successivo.rpm_limitetpm_limitlimitano rispettivamente le richieste al minuto e i token al minuto per questa sola chiave.key_aliasè il valore che riconoscerai nel log dei costi sei settimane dopo. Impostalo sempre.
Quando il budget è esaurito, la chiamata non riesce e restituisce un errore di tipo budget_exceeded con un messaggio di questo formato:
Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>Il codice di stato dipende dalla release. Nella v1.95.0 bloccata è HTTP 429. Dalla v1.104.0 il valore predefinito è HTTP 422; impostando budget_exceeded_status_code: 429 in litellm_settings si ripristina il codice precedente. I veri superamenti di rpm_limit e tpm_limit restituiscono comunque 429 in entrambe le release. Dopo ogni upgrade, verifica quale codice viene restituito.
Il codice di stato è ciò che rende il problema difficile da individuare, perché nessuno dei due codici indica il budget. Una libreria client interpreta 429 come un superamento del rate limit e può ritentare la richiesta con un backoff, anche se il budget non sarà nuovamente disponibile fino al reset. Interpreta invece 422 come una richiesta che non è stato possibile elaborare. Registra il corpo della risposta insieme al codice di stato; in caso contrario, l'esaurimento del budget apparirà ogni volta come un problema diverso.
Ispeziona e modifica le chiavi tramite la stessa API di gestione:
curl -s "http://127.0.0.1:4000/key/info?key=sk-..." \
-H "Authorization: Bearer $LITELLM_MASTER_KEY"
curl -s -X POST http://127.0.0.1:4000/key/update \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H 'Content-Type: application/json' \
-d '{"key": "sk-...", "max_budget": 25}'Un budget applicato al gateway continua a essere rispettato anche quando il problema riguarda l'agente stesso. Per questo costituisce la base del controllo dei costi per gli agenti AI su un VPS.
Inviare elaborazioni in batch a un modello economico
Indicare al client il gateway. URL di base, chiave e nome del modello:
curl -s http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{
"model": "bulk",
"messages": [{"role": "user", "content": "Say hello in five words."}]
}'Qualsiasi libreria client OpenAI funziona allo stesso modo: impostare base_url su https://gateway.example.com/v1 e api_key sulla chiave virtuale.
La policy di routing definita in config.yaml viene ora applicata senza che il chiamante debba conoscerla. Una richiesta per bulk viene inviata al modello economico. Se la chiamata non riesce dopo i tentativi configurati, la richiesta viene ripetuta usando strong. Se il prompt è troppo lungo per bulk, context_window_fallbacks lo invia a strong invece di restituire un errore. Le elaborazioni in batch, come una classificazione completa o il riepilogo di un arretrato, usano per impostazione predefinita il modello economico; solo le richieste più complesse hanno un costo maggiore.
È anche in questo caso che un gateway dimostra la propria utilità con gli agenti che usano strumenti. Un server MCP (model context protocol) sullo stesso VPS e l’agente che lo utilizza possono puntare entrambi a un unico endpoint. In questo modo è possibile cambiare il modello sottostante senza ridistribuire nessuno dei due.
Come si rileva un fallback?
Questo è il caso di errore più costoso, perché nulla sembra non funzionare. Un fallback riuscito restituisce HTTP 200 con un normale corpo della risposta. Il modello economico può rimanere non disponibile per un giorno, mentre ogni richiesta viene servita silenziosamente da quello costoso. La prima prova può comparire nella fattura.
La prova è presente negli header della risposta. Richiedili:
curl -s -D - -o /dev/null http://127.0.0.1:4000/v1/chat/completions \
-H "Authorization: Bearer sk-<the virtual key>" \
-H 'Content-Type: application/json' \
-d '{"model":"bulk","messages":[{"role":"user","content":"ping"}]}' \
| grep -i '^x-litellm'x-litellm-model-groupè il nome del modello utilizzato per instradare la richiesta, ad esempiobulk.x-litellm-model-idè l'ID della distribuzione che ha risposto; puoi cercarlo con/v1/model/info?litellm_model_id=.... Se l'ID non corrisponde a una delle tue distribuzionibulk, si è verificato un fallback.x-litellm-attempted-fallbacksex-litellm-attempted-retriescontano questi eventi. In una chiamata normale, nessuno dei due deve mostrare un valore superiore a 0.x-litellm-response-costè il costo di quella singola chiamata in dollari statunitensi.x-litellm-call-idè l'identificatore da usare per trovare la stessa chiamata nei log.
Registra x-litellm-attempted-fallbacks per ogni richiesta e genera un alert quando il valore è superiore a 0. Questo singolo numero distingue una policy di instradamento funzionante da una policy che è diventata silenziosamente «usa sempre il modello costoso».
La versione completa usa il tracing e richiede una configurazione dedicata: Langfuse self-hosted per il tracing delle chiamate degli agent. LiteLLM include il callback, quindi il collegamento richiede due righe più le credenziali.
litellm_settings:
success_callback: ["langfuse"]
failure_callback: ["langfuse"]LANGFUSE_PUBLIC_KEY=pk-lf-...
LANGFUSE_SECRET_KEY=sk-lf-...
LANGFUSE_HOST=https://langfuse.example.comPer Langfuse v3 e versioni successive, la pagina di LiteLLM dedicata a Langfuse raccomanda ora il preset langfuse_otel; il callback langfuse riportato sopra è ancora documentato. Imposta failure_callback oltre a success_callback. Se lo ometti, conserverai solo le tracce delle richieste in cui non si è verificato alcun problema. Separatamente da tutto questo, LiteLLM scrive una riga di spesa per ogni richiesta in Postgres e l'Admin UI all'indirizzo /ui legge quella tabella. La tabella cresce con il traffico, quindi monitorala se il disco è di dimensioni ridotte.
Metti il gateway dietro un reverse proxy
Niente al di fuori del server deve poter raggiungere la porta 4000. Termina TLS in nginx o Caddy e inoltra le richieste all'indirizzo di loopback.
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_buffering off;
proxy_read_timeout 600s;
}Quelle due direttive vengono spesso omesse. proxy_buffering off è importante perché una risposta in streaming è costituita da una serie di eventi inviati dal server e, quando il buffering è attivo, nginx raccoglie i blocchi nei buffer prima di inoltrarli, ritardando la consegna al client. proxy_read_timeout 600s è importante perché il valore predefinito di nginx, pari a 60 secondi, è il tempo massimo che attende tra due letture dal gateway, non un limite per l'intera risposta. Una risposta senza streaming non invia dati finché la generazione non è terminata. Se la generazione è lunga, trascorrono più di 60 secondi senza che arrivi alcun byte e il client riceve un errore 504, mentre il log degli errori registra upstream timed out (110: Connection timed out) while reading response header from upstream. Una risposta in streaming che continua a inviare blocchi può durare molto più di 60 secondi. Il timeout scatta soltanto se il modello rimane inattivo per quel periodo.
Per il certificato, Certbot con Let's Encrypt su nginx è la soluzione più rapida. Se il server pubblica già diversi container, Traefik davanti a più applicazioni Compose gestisce routing e certificati in un unico punto.
Il gateway è ora un singolo punto di errore
Siate consapevoli di ciò che avete configurato. Tutte le applicazioni che gestite dipendono ora da un unico container su un unico VPS. Quando il container è inattivo, nulla può chiamare alcun modello, compresi i provider perfettamente operativi. Ne conseguono quattro aspetti.
- Una configurazione errata arresta tutto contemporaneamente.
restart: unless-stoppedriavvia un processo in caso di crash e continua a riavviare un container che non riesce ad analizzareconfig.yaml. Leggetedocker compose logs litellmdopo ogni modifica alla configurazione e apportate le modifiche quando avete tempo di monitorarne l'effetto. - Postgres si trova nel percorso delle richieste in caso di cache miss. La ricerca della chiave virtuale usa il database quando la chiave non è nella cache; la registrazione della spesa viene eseguita in modo asincrono dopo la risposta.
/health/readinessche restituisce 503 indica che il gateway è in esecuzione, ma non riesce a svolgere nessuna delle due operazioni. - Usate prima i core, quindi aggiungete istanze. Le indicazioni di produzione del progetto, che prevedono un worker per istanza (
--num_workers 1), sono pensate per Kubernetes o per un altro autoscaler dei pod che aggiunge automaticamente le istanze. Per una singola VM o un container standalone come questo indicano il contrario: impostate il numero di worker in base al numero di vCPU della macchina. Sulla macchina con 1 vCPU indicata sopra il valore è comunque--num_workers 1; su una macchina più grande aumentatelo e ricordate che ogni worker utilizza la propria memoria. Un secondo gateway dietro un load balancer elimina il singolo container dall'architettura. Non elimina il database. - Eseguite il backup di ciò che non può essere rigenerato. Si tratta di
config.yamle.env, insieme a unpg_dumpdel database. La perdita diLITELLM_SALT_KEYrende inutilizzabili le credenziali dei provider cifrate contenute in quel dump. Per questo il file env e il dump devono essere inclusi nello stesso job di backup: backup restic su storage esterno.
L'aggiornamento consiste nel modificare il tag dell'immagine ed eseguire docker compose up -d. Per impostazione predefinita, LiteLLM esegue prisma migrate deploy all'avvio; il nuovo container esegue quindi la migrazione dello schema del database al primo avvio. Eseguite il dump prima di modificare il tag, perché ripristinare l'immagine precedente non annulla una migrazione già eseguita.
Leggete le note di rilascio di ogni versione che avete saltato, non soltanto di quella a cui arrivate. Il passaggio da v1.95.0 a v1.104.0 o a una versione successiva attraversa diverse modifiche incompatibili: il codice di stato del budget indicato sopra, un proxy che rifiuta di avviarsi quando la master key non è impostata, è vuota o è nota pubblicamente, e un proxy che termina quando la configurazione del database non riesce all'avvio; con restart: unless-stopped questo si manifesta come un ciclo di riavvii. Se provenite da v1.102.x o da una versione precedente, le note di v1.104.0 chiedono inoltre di creare autonomamente due indici LiteLLM_SpendLogs.
FAQ
LiteLLM aggiunge una latenza rilevabile a ogni chiamata?
Il progetto indica 8 ms al 95° percentile con 1000 richieste al secondo, come riportato nel README a ottobre 2026. Consideralo un dato del fornitore. Il fattore che incide realmente sulla latenza è la distanza di rete tra le applicazioni e il gateway, perché ogni chiamata aggiunge un round trip. Esegui il gateway nella stessa area geografica delle applicazioni che lo chiamano, quindi misura il sovraccarico effettivo con l'header x-litellm-overhead-duration-ms su una risposta reale.
Perché lo streaming ha smesso di funzionare dopo aver messo nginx davanti al servizio?
Perché nginx, per impostazione predefinita, memorizza nel buffer le risposte upstream e una risposta in streaming è costituita da una serie di eventi inviati dal server. Quando proxy_buffering è attivo, nginx raccoglie i blocchi nei buffer prima di inoltrarli e ritarda la consegna al client. Imposta proxy_buffering off; nel blocco location. Aumenta anche proxy_read_timeout nello stesso blocco. Per impostazione predefinita, nginx interrompe l'attesa dopo 60 secondi senza dati dal gateway. Una generazione lunga senza streaming raggiunge facilmente questo limite e il client riceve un errore 504.
Cosa succede quando una virtual key esaurisce il budget?
La chiamata fallisce con un errore di tipo budget_exceeded e un messaggio nella forma Budget has been exceeded! Key=<key> Current cost: <spend>, Max budget: <max_budget>. Nella versione fissata v1.95.0 lo stato è HTTP 429; dalla versione v1.104.0 il valore predefinito è invece HTTP 422. Nessuno dei due codici indica il budget. Questo è l'aspetto problematico: una libreria client interpreta 429 come un limite di frequenza e può riprovare la richiesta. In questo modo si cerca la causa nel throttling invece di leggere il messaggio. Registra il corpo della risposta insieme al codice di stato. Verifica la posizione effettiva della key con /key/info?key=sk-... usando la master key, quindi aumenta il limite con /key/update se il budget era troppo basso.
Il gateway può instradare verso un modello locale oltre che verso modelli hosted?
Sì. È un'altra voce in model_list. Usa il prefisso ollama_chat/ con un api_base, ad esempio model: ollama_chat/llama3.1 insieme a api_base: http://ollama:11434. Nella rete predefinita di Compose, localhost all'interno di un container indica quel container. Usa quindi il nome del servizio Compose o l'indirizzo dell'host sulla rete Docker, mai 127.0.0.1. Il networking dell'host, in cui il container condivide lo stack di rete dell'host, è l'eccezione. L'avvio del modello locale è un'attività separata: consulta ospitare autonomamente un LLM con Ollama su un VPS.