Documentation
Gardez le SDK OpenAI ou Anthropic que vous utilisez déjà, et envoyez votre première requête en quelques minutes.
Démarrage rapide
Créez une clé, définissez deux variables d'environnement, puis envoyez une requête.
Pointez votre SDK OpenAI vers http://127.0.0.1:3001/v1, ou votre SDK Anthropic vers http://127.0.0.1:3001, et utilisez votre clé yourbrand. Les requêtes, les réponses et les flux gardent les formats que votre code attend déjà. Un champ que nous ne prenons pas en charge reçoit une erreur 400 au lieu d'être ignoré. Le fine-tuning, le batch, les fichiers et les assistants ne sont pas offerts.
- 1Créer une clé
Inscrivez-vous avec un nom d'utilisateur, achetez des bons de 5 $ et utilisez-les pour obtenir du crédit, puis créez une clé depuis le tableau de bord.
- 2Définir l'URL de base
export YOURBRAND_BASE_URL=http://127.0.0.1:3001/v1 export YOURBRAND_KEY=sk_...
- 3Envoyer une requête
curl $YOURBRAND_BASE_URL/chat/completions \ -H "Authorization: Bearer $YOURBRAND_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3.8-27b-abliterated","messages":[{"role":"user","content":"hello"}]}'
import OpenAI from "openai"; const client = new OpenAI({ apiKey: process.env.YOURBRAND_KEY, baseURL: process.env.YOURBRAND_BASE_URL, }); const res = await client.chat.completions.create({ model: "qwen3.8-27b-abliterated", messages: [{ role: "user", content: "hello" }], }); console.log(res.choices[0].message.content);
import os from openai import OpenAI client = OpenAI( api_key=os.environ["YOURBRAND_KEY"], base_url=os.environ["YOURBRAND_BASE_URL"], ) res = client.chat.completions.create( model="qwen3.8-27b-abliterated", messages=[{"role": "user", "content": "hello"}], ) print(res.choices[0].message.content)
using System.Net.Http.Json; var key = Environment.GetEnvironmentVariable("YOURBRAND_KEY"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", $"Bearer {key}"); var res = await http.PostAsJsonAsync("http://127.0.0.1:3001/v1/chat/completions", new { model = "qwen3.8-27b-abliterated", messages = new[] { new { role = "user", content = "hello" } }, }); Console.WriteLine(await res.Content.ReadAsStringAsync());
#include <cpr/cpr.h> #include <cstdlib> #include <iostream> int main() { std::string key = std::getenv("YOURBRAND_KEY"); auto res = cpr::Post( cpr::Url{"http://127.0.0.1:3001/v1/chat/completions"}, cpr::Header{{"Authorization", "Bearer " + key}, {"Content-Type", "application/json"}}, cpr::Body{R"({ "model": "qwen3.8-27b-abliterated", "messages": [{"role":"user","content":"hello"}] })"}); std::cout << res.text << "\n"; }
require "json" require "net/http" res = Net::HTTP.post( URI("http://127.0.0.1:3001/v1/chat/completions"), { model: "qwen3.8-27b-abliterated", messages: [{ role: "user", content: "hello" }], }.to_json, "Authorization" => "Bearer #{ENV['YOURBRAND_KEY']}", "Content-Type" => "application/json", ) puts res.body
package main import ( "fmt" "io" "net/http" "os" "strings" ) func main() { body := `{ "model": "qwen3.8-27b-abliterated", "messages": [{"role":"user","content":"hello"}] }` req, _ := http.NewRequest("POST", "http://127.0.0.1:3001/v1/chat/completions", strings.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("YOURBRAND_KEY")) req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() out, _ := io.ReadAll(res.Body) fmt.Println(string(out)) }
Configurer un agent
Tout agent qui accepte une URL de base OpenAI fonctionne. Voici les réglages des plus courants. OpenCode lit ses réglages dans ~/.config/opencode/opencode.json.
export OPENAI_API_BASE=http://127.0.0.1:3001/v1 export OPENAI_API_KEY=$YOURBRAND_KEY aider --model openai/qwen3.8-27b-abliterated
{
"provider": {
"yourbrand": {
"npm": "@ai-sdk/openai-compatible",
"options": { "baseURL": "http://127.0.0.1:3001/v1", "apiKey": "{env:YOURBRAND_KEY}" },
"models": { "qwen3.8-27b-abliterated": {} }
}
}
}
# ~/.continue/config.yaml
models:
- name: qwen3.8-27b-abliterated
provider: openai
model: qwen3.8-27b-abliterated
apiBase: http://127.0.0.1:3001/v1
apiKey: ${{ secrets.YOURBRAND_KEY }}
Streaming
Passez stream: true et la réponse arrive en server-sent events pendant que le modèle l'écrit. Les SDK s'occupent de l'analyse ; voici ce qu'ils font en coulisses, pour quand vous lisez le flux vous-même.
curl -N $YOURBRAND_BASE_URL/chat/completions \ -H "Authorization: Bearer $YOURBRAND_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3.8-27b-abliterated","stream":true,"messages":[{"role":"user","content":"hello"}]}'
const stream = await client.chat.completions.create({ model: "qwen3.8-27b-abliterated", stream: true, messages: [{ role: "user", content: "hello" }], }); for await (const chunk of stream) { process.stdout.write(chunk.choices[0]?.delta?.content ?? ""); if (chunk.usage) console.error("\ntokens:", chunk.usage.total_tokens); }
stream = client.chat.completions.create( model="qwen3.8-27b-abliterated", stream=True, messages=[{"role": "user", "content": "hello"}], ) for chunk in stream: if chunk.choices: print(chunk.choices[0].delta.content or "", end="", flush=True) if chunk.usage: print("\ntokens:", chunk.usage.total_tokens)
using System.Net.Http.Json; using System.Text.Json; var baseUrl = Environment.GetEnvironmentVariable("YOURBRAND_BASE_URL"); var key = Environment.GetEnvironmentVariable("YOURBRAND_KEY"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", $"Bearer {key}"); var req = new HttpRequestMessage(HttpMethod.Post, $"{baseUrl}/chat/completions") { Content = JsonContent.Create(new { model = "qwen3.8-27b-abliterated", stream = true, messages = new[] { new { role = "user", content = "hello" } }, }), }; using var res = await http.SendAsync(req, HttpCompletionOption.ResponseHeadersRead); using var reader = new StreamReader(await res.Content.ReadAsStreamAsync()); while (await reader.ReadLineAsync() is { } line) { if (!line.StartsWith("data: {")) continue; var choices = JsonDocument.Parse(line[6..]).RootElement.GetProperty("choices"); if (choices.GetArrayLength() > 0 && choices[0].GetProperty("delta").TryGetProperty("content", out var text)) Console.Write(text.GetString()); }
#include <cpr/cpr.h> #include <nlohmann/json.hpp> #include <cstdlib> #include <iostream> int main() { std::string base = std::getenv("YOURBRAND_BASE_URL"); std::string key = std::getenv("YOURBRAND_KEY"); std::string buffer; cpr::Post( cpr::Url{base + "/chat/completions"}, cpr::Header{ {"Authorization", "Bearer " + key}, {"Content-Type", "application/json"} }, cpr::Body{R"({"model": "qwen3.8-27b-abliterated", "stream": true, "messages": [{"role": "user", "content": "hello"}]})"}, cpr::WriteCallback{[&](std::string_view data, intptr_t) { buffer.append(data); for (size_t end; (end = buffer.find('\n')) != std::string::npos; buffer.erase(0, end + 1)) { std::string line = buffer.substr(0, end); if (line.rfind("data: {", 0) != 0) continue; auto chunk = nlohmann::json::parse(line.substr(6)); if (!chunk["choices"].empty()) std::cout << chunk["choices"][0]["delta"].value("content", "") << std::flush; } return true; }}); }
require "json" require "net/http" uri = URI("#{ENV['YOURBRAND_BASE_URL']}/chat/completions") body = { model: "qwen3.8-27b-abliterated", stream: true, messages: [{ role: "user", content: "hello" }] } Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == "https") do |http| req = Net::HTTP::Post.new(uri, "Authorization" => "Bearer #{ENV['YOURBRAND_KEY']}", "Content-Type" => "application/json") req.body = body.to_json http.request(req) do |res| buffer = +"" res.read_body do |data| buffer << data while (line = buffer.slice!(/.*\n/)) next unless line.start_with?("data: {") text = JSON.parse(line[6..]).dig("choices", 0, "delta", "content") print text if text end end end end
package main import ( "bufio" "encoding/json" "fmt" "net/http" "os" "strings" ) func main() { body := `{"model": "qwen3.8-27b-abliterated", "stream": true, "messages": [{"role": "user", "content": "hello"}]}` req, _ := http.NewRequest("POST", os.Getenv("YOURBRAND_BASE_URL")+"/chat/completions", strings.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("YOURBRAND_KEY")) req.Header.Set("Content-Type", "application/json") res, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer res.Body.Close() scanner := bufio.NewScanner(res.Body) for scanner.Scan() { data, ok := strings.CutPrefix(scanner.Text(), "data: ") if !ok || data == "[DONE]" { continue } var chunk struct { Choices []struct { Delta struct{ Content string } `json:"delta"` } `json:"choices"` } if json.Unmarshal([]byte(data), &chunk) == nil && len(chunk.Choices) > 0 { fmt.Print(chunk.Choices[0].Delta.Content) } } }
- Chaque événement est une ligne
data:contenant unchat.completion.chunk. - Le dernier fragment contient
usage: vous pouvez compter les tokens d'un flux sans seconde requête. - Le flux se termine par
data: [DONE]. Fermer la connexion plus tôt arrête la génération.
Le format de chaque événement, flux Anthropic compris, est dans la référence API.
Gérer les erreurs
Trois erreurs valent une nouvelle tentative : 429 quand vous dépassez la limite de parallélisme de votre forfait, avec un en-tête Retry-After en secondes ; 500 quand quelque chose échoue de notre côté ; et 503 quand un modèle est brièvement hors service. Tout le reste demande de corriger la requête, et réessayer n'y changera rien.
curl --retry 5 --retry-all-errors --retry-max-time 60 \ $YOURBRAND_BASE_URL/chat/completions \ -H "Authorization: Bearer $YOURBRAND_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3.8-27b-abliterated","messages":[{"role":"user","content":"hello"}]}'
// Le SDK OpenAI réessaie déjà les 429 et 5xx avec backoff et respecte Retry-After. const client = new OpenAI({ apiKey: process.env.YOURBRAND_KEY, baseURL: process.env.YOURBRAND_BASE_URL, maxRetries: 5, });
# Le SDK OpenAI réessaie déjà les 429 et 5xx avec backoff et respecte Retry-After. client = OpenAI( api_key=os.environ["YOURBRAND_KEY"], base_url=os.environ["YOURBRAND_BASE_URL"], max_retries=5, )
using System.Net.Http.Json; var baseUrl = Environment.GetEnvironmentVariable("YOURBRAND_BASE_URL"); var key = Environment.GetEnvironmentVariable("YOURBRAND_KEY"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", $"Bearer {key}"); async Task<HttpResponseMessage> WithRetry(Func<Task<HttpResponseMessage>> call, int tries = 5) { for (var attempt = 0; ; attempt++) { var res = await call(); var retryable = (int)res.StatusCode is 429 or 500 or 503; if (!retryable || attempt == tries - 1) return res; var wait = res.Headers.RetryAfter?.Delta ?? TimeSpan.FromMilliseconds((250 << attempt) + Random.Shared.Next(100)); await Task.Delay(wait); } } var res = await WithRetry(() => http.PostAsJsonAsync($"{baseUrl}/chat/completions", new { model = "qwen3.8-27b-abliterated", messages = new[] { new { role = "user", content = "hello" } }, }));
#include <cpr/cpr.h> #include <chrono> #include <cstdlib> #include <functional> #include <thread> cpr::Response with_retry(const std::function<cpr::Response()>& call, int tries = 5) { for (int attempt = 0;; attempt++) { cpr::Response res = call(); bool retryable = res.status_code == 429 || res.status_code == 500 || res.status_code == 503; if (!retryable || attempt == tries - 1) return res; std::string after = res.header["retry-after"]; int wait_ms = !after.empty() ? std::stoi(after) * 1000 : (250 << attempt) + std::rand() % 100; std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms)); } } int main() { std::string base = std::getenv("YOURBRAND_BASE_URL"); std::string key = std::getenv("YOURBRAND_KEY"); auto res = with_retry([&] { return cpr::Post(cpr::Url{base + "/chat/completions"}, cpr::Header{ {"Authorization", "Bearer " + key}, {"Content-Type", "application/json"} }, cpr::Body{R"({"model": "qwen3.8-27b-abliterated", "messages": [{"role": "user", "content": "hello"}]})"}); }); }
require "json" require "net/http" def with_retry(tries: 5) tries.times do |attempt| res = yield retryable = %w[429 500 503].include?(res.code) return res if !retryable || attempt == tries - 1 sleep(res["retry-after"]&.to_f || (2**attempt * 0.25) + (rand * 0.1)) end end uri = URI("#{ENV['YOURBRAND_BASE_URL']}/chat/completions") res = with_retry do Net::HTTP.post(uri, { model: "qwen3.8-27b-abliterated", messages: [{ role: "user", content: "hello" }] }.to_json, "Authorization" => "Bearer #{ENV['YOURBRAND_KEY']}", "Content-Type" => "application/json") end
package main import ( "math/rand/v2" "net/http" "os" "strconv" "strings" "time" ) func withRetry(call func() (*http.Response, error), tries int) (*http.Response, error) { for attempt := 0; ; attempt++ { res, err := call() if err != nil { return nil, err } retryable := res.StatusCode == 429 || res.StatusCode == 500 || res.StatusCode == 503 if !retryable || attempt == tries-1 { return res, nil } res.Body.Close() wait := time.Duration(250<<attempt+rand.IntN(100)) * time.Millisecond if after, err := strconv.Atoi(res.Header.Get("Retry-After")); err == nil { wait = time.Duration(after) * time.Second } time.Sleep(wait) } } func main() { body := `{"model": "qwen3.8-27b-abliterated", "messages": [{"role": "user", "content": "hello"}]}` res, err := withRetry(func() (*http.Response, error) { req, _ := http.NewRequest("POST", os.Getenv("YOURBRAND_BASE_URL")+"/chat/completions", strings.NewReader(body)) req.Header.Set("Authorization", "Bearer "+os.Getenv("YOURBRAND_KEY")) req.Header.Set("Content-Type", "application/json") return http.DefaultClient.Do(req) }, 5) if err != nil { panic(err) } defer res.Body.Close() }
Tous les codes de statut et les deux formats d'erreur sont listés sous Erreurs ; les limites des forfaits sous Limites de débit.