Inférence Nordique transmet directement les images aux modèles capables de vision (Gemini, Claude, la classe Gemini 2.5 Pro, et d'autres). Deux éléments méritent d'être connus : comment envoyer une image, et comment un client sensible aux capacités peut détecter qu'une route prend en charge les images.
Comment NI annonce les capacités
Chaque route de modèle desservie par NI porte des métadonnées de capacités à la fois sur /v1/models et sur /api/billing/models. La réponse de style OpenAI /v1/models ajoute des champs NI sur chaque objet de modèle :
curl -sS https://northerninference.ca/v1/models \
-H "Authorization: Bearer $NI_API_KEY" | jq '.data[] | {id, supports_vision, capabilities}'
Vous verrez, par route :
{
"id": "claude-sonnet-4-6-t4",
"supports_vision": true,
"capabilities": {
"supports_vision": true,
"modalities": ["text", "image"],
"context_window": 1048576,
"max_output_tokens": 65535,
"supports_function_calling": true
}
}
supports_vision est reproduit au niveau supérieur afin qu'un client qui ne lit que des champs plats puisse quand même le détecter. Le même objet capabilities se trouve sur chaque entrée de /api/billing/models.
Ces informations sont fondées sur les données : NI les détermine à partir du registre des capacités des modèles (le catalogue de modèles en amont), puis d'une correspondance sélective avec la famille de modèles de base, puis d'une valeur par défaut prudente. Il ne s'agit pas d'une liste tenue manuellement, de sorte que les modèles nouvellement découverts portent automatiquement leurs capacités.
Envoyer une image (bloc de contenu image_url d'OpenAI)
Envoyez l'image comme bloc de contenu dans le message de l'utilisateur. Une URL de données en base64 fonctionne sans aucune étape de téléversement :
B64=$(base64 -i screenshot.png | tr -d '\n')
curl -sS https://northerninference.ca/v1/chat/completions \
-H "Authorization: Bearer $NI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-6-t4",
"messages": [
{"role": "user", "content": [
{"type": "text", "text": "What does this image say? Quote the text exactly."},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,'"$B64"'"}}
]}
],
"max_tokens": 300
}'
Une URL d'image publique https:// fonctionne aussi (le fournisseur la récupère) :
{"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}}
Choisissez n'importe quelle route dont le supports_vision est true. Les routes Gemini 2.5 pro/flash, Claude 4.x et de la classe Gemini 2.5 Pro sont toutes admissibles.
Anthropic-native /v1/messages
Si vous appelez /v1/messages plutôt que /v1/chat/completions, utilisez la structure de bloc d'image Anthropic :
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "<BASE64>"}}
Si votre client refuse de joindre des images
Certains clients (Cursor, Continue et d'autres outils sensibles aux capacités) conservent une table intégrée indiquant quels noms de modèles prennent en charge les images, indexée sur des noms standards comme gpt-4o ou gemini-2.5-pro. Les identifiants de route NI sont personnalisés (par exemple claude-sonnet-4-6-t4), donc un client avec une table codée en dur ne trouvera pas de correspondance pour la route et refusera de joindre l'image, la retirant avant même qu'elle n'atteigne NI. La requête arrive alors en texte seulement et le modèle ne voit jamais l'image.
Deux réglages corrigent cela :
- Utilisez un client qui lit les capacités à partir de
/v1/models. Il détectera
supports_vision et autorisera automatiquement les images sur les routes NI.
- Pour un client avec une table codée en dur, définissez une substitution par modèle afin que le
client traite la route NI comme prenant en charge la vision. La plupart de ces clients exposent un bouton « supports images » / « vision » par modèle dans leurs paramètres de modèle. Activez-le pour la route NI que vous avez ajoutée. (Consultez le guide propre au client, par exemple cursor.md, pour savoir où se trouve ce bouton.)
Si les images n'arrivent toujours pas, confirmez que le client intègre bien l'image comme un bloc image_url et n'envoie pas un chemin de fichier en texte brut. Vous pouvez vérifier que NI a reçu une image en consultant la requête dans portail → Utilisation : une requête de vision affiche des parties de contenu image.
Raisonnement et effort de réflexion
Les modèles qui réfléchissent avant de répondre (réflexion étendue de Claude, série o d'OpenAI et raisonnement gpt-5+) exposent deux contrôles différents. Choisissez celui qui est portable, à moins que vous soyez certain que votre route est Anthropic.
Utilisez reasoning_effort pour la portabilité entre fournisseurs
reasoning_effort accepte low, medium ou high et constitue le contrôle portable :
- Sur une route de raisonnement OpenAI (série o, gpt-5+), il correspond à l'effort de raisonnement natif de ce modèle.
- Sur une route Claude, NI le convertit dans le réglage qu'utilise cette route. Une route en réflexion adaptative reçoit la réflexion adaptative à cet effort. Une route en réflexion à budget reçoit un budget de réflexion Anthropic (faible : environ 8k, moyen : environ 25k, élevé : environ 64k jetons de réflexion).
{
"model": "claude-sonnet-4-6-t4",
"messages": [{"role": "user", "content": "Plan a refactor of this module."}],
"reasoning_effort": "high",
"max_tokens": 70000
}
Le raisonnement fonctionne avec les API Chat Completions et Responses
Envoyez reasoning_effort sur /v1/chat/completions, ou reasoning.effort sur /v1/responses. Dans les deux cas, le modèle raisonne, et usage indique les jetons de raisonnement.
- Le texte du raisonnement est fourni sur demande, comme dans l'API Responses d'OpenAI. Il n'est renvoyé que lorsqu'une requête
/v1/responsesrèglereasoning.summaryà"auto"ou"detailed". Sur/v1/chat/completions, un champreasoning_summaryest refusé avec un code 400. - Sans
reasoning.summary, le modèle raisonne quand même etusageen tient compte, mais l'élémentreasoningde la réponse a unsummaryvide et aucun texte lisible. Ce que cet élément contient sur les routes Claude est expliqué sous « Conserver le raisonnement de Claude entre les appels d'outils sur /v1/responses » ci-dessous. - Certains modèles refusent un paramètre d'échantillonnage comme
temperatureoutop_p. NI omet un paramètre refusé, et la requête s'exécute avec la valeur par défaut du modèle au lieu d'échouer. L'en-tête de réponsex-ni-params-droppednomme ce qui a été omis, et, dans une réponse/v1/responses, ces champs valentnull.
thinking budget_tokens est natif à Anthropic, traduit automatiquement ailleurs
Le bloc thinking natif d'Anthropic (et le drapeau d'effort de Claude Code, qui l'envoie) est natif sur les routes Anthropic. Sur une route non Anthropic, NI convertit automatiquement le budget de réflexion en reasoning_effort portable (regroupé en faible, moyen ou élevé) afin que votre requête de raisonnement fonctionne quand même sur GPT, Gemini, DeepSeek et d'autres modèles de raisonnement, plutôt que d'être rejetée. Cette conversion est grossière (un budget de jetons précis devient un effort à trois niveaux), donc pour un contrôle précis entre fournisseurs, préférez directement reasoning_effort. Une route sans aucun mode de raisonnement (par exemple Llama ou Mistral) renvoie une réponse normale sans raisonnement.
max_tokens doit dépasser le budget de réflexion
Le budget de réflexion est prélevé sur max_tokens. Si votre budget est de 32000, max_tokens doit être plus grand (par exemple 40000), sinon la requête renvoie une erreur 400 parce qu'il ne reste plus de place pour la réponse visible. Règle de base : réglez max_tokens à au moins le budget de réflexion plus la réponse la plus longue que vous attendez.
Où va le texte de raisonnement
- Les routes Anthropic renvoient le texte de réflexion dans un bloc de contenu
thinking(oureasoning_contentsur le chemin compatible OpenAI), afin que vous puissiez l'afficher ou le consigner. - Les routes série o d'OpenAI masquent le raisonnement brut; vous n'obtenez que la réponse finale ainsi qu'un nombre de jetons de raisonnement dans
usage.
NI facture explicitement les jetons de réflexion selon le tarif de réflexion de chaque route, sans double facturation par rapport aux jetons de sortie.
Conserver le raisonnement de Claude entre les appels d'outils sur /v1/responses
Lorsqu'une route Claude réfléchit avant d'appeler un outil, la réponse /v1/responses comprend un élément reasoning dans output, juste avant l'élément auquel il a mené. Son champ encrypted_content transporte les blocs de réflexion de Claude exactement tels que le modèle les a renvoyés, avec la signature de Claude.
Renvoyez ces éléments pour que Claude puisse reprendre son propre raisonnement après l'exécution de votre outil :
- Conservez chaque élément de
output, dans l'ordre où vous l'avez reçu, y compris chaque élémentreasoning. - À la requête suivante, placez ces éléments dans
input, suivis de vos élémentsfunction_call_output. - Ne modifiez pas, ne réordonnez pas et ne reconstruisez pas les éléments
reasoning.
Si vous les omettez, la requête fonctionne quand même, mais Claude répond au résultat de l'outil sans sa réflexion antérieure.
- Vous recevez
encrypted_contentdans chaque réponse de ces routes. Vous n'avez pas besoin d'envoyerinclude: ["reasoning.encrypted_content"], et l'envoyer ne change rien. - Tant qu'Inférence Nordique garde cette fonction désactivée, les réponses ne contiennent aucun
encrypted_content,x-ni-reasoning-stateindiqueskipped=disabled, et les éléments de raisonnement que vous renvoyez sont omis. Vos requêtes fonctionnent quand même. - NI ne stocke pas les réponses, donc
previous_response_idne peut pas vous rendre le raisonnement. Conservez les éléments vous-même. - Une réponse peut contenir plus d'un élément
reasoning, par exemple lorsque Claude rédige une courte note d'avancement avant un appel d'outil ultérieur. Conservez-les tous. summarycontient du texte de réflexion lisible seulement lorsque la route le renvoie, par exemple lorsque vous demandezreasoning.summarysur une route qui le prend en charge. Sinon,summaryest vide et le raisonnement ne voyage que dansencrypted_content.- NI signe
encrypted_contentafin de pouvoir détecter toute modification. NI ne le chiffre pas, et il peut contenir le même texte que celui que vous voyez danssummary. Conservez-le avec le même soin que le reste de la conversation. - NI ne transmet votre raisonnement que si le même fournisseur, avec le même compte, traite votre requête suivante. Sinon, cette requête s'exécute sans le raisonnement antérieur, et
x-ni-reasoning-stateindiqueskipped=domain_mismatch. - NI vérifie chaque élément qu'il reçoit. Si un élément a été modifié, provient d'une autre route ou d'un autre compte, ou ne se trouve pas juste avant l'élément auquel il appartient, NI omet tous les éléments de raisonnement de cette réponse, et pas seulement celui-là. La requête s'exécute alors comme si vous n'aviez pas envoyé ce raisonnement. L'en-tête de réponse
x-ni-reasoning-statevous indique si votre raisonnement a été transmis. - Les éléments de raisonnement d'autres fournisseurs sont ignorés sur les routes Claude, et NI retire ses propres éléments avant qu'une requête soit envoyée à une route qui ne peut pas les utiliser.
- Claude lit le raisonnement que vous renvoyez comme entrée, facturé en jetons d'entrée ou en jetons d'entrée en cache exactement comme le fournisseur les déclare.