Avviso: Novità GPT Image 2.6 Flare e Sunburst, sconto del 20% per tempo limitato, prova subito
HiAPI
Blog

Tutoriale

Come chiamare kimi-k3.1-pro tramite l'API HiAPI: curl, Python e richieste eseguibili direttamente

Una guida pratica all'integrazione, che copre endpoint, parametri della richiesta, streaming, tool calling e risoluzione dei problemi

Nov 12, 2026
封面图:深墨绿底色上,两组扁平缎带呈经纬交错编织成规整的开放式网格,缎带为克制的黄铜色与暗绿色。
In questa pagina

Perché chiamare kimi-k3.1-pro tramite un'API aggregata

Ogni integrazione di un modello porta con sé lo stesso costo nascosto: il primo giorno è divertente, il secondo mese è manutenzione. Quando colleghi kimi-k3.1-pro direttamente alla tua applicazione, erediti anche lo schema di autenticazione, la semantica degli errori, il modello delle quote e il ritmo di rilascio di quel fornitore. Per un prototipo con un solo modello va bene. Ma appena vuoi un secondo modello, un secondo ambiente, o un percorso di fallback quando un endpoint ha problemi, diventa attrito.

Un'API aggregata riduce queste differenze a un unico contratto. HiAPI espone kimi-k3.1-pro con una forma di richiesta compatibile con OpenAI, il che significa che il codice client che scrivi qui non è usa e getta. Cambiando l'identificatore del modello, la stessa struttura di richiesta può essere riutilizzata con altri modelli sulla piattaforma—stessi header, stesso array di messaggi, stesso wrapper di streaming.

Nello specifico di kimi-k3.1-pro, questo ha tre implicazioni pratiche:

  • Un'unica superficie di credenziali. Gestisci una sola API Key e un solo URL di base, invece di un insieme crescente di account dei fornitori.
  • Payload prevedibili. Gli schemi di richiesta e risposta restano stabili tra i modelli, quindi il tuo livello di parsing, retry e logging va scritto una volta sola.
  • Costi di migrazione bassi. Se in futuro un tipo di carico è più adatto a un altro modello, la modifica è una stringa nel payload, non una riscrittura del livello di trasporto.

Il resto di questa guida è l'integrazione stessa: anatomia della richiesta, chiamate curl pronte da copiare, il client Python equivalente, poi le due funzionalità che di solito causano più problemi in produzione—streaming e tool calling—e infine una checklist per la risoluzione dei problemi.

Cosa ti serve prima di iniziare

  • Una API Key di HiAPI, conservata dove il tuo progetto archivia i segreti.
  • L'URL di base dell'API del tuo account, dalla console HiAPI. Tutti gli esempi sotto usano https://api.hiapi.ai/v1 come URL di base segnaposto; prima di andare in produzione verifica l'host reale nella console.
  • La stringa dell'identificatore del modello kimi-k3.1-pro—copiala esattamente dalla lista dei modelli della console, perché l'identificatore è sensibile alle maiuscole.
  • curl per il primo test, e Python 3.9+ con la libreria requests per l'esempio del client.

Forma della richiesta: endpoint, header e parametri del modello

Ogni chiamata di chat segue la stessa anatomia. Una volta capita ogni parte, non dovrai più eseguire il debug campo per campo.

Endpoint

Le completion di chat si trovano su un unico percorso sotto l'URL di base:

POST {BASE_URL}/chat/completions

Questo è l'unico endpoint necessario per tutti gli esempi di questa guida. Streaming e tool calling non sono endpoint separati—sono opzioni nello stesso corpo della richiesta.

Solo due header contano davvero:

Authorization: Bearer $HIAPI_API_KEY
Content-Type: application/json

La chiave va nell'header Authorization, con il prefisso Bearer. Non metterla nell'URL, nei parametri di query o nel corpo della richiesta—tutte e tre le pratiche la fanno trapelare nei log e nei report degli errori. Imposta esplicitamente Content-Type; alcuni client HTTP non lo deducono per te.

I campi del corpo della richiesta che contano davvero

