HiAPI
Blog

Tutoriale

Costruire un proxy per l'API OpenAI con Python: prima scrivilo a mano, poi fallo dialogare con tutti i modelli

Un proxy FastAPI funzionante, con autenticazione, limitazione della frequenza e streaming; e come l'API compatibile con OpenAI di HiAPI permette allo stesso proxy di servire contemporaneamente modelli come DeepSeek, Claude e GPT.

Jun 26, 2026
Costruire un proxy per l'API OpenAI con Python: prima scrivilo a mano, poi fallo dialogare con tutti i modelli

TL;DR

  • Un proxy per l'API OpenAI è un piccolo server fra la tua applicazione e l'API del modello. Custodisce le chiavi reali e aggiunge capacità che l'API di per sé non offre: chiavi per cliente, limitazione della frequenza, log e rotazione delle chiavi. Qui sotto trovi una versione funzionante in FastAPI di circa 50 righe.
  • L'API testuale di HiAPI è compatibile con OpenAI: POST /v1/chat/completions e POST /v1/responses si trovano su https://api.hiapi.ai/v1. Puntando l'SDK ufficiale openai o il tuo proxy a questo base URL, puoi chiamare con una sola chiave i modelli testuali DeepSeek, Claude, GPT, Kimi, GLM e Grok.
  • Immagini e video sono diversi: richiedono da qualche secondo a qualche minuto, quindi girano sull'endpoint asincrono POST /v1/tasks di HiAPI. Non inserire questo tipo di richieste in un proxy sincrono.

Passo 1: un proxy pass-through minimale

Il proxy verifica la chiave interna inviata dal client, la sostituisce con la vera chiave upstream e poi trasmette la risposta in streaming.

pip install fastapi uvicorn httpx
# proxy.py
import os
import httpx
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
from starlette.background import BackgroundTask

UPSTREAM = os.environ.get("UPSTREAM_BASE", "https://api.openai.com/v1")
UPSTREAM_KEY = os.environ["UPSTREAM_KEY"]
INTERNAL_KEYS = set(os.environ["INTERNAL_KEYS"].split(","))  # comma-separated

app = FastAPI()
client = httpx.AsyncClient(timeout=120.0)

def auth(request: Request) -> str:
    header = request.headers.get("authorization", "")
    key = header.removeprefix("Bearer ").strip()
    if key not in INTERNAL_KEYS:
        raise HTTPException(401, "invalid internal key")
    return key

@app.post("/v1/{path:path}")
async def forward(path: str, request: Request):
    tenant = auth(request)
    body = await request.body()
    upstream_req = client.build_request(
        "POST", f"{UPSTREAM}/{path}", content=body,
        headers={"Authorization": f"Bearer {UPSTREAM_KEY}",
                 "Content-Type": request.headers.get("content-type", "application/json")},
    )
    upstream = await client.send(upstream_req, stream=True)
    # Stream back so long answers and SSE don't time out; close the upstream stream when done
    return StreamingResponse(upstream.aiter_raw(), status_code=upstream.status_code,
                             media_type=upstream.headers.get("content-type"),
                             background=BackgroundTask(upstream.aclose))

Avvialo:

UPSTREAM_KEY=your-upstream-key INTERNAL_KEYS=tenant-a,tenant-b \
uvicorn proxy:app --host 0.0.0.0 --port 8000

Il client usa l'SDK OpenAI come al solito, impostando l'indirizzo del proxy come base URL:

from openai import OpenAI

client = OpenAI(api_key="tenant-a", base_url="http://localhost:8000/v1")
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

Conversazioni, streaming ed embedding passano tutti dallo stesso gestore, perché il proxy non analizza mai il contenuto del corpo della richiesta.

Passo 2: aggiungere ciò che l'API upstream non offre

Limitazione della frequenza per tenant. Senza di essa, un singolo cliente molto attivo può esaurire tutta la tua quota.

import time
from collections import defaultdict

_window: dict[str, list[float]] = defaultdict(list)
LIMIT = 60  # requests per 60 s

def check_rate_limit(tenant: str):
    now = time.time()
    _window[tenant] = [t for t in _window[tenant] if now - t < 60]
    if len(_window[tenant]) >= LIMIT:
        raise HTTPException(429, "rate limit exceeded")
    _window[tenant].append(now)

Chiamalo subito dopo auth(). Se ci sono più processi server, sposta il contatore su Redis (INCR più EXPIRE).

Log. Registra tenant, percorso, codice di stato, latenza e numero di token. Non registrare mai l'header Authorization.

Rotazione delle chiavi. Carica UPSTREAM_KEY da un servizio di gestione dei segreti e aggiornala periodicamente. Quando la chiave upstream viene cambiata alla base, i client continuano a usare le rispettive chiavi tenant.

Regole di costo. Analizza il corpo della richiesta e rifiuta le richieste che violano le policy, ad esempio l'uso di modelli costosi su piani gratuiti o un max_tokens superiore al tuo limite.

Passo 3: mettere più fornitori di modelli dietro lo stesso proxy

Un proxy che parla con un solo fornitore è facile. Aggiungere Anthropic, DeepSeek o Moonshot significa header di autenticazione, strutture di richiesta e formati di errore diversi, e il proxy sottile diventa un livello di traduzione.

L'API testuale di HiAPI adotta la struttura di richiesta di OpenAI per tutti i suoi modelli testuali, quindi il proxy qui sopra funziona senza modifiche. Imposta due variabili d'ambiente:

UPSTREAM_BASE=https://api.hiapi.ai/v1 UPSTREAM_KEY=your-hiapi-key INTERNAL_KEYS=tenant-a,tenant-b \
uvicorn proxy:app --host 0.0.0.0 --port 8000

Oppure salta il proxy e usa direttamente l'SDK:

import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["HIAPI_KEY"], base_url="https://api.hiapi.ai/v1")
resp = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[{"role": "user", "content": "Explain sparse attention in two sentences."}],
    max_tokens=400,
)
print(resp.choices[0].message.content)

Abbiamo eseguito questo codice con il pacchetto Python ufficiale openai (3.35.1), una volta con una chiamata normale e una volta con stream=True; entrambe le chiamate sono terminate senza errori e l'SDK ha analizzato le risposte come al solito. Un'insidia emersa in questo test: con max_tokens=20 la risposta era vuota, perché deepseek-v4-flash ha speso tutti i 20 token nel ragionamento (usage.completion_tokens_details.reasoning_tokens era 22). Lascia qualche centinaio di token di margine ai modelli di ragionamento.

Alcuni modelli testuali su HiAPI:

ID modello Instradamento Input / output, dollari per milione di token
deepseek-v4-flash Chat Completions $0.14 / $0.28
deepseek-v4.1-flash Chat Completions e Responses $0.44 / $1.32
gpt-5.6-luna Solo Responses $0.05 / $0.30
grok-4.6 Chat Completions $0.84 / $2.52
deepseek-v4-pro Chat Completions e Responses $1.50 / $4.50
claude-opus-5-5 Chat Completions $2.02 / $10.08
kimi-k3 Chat Completions $2.32 / $11.60
claude-sonnet-4-6 Chat Completions $3.00 / $15.00

Prezzi HiAPI in tempo reale, rilevati il 20 ottobre 2026. GET https://api.hiapi.ai/v1/models elenca tutti i modelli disponibili per la tua chiave.

Modelli GPT come gpt-5.6-luna sono offerti solo tramite l'API Responses (client.responses.create), quindi un proxy che inoltra /v1/{path} copre entrambi.

Un ID modello sconosciuto restituisce HTTP 400 nello stile degli errori OpenAI, con un request_id per contattare l'assistenza:

{"error": {"code": "model_not_found", "type": "hiapi_error",
           "message": "The requested model does not exist or is not available. Check the exact model ID with GET /v1/models and try again. ...",
           "request_id": "..."}}

Passo 4: immagini e video non vanno messi in un proxy sincrono

Un proxy sincrono mantiene la connessione aperta finché la risposta non arriva. Per il testo va bene. Le immagini richiedono decine di secondi e i video minuti, più a lungo di quanto la maggior parte dei load balancer e dei browser sia disposta ad attendere.

HiAPI esegue i modelli per immagini e video su endpoint asincroni: invii un task, ricevi un task id, poi esegui polling o ricevi un callback.

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image",
    "input": {"prompt": "a glass data center at golden hour, isometric", "aspect_ratio": "16:9"},
    "callback": {"url": "https://your-app.example.com/hiapi/callback", "when": "final"}
  }'
# => {"code":200,"message":"success","data":{"taskId":"tk-hiapi-..."}}

Il tuo proxy può comunque inoltrare la chiamata di invio, che restituisce subito il controllo. Il risultato arriva in seguito tramite il tuo URL di callback o con GET /v1/tasks/{taskId}. I link di output scadono dopo circa 7 giorni, quindi salva i file.

Checklist per la produzione

  • Rimuovi le chiavi dai log. Non registrare mai Authorization, né in entrata né in uscita.
  • Usa i callback per i task multimediali. Il polling di migliaia di task spreca richieste. Scrivi il gestore dei callback in modo idempotente e con chiave taskId, perché le consegne possono essere ritentate.
  • Salva il task id prima del polling. Se il processo va in crash, riprendi il polling invece di inviare di nuovo e pagare due volte.
  • Lascia spazio ai token di ragionamento. Imposta max_tokens molto più alto della lunghezza di risposta che ti aspetti.
  • Controlla cosa può usare la chiave. GET /v1/models restituisce l'elenco corrispondente a quella chiave.

Domande frequenti

Posso usare l'SDK Python di OpenAI su HiAPI?

Sì, per i modelli testuali. Imposta base_url="https://api.hiapi.ai/v1" e usa la tua chiave HiAPI. Immagini e video usano /v1/tasks, endpoint non coperto dall'SDK OpenAI; chiamalo con requests o httpx.

Mi serve ancora un proxy mio?

Solo per gli stessi motivi di qualsiasi fornitore: chiavi separate per tenant, limitazione della frequenza e log di controllo. All'interno del proxy non serve più alcuna conversione per fornitore.

Lo streaming funziona?

Sì. stream=True restituisce eventi inviati dal server che terminano con data: [DONE], e il proxy qui sopra li inoltra in streaming senza buffering.

Come si ruota una chiave HiAPI senza interrompere il servizio?

Crea una nuova chiave nella console, distribuiscila al tuo proxy o al tuo archivio di chiavi, poi revoca quella vecchia. Durante il passaggio entrambe le chiavi sono utilizzabili.

Per maggiori dettagli: documentazione di Chat Completions, documentazione di Responses e HiAPI come alternativa ai proxy per l'API OpenAI.

Inizia a creare con artefatti IA persistenti

Ottieni la tua chiave API e chiama modelli di immagini, video e audio tramite un'unica API basata sui task.

Leggi la documentazione API