EN ZalogujZałóż konto
Startujemy w październiku 2026. Działają konta, katalog modeli, kalkulator i dokumentacja. Studio jest dostępne w podglądzie; generowanie czeka na uruchomienie.

Jedno API do GPT, Claude, Gemini i DeepSeek - Python i Node

GPT-6, Claude, Gemini i DeepSeek jednym kluczem z Pythona i Node: zmiana modelu jedną linijką, fallback przy błędach i porównanie odpowiedzi z kosztem.

Do GPT, Claude, Gemini i DeepSeek wystarczy jeden klient i jeden klucz: oficjalne SDK OpenAI z adresem https://jantaris.com/v1 obsługuje wszystkie 22 modele czatu z katalogu Jantarisa, a model zmieniasz jedną linijką, np. z gpt-6-sol na claude-sonnet-5 albo deepseek-v4.1-flash. Płacisz w złotówkach z jednego salda, z fakturą VAT. Poniżej działający kod w Pythonie i Node: przełączanie modelu z konfiguracji, fallback przy awarii i porównanie odpowiedzi kilku modeli z czasem i kosztem w złotówkach.

Dlaczego jedno API zamiast czterech SDK

Każdy producent ma własne SDK, własny format wiadomości, własne błędy i własne konto z płatnością w dolarach. Obsługa czterech producentów to cztery ścieżki w kodzie, cztery klucze i cztery faktury z zagranicy.

Jantaris wystawia jeden endpoint w formacie OpenAI (/v1/chat/completions) dla wszystkich modeli czatu i drugi w formacie Anthropic (/v1/messages) dla modeli Claude. Dla kodu model staje się zwykłym napisem w konfiguracji. Dla księgowości to jedno saldo w złotówkach i krajowa faktura VAT po każdym doładowaniu.

Model (przykłady)IdCena za 1 mln tokenów (wejście / wyjście)
GPT-6 Solgpt-6-sol11,75 zł / 58,75 zł za 1 mln tokenów
Claude Sonnet 5claude-sonnet-517,62 zł / 88,12 zł za 1 mln tokenów
gemini-3.8-flashgemini-3.8-flash
DeepSeek V4.1 Flashdeepseek-v4.1-flash2,94 zł / 9,55 zł za 1 mln tokenów
GPT-6 Lunagpt-6-luna0,587 zł / 2,94 zł za 1 mln tokenów

Pełna lista, z GLM, Kimi, Qwen, MiniMax i Grokiem, jest w katalogu modeli i pod GET /v1/models?category=chat.

Krok 1: klucz i instalacja

  1. Załóż konto na stronie rejestracji i doładuj saldo (BLIK, od 40 zł).
  2. W panelu utwórz klucz API i ustaw mu limit miesięczny. Klucz sk-jt-... pokazuje się tylko raz.
  3. Zapisz klucz w zmiennej środowiskowej, nie w kodzie.
Panel Jantarisa: tworzenie klucza API z polem limitu miesięcznego w PLN
Jeden klucz dla wszystkich modeli - limit miesięczny w złotówkach chroni przed zapętlonym skryptem
bash
pip install openai requests
export JANTARIS_API_KEY=sk-jt-...
export LLM_MODEL=gpt-6-sol

W PowerShellu: $env:JANTARIS_API_KEY = "sk-jt-...".

Zmiana modelu jedną linijką

Najprostsza wersja: model czytasz ze zmiennej środowiskowej, więc przełączasz go bez dotykania kodu.

python
import os
from openai import OpenAI

client = OpenAI(base_url="https://jantaris.com/v1", api_key=os.environ["JANTARIS_API_KEY"])
MODEL = os.environ.get("LLM_MODEL", "gpt-6-sol")

def ask(prompt: str, model: str = MODEL) -> str:
    resp = client.chat.completions.create(
        model=model,
        messages=[
            {"role": "system", "content": "Odpowiadasz po polsku, konkretnie."},
            {"role": "user", "content": prompt},
        ],
    )
    return resp.choices[0].message.content

print(ask("Czym różni się PUT od PATCH w REST?"))
print(ask("Czym różni się PUT od PATCH w REST?", model="claude-sonnet-5"))

LLM_MODEL=deepseek-v4.1-flash python app.py i ten sam program działa na DeepSeeku. Streaming (stream=True) i narzędzia (tools) mają identyczny format dla wszystkich modeli, opisałem je w dokumentacji czatu.

Porównanie odpowiedzi kilku modeli z kosztem

Zanim wybiorę model do projektu, puszczam te same pytania przez kilka modeli naraz i patrzę na trzy rzeczy: jakość odpowiedzi, czas i koszt. Ceny biorę z publicznego GET /v1/models (w złotówkach z VAT), a zużycie z pola usage każdej odpowiedzi.

python
import os, time
from concurrent.futures import ThreadPoolExecutor

import requests
from openai import OpenAI