Un corpo di richiesta minimo ha quattro campi significativi:

  • model — l'identificatore di kimi-k3.1-pro. Obbligatorio. È il campo che si sbaglia più facilmente al primo tentativo, perché deve corrispondere esattamente.
  • messages — un array ordinato di oggetti, ciascuno con role (system, user o assistant) e content. Obbligatorio e non vuoto. L'ordine è la cronologia della conversazione; il modello vede esattamente questo array, nient'altro.
  • stream — booleano, predefinito false. Se true, la risposta arriva come server-sent event invece che come un unico corpo JSON. C'è una sezione dedicata più sotto.
  • temperature — controllo opzionale del campionamento. Valori più bassi producono output più deterministici; valori più alti più variazione. Scegli un valore una volta per caso d'uso e non toccarlo, non regolarlo a ogni richiesta.

Campi opzionali che puoi aggiungere man mano che l'integrazione matura:

  • max_tokens — limite superiore alla lunghezza generata. Utile come barriera per costi e latenza. Nota che limita l'output, non l'input.
  • tools — array di definizioni di strumenti, descritto in dettaglio più avanti.
  • tool_choice — controlla se e come il modello chiama gli strumenti che fornisci.
  • stop — una o più sequenze che terminano la generazione.

La risposta che dovresti aspettarti

Una risposta non in streaming restituisce un oggetto JSON il cui array choices contiene almeno una voce. In quella voce troverai un oggetto message con role e content, più un finish_reason che ti dice perché la generazione si è fermata. Ramifica sempre in base a finish_reason, non assumere che il contenuto sia completo—una risposta troncata ha comunque contenuto, solo non è la risposta completa.

Scrivi il parser su questa struttura, non su una risposta serializzata in stringa. Così sopravviverà a qualunque cambio di modello tu faccia sulla piattaforma.

Una richiesta curl eseguibile

Inizia da qui. Se restituisce una risposta valida, la tua chiave, l'URL di base e l'identificatore del modello sono corretti, e qualsiasi problema successivo sarà nel codice, non nelle credenziali.

curl -sS "$HIAPI_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3.1-pro",
    "messages": [
      {"role": "system", "content": "Sei un assistente tecnico conciso."},
      {"role": "user", "content": "Spiega in due frasi cos'è una chiave di idempotenza."}
    ],
    "temperature": 0.3,
    "max_tokens": 256
  }'

Spiegazione dei campi

  • -sS mantiene curl silenzioso sul progresso, ma espone comunque gli errori. Senza la seconda S, una richiesta fallita potrebbe uscire silenziosamente, sprecando un giro di debug.
  • Le variabili d'ambiente evitano che la chiave finisca nella cronologia della shell o nel buffer di scorrimento del terminale. Esporta HIAPI_BASE_URL e HIAPI_API_KEY nel tuo profilo della shell o in un .env caricato.
  • Corpo della richiesta tra apici singoli è corretto per una shell POSIX, finché il payload non contiene apici singoli. Appena servono apici singoli, sposta il corpo in un file e passalo con -d @body.json—così eviti una classe di bug di quoting che sembrano errori di formato JSON.
  • Il messaggio system è opzionale, ma vale la pena includerlo. È il posto più comodo per fissare tono e formato dell'output.
  • max_tokens in questo esempio è volutamente conservativo. Limita sia la latenza che il costo dello smoke test.

Interpretare il risultato

Una chiamata riuscita restituisce HTTP 200 e un corpo JSON. Prima di procedere conferma tre cose:

  1. choices è un array non vuoto.
  2. choices[0].message.content contiene una risposta reale.
  3. choices[0].finish_reason è un valore di completamento normale, non un troncamento per lunghezza.

Se il corpo della risposta è un oggetto di errore, salta alla sezione sulla risoluzione dei problemi—il messaggio di errore di solito indica il campo specifico che ha causato il problema.

Consiglio per la riproducibilità

Salva quella chiamata curl come script shell nel repository. Un singolo comando che esegue uno smoke test sull'API live è il modo più rapido per distinguere "la mia integrazione è rotta" da "il mio account o la mia chiave sono cambiati". Eseguilo ogni volta che qualcosa sembra sbagliato.

