NouveauBranchez n’importe quel agent sur UberLLM : une clé, tous les modèles, au prix catalogue ou moins.
UberLLM

Responses API

POST https://api.uberllm.dev/v1/responses propose l'API Responses d'OpenAI sur chaque modèle de chat du catalogue. Utilisez-la depuis le SDK OpenAI (client.responses.create), le Codex CLI, ou toute application dotée d'un mode "Responses". Les requêtes passent par le même routage, les mêmes nouvelles tentatives, les mêmes limites de clés et la même facturation que /v1/chat/completions, et chaque appel est répertorié dans Tableau de bord → Activité avec son coût.

curl https://api.uberllm.dev/v1/responses \
  -H "Authorization: Bearer $UBERLLM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek/deepseek-v4.1-flash",
    "instructions": "Answer in one short sentence.",
    "input": "What is the capital of France?"
  }'
from openai import OpenAI

client = OpenAI(base_url="https://api.uberllm.dev/v1", api_key="ull_...")
r = client.responses.create(model="deepseek/deepseek-v4.1-flash", input="Say hi")
print(r.output_text)

Aucun état stocké

UberLLM ne conserve pas les réponses pour que vous puissiez les reprendre plus tard. Chaque réponse a "store": false, et vous envoyez toute la conversation en input à chaque appel : les messages utilisateur précédents, les éléments de sortie du modèle et les résultats de vos outils. Codex CLI fonctionne déjà de cette manière.

Ceux-ci sont refusés avec un 400 (code: unsupported_parameter) qui nomme le champ :

  • previous_response_id et conversation
  • background: true
  • éléments d'entrée de type item_reference
  • modèles d'invite stockés (prompt)

GET /v1/responses/{id} et les autres routes de réponse stockées n'existent pas.

Requête

Champ Ce qui se passe
model Tout ID de modèle de chat, alias ou suffixe :floor / :nitro, comme pour les complétions de chat.
input Une chaîne de caractères, ou une liste d'éléments (ci-dessous).
instructions Envoyé au modèle comme message système.
stream true pour les événements envoyés par le serveur.
max_output_tokens La limite de sortie.
temperature, top_p, seed, stop Transmis au modèle.
tools, tool_choice, parallel_tool_calls Voir Outils ci-dessous.
reasoning.effort Transmis comme effort de raisonnement du modèle (modèles qui réfléchissent).
text.format text, json_object, ou json_schema (sortie structurée).
metadata Vos propres tags, affichés sur la ligne d'Activité, comme pour les complétions de chat.
provider, models Options de routage UberLLM, comme pour les complétions de chat (Modèles et routage).
store, include, prompt_cache_key, service_tier, truncation Acceptés et non utilisés. Le raisonnement chiffré est toujours renvoyé.

Éléments d'entrée

Élément Devient
message avec le rôle user, assistant, system ou developer Un message de chat. developer est envoyé comme system. Parties de contenu input_text, output_text, input_image (image_url : une URL https ou data:) et input_file (file_data ou file_url).
function_call L'appel d'outil de l'assistant, maintenu dans l'ordre.
function_call_output Le résultat de l'outil. Les images dans une sortie sont envoyées au tour d'utilisateur suivant.
custom_tool_call, custom_tool_call_output Un appel à un outil personnalisé (libre), et son résultat.
reasoning Le raisonnement antérieur du modèle, redonné au modèle au tour suivant.
web_search_call et autres enregistrements d'outils hébergés Ignorés.

Les éléments id sont acceptés et ignorés. file_id (fichiers téléchargés) n'est pas pris en charge dans input_image / input_file : envoyez le fichier en ligne ou par URL.

Outils

  • function : {"type": "function", "name", "description", "parameters", "strict"}. L'appel du modèle revient sous forme d'un élément function_call avec call_id, name et arguments (une chaîne JSON). Répondez avec un élément function_call_output portant le même call_id.
  • custom (entrée libre, comme apply_patch de Codex) : le modèle reçoit l'outil avec une seule entrée de chaîne, et la grammaire en format.definition comme description. L'appel revient sous forme d'un élément custom_tool_call avec le input brut.
  • namespace (outils MCP de Codex) : chaque outil à l'intérieur est proposé au modèle sous son espace de noms et son nom joints (mcp__github__get_issue) ; l'appel revient avec name et namespace à nouveau séparés.
  • Outils hébergés (web_search, file_search, code_interpreter, image_generation, computer_use, mcp) fonctionnent sur les propres serveurs d'OpenAI. Ils sont exclus de la requête et le modèle répond sans eux.

tool_choice prend "auto", "none", "required", ou {"type": "function", "name": "…"}.

Réponse

{
  "id": "resp_…",
  "object": "response",
  "created_at": 1793333237,
  "status": "completed",
  "model": "deepseek/deepseek-v4.1-flash",
  "output": [
    {"type": "reasoning", "id": "rs_…", "summary": [],
     "content": [{"type": "reasoning_text", "text": "…"}], "encrypted_content": "ull1:…"},
    {"type": "message", "id": "msg_…", "status": "completed", "role": "assistant",
     "content": [{"type": "output_text", "text": "Paris.", "annotations": []}]},
    {"type": "function_call", "id": "fc_…", "status": "completed",
     "call_id": "call_…", "name": "get_weather", "arguments": "{\"city\":\"Paris\"}"}
  ],
  "usage": {
    "input_tokens": 43, "input_tokens_details": {"cached_tokens": 0},
    "output_tokens": 23, "output_tokens_details": {"reasoning_tokens": 0},
    "total_tokens": 66, "cost_usd": 0.0000184
  },
  "store": false
}
  • Un élément reasoning apparaît lorsque le modèle renvoie son raisonnement. Renvoyez-le dans le prochain input tel quel : encrypted_content contient le raisonnement afin que les modèles qui en ont besoin au tour suivant le reçoivent.
  • status est incomplete lorsque la réponse a atteint max_output_tokens (incomplete_details.reason: "max_output_tokens") ou un filtre de contenu ("content_filter").
  • usage.cost_usd correspond à ce qui a été facturé pour l'appel. Les réponses non-streaming le contiennent également dans l'en-tête X-UberLLM-Cost-USD, et chaque réponse a X-Request-Id, l'id de sa ligne d'Activity.
  • Les paramètres que vous avez envoyés (instructions, tools, temperature, max_output_tokens…) sont renvoyés comme le fait OpenAI.

Streaming

Avec "stream": true la réponse est des événements Server-Sent, chacun avec type et un sequence_number commençant à 0 :

  1. response.created, response.in_progress
  2. Pour chaque élément de sortie : response.output_item.added, puis ses deltas, puis response.output_item.done avec l'élément terminé :
    • texte : response.content_part.added, response.output_text.delta…, response.output_text.done, response.content_part.done
    • raisonnement : response.reasoning_text.delta…, response.reasoning_text.done
    • appel de fonction : response.function_call_arguments.delta…, response.function_call_arguments.done
    • appel d'outil personnalisé : response.custom_tool_call_input.done
  3. response.completed (ou response.incomplete) avec la réponse complète et ses usage, incluant cost_usd.

Pendant qu'un modèle lent démarre, : ping lignes de commentaire maintiennent la connexion ouverte. Chaque client SSE les ignore.

Erreurs

Une requête refusée avant le démarrage du stream reçoit un statut HTTP et l'enveloppe d'erreur d'OpenAI, identique à celle des complétions de chat (401, 402 hors crédit, 404 modèle inconnu, 429 ; voir Erreurs). Si quelque chose échoue après le démarrage du stream, cela se termine par response.failed, dont le response.error contient code et message. Un stream qui s'arrête avant que le modèle n'ait terminé se termine également par response.failed, jamais par response.completed, afin que les clients réessayent au lieu de garder une demi-réponse.