Sari la conținut
Blog

API compatibil cu OpenAI: schimbi în trei rânduri

Ce înseamnă de fapt un API compatibil cu OpenAI, cele trei rânduri care îți mută aplicația pe un API european și o listă cinstită cu ce nu se transferă.

Union AI8 min de citit
DezvoltatoriOpen weights

Trei rânduri. Îndrepți base_url-ul clientului spre noul furnizor, schimbi cheia API și înlocuiești numele modelului cu numele unui nivel. Tot restul unui apel chat completions, array-ul de mesaje, streamingul, tools, schemele JSON, rămâne exact cum e, pentru că compatibil cu OpenAI înseamnă să implementezi același contract HTTP, nu doar să semeni cu el.

Partea interesantă a unei migrări nu e codul. E ce nu se transferă: endpointurile care încă nu există, comportamentul modelului care se schimbă la același prompt și acel singur cod de eroare pe care probabil nu l-ai tratat niciodată.

Infografic care împarte o migrare de API în ce merge neschimbat, ce cere o mică modificare și ce lipsește.

Ce înseamnă de fapt „compatibil cu OpenAI”

Înseamnă contractul unui singur endpoint: POST /v1/chat/completions, cu același corp al cererii și aceeași formă a răspunsului, inclusiv formatul server-sent events pentru streaming. Contractul ăsta a devenit interfața implicită a industriei așa cum API-ul S3 a devenit standardul pentru object storage, și din același motiv: totul era deja scris pe baza lui.

SDK-urile oficiale sunt clienți subțiri peste acest contract. În biblioteca Python a OpenAI, base URL-ul e un argument al constructorului, așa că îndreptarea lui în altă parte e o operație suportată, nu un hack. Logica de retry, handlerul de streaming și definițiile de tipuri continuă să funcționeze.

Ce nu înseamnă e paritate de funcții pe toată platforma. Serviciile compatibile implementează bine endpointul de chat și apoi se despart, de aceea varianta cinstită a acestui articol e mai ales o listă de diferențe.

Toată migrarea
from openai import OpenAI
client = OpenAI(
api_key=os.environ["UNION_API_KEY"],
base_url="https://api.europeanailab.eu/v1",
)
response = client.chat.completions.create(
model="eu-standard",
messages=[{"role": "user", "content": prompt}],
stream=True,
)

Diferă 3 rânduri: cheia, base URL-ul și un nume de nivel în locul numelui de model.

Tot restul apelului respectă același contract: mesaje, streaming, tools, scheme JSON. Nu se schimbă forma cererii, ci modelul care scrie răspunsul, și de aceea lista de verificare de mai jos e despre evaluare, nu despre cod.

Cele trei rânduri, în practică

Iată toată schimbarea în Python. SDK-urile pentru Node, Go și .NET primesc aceleași două argumente, sub alte nume.

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["UNION_API_KEY"],
    base_url="https://api.europeanailab.eu/v1",
)

response = client.chat.completions.create(
    model="eu-standard",
    messages=[{"role": "user", "content": prompt}],
    stream=True,
)

Dacă codul tău citește deja base URL-ul dintr-o variabilă de mediu, lucru care merită făcut înaintea oricărei migrări, asta e o schimbare de configurație, nu un deploy de cod nou. Îți dă și cel mai ieftin rollback posibil: îl îndrepți înapoi.

Ce se transferă, ce se schimbă, ce lipsește

Tabelul de care ai de fapt nevoie înainte să planifici munca.

Funcție Stare Ce faci
Chat completions Merge neschimbat Nimic
Streaming (SSE) Merge neschimbat Cere consumul în flux ca să păstrezi contorizarea exactă
Function calling și tools Aceleași forme Retestează ce tool alege modelul, nu dacă poate
Ieșire structurată (JSON schema) Aceleași forme Validează mereu și pe partea ta
Prompturi de sistem Merg Așteaptă-te să ajustezi formularea, nu structura
Nume de modele Se schimbă Folosește un nivel: eu-lite, eu-standard, eu-long, eu-pro
Consum și cost Se schimbă Citește headerele răspunsului în loc de un dashboard
Embeddings, imagini, voce Lipsesc Păstrează furnizorul actual pentru acestea
Batch API Lipsește În roadmap, nelansat
API cu stare în stilul assistants Lipsește Nu e planificat; ține starea la tine

Trei dintre aceste rânduri sunt absențe. Le publicăm ca listă pe pagina principală, în loc să le descoperi în mijlocul migrării, pentru că „compatibil” e un cuvânt întins până la subțiere de servicii care implementează jumătate din contract și declară treaba încheiată.

De ce numele de modele devin nume de niveluri

Cumperi un nivel, nu un model. eu-standard e calul de povară, eu-long primește un milion de tokeni de context, eu-pro e modelul greu pentru raționament, iar fiecare corespunde unui model open-weight numit, publicat împreună cu licența lui pe pagina de transparență AI.

