Aller au contenu

Chat compatible OpenAI ​

Utilisez POST /v1/chat/completions et GET /v1/models avec le SDK OpenAI Python ou JavaScript en modifiant l’URL de base et la clé API. La compatibilité couvre le format texte Chat Completions, pas toutes les fonctionnalités OpenAI.

Authentification et modèles ​

Utilisez la clé de la console : Authorization: Bearer sk-your-key. La liste contient les modèles texte disponibles et leurs identifiants publics. Utilisez le champ id renvoyé, pas le nom affiché. Les tarifs et les voix restent accessibles via /v1/chat/catalog.

bash
curl https://api.coldstart.win/v1/models -H "Authorization: Bearer sk-your-key"
json
{"object":"list","data":[{"id":"chat-standard","object":"model","created":0,"owned_by":"girllab"}]}

Requêtes et historique ​

Chaque requête doit fournir le tableau messages complet et ordonné. Rôles acceptés : system, developer, user, assistant, tool. Le contenu est une chaîne ou un tableau de { "type": "text", "text": "..." }. Aucun historique serveur ni personnage par défaut n’est ajouté. Renvoyez les instructions système nécessaires et l’historique pertinent à chaque tour.

bash
curl https://api.coldstart.win/v1/chat/completions \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{"model":"chat-standard","messages":[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"Hello!"}],"max_tokens":256}'
json
{
  "id": "chatcmpl_example",
  "object": "chat.completion",
  "created": 1792540800,
  "model": "chat-standard",
  "choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello!", "refusal": null}, "logprobs": null, "finish_reason": "stop"}],
  "usage": {"prompt_tokens": 12, "completion_tokens": 3, "total_tokens": 15}
}

Paramètres acceptés ​

model et un tableau messages non vide sont obligatoires. Options : stream (false par défaut), temperature (0–2), top_p (0–1), max_tokens ou max_completion_tokens (entier 1–8192, exclusifs), stop (une chaîne ou 1–4 chaînes), presence_penalty et frequency_penalty (−2–2), seed (entier sûr), n (1 uniquement). Les paramètres omis utilisent les valeurs du service ; leur effet dépend du modèle. stream_options: {"include_usage": true} exige stream: true. Les valeurs null optionnelles utilisent les valeurs par défaut. Le corps JSON est limité à 15 MiB ; la limite de contexte dépend du modèle.

Streaming et utilisation ​

Le SSE utilise uniquement data:, sans événements personnalisés event: delta ou event: completed. Lisez choices[0].delta.content, puis finish_reason (stop, length, content_filter, tool_calls) et data: [DONE]. Avec include_usage: true, un bloc supplémentaire contenant choices: [] et le usage final précède la fin ; les autres blocs ont usage: null. Sinon, usage est omis. Tous les blocs partagent un identifiant local, une date de création et un identifiant public de modèle.

json
{"model":"chat-standard","messages":[{"role":"user","content":"Hello!"}],"stream":true,"stream_options":{"include_usage":true}}
text
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"usage":null}

data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"content":"Hello!"},"logprobs":null,"finish_reason":null}],"usage":null}

data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null}

data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":3,"total_tokens":15}}

data: [DONE]

Erreurs et périmètre ​

Format des erreurs : { "error": { "message": "...", "type": "invalid_request_error", "param": null, "code": "invalid_request" } }. HTTP 400 indique une entrée invalide ou non prise en charge ; 401 une clé invalide, 402 un solde insuffisant, 429 une limite de débit, 503 une panne temporaire et 504 un délai dépassé. Les erreurs sont anonymisées. Avant le streaming, l’échec est une erreur HTTP JSON ; après, un bloc data: {"error": ...} termine le flux sans marqueur de succès. Une réponse partielle n’est pas complète. Délais : 90 secondes avant le premier texte, 60 secondes sans nouveau texte (réinitialisées à chaque delta), 60 secondes hors streaming.

Non pris en charge : entrées image/audio, recherche et exécution de code hébergées, anciens functions / function_call, types d’outils personnalisés, logprobs, plusieurs candidats, store, Responses API et paramètres non répertoriés. Ils sont refusés. Pour la voix, utilisez /v1/chat/speech.

Facturation et exemples SDK ​

Le solde, les tarifs publics et la facturation des tokens d’entrée/sortie sont communs. Des crédits sont réservés avant la génération, puis facturés selon l’usage réel ; le reste est libéré. Un échec, un usage invalide ou une déconnexion avant le règlement libère la réservation. Une annulation après règlement ne l’annule pas. Les appels apparaissent dans l’historique d’utilisation et le tableau de bord administrateur. Le JSON standard contient usage, pas de champ personnalisé billing. Une requête répétée peut être refacturée ; aucune idempotence n’est garantie.

bash
pip install openai
npm install openai
python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ["KARMAN_API_KEY"], base_url="https://api.coldstart.win/v1", max_retries=0)
print([model.id for model in client.models.list().data])
model = os.environ["KARMAN_MODEL"]
messages = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
reply = client.chat.completions.create(model=model, messages=messages, max_tokens=256)
print(reply.choices[0].message.content)

