Vai al contenuto principale

Migrare un flusso di revisione dei testi a DeepSeek V4.1 Flash

Porta la tua chat DeepSeek su V4.1 Flash: ID del modello, campi da eliminare, budget di ragionamento, un test verificato e il costo in token.

Autore
Lydia
Pubblicato
Lettura
13 min di lettura
Aggiornato
Una donna e un uomo parlano ai due lati di una bicicletta turchese in un'officina di riparazione piena di sole.

Immagina un servizio che invia note di riparazione a un modello DeepSeek e si aspetta in risposta un oggetto JSON: cosa è stato ispezionato, cosa è stato consigliato, se il cliente ha approvato, se il lavoro è stato fatto. Oggi chiama deepseek-chat, deepseek-flash o una route OpenRouter, e tu vuoi farlo girare su DeepSeek V4.1 Flash tramite SpicyAPI (spicyapi.ai).

Bastano quattro modifiche: usare l'ID del modello deepseek/v4.1-flash/chat, eliminare ogni campo che questo modello non accetta, scegliere un reasoning_effort e dare a max_tokens un margine reale, perché il ragionamento si paga con lo stesso budget. Poi esegui un piccolo caso di test prima del traffico reale. Usa la pagina del modello V4.1 Flash per provare la richiesta.

Cosa cambiare nella richiesta

URL di base, chiave e ID del modello sono la parte facile (guida alla migrazione). È il corpo della richiesta che si rompe:

Nel tuo client attualeSu SpicyAPI
URL di base https://api.deepseek.com e una chiave DeepSeekhttps://api.spicyapi.ai/v1 e una chiave che inizia con sk-spicy-
Modello deepseek-flash, o i vecchi deepseek-chat, deepseek-reasoner, deepseek-v4-flash, deepseek-v4-prodeepseek/v4.1-flash/chat
thinking: {"type": "disabled"}, il comportamento che dava deepseek-chatreasoning_effort: "none" salta il passaggio di ragionamento
Thinking attivo (il valore predefinito)Ometti reasoning_effort per high, oppure imposta low per il lavoro in volume
reasoning_effort con max, medium, minimal, xhighSono accettati solo none, low e high; qualsiasi altro valore restituisce 400 invalid_request
temperature, top_p, presence_penalty, frequency_penaltyEliminali; 400 unsupported_parameter
parallel_tool_callsEliminalo; non esposto su questo modello
stopTienilo: fino a 4 sequenze, e il testo corrispondente non compare nella risposta
Parti image_url o fileTieni le parti image_url per le immagini; rimuovi le parti PDF/file ed estrai prima il loro testo
OpenRouter models, route, provider, usage, transforms, plugins e un oggetto reasoningElimina i primi sei; sostituisci reasoning con reasoning_effort di primo livello

Questo modello ospitato non ha alcun controllo di campionamento, nemmeno con reasoning_effort: "none". Convalida i risultati dei compiti invece di affidarti a temperature: 0 per la ripetibilità.

Cosa resta uguale: messages (contenuto testuale o immagine, fino a 256), tools (fino a 128 definizioni) con tool_choice (auto, none, required o una funzione indicata per nome), response_format con {"type": "json_object"}, stop, max_tokens (predefinito 32.768, massimo 384.000) e una finestra di input di 1.048.576 token che conta ogni messaggio inviato, compresi il prompt di sistema e i risultati degli strumenti precedenti.

SpicyAPI non scarta mai un campo in silenzio: il 400 indica il campo e non viene addebitato nulla. L'API di DeepSeek accetta e ignora temperature e i campi di penalità in modalità thinking, quindi un vecchio client può portarseli dietro senza che nessuno se ne accorga.

L'errore silenzioso è il nome del modello. Sull'API di DeepSeek, V4 Flash è stato ritirato e deepseek-v4-flash reindirizza temporaneamente a V4.1 Flash; il nome attuale è deepseek-flash. V4 Pro è diverso: DeepSeek aveva annunciato inizialmente il passaggio a Flash per il 14 settembre, poi il suo registro delle modifiche ha confermato che il servizio V4 Pro sarebbe proseguito con la fatturazione invariata. Non migrare dando per scontato che ogni vecchia chiamata Pro giri già su Flash.

Su SpicyAPI le tre route chat di DeepSeek hanno contratti pubblicati distinti: mantenere deepseek/v4-flash/chat nella configurazione è una richiesta valida, con un tetto di output di 65.536 token e prezzi più alti. Un alias del servizio nativo non cambia quel contratto ospitato. Per questa migrazione usa esplicitamente deepseek/v4.1-flash/chat.