La stessa richiesta scritta in Python

La versione Python dovrebbe sembrare noiosa—è esattamente l'obiettivo. Tutte le decisioni interessanti (identificatore del modello, URL di base, timeout) dovrebbero stare nella configurazione, non sparse nei vari punti di chiamata.

import os
import requests

BASE_URL = os.environ["HIAPI_BASE_URL"].rstrip("/")
API_KEY = os.environ["HIAPI_API_KEY"]
MODEL = os.environ.get("HIAPI_MODEL", "kimi-k3.1-pro")

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}


def chat(messages, temperature=0.3, max_tokens=512, timeout=60):
    payload = {
        "model": MODEL,
        "messages": messages,
        "temperature": temperature,
        "max_tokens": max_tokens,
    }
    resp = requests.post(
        f"{BASE_URL}/chat/completions",
        headers=HEADERS,
        json=payload,
        timeout=timeout,
    )
    resp.raise_for_status()
    data = resp.json()
    choice = data["choices"][0]
    return choice["message"]["content"], choice.get("finish_reason")


if __name__ == "__main__":
    text, reason = chat([
        {"role": "system", "content": "Sei un assistente tecnico conciso."},
        {"role": "user", "content": "Spiega in due frasi cos'è una chiave di idempotenza."},
    ])
    print(reason)
    print(text)

Perché è organizzato così

  • Usa json= invece di data= — la libreria requests serializza il dizionario e imposta il content type per te. La serializzazione manuale introduce facilmente errori di escaping.
  • Sempre timeout=60 — non impostare un timeout è la causa più comune di processi worker che restano appesi finché il gestore non li uccide. Ogni chiamata di rete in un servizio dovrebbe avere un timeout.
  • raise_for_status() prima del parsing — converte i fallimenti a livello HTTP in eccezioni nel punto di chiamata, invece di lasciare che corpi di risposta malformati scorrano a valle.
  • MODEL dall'ambiente — quando cambi modello, l'identificatore del modello è l'unica cosa che cambia. Averlo nella configurazione significa che il cambio è una variabile di deploy, non una modifica al codice.
  • Restituisce finish_reason — chi chiama ha quasi sempre bisogno di sapere se la risposta è stata troncata.

Mantienilo riutilizzabile tra i modelli

La firma di chat(messages, ...) non espone volutamente nulla di specifico al modello. Se in futuro instradi carichi più economici verso altri modelli, o passi un parametro esplicito di override del modello, o costruisci un secondo oggetto client con un MODEL diverso. Trasporto, header, policy di retry e gestione degli errori restano invariati.

Nota sui retry

Non fare retry ciechi dentro chat(). Fai retry al livello che sa se l'operazione può essere ripetuta in sicurezza—le completion fallite di solito sono sicure, ma le richieste che hanno già modificato lo stato a valle non lo sono. Fai retry solo su fallimenti transitori di trasporto e risposte di rate limit, e solo con backoff esponenziale con tetto massimo.

Consumare lo streaming senza rompere il client

Lo streaming è la differenza tra una UI di chat che sembra immediata e dieci secondi di schermo bianco. Introduce anche la maggior parte dei bug di integrazione, perché la risposta non è più un singolo documento JSON.

Come abilitarlo

Aggiungi "stream": true al corpo della richiesta. Il resto della richiesta resta invariato.

with requests.post(
    f"{BASE_URL}/chat/completions",
    headers=HEADERS,
    json={"model": MODEL, "messages": messages, "stream": True},
    stream=True,
    timeout=120,
) as resp:
    resp.raise_for_status()
    for line in resp.iter_lines(decode_unicode=True):
        if not line or not line.startswith("data:"):
            continue
        chunk = line[len("data:"):].strip()
        if chunk == "[DONE]":
            break
        # Analizza chunk come JSON e leggi choices[0].delta.content

Cosa arriva effettivamente

