Volání API

Request, streaming, chyby, retry, timeouty.

Co se naučíš: Budeš umět zavolat API včetně streamování, retry, timeoutů a ošetření chyb.

6 min čtení + cvičeníNavazuje na:💬 Zprávy a role

Volání LLM je obyčejný HTTP požadavek, ale chová se jinak než API, na která jsi zvyklý: odpovídá v řádu sekund, počítá si tě podle tokenů, umí posílat odpověď po kouscích a občas ti prostě řekne „teď ne, zkus později“. Tahle kapitola je o tom, jak takové volání napsat, aby ti nespadlo v produkci.


Jak vypadá požadavek

POST /v1/messages
Authorization: Bearer sk-...
Content-Type: application/json

{
  "model": "nazev-modelu",
  "max_tokens": 1000,
  "temperature": 0.2,
  "messages": [
    { "role": "user", "content": "Shrň tenhle text do tří bodů: ..." }
  ]
}

Odpověď obsahuje vygenerovaný text, důvod ukončení a spotřebu tokenů:

{
  "content": [{ "type": "text", "text": "• ...\n• ...\n• ..." }],
  "stop_reason": "end_turn",
  "usage": { "input_tokens": 412, "output_tokens": 88 }
}

💡 usage si loguj vždycky. Bez něj nezjistíš, která část aplikace ti utrácí peníze, a nemáš jak hlídat trend, když se prompty postupně nafukují.


Streaming

Bez streamingu čeká uživatel na celou odpověď (klidně 10 sekund) a kouká na prázdno. Se streamingem dostáváš tokeny průběžně a rovnou je vypisuješ.

klient ──▶ server ──▶ LLM
                 ◀── "Ob" "jed" "návka" " je" ...
klient ◀── SSE / websocket

Na co dát pozor:

  • Chyba může přijít i uprostřed streamu, když už jsi něco zobrazil. Musíš to umět ošetřit.
  • JSON se streamovat nedá rozumně: dokud není celý, nedá se parsovat. Struktura = bez streamu.
  • Zrušení požadavku ukončí generování a tím i placení. Když uživatel odejde ze stránky, zruš to.

Chyby, které tě potkají

StavCo znamenáCo dělat
429Překročil jsi limit (rate limit)Počkat a zkusit znovu s exponenciálním backoffem
529 / 503Model je přetíženýTotéž, případně přepnout na jiný model
400Špatný požadavek (moc tokenů, špatný formát)Neopakovat, je to chyba v kódu
401Špatný klíčNeopakovat
timeoutOdpověď nedorazila včasOpakovat, ale s nižším limitem tokenů

Retry piš jen na dočasné chyby (429, 5xx, timeout), s náhodným rozptylem (jitter), aby ti všechny instance nezkoušely znovu ve stejnou milisekundu. Trvalé chyby opakovat nemá smysl a jen platíš.


Timeouty a latence

LLM je pomalé API. Počítej s tím:

  • Nastav timeout vědomě (např. 60 s pro dlouhé odpovědi), ne default knihovny.
  • Nevolej to synchronně v HTTP requestu, pokud odpověď trvá dlouho, použij frontu a job.
  • Latence roste s délkou výstupu, ne vstupu. Když potřebuješ rychlost, zkrať odpověď.

Klíče a bezpečnost

  • Klíč nikdy nedávej do frontendu. Ani „dočasně“, vytáhne ho kdokoli z prohlížeče a bude utrácet tvoje peníze. Volání jde vždy přes tvůj backend.
  • Klíč patří do proměnných prostředí, ne do gitu.
  • Nastav si limit útraty u poskytovatele. Chyba ve smyčce umí za noc utratit měsíční rozpočet.
  • Loguj prompty opatrně. Můžou obsahovat osobní údaje zákazníků, viz bezpečnost dat.

Kostra, která obstojí

1. sestav prompt (a spočítej tokeny, ať víš, že se vejde)
2. zavolej API s timeoutem
3. retry na 429/5xx s backoffem, max 3 pokusy
4. zkontroluj stop_reason (usekla se odpověď?)
5. zvaliduj obsah (schéma, rozsahy)
6. zaloguj usage + latenci + verzi promptu
7. při selhání fallback: jiný model / cache / hláška uživateli

Cvičení

  1. Volání občas vrátí 429 a občas se zasekne na dvě minuty. Napiš, jak se má chovat retry v obou případech a proč se liší.
  2. Streamuješ odpověď a uživatel zavře záložku. Co se stane s účtem?
Náčrt řešení: rozbal, až si cvičení zkusíš sám
  1. Na 429 opakuj s exponenciálním odstupem a jitterem, na timeout opakuj nejvýš jednou. 429 znamená „teď ne, zkus později“, takže má smysl počkat a zopakovat, ale s náhodným rozptylem, jinak se ti všechny paralelní požadavky sejdou v jedné sekundě a poskytovatele dorazíš sám. Timeout je jiný případ: požadavek se možná zpracovává dál, takže opakováním platíš dvakrát. U timeoutu proto raději jeden pokus a pak fallback nebo poctivá chyba.
  2. Zaplatíš za tokeny, které se do zavření stihly vygenerovat. Streamování je jen způsob doručení, ne účtování. Pokud tvůj kód spojení opravdu ukončí, generování se zastaví a dál neplatíš; pokud ho drží nějaká fronta nebo proxy, doběhne celé. Proto se u dlouhých odpovědí hlídá zrušení požadavku, ne jen zavření prohlížeče.

Shrnutí

  • Volání je běžné HTTP, ale pomalé, placené podle tokenů a občas přetížené.
  • Streaming zlepší vnímanou rychlost, ale komplikuje chyby a nejde s ním parsovat JSON.
  • Opakuj jen dočasné chyby, s backoffem a jitterem; klíč nikdy nepatří do frontendu.
  • Vždy loguj spotřebu tokenů, latenci a důvod ukončení.
Dostáváš `429`. Co uděláš?

Počkáš a zkusíš znovu s exponenciálním backoffem a náhodným rozptylem, s omezeným počtem pokusů. Zároveň se podíváš, jestli nejde snížit zátěž, kratší prompty, cache, dávkování nebo rozložení požadavků v čase.

Proč nedávat API klíč do frontendové aplikace, i když je to „jen interní nástroj“?

Protože všechno, co je v prohlížeči, si může kdokoli přečíst, včetně klíče, kterým pak bude utrácet na tvůj účet. Volání LLM patří na backend, který drží klíč a řídí autorizaci i limity.

Aplikace vrací uživatelům občas useknuté odpovědi a nikdo neví proč. Kde hledat?

U stop_reason. Když je length, došel limit max_tokens nebo se vstup s výstupem nevešly do kontextového okna. Proto se důvod ukončení kontroluje a loguje, jinak je to tichá chyba.