BASE = "https://jantaris.com/v1"
client = OpenAI(base_url=BASE, api_key=os.environ["JANTARIS_API_KEY"])

catalog = requests.get(f"{BASE}/models", params={"category": "chat", "currency": "PLN"}, timeout=30).json()["data"]
PRICES = {m["id"]: m["pricing"] for m in catalog}

MODELS = ["gpt-6-sol", "claude-sonnet-5", "gemini-3.8-flash", "deepseek-v4.1-flash"]
PROMPT = "Klient pisze: 'Paczka nie dotarła od 6 dni'. Napisz uprzejmą odpowiedź w 3 zdaniach."

def run(model):
    t0 = time.perf_counter()
    r = client.chat.completions.create(model=model, messages=[{"role": "user", "content": PROMPT}])
    u, p = r.usage, PRICES[model]
    cost = (u.prompt_tokens * float(p["input_per_mtok"]) + u.completion_tokens * float(p["output_per_mtok"])) / 1_000_000
    return model, time.perf_counter() - t0, u.prompt_tokens, u.completion_tokens, cost, r.choices[0].message.content

with ThreadPoolExecutor(max_workers=len(MODELS)) as pool:
    results = list(pool.map(run, MODELS))

for model, sec, tin, tout, cost, text in sorted(results, key=lambda x: x[4]):
    print(f"\n=== {model} | {sec:.1f} s | {tin} + {tout} tokenów | {cost:.4f} zł")
    print(text)

Wynik jest posortowany od najtańszej odpowiedzi. Kilka uwag z praktyki:

  • jedno pytanie niczego nie dowodzi, do decyzji biorę 20-50 prawdziwych przykładów z projektu,
  • liczba tokenów wyjścia u modeli rozumujących obejmuje myślenie, więc krótka odpowiedź potrafi mieć sporo tokenów,
  • ten sam tekst to różna liczba tokenów w różnych modelach, dlatego porównuję koszt całego zapytania, a nie stawki.

Jak wygląda ranking samych stawek na przykładzie 1000 odpowiedzi czatu, pokazałem w tekście Najtańsze API LLM 2026.

Fallback: gdy model nie odpowiada

Każdy producent ma czasem gorszy dzień. Część modeli w Jantarisie ma automatyczny failover między dostawcami infrastruktury, ale warto dołożyć drugą warstwę w kodzie: przejście na inny model. Ważne, żeby nie przełączać się przy błędach, których zmiana modelu nie naprawi.

python
import time
from openai import APIStatusError, APIConnectionError

CHAIN = ["claude-sonnet-5", "gpt-6-sol", "gemini-3.8-flash"]
NO_RETRY = {401, 402, 403, 422}  # klucz, saldo, limit klucza, błędne parametry

def ask_with_fallback(messages, **kw):
    last = None
    for model in CHAIN:
        for attempt in range(2):
            try:
                r = client.chat.completions.create(model=model, messages=messages, **kw)
                return model, r.choices[0].message.content
            except APIStatusError as e:
                if e.status_code in NO_RETRY:
                    raise
                last = e
                if e.status_code == 404:
                    break  # nieznany model - od razu następny w łańcuchu
                time.sleep(2 * (attempt + 1))  # 429 i 5xx: chwila przerwy, potem następna próba
            except APIConnectionError as e:
                last = e
                time.sleep(2 * (attempt + 1))
    raise last

model, answer = ask_with_fallback([{"role": "user", "content": "Streść RODO w 5 punktach."}])
print(f"[{model}] {answer}")

Co oznaczają kody w tym kontekście:

KodZnaczeniePrzełączać model?
401zły albo usunięty klucznie
402za niskie saldonie, doładuj
403klucz doszedł do limitu miesięcznegonie, podnieś limit w panelu
404model nie istniejetak, i popraw id
422błędne parametrynie, popraw zapytanie
429limit zapytańtak, po krótkiej przerwie
502błąd po stronie dostawcytak

Zapytanie, które się nie powiedzie, nie jest płatne, więc ponowienie po błędzie nie kosztuje podwójnie. Pełna lista błędów: dokumentacja błędów.

To samo w Node.js

bash
npm install openai
javascript
import OpenAI from "openai";

const BASE = "https://jantaris.com/v1";
const client = new OpenAI({ baseURL: BASE, apiKey: process.env.JANTARIS_API_KEY });

const res = await fetch(`${BASE}/models?category=chat&currency=PLN`);
const prices = Object.fromEntries((await res.json()).data.map((m) => [m.id, m.pricing]));

const models = ["gpt-6-luna", "claude-haiku-4.5", "deepseek-v4.1-flash"];
const prompt = "Podaj 3 pomysły na nazwę kawiarni przy dworcu.";

const results = await Promise.allSettled(
  models.map(async (model) => {
    const r = await client.chat.completions.create({ model, messages: [{ role: "user", content: prompt }] });
    const p = prices[model];
    const cost = (r.usage.prompt_tokens * Number(p.input_per_mtok) + r.usage.completion_tokens * Number(p.output_per_mtok)) / 1e6;
    return { model, cost: cost.toFixed(4) + " zł", text: r.choices[0].message.content };
  }),
);