Il corpo della risposta è una serie di server-sent event. Ogni evento è una riga data: che trasporta un piccolo oggetto JSON. Dentro choices[0] c'è un oggetto delta invece di un oggetto message—il delta di solito contiene un frammento di content, ma può anche non contenerne nulla. Lo stream termina con la riga sentinella data: [DONE].

Quattro regole coprono quasi tutti gli errori:

  1. Accumula, non sostituire. Ogni delta è un frammento. Accoda delta.content a un buffer; la risposta completa è la concatenazione in ordine di ogni frammento.
  2. Salta i delta vuoti. Il primo e l'ultimo evento spesso non contengono content. Evita di accodare None.
  3. Tratta [DONE] come terminatore, non come dato. Ferma la lettura lì; ciò che segue non fa parte della risposta.
  4. Leggi finish_reason dall'ultimo evento che lo trasporta. In modalità streaming, lo stato di completamento compare in un delta successivo, non in un campo di primo livello.

Trappole che vale la pena nominare

  • Dimenticare stream=True nella chiamata client. Riceverai l'intero stream come un unico corpo bufferizzato, il che vanifica lo scopo e sembra una richiesta non in streaming molto lenta.
  • Timeout impostati come per il non streaming. Gli stream di generazioni lunghe durano più di una richiesta breve. Dai al percorso di streaming un timeout di lettura più permissivo, e considera un timer di inattività che interrompa se non arriva nessun byte per un intervallo scelto.
  • Parsing riga per riga senza controllare il prefisso. Non ogni riga è un dato. Le righe vuote separano gli eventi; ignorale.
  • Assumere che il delta abbia la chiave content. Lo streaming di tool calling inserisce altre chiavi nei delta. Leggi sempre in modo difensivo.
  • Dimenticare il consumatore lato client. Un server che scrive lo stream in un buffer e lo emette solo alla fine è tecnicamente streaming, ma in pratica no. Assicurati che il downstream renderizzi i frammenti man mano che arrivano.

Quando non usare lo streaming

Attività batch, riepiloghi in background e qualsiasi cosa il cui output sia consumato da un programma invece che mostrato a un umano, di solito sono più semplici senza streaming. Una risposta non in streaming richiede un solo parsing, è più facile da loggare e più facile da validare secondo uno schema. Usa lo streaming dove la latenza è visibile all'utente; non farlo per impostazione predefinita.

Aggiungere tool calling al flusso

Il tool calling permette al modello di chiedere al tuo codice di eseguire un'azione, invece di inventare una risposta. Il protocollo è una conversazione in due turni: dichiari gli strumenti, il modello può rispondere con una richiesta di chiamata, tu la esegui, poi rimandi indietro il risultato.

Dichiarare gli strumenti

Aggiungi l'array tools alla richiesta. Ogni voce racchiude la descrizione di una funzione:

{
  "model": "kimi-k3.1-pro",
  "messages": [{"role": "user", "content": "Che tempo fa a Lisbona?"}],
  "tools": [
    {
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Restituisce il meteo attuale della città indicata.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "Nome della città"}
          },
          "required": ["city"]
        }
      }
    }
  ],
  "tool_choice": "auto"
}

La description sulla funzione e su ciascun parametro non è decorazione—è l'unica guida che il modello ha per decidere quando e come chiamare lo strumento. Scrivila come scriveresti le istruzioni per un nuovo collega.

Il ciclo di risposta

  1. Invia la richiesta.
  2. Se choices[0].finish_reason indica una chiamata a strumento, leggi choices[0].message.tool_calls. Ogni voce ha id, il name della funzione e arguments—una stringa codificata in JSON, non un oggetto. Analizzala.
  3. Esegui la funzione nel tuo codice. Valida i parametri prima di fare qualsiasi cosa con essi; il modello può generare payload plausibili ma con campi mancanti o tipi errati.
  4. Accoda il messaggio dell'assistente—incluse le sue tool_calls—al tuo array messages.
  5. Accoda un nuovo messaggio con ruolo tool, con il tool_call_id corrispondente e il risultato come content.
  6. Invia di nuovo la richiesta. Il modello ora usa l'output dello strumento per comporre la risposta finale.