Questa route accetta immagini tramite parti image_url, ma non parti PDF/file. Estrai il testo di un PDF prima di inviarlo; gli esempi sotto, con sole note di riparazione in testo, non richiedono input di immagini.

Lascia spazio alla risposta

Il modello ragiona prima di rispondere, e il ragionamento viene prelevato da max_tokens. L'effort predefinito è high, e un tetto di 120 token non ha restituito alcun contenuto. Il max_tokens predefinito è 32.768, e un risultato più lungo viene troncato. Dimensiona il tetto sulla risposta visibile più alcune migliaia di token di spazio per pensare, non sul massimo di 384.000.

Inizia l'estrazione con effort Low. Se perde una distinzione necessaria, prova High su quel record invece di rendere più costosa ogni riga. Per input grandi usa l'interfaccia di streaming.

Prova prima nel Playground

  1. Apri DeepSeek V4.1 Flash, scegli Playground e imposta il controllo dell'effort su Low.
  2. Inserisci l'istruzione sulla forma del JSON dallo script qui sotto in System prompt e la nota di riparazione R17 in Message to the model, poi fai clic su Run model.
  3. Verifica che un'approvazione in sospeso non diventi una riparazione completata prima di migrare la tua app.

Esegui un caso di test che intercetta l'errore costoso

Una nota di riparazione è un buon caso di test perché un riassunto scorrevole può essere sbagliato in un modo che costa denaro. «Consigliata la sostituzione» non è approvazione del cliente, e l'approvazione non è lavoro completato.

Metti una chiave da API Keys in SPICY_API_KEY, salva questo script come check_repair.py ed esegui python3 check_repair.py. Il prompt di sistema mostra la forma del JSON e contiene la parola «json», richiesta dalla guida alla modalità JSON di DeepSeek.

python
import json
import os
import uuid
import urllib.request
import re

SOURCE = (
    'Repair note R17: "Inspected the rear brake pads. Recommend replacement before '
    'the next long ride. Customer approval is pending." No later work record is supplied.'
)
KEYS = {"inspected", "recommended_action", "authorized", "completed", "evidence"}
REQUIRED_QUOTES = (
    "Inspected the rear brake pads.",
    "Recommend replacement before the next long ride.",
    "Customer approval is pending.",
)


def check(response: dict) -> list[str]:
    choice = response["choices"][0]
    problems = []
    if choice.get("finish_reason") != "stop":
        problems.append(f"finish_reason is {choice.get('finish_reason')!r}: the reply may be cut off")
    content = (choice.get("message") or {}).get("content")
    if not content or not content.strip():
        return problems + ["empty content: reasoning may have used the whole max_tokens budget"]
    try:
        data = json.loads(content)
    except json.JSONDecodeError as error:
        return problems + [f"not valid JSON: {error}"]

    if not isinstance(data, dict):
        return problems + ["JSON must be an object"]
    if missing := KEYS - data.keys():
        problems.append(f"missing keys: {sorted(missing)}")
    for key in ("inspected", "authorized", "completed"):
        if data.get(key) is not None and type(data.get(key)) is not bool:
            problems.append(f"{key} must be true, false or null")
    if data.get("inspected") is not True:
        problems.append("inspected should be true")
    if data.get("authorized") is not False:
        problems.append("authorized must be false: approval is pending")
    if data.get("completed") is not None:
        problems.append("completed must be null: no completion record is supplied")
    action = data.get("recommended_action")
    if not isinstance(action, str) or not action.strip():
        problems.append("recommended_action must be a non-empty string")
    else:
        words = set(re.findall(r"[a-z]+", action.lower()))
        # A lexical screen, not a proof of semantic equivalence.
        required = {"rear", "long", "ride"}
        compatible = (required <= words
                      and bool(words & {"replace", "replacement", "replacing"})
                      and bool(words & {"pad", "pads"})
                      and not words & {"not", "no", "never", "front", "after"})
        if not compatible:
            problems.append("review recommendation wording against R17")
    quotes = data.get("evidence")
    if not isinstance(quotes, list) or not quotes:
        problems.append("evidence must be a non-empty list of quotes")
    else:
        problems += [f"invalid or unmatched quote: {q!r}" for q in quotes
                     if not isinstance(q, str) or not q.strip() or q not in SOURCE]
        for expected in REQUIRED_QUOTES:
            if not any(isinstance(q, str) and expected in q for q in quotes):
                problems.append(f"missing supporting quote: {expected}")
    return problems