Motivul e rotația. Modelele open-weight sunt înlocuite la câteva luni, iar dacă scrii direct în aplicație numele modelului de azi, trebuie să faci redeploy de fiecare dată când domeniul avansează. Un nivel e o promisiune despre capacitate și preț care supraviețuiește schimbării modelului de dedesubt, iar când îl schimbăm, spunem asta, în loc să schimbăm pe tăcute ce face codul tău.

Contează și licențele, și sunt destul de scurte ca să le citești. Mare parte din ce rulăm e sub Apache 2.0 sau MIT, și de aceea aceleași ponderi pot fi servite legal de pe hardware european.

Doi dezvoltatori la un birou înalt, analizând cod pe ecranul unui laptop.

Ce se schimbă în răspunsuri, nu în API

Partea asta surprinde echipele, așa că planifică timp pentru ea. O schimbare de furnizor e o schimbare de model, iar modelele diferă în moduri pe care niciun strat de compatibilitate nu le poate ascunde.

Formatarea alunecă. Un prompt ajustat ca un model să producă markdown curat poate produce pe altul o introducere inutilă. De obicei se rezolvă cu un rând, dar tot e o corectură.

Judecata la apelarea tools diferă. Forma unui function call e identică; disponibilitatea modelului de a-l apela nu. Există și modele care apelează prea ușor, și modele care răspund din memorie.

Refuzurile diferă. Unele modele open-weight ocolesc întrebări factuale despre politică sau istorie. Tratăm asta ca pe un defect și redirecționăm o dată spre un model fără acel punct orb, iar în headerul X-EU-Routed îți spunem când am făcut-o. Totul e descris pe pagina de transparență AI.

Răspunsul practic e un set de test. Păstrează douăzeci de cereri reale cu rezultatele așteptate, rulează-le pe ambii furnizori și citește singur diferențele. Douăzeci ajung ca să prinzi regresiile de formatare și de alegere a tools, și sunt destul de puține încât chiar s-o faci.

Cost și contorizare după schimbare

Prețul per token e aceeași idee peste tot, dar se schimbă locul unde citești cifrele. Fiecare răspuns spune cât a costat cererea:

  • X-EU-Tokens-In și X-EU-Tokens-Out, tokenii contorizați.
  • X-EU-Cost-EUR, cât s-a scăzut din sold pentru această cerere.
  • X-EU-Balance-EUR, cât a rămas.
  • X-EU-Model-Tier, ce nivel a rulat-o de fapt.

Asta înseamnă că propriile tale loguri pot răspunde la întrebarea despre cost pe funcție, pe client, pe endpoint, fără să aștepți o factură lunară care să te contrazică. Tarifele din spatele acestor cifre sunt pe pagina de prețuri, iar cum să gândești costul pe token în general, inclusiv de ce ieșirea e mai scumpă decât intrarea, e explicat în cât costă un API AI per token.

Un obicei care merită păstrat: setează max_tokens la fiecare apel. E cel mai eficient control al costurilor din orice API cu plată per token, și e un singur rând.

Erori, limite și codul 402 pe care nu l-ai tratat

Gestionarea ta a erorilor acoperă probabil 429 și 500. Creditul preplătit mai adaugă unul.

  1. 402, sold insuficient. Cererea e refuzată cu un link de încărcare, nu se facturează nimic după aceea, iar soldul nu scade niciodată sub zero. Tratează-l ca pe o eroare de autentificare: alertă, nu retry în buclă.
  2. 429, limită de rată sau plafon. Respectă Retry-After. Plafoanele le setezi tu, pe fiecare cheie, în euro pe zi și pe lună.
  3. 502 și 503, serviciul din amonte indisponibil. Reîncearcă cu backoff. Ce se întâmplă în timpul unei întreruperi și limitarea de a depinde de un singur furnizor care stă în spatele ei sunt explicate pe pagina de status.
  4. Cererile eșuate sunt gratuite. Dacă nu s-a întors niciun răspuns utilizabil, nu se scade nimic din sold, iar o cerere redirecționată spre un model mai slab e taxată la cel mai mic dintre cele două tarife.

Plafonul pentru conturile noi îi prinde pe oameni o dată: 25 € pe zi în primele 48 de ore, indiferent de sold. Există pentru că o cheie scursă în prima zi e cea mai scumpă greșeală pe care o face o integrare nouă.

Te face compatibilitatea chiar portabil?

Parțial, și merită să fii precis despre care parte. Contractul de comunicare e portabil: orice serviciu care vorbește chat completions poate fi pus în locul altuia în spatele aceluiași client. Doar asta elimină forma cea mai grosolană de lock-in, cea în care plecarea înseamnă rescrierea stratului de integrare.

Ce nu e portabil e tot ce ai construit deasupra unui model anume. Prompturi ajustate luni de zile, exemple few-shot alese pentru ciudățeniile unui model, seturi de evaluare punctate după stilul de răspuns al unui model și orice prag pe care l-ai stabilit urmărind cum se comportă acel model. Nimic din toate astea nu se transferă curat și nimic nu apare într-o diagramă de arhitectură.