Il passo 4 è quello che tutti saltano, ed è esattamente quello che si rompe. Se rimandi indietro solo il risultato dello strumento senza il turno di tool call dell'assistente, la conversazione ha un riferimento pendente e il modello non ha traccia di aver chiesto nulla.

Gestire più chiamate

Una risposta può contenere più chiamate a strumenti nello stesso turno. Eseguile una per una e restituisci un messaggio tool per ciascuna chiamata, ciascuno con il proprio tool_call_id. Non unirli.

Controllare le chiamate

tool_choice è la tua leva di policy: auto lascia decidere al modello, richiedere uno strumento specifico ne forza una chiamata, disabilitare gli strumenti gli dice di rispondere direttamente. Mantieni un budget—se uno strumento continua a fallire e il modello continua a riprovare, il ciclo degli strumenti può durare molto. Limita il numero di iterazioni nel tuo ciclo e, al raggiungimento del limite, restituisci un messaggio chiaro invece di lasciare che la richiesta continui a consumarsi.

Trattare l'output degli strumenti come non attendibile

Il modello legge i risultati degli strumenti come testo. Mantienili piccoli, strutturati, privi di istruzioni, e valida i parametri dalla tua parte. Uno strumento che restituisce testo illimitato è sia un problema di costo che un rischio di correttezza.

Risolvere gli errori comuni

La maggior parte dei fallimenti di integrazione ricade in cinque categorie. Segui questa checklist prima di modificare i prompt.

1. Autenticazione e autorizzazione

  • Sintomo: stato HTTP nell'intervallo 401/403.
  • Controlla: la chiave esiste, non ha spazi prima o dopo quando incollata, e ha esattamente il prefisso Bearer .
  • Controlla: l'URL di base corrisponde a quello mostrato nella console HiAPI—un host obsoleto o incollato male produce errori di autenticazione confusi.
  • Correggi: riesporta la variabile d'ambiente, poi riesegui lo smoke test curl, prima di toccare il codice.

2. Payload malformati

  • Sintomo: errore di validazione della richiesta che nomina un campo, o corpo della risposta non analizzabile.
  • Controlla: il corpo della richiesta è JSON valido. Se costruito a mano, validalo con un rapido json.tool; se costruito dal codice, assicurati che il dizionario non sia stato accidentalmente annidato un livello di troppo.
  • Controlla: messages non è vuoto e ogni voce ha role e content.
  • Controlla: i valori di role provengono dall'insieme supportato. Un errore di ortografia come role: "human" in alcuni client è un errore silenzioso invece che evidente.
  • Controlla: le voci di tools hanno type: "function" e un oggetto function annidato. Le definizioni appiattite sono l'errore di tool calling più comune.

3. Identificatore del modello

  • Sintomo: errore di tipo non trovato, o avviso che il modello non è disponibile per il tuo account.
  • Controlla: l'identificatore è copiato esattamente dalla console. Maiuscole e separatori contano.
  • Controlla: il modello è abilitato per la tua chiave. Anche con un identificatore valido, un modello che il tuo account non può chiamare fallirà comunque.

4. Limiti di contesto e lunghezza

  • Sintomo: errore che la richiesta supera il contesto massimo, o risposta che termina con un finish_reason legato alla lunghezza.
  • Controlla: la somma del tuo system prompt, della cronologia dei messaggi e di ogni definizione di strumento. Gli schemi degli strumenti contano nel budget e si dimenticano facilmente.
  • Correggi: riduci la cronologia, riassumi i turni precedenti o suddividi il compito. Per il troncamento dell'output, se il carico richiede davvero di più, aumenta max_tokens; altrimenti mantienilo limitato.

5. Rate limit e timeout

  • Sintomo: stato di rate limit sotto carico, o timeout di lettura del client.
  • Controlla: se i retry partono senza alcun backoff. Un ciclo di retry stretto trasforma un rate limit temporaneo in uno persistente.
  • Correggi: rispetta il segnale di rate limit indicato dalla risposta, usa backoff esponenziale con tetto massimo e jitter, e controlla la concorrenza per chiave. Per i timeout, controlla prima il valore di timeout del client—un limite client più breve del tempo di generazione del modello produce esattamente questo sintomo.

Disciplina generale di debug

Registra quattro cose per ogni fallimento: stato HTTP, corpo della risposta, identificatore del modello e se stream era impostato. Questi quattro elementi spiegano la stragrande maggioranza degli incidenti. E mantieni aggiornato lo smoke test curl—quando passa e la tua applicazione fallisce, sai che il problema è nel codice, non nelle credenziali.

Leggere i messaggi di errore

Il livello di aggregazione di solito dice chiaramente quale campo ha causato il rifiuto. Resisti all'impulso di riscrivere il prompt. Leggi il messaggio, correggi il campo indicato, riprova una volta. Se lo stesso errore persiste, prima di approfondire verifica la richiesta con lo smoke test.

Prima di andare in produzione: checklist di produzione

Il divario tra "funziona nel mio terminale" e "funziona in produzione" è soprattutto una checklist che nessuno ha scritto. Eccone una che vale la pena copiare.

Configurazione e segreti

  • La API key è conservata in un gestore di segreti, mai nel controllo del codice sorgente e mai in un URL o in una riga di log. Verifica che il tuo client HTTP non possa stampare l'header Authorization a livello di debug.
  • L'URL di base e l'identificatore del modello sono configurazione, non costanti sparse nel codice. Verifica l'URL di base con la console.
  • Ruota le chiavi secondo un piano, e dopo l'uscita di qualsiasi membro del team. Il tuo codice client dovrebbe raccogliere la chiave ruotata senza modifiche.

Igiene delle richieste

  • Ogni chiamata in uscita ha un timeout esplicito; il percorso di streaming ha un timeout più permissivo più regole di interruzione per inattività.
  • Ogni percorso di chiamata imposta max_tokens. La generazione illimitata è fatturazione illimitata.
  • Le impostazioni di campionamento sono fissate per caso d'uso e documentate, così i risultati sono riproducibili quando serve il debug.

Gestione delle risposte

  • Il tuo parser ramifica in base a finish_reason e tratta il troncamento come un risultato distinto, non come una risposta completa.
  • L'accumulo in streaming è testato sia su risposte brevi che lunghe, comprese quelle che terminano in anticipo.
  • I parametri del tool calling sono validati prima dell'uso, e il turno di tool call dell'assistente è sempre riportato nell'array dei messaggi.
  • Il ciclo degli strumenti ha un limite di iterazioni e un messaggio di fallimento chiaro.

Comportamento in caso di fallimento

  • I retry sono limitati, usano backoff esponenziale con tetto massimo e jitter, e si applicano solo a operazioni ripetibili in sicurezza.
  • Le risposte di rate limit sono rispettate, non martellate.
  • I fallimenti registrano stato, corpo della risposta, identificatore del modello e flag stream—questi quattro campi sono ciò che risolve davvero gli incidenti.
  • Lo smoke test curl viene eseguito in CI o secondo un piano, così vieni a sapere di cambi di credenziali o di modello dalla dashboard, non dai clienti.

Costi e capacità

  • Sai come viene fatturato l'uso—la piattaforma fattura in base ai token elaborati, quindi contano sia i prompt lunghi che le generazioni lunghe. Controlla le tariffe attuali nel pannello prezzi della console.
  • Sai quale tipo di carico è il maggiore consumatore, e se richiede il modello completo o uno più leggero.
  • Hai un percorso di degradazione: se una chiamata fallisce ripetutamente, l'applicazione degrada in modo visibile invece di restare appesa silenziosamente.

L'ultima domanda

Chiediti: qualcuno che non ha scritto questa integrazione può osservarla. Se uno sviluppatore del tuo team sa leggere lo smoke test, i campi dei log degli errori e la configurazione, e capisce come diagnosticare un fallimento, hai finito. Se no, la checklist non è completa.

Con una chiamata curl eseguibile, un client Python riutilizzabile e questa checklist, kimi-k3.1-pro è davvero integrato, non solo connesso.

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