SGLang 0.5.19 odmítne požadavek s víc než 32 zastavovacími řetězci
Inferenční server SGLang přijme od verze 0.5.19 v jednom požadavku nejvýš 32 zastavovacích řetězců a 32 regulárních výrazů, každý výraz do 256 bajtů. Přes tu mez vrátí HTTP 400. OpenAI dovoluje ve svém rozhraní čtyři sekvence, vLLM počet neomezuje vůbec.

Vydání 0.5.19 inferenčního serveru SGLang vyšlo 5. září 2026 a nese 786 návrhů změn od 214 přispěvatelů. Jedna položka z toho seznamu se ale provozovatele netýká vůbec a jeho klienta hned: požadavek s dlouhým seznamem zastavovacích řetězců server od téhle verze nepřijme.
Zastavovací řetězec (stop) je běžná součást požadavku na generování. Klient v něm řekne, čím má odpověď skončit, a server generování ukončí, jakmile ten text ve výstupu uvidí. SGLang k tomu má navíc vlastní stop_regex, tedy totéž zadané regulárním výrazem.
Tři konstanty v jednom souboru
Meze stojí v souboru python/sglang/srt/sampling/sampling_params.py jako tři konstanty: MAX_STOP_COUNT a MAX_STOP_REGEX_COUNT po 32, k tomu MAX_STOP_REGEX_LEN na 256. První dvě počítají položky seznamu, třetí měří délku jednoho výrazu v bajtech.
Kontrolu dělá metoda normalize(), kterou projde každý požadavek bez ohledu na to, jestli přišel na rozhraní kompatibilní s OpenAI, nebo na vlastní /generate. Když se mez překročí, vznikne výjimka a webová vrstva z ní udělá odpověď se stavem 400. Text hlášky je přesně ten z kódu, takže klient dostane například at most 32 stop strings are allowed, got 33 a ví, kde je.
Přenastavit se to nedá. Nejsou to přepínače příkazové řádky ani proměnné prostředí, ale konstanty ve zdrojovém souboru. Kdo provozuje SGLang pro klienty, kterým 32 nestačí, musí sáhnout do kódu.
Proč to autor napsal
Odůvodnění je v návrhu #37029, sloučeném 30. srpna: dosud šlo poslat neomezený počet zastavovacích řetězců i výrazů a kontrolují se při dekódování, takže nadměrný vstup podle autora „plýtvá procesorem a zpomaluje ostatní požadavky“ (přeloženo). Není to tedy oprava chyby, ale ochrana sousedů na témže stroji.
Návrh přidal 60 řádků ve dvou souborech a polovina z nich jsou testy na hranici meze – zvlášť pro počet řetězců, počet výrazů a délku jednoho výrazu.
Bajty, ne znaky
Mez 256 se měří na kódování UTF-8, ne na znacích. V testu je to vidět doslova: hraniční případ je poskládaný z písmene „é“ opakovaného stodvacetosmkrát, protože to písmeno zabírá dva bajty.
Pro češtinu z toho plyne dopočet, který v dokumentaci nikde nestojí: výraz psaný samou diakritikou se vejde do 128 znaků místo 256. U čínštiny nebo emodži, kde znak zabírá tři až čtyři bajty, klesne strop na 85, respektive 64 znaků. Základní ASCII znaky regulárního výrazu – závorky, hvězdičky, kvantifikátory – zůstávají po jednom bajtu, takže se to týká jen doslovného textu uvnitř vzoru.
Kolik dovolí ostatní
Číslo 32 samo o sobě nic neříká, dokud se nemá k čemu přiložit. Referenční dokumentace OpenAI u parametru stop uvádí „Up to 4 sequences“, tedy nejvýš čtyři. SGLang je proti tomu osmkrát štědřejší.
Druhý směr je zajímavější. Ve vydání 0.28.0 serveru vLLM jsme v souboru vllm/sampling_params.py žádnou mez na počet ani na délku nenašli; jediná kontrola nad zastavovacími řetězci tam zakazuje prázdný řetězec. Kdo tedy posílá stovku zastavovacích řetězců, projde na vLLM dál a na SGLangu od téhle verze ne.
Na co strop nesahá
Bajtová mez omezuje zápis výrazu, ne práci, kterou ten výraz serveru nadělá. Ty dvě věci spolu nesouvisejí tak těsně, jak by se čekalo.
SGLang si u každého výrazu spočítá funkcí get_max_seq_length() horní mez toho, kolik posledních tokenů výstupu musí držet a prohledávat, aby shodu neminul. Tu funkci jsme si vzali ze souboru na značce v0.5.19 a pustili na pár vzorů. Dvouznakový výraz a+ vyjde na 1 073 741 824, protože neomezené opakování se v ní počítá konstantou 230. Totéž dá .*. Naproti tomu vzor (foo|barbaz) o dvanácti bajtech vyjde na šest.
Ta horní mez pak řídí, kolik tokenů se v každém kroku dekóduje zpátky na text a prohledá; kód ji ořízne na délku dosavadního výstupu. U vzoru s neomezeným opakováním to znamená, že se s každým dalším tokenem znovu dekóduje celá dosud napsaná odpověď. Takový vzor má přitom dva bajty a dvaatřicet jich smí přijít v jednom požadavku.
Je to čtení kódu, ne měření na běžícím serveru – kolik to stojí ve skutečnosti, jsme nezkoušeli. Směr je z něj ale čitelný: nová mez bere odesílateli šířku, ne hloubku. Návrh sám v kolonce o měření rychlosti uvádí, že se neměřilo nic, protože jde o kontrolu vstupu.