Așa că tratează modelul ca pe o dependență cu versiune, nu ca pe o constantă. Ține prompturile în fișiere, nu împrăștiate prin cod, ține setul de test în repository și notează de ce un prag are valoarea pe care o are. Echipele care fac asta schimbă furnizorul într-o după-amiază. Cele care nu, petrec un trimestru descoperind ce compensau de fapt prompturile lor.

O listă de verificare pentru migrare

O jumătate de zi pentru un serviciu mic, un sprint pentru ceva cu trafic real.

  1. Mută base URL-ul în configurație, dacă nu e deja acolo. Tot ce urmează devine mai ușor după asta.
  2. Alege nivelul după sarcină, nu după nume. Clasificarea și extragerea își au locul pe nivelul ieftin; doar munca grea de raționament are nevoie de cel scump.
  3. Construiește setul de test. Douăzeci de cereri reale, rezultatele așteptate, salvate în repository.
  4. Rulează ambii furnizori în paralel pe o mică parte din trafic și compară rezultatele.
  5. Leagă headerele de cost de ce înregistrezi deja în loguri.
  6. Adaugă ramura pentru 402 și, dacă tot ești acolo, un plafon pe fiecare cheie.
  7. Păstrează furnizorul vechi configurat încă două săptămâni. O migrare pe care o poți anula cu o singură schimbare de configurație e o migrare pe care o poți face într-o marți oarecare.

Pe ce furnizor să faci evaluarea e o întrebare separată, iar cele patru opțiuni realiste sunt comparate în furnizori europeni de AI comparați. Primele zece cereri sunt gratuite, iar încărcarea minimă e 10 €, așa că evaluarea costă mai puțin decât ședința în care se decide dacă s-o faceți. Contractul complet, cu exemple curl și Python gata de copiat, e în documentația API, iar unde sunt procesate acele cereri, pas cu pas, afli în unde ajung prompturile tale.

Întrebări frecvente

Ce înseamnă compatibil cu OpenAI?

Înseamnă că serviciul implementează același contract HTTP ca endpointul chat completions de la OpenAI: același corp al cererii, aceeași formă a răspunsului, același format de streaming. Pentru că SDK-urile oficiale sunt niște învelișuri subțiri peste acest contract, de obicei e suficient să le îndrepți spre alt base URL.

Cum trec de la API-ul OpenAI la alt furnizor?

Schimbi cheia API, setezi base_url-ul clientului pe noul furnizor și înlocuiești numele modelului. În SDK-urile OpenAI pentru Python și Node, base URL-ul e un argument al constructorului, așa că schimbarea înseamnă trei rânduri: cheia, base URL-ul și numele modelului.

Mai funcționează streamingul și function calling după schimbare?

La Union AI, da. Streamingul folosește același format server-sent events și poate returna consumul de tokeni la finalul fluxului, iar function calling și ieșirea structurată cu JSON schema păstrează aceleași forme ale cererii și răspunsului. Ce diferă e judecata modelului despre când să apeleze un tool, și asta merită testat.

Ce funcții OpenAI lipsesc din API-urile compatibile?

Depinde de furnizor, iar cei cinstiți publică lista. La Union AI, versiunea 1 înseamnă doar contractul chat completions: nu există endpointuri pentru embeddings, imagini sau voce, nici API de batch, nici un API cu stare în stilul assistants. Acestea sunt numite în roadmap, nu sugerate ca existente, așa că verifică aceleași patru lipsuri la orice furnizor compatibil.

Vor da prompturile mele aceleași răspunsuri pe un model open-weight?

Nu, și nici două modele oarecare nu dau vreodată aceleași răspunsuri. Instrucțiunile de formatare, comportamentul la apelarea tools și stilul refuzurilor se schimbă, așa că tratează schimbarea furnizorului ca pe o schimbare de model: păstrează douăzeci de cereri reale ca set de test și compară rezultatele înainte de trecerea definitivă.

Cum compar costul înainte de schimbare?

Ia o săptămână de trafic real, numără separat tokenii de intrare și de ieșire și calculează ambele variante per milion de tokeni, la prețurile de listă. Ieșirea domină majoritatea facturilor, așa că un furnizor care pare ieftin la intrare poate fi totuși mai scump pentru o sarcină în care modelul scrie mult.

Pot folosi în continuare SDK-ul OpenAI?

Da. SDK-urile oficiale OpenAI funcționează neschimbate cu orice serviciu care implementează același contract, și exact asta e ideea compatibilității. Îți păstrezi logica de retry, gestionarea streamingului și tipurile și schimbi doar unde merg cererile.

Începe cu AI pentru europeni.

Folosește AI fără să-ți trimiți datele în străinătate: totul pe servere europene, la un preț european.

13 € pe lună pentru chat, anulezi oricând. Sau plătești pe token, cu credit de la 10 €.

Nu ești sigur? Fă testul de 60 de secunde →