for (const r of results) console.log(r.status === "fulfilled" ? r.value : r.reason.message);

Promise.allSettled sprawia, że błąd jednego modelu nie przerywa porównania pozostałych. Zwróć uwagę na nazwę opcji: w Node to baseURL, w Pythonie base_url.

Kiedy zostać przy SDK Anthropic

Jeśli masz kod napisany pod SDK Anthropic (np. z blokami tool_use albo z prompt cachingiem), nie musisz go przepisywać. Endpoint /v1/messages obsługuje modele Claude w oryginalnym formacie:

python
from anthropic import Anthropic

claude = Anthropic(base_url="https://jantaris.com", api_key=os.environ["JANTARIS_API_KEY"])
msg = claude.messages.create(
    model="claude-opus-5.5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Zaproponuj schemat tabel dla systemu rezerwacji sal."}],
)
print(msg.content[-1].text)

Adres dla SDK Anthropic podajesz bez /v1. Ten endpoint obsługuje tylko modele Claude. Kiedy w jednej aplikacji mieszasz Claude z GPT i Gemini, prościej trzymać wszystko w formacie OpenAI. Szczegóły kosztów i cache Claude opisałem w tekście Claude Opus 5.5 i Sonnet 5 przez API.

Pułapki przy przełączaniu modeli

Format jest wspólny, ale modele nie są identyczne. Na to trafiam najczęściej:

  • temperature i top_p. Claude Sonnet 5 odrzuca niestandardowe wartości błędem 400, a OpenAI podaje, że GPT-6 Astra też ich nie przyjmuje. Jeśli zapytanie ma działać na każdym modelu, nie ustawiaj tych parametrów.
  • max_tokens u modeli rozumujących. Myślenie zużywa część limitu wyjścia, więc za niski limit kończy się uciętą albo pustą odpowiedzią. Na starcie nie ustawiaj go wcale albo daj zapas.
  • Limity odpowiedzi. Gemini 3.6 Flash ma w Jantarisie limit 8192 tokenów odpowiedzi, Claude Haiku 4.5 kontekst 200 tys. tokenów zamiast 1 mln. Sprawdzisz to w GET /v1/models (pola context_window i max_output_tokens).
  • Styl odpowiedzi. Ten sam prompt systemowy daje u różnych modeli różną długość i ton. Po zmianie modelu przejrzyj kilkanaście odpowiedzi, zanim puścisz go na produkcję.
Dokumentacja Jantarisa: szybki start z adresem bazowym API i pierwszym zapytaniem do czatu
Szybki start w dokumentacji - adres bazowy, klucz i pierwsze zapytanie do czatu

Jeśli zamiast pisać kod wolisz narzędzia no-code, ten sam klucz działa w n8n, Make i Zapierze (adres https://jantaris.com/v1) - instrukcja jest w dokumentacji no-code. Ceny poszczególnych modeli GPT-6 rozpisałem w tekście GPT-6 API cena.

Najczęstsze pytania

Czy mogę wołać Claude i Gemini przez SDK OpenAI?

Tak. Ustaw base_url="https://jantaris.com/v1", klucz sk-jt-... i model, np. claude-sonnet-5 albo gemini-3.8-flash. Format zapytania i odpowiedzi to standardowe Chat Completions, razem ze streamingiem i narzędziami.

Jak przełączyć model bez zmiany kodu?

Trzymaj id modelu w zmiennej środowiskowej albo pliku konfiguracyjnym i przekazuj go do model. Zmiana z gpt-6-sol na deepseek-v4.1-flash to wtedy zmiana jednej wartości.

Jak zrobić fallback między modelami?

Złap błędy 429, 5xx i błędy połączenia, a potem spróbuj kolejnego modelu z listy. Nie przełączaj się przy 401, 402, 403 i 422, bo to problem z kluczem, saldem, limitem albo parametrami. Kod jest wyżej w tekście.

Ile kosztuje porównanie kilku modeli?

Tyle, ile tokenów zużyją wszystkie zapytania razem, według stawek każdego modelu. Skrypt z tego tekstu liczy koszt każdej odpowiedzi w złotówkach na podstawie usage i cen z GET /v1/models.

Czy potrzebuję osobnych kont u OpenAI, Anthropic i Google?

Nie. Jeden klucz Jantarisa i jedno saldo w złotówkach obsługują wszystkie modele z katalogu, także obraz, wideo i muzykę. Fakturę VAT dostajesz po każdym doładowaniu.

Czy to działa z Node.js i TypeScriptem?

Tak, z oficjalnym pakietem openai dla Node. W konstruktorze podajesz baseURL: "https://jantaris.com/v1" i klucz, reszta kodu jest taka sama jak przy API OpenAI.