body = {'model': 'deepseek/v4.1-flash/chat',
 'messages': [{'role': 'system',
               'content': 'Extract only facts stated in the source. Reply with one '
                          'JSON object shaped like {"inspected": null, '
                          '"recommended_action": null, "authorized": null, '
                          '"completed": null, "evidence": []}. inspected, '
                          'authorized and completed are true, false or null; use '
                          'null for anything the source does not state. evidence '
                          'lists exact quotes from the source that support every '
                          'non-null value.'},
              {'role': 'user',
               'content': 'Repair note R17: "Inspected the rear brake pads. '
                          'Recommend replacement before the next long ride. '
                          'Customer approval is pending." No later work record is '
                          'supplied.'}],
 'max_tokens': 2048,
 'reasoning_effort': 'low',
 'response_format': {'type': 'json_object'}}
request = urllib.request.Request(
    "https://api.spicyapi.ai/v1/chat/completions",
    data=json.dumps(body).encode(),
    headers={"Authorization": "Bearer " + os.environ["SPICY_API_KEY"],
             "Content-Type": "application/json",
             "Idempotency-Key": str(uuid.uuid4())},
)
with urllib.request.urlopen(request, timeout=90) as reply:
    response = json.load(reply)
problems = check(response)
print(json.dumps(response.get("usage", {})))
if problems:
    raise RuntimeError("; ".join(problems))
print(response["choices"][0]["message"]["content"])

La decisione attesa è: ispezionato, approvazione ancora in sospeso, completamento sconosciuto. La raccomandazione deve mantenere le pastiglie posteriori e la scadenza «prima del prossimo viaggio lungo».

Aggiungi approvazione e completamento come casi di test separati

Non fermarti al caso dell'approvazione in sospeso. Usa questi come modelli per altri casi di test: aggiorna SOURCE, REQUIRED_QUOTES e i valori attesi di approvazione/completamento prima di eseguire ciascuno. Il controllo di R17 non è eseguibile direttamente su R18 o R19:

Ultimo recordAuthorizedCompleted
R17: “Customer approval is pending.” Nessun record successivofalsenull
R18: “Customer approved the quoted replacement. Parts ordered; work scheduled for Thursday.”truenull
R19: “Replaced pads; road check completed Thursday.” Collegato all'intervento approvatotruetrue

Conserva insieme alla fonte l'ID dell'intervento, l'ordine dei record e le date: R18 sostituisce l'approvazione in sospeso, ma la programmazione del lavoro non stabilisce il completamento. Se una nota «fatto» senza data non può essere collegata allo stesso intervento, restituisci il collegamento irrisolto invece di fonderla con R17.

La stessa divisione in tre appare nel flusso di produzione di un creator: «Approva questo design del personaggio», «design approvato» e «video generato dal design approvato» sono una richiesta, una decisione e un'esecuzione. Chiedi al prompt di estrazione queste fasi separatamente, con il record che sostiene ciascuna, e conserva ogni conflitto tra note invece di chiedere al modello di scegliere la frase che suona più sicura.

Tieni separati approvazione e completamento nei flussi con strumenti

Un record di approvazione non prova che la riparazione sia avvenuta: cerca il record di completamento prima di cambiare lo stato, e tieni approvazione e completamento come campi separati in ciò che restituiscono i tuoi strumenti.

La chat senza strumenti non richiede nulla di extra. Con tools nella richiesta, un client che ricostruisce ogni messaggio dell'assistente con solo ruolo e contenuto supera il primo turno e fallisce al secondo con un 400, quindi un test a turno singolo nasconde il bug. Aggiungi il messaggio dell'assistente esattamente come restituito, compreso reasoning_content, poi un messaggio tool per ogni chiamata con il tool_call_id corrispondente, e limita il numero di round. Testa due turni, non uno. Le ricette per la chat mostrano il ciclo completo.

Lascia che un Agent prepari la chiamata

Per l'estrazione ripetuta di record, chiedi al tuo Agent di programmazione di usare lo Skill SpicyAPI: “Read deepseek/v4.1-flash/chat, then adapt the example to my input; show the request before running it.” La consultazione con la CLI è spicyapi models get deepseek/v4.1-flash/chat --json; con MCP è spicyapi_model_get con model: "deepseek/v4.1-flash/chat". Le chiamate chat usano un client compatibile o l'API chat; i comandi per le attività multimediali non generano risposte di chat.

Ricalcola il conto

Le tariffe sono 0,30 $ per milione di token di input non in cache, 0,006 $ per milione di input in cache e 1,20 $ per milione di output, una tariffa unica a qualsiasi lunghezza di richiesta. Un prompt da 40.000 token non in cache con 2.000 token di output costa 0,0144 $. Se 30.000 dei token di input sono fatturati come in cache e 10.000 come non in cache, la stessa chiamata costa 0,00558 $. I token di ragionamento si fatturano come output, quindi una breve risposta visibile può usare più output di quanto ti aspetti; none è l'unica impostazione che li tiene fuori dal conto.

Due confronti contano quando lasci l'API di DeepSeek. I suoi prezzi di listino sono gli stessi 0,30 $, 0,006 $ e 1,20 $ nelle ore di punta, ma fuori punta lì costano la metà, mentre qui c'è una tariffa unica: un batch che pianifichi fuori punta su DeepSeek costa circa il doppio su SpicyAPI per gli stessi token. E la tariffa in cache è un cinquantesimo di quella di input, ma solo per un prefisso identico byte per byte da una chiamata all'altra: un prompt di sistema da 1.500 token su 10.000 chiamate fa 15 milioni di token di input, 4,50 $ non in cache e al massimo 0,09 $ se ognuno fosse una lettura da cache. Confronta lo usage restituito e il costo liquidato con queste stime. Un timestamp o istruzioni riordinate possono rompere un prefisso condiviso; un input invariato da solo non garantisce un cache hit.

Dove approda ogni route DeepSeek

V4.1 FlashV4 FlashV4 Pro
ID del modellodeepseek/v4.1-flash/chatdeepseek/v4-flash/chatdeepseek/v4-pro/chat
Output max384.00065.536384.000
Input / cache / output per 1 M0,30 $ / 0,006 $ / 1,20 $0,44 $ / 0,014 $ / 1,32 $1,32 $ / 0,044 $ / 3,96 $
parallel_tool_callsNon espostoNon espostoEsposto

Tutte e tre accettano 1.048.576 token di input, effort none, low o high (predefinito high) e un max_tokens predefinito di 32.768. Se parti da deepseek/v4-flash/chat, il corpo della richiesta è identico, quindi cambia solo l'ID: il tetto di output cresce di quasi sei volte e ogni tariffa scende. Se parti da V4 Pro, perdi parallel_tool_calls e paghi il 77% in meno per l'input e circa il 70% in meno per l'output. Se per un dato compito sia meglio V4 Flash o V4 Pro è un'altra decisione, trattata in DeepSeek V4 Flash vs Pro.

Se la tua app scrive narrativa per adulti

V4.1 Flash è indicato come senza censura su SpicyAPI, ma questo non è una promessa che completi ogni richiesta di narrativa per adulti. Nei nostri test di settembre 2026, le richieste dirette di scene mature intense sono tornate attenuate ogni volta, mentre inquadrarle come narrativa o impostare la cornice nel prompt di sistema ne ha reso di più per intero, anche se non tutte (dettagli nella recensione di V4.1 Flash). Se i tuoi prompt erano scritti per un modello che accettava richieste dirette, sposta l'inquadramento nel messaggio di sistema durante la migrazione e mantieni adulto ogni personaggio.

Correggi direttamente i fallimenti della migrazione

SintomoCausa probabileCorrezione
400 unsupported_parameter che indica temperature, top_p, una penalità, parallel_tool_calls o thinkingCampo portato dal vecchio clientEliminalo
content è vuoto o finish_reason è lengthmax_tokens consumato dal ragionamento, o la risposta lo ha superatoAlza max_tokens, abbassa l'effort, riprova
Il JSON viene analizzato ma riporta lavoro completatoRaccomandazione letta come completamentoMantieni campi separati, richiedi citazioni, esegui il controllo
Errore al secondo turno di una conversazione con strumentiMessaggio dell'assistente ricostruito senza reasoning_contentAggiungi il messaggio restituito senza modifiche
402 con saldo sufficienteIl blocco (hold) 40201 supera il saldo, oppure è stato raggiunto il limite di spesa 40202Ispeziona l'errore: riduci un budget di output eccessivo per il blocco, oppure controlla i limiti di chiave/workspace
Idempotency-Key riutilizzata rifiutata (400 o 409)La chiave appartiene a una richiesta completata o a un corpo diversoUn 400 per una richiesta completata non può riprodurre la risposta; un 409 può indicare un corpo cambiato. Riusa la chiave solo per un nuovo tentativo di rete identico entro la sua finestra; controlla la liquidazione dell'attività prima di scegliere una nuova chiamata a pagamento
Una chiamata lunga senza streaming cade intorno ai 100 secondiInterruzione al bordo della reteTrasmetti la risposta in streaming

Passa al nuovo modello senza perdere la vecchia base di confronto

Tieni l'ID del vecchio modello nella configurazione ed esegui il caso di test su entrambi. Sposta il traffico quando il test passa con il nuovo ID, le tue fonti si convalidano e lo usage registrato corrisponde ai calcoli sopra.

Anche in English · 日本語 · 한국어 · Deutsch · Français · Español · Português (Brasil) · Русский · Polski

Provalo tu stesso

Paghi solo quello che esegui: nessun piano, nessun abbonamento.

Creato con MiniMax H3 · ByteDance Seedance 2.0 Fast