stream = client.chat.completions.create(model=model, messages=messages, max_tokens=256,
    stream=True, stream_options={"include_usage": True})
for chunk in stream:
    if chunk.choices:
        print(chunk.choices[0].delta.content or "", end="", flush=True)
    if chunk.usage:
        print("\n", chunk.usage)
javascript
import OpenAI from "openai";

const client = new OpenAI({ apiKey: process.env.KARMAN_API_KEY, baseURL: "https://api.coldstart.win/v1", maxRetries: 0 });
const models = await client.models.list();
console.log(models.data.map(model => model.id));
const stream = await client.chat.completions.create({
  model: process.env.KARMAN_MODEL,
  messages: [{ role: "user", content: "Hello!" }],
  stream: true,
  stream_options: { include_usage: true }
});
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta.content ?? "");
  if (chunk.usage) console.log("\n", chunk.usage);
}

Outils d’agent et sorties structurées ​

Consultez models[].capabilities dans /v1/chat/catalog : tool_calling, parallel_tool_calls, json_mode, structured_outputs. Les capacités varient selon le modèle ; une capacité non prise en charge renvoie HTTP 400 avant la génération. Votre application exécute les outils. L’API n’exécute pas de fonctions et ne conserve pas la mémoire de l’agent.

Utilisez tools (128 fonctions maximum), tool_choice (auto, none, required ou fonction nommée) et parallel_tool_calls (booléen, tools requis). Chaque fonction accepte name, description, des parameters JSON Schema et strict facultatif. Lisez message.tool_calls ; content peut être null. Conservez le message assistant tel quel, puis ajoutez un message role: "tool" par appel avec le bon tool_call_id. Renvoyez tous les résultats, y compris les échecs, avant l’appel suivant. Préservez les identifiants uniques et l’ordre.

En streaming, regroupez choices[0].delta.tool_calls par index, concaténez les fragments de function.arguments et conservez id, type, function.name. N’exécutez les outils qu’après finish_reason: "tool_calls" et la fin réussie du flux, jamais en cas de length ou d’erreur. Les deltas d’outils réinitialisent aussi le délai d’inactivité de 60 secondes ; le premier résultat dispose de 90 secondes. Validez les noms, arguments et permissions, et limitez les tours.

response_format accepte text, json_object, ou json_schema avec json_schema: {name, schema, strict, description?}. Demandez explicitement du JSON dans le prompt en mode JSON. Un schéma strict doit inclure toutes les propriétés dans required et additionalProperties: false ; null permet de représenter une valeur facultative. Ne combinez pas JSON Schema avec parallel_tool_calls: true. Vérifiez refusal, length et les erreurs avant l’analyse. Le schéma ne garantit pas l’exactitude des faits. Définitions, arguments et résultats d’outils comptent dans les tokens ; chaque tour est facturé séparément.

Boucle complète d’outils ​

python
import os, json
from openai import OpenAI

client = OpenAI(api_key=os.environ["KARMAN_API_KEY"],
                base_url="https://api.coldstart.win/v1", max_retries=0)
model = os.environ["KARMAN_MODEL"]
tools = [{"type": "function", "function": {
    "name": "lookup_memory", "description": "Read a saved preference.",
    "parameters": {"type": "object", "properties": {"topic": {"type": "string"}},
                   "required": ["topic"], "additionalProperties": False},
    "strict": True
}}]
messages = [{"role": "user", "content": "What food do I like? Use my saved memory."}]

for _ in range(4):
    reply = client.chat.completions.create(
        model=model, messages=messages, tools=tools,
        tool_choice="auto", parallel_tool_calls=False, max_tokens=512)
    choice = reply.choices[0]
    message = choice.message
    if message.refusal or choice.finish_reason not in ("stop", "tool_calls"):
        raise RuntimeError("Incomplete or refused response")
    messages.append(message.model_dump(exclude_none=True))
    if not message.tool_calls:
        print(message.content)
        break
    for call in message.tool_calls:
        try:
            if call.function.name != "lookup_memory":
                raise ValueError("Unknown function")
            args = json.loads(call.function.arguments)
            if not isinstance(args, dict) or set(args) != {"topic"} or not isinstance(args["topic"], str):
                raise ValueError("Invalid arguments")
            result = {"topic": args["topic"], "preference": "apples"}
        except (ValueError, TypeError):
            result = {"error": "Invalid tool request"}
        messages.append({"role": "tool", "tool_call_id": call.id,
                         "content": json.dumps(result)})
else:
    raise RuntimeError("Agent round limit reached")

Exemple de sortie structurée ​

python
reply = client.chat.completions.create(
    model=model,
    messages=[{"role": "user", "content": "I like apples. Extract this preference as JSON."}],
    response_format={"type": "json_schema", "json_schema": {
        "name": "memory", "strict": True,
        "schema": {"type": "object", "properties": {"preference": {"type": "string"}},
                   "required": ["preference"], "additionalProperties": False}
    }}, max_tokens=256)
choice = reply.choices[0]
if choice.finish_reason != "stop" or choice.message.refusal:
    raise RuntimeError("Incomplete or refused response")
memory = json.loads(choice.message.content)
print(memory)