Az LLM-késleltetés csökkentése az egyik legkritikusabb kihívás azoknak a mérnököknek, akik reszponzív AI-alkalmazásokat építenek. Miközben a nagy nyelvi modellek (LLM-ek) képességei folyamatosan nőnek, tokenről tokenre történő generálásuk frusztráló szűk keresztmetszeteket okozhat a végfelhasználók számára, a hosszú várakozási idők pedig közvetlenül alacsonyabb elköteleződéshez és az alkalmazások elhagyásához vezetnek. A következtetési pipeline-ok sebességre való optimalizálása ezért alapvető fejlesztői követelmény. Ez az útmutató bemutatja, hogyan konfigurálj prompt cachinget, valósíts meg válasz-streaminget, alakítsd ki az edge hálózati útválasztást, és használj serverless konfigurációkat a feldolgozási késleltetések csökkentésére.

[!TIP] Teljesítménymutató-tipp: Az API-késleltetések mérésekor különítsd el a Time to First Tokent (TTFT) az általános generálási sebességtől. Az alacsony TTFT azonnalinak érezteti az alkalmazást a felhasználóval, még akkor is, ha a teljes kimenet generálása több másodpercig tart, mert a szöveg azonnal megjelenni kezd.

Legfontosabb tanulságok:

  • Prompt caching: Használd újra a statikus előtag-blokkokat, hogy megkerüld a parsing fázisokat, és 80%-kal csökkentsd a TTFT-t.
  • Válasz-streaming: Küldd a tokeneket Server-Sent Events (SSE) segítségével, hogy a felhasználók azonnali szöveggenerálást lássanak.
  • Edge Workerek: Futtasd az autorizációt és a kérésútválasztást a felhasználókhoz közeli regionális edge központokban.
  • Modellútválasztás: Irányítsd az egyszerű kéréseket könnyűsúlyú modellekhez a sebesség optimalizálása érdekében.

Az LLM API-késleltetés összetevői

A válaszidők csökkentéséhez először meg kell értened, mely elemek határozzák meg az összesített API-késleltetést. Az összesített késleltetés három különböző változó együttes összege.

Először is, a hálózati átviteli idő azt méri, mennyi ideig utazik egy kérés a klienstől a szerveredhez, majd tovább a modellszolgáltató API-jához. Ez teszi az átviteli távolságot jelentős szűk keresztmetszetté.

Másodszor, a Time to First Token (TTFT) azt az időtartamot jelöli, amely a kérés modell általi fogadása és az első kimeneti token generálása között telik el, ezért olyan fontos a prompt caching.

Végül a tokengenerálási sebesség azt a rátát méri, amellyel a hardver a további tokeneket kiadja. A hardveres korlátok határozzák meg a generálási sebességet, a fejlesztők azonban teljes körű kontrollt tartanak fenn az átviteli idő és a TTFT felett, így az intelligens útválasztás és caching drasztikusan csökkentheti az LLM-késleltetést.

Gyorsítsd fel az LLM-integrációdat

Előfeltételek

Mielőtt nekilátnál az alábbi optimalizációk beállításának, győződj meg róla, hogy a következők rendelkezésre állnak. Egyik sem egzotikus, de bármelyik kihagyása később gyakran zavarba ejtő hibákat okoz.

  • Egy általad kontrollált middleware vagy edge futtatókörnyezet. A példák Cloudflare Workerst használnak, de bármely serverless platform megfelel, amely proxyzni tud egy kérést. Szükséged van valamire, ami a böngésző és a modellszolgáltató között helyezkedik el.
  • API-hitelesítő adatok egy olyan szolgáltatóhoz, amely támogatja a streaminget és a cachinget. Az OpenAI és az Anthropic egyaránt támogatja. A kulcsot secretként tárold (Wrangler secretként vagy környezeti változóként), soha ne a kliensoldali kódban.
  • Node.js 18 vagy újabb, ha a Workereket helyben szeretnéd tesztelni a wrangler dev segítségével. A végig használt globális fetch és ReadableStream API-k elérhetők ebben a futtatókörnyezetben és a modern böngészőkben.
  • Egy alapmérés (baseline). Rögzítsd a jelenlegi Time to First Tokent és a teljes válaszidőt, mielőtt bármit módosítanál, hogy bizonyítani tudd, minden optimalizáció valóban segített. Az alábbi benchmarking rész megmutatja, hogyan.
  • A Server-Sent Events (SSE) ismerete. A streaming válaszok data: sorok sorozataként érkeznek, amelyeket a kliensen fogsz feldolgozni.

A prompt caching megvalósítása

A prompt caching a leghatékonyabb módja a TTFT optimalizálásának a nagy rendszerpromptok köré épülő alkalmazásokban. Amikor egy kérés hosszú, statikus utasításblokkot tartalmaz (például egy ügynök rendszerpromptját vagy egy RAG referenciadokumentumot), a modellszolgáltatónak minden végrehajtáskor fel kell dolgoznia és kódolnia kell ezeket a tokeneket. Az Anthropic és az OpenAI egyaránt támogatja a prompt cachinget, amely memóriában tárolja a feldolgozott token-állapotokat. Az ugyanazt az előtagot használó későbbi kérések ekkor megkerülik a parsing fázist, akár 80%-kal csökkentve a TTFT-t.

A cache élettartama szolgáltatónként eltér. Az Anthropic körülbelül öt perc inaktivitásig tartja fenn a cache-t, míg az OpenAI dinamikus lecsengési modellt használ. A rendszeres háttérbeli fetch pingek ütemezése ezért aktívan tarthatja a kritikus rendszerutasításokat a szerver memóriájában.

A mechanizmus némileg eltér a két szolgáltató között, és a kérés helyes strukturálása dönti el, hogy a cache valóban életbe lép-e. Az Anthropicnál explicit módon jelölöd meg a cache töréspontját a cache_control segítségével. A töréspont előtti minden tartalom tárolásra kerül, ezért a stabil, statikus tartalomnak elöl, a változékony, kérésenkénti tartalomnak pedig a végén kell szerepelnie:

 1import Anthropic from "@anthropic-ai/sdk";
 2
 3const anthropic = new Anthropic();
 4
 5const response = await anthropic.messages.create({
 6  model: "claude-opus-4-8",
 7  max_tokens: 1024,
 8  system: [
 9    {
10      type: "text",
11      text: SYSTEM_INSTRUCTIONS       // small, sent on every request
12    },
13    {
14      type: "text",
15      text: KNOWLEDGE_BASE,           // large, static reference block
16      cache_control: { type: "ephemeral" }
17    }
18  ],
19  messages: [
20    { role: "user", content: userQuestion }   // volatile — after the breakpoint
21  ]
22});
23
24// Confirm the cache is working
25console.log(response.usage.cache_read_input_tokens);

A messze leggyakoribb hiba egy időbélyeg, kérésazonosító vagy bármilyen kérésenkénti karakterlánc elhelyezése a cache-elt blokk elé. Mivel a caching előtag-egyezésen alapul, egyetlen megváltozott bájt a töréspont előtt bárhol érvényteleníti az utána következő mindent, és a cache csendben soha nem talál. Ellenőrizd a működést a válaszból kiolvasott usage.cache_read_input_tokens értékkel: ha ez azonos kérések esetén nullán marad, valami dinamikus került az előtagba. Vedd figyelembe azt is, hogy a cache-elt előtagnak el kell érnie egy minimális hosszúságot (a modelltől függően nagyjából 1024 és 4096 token között), mielőtt a caching egyáltalán életbe lépne.

Az OpenAI egyszerűbb megközelítést alkalmaz: a caching automatikus a nagyjából 1024 tokennél nagyobb promptokhoz, semmilyen cache_control flaget nem kell beállítani. Ugyanaz a fegyelem azonban továbbra is érvényes. Tartsd a statikus utasításblokkot a messages tömb legelején, és a változó felhasználói bemenetet fűzd a végére, hogy az újrahasznosítható előtag bájtról bájtra azonos maradjon a kérések között.

A prompt caching árazási és paraméterstruktúráinak megtekintéséhez tekintsd meg az Anthropic prompt caching útmutatóját .


Edge compute és serverless útválasztás

Az LLM-kérések egyetlen központosított szerveren történő feldolgozása hatalmas hálózati ugrásokat okoz a globális felhasználók számára. Az API middleware serverless edge hálózatokra (például Cloudflare Workersre) történő telepítése drasztikusan lerövidíti ezeket az útvonalakat.

Az edge worker fogadja a kliens kérését, autorizálja a munkamenetet, és a legközelebbi modellszolgáltatói adatközponthoz irányítja azt. Ez a serverless struktúra abban a pillanatban juttatja el a tokeneket a felhasználó képernyőjére, amint kiszámításra kerülnek, így a felület rendkívül reszponzívnak érződik. Az alábbi JavaScript middleware bemutatja, hogyan konfigurálhatsz streaming válaszokat közvetlenül egy edge futtatókörnyezetből:

 1export default {
 2  async fetch(request, env) {
 3    const payload = await request.json();
 4
 5    // Call the streaming LLM endpoint
 6    const response = await fetch("https://api.openai.com/v1/chat/completions", {
 7      method: "POST",
 8      headers: {
 9        "Authorization": `Bearer ${env.OPENAI_API_KEY}`,
10        "Content-Type": "application/json"
11      },
12      body: JSON.stringify({
13        model: "gpt-4o-mini",
14        messages: payload.messages,
15        stream: true
16      })
17    });
18
19    // Forward the stream directly to the client browser
20    return new Response(response.body, {
21      headers: { "Content-Type": "text/event-stream" }
22    });
23  }
24};

Ez a serverless struktúra azonnal, a kiszámításuk pillanatában juttatja el a tokeneket a felhasználó képernyőjére. Ha meg szeretnéd tanulni, hogyan építs edge-re optimalizált backendeket, olvasd el útmutatónkat a serverless API építéséről Cloudflare Workersszel .


A stream feldolgozása a kliensen

A stream továbbítása az edge-ről csak a munka fele. A böngészőnek még mindig olvasnia kell ezeket a chunkokat, amint megérkeznek, és renderelnie kell minden tokent, különben a válasz egy pufferben halmozódik fel, és egyszerre jelenik meg, meghiúsítva a célt. Ezt a lépést hagyja ki a legtöbb útmutató, és itt dől el valójában a felhasználó által érzékelt teljesítmény.

A választörzs nyers bájtok ReadableStream-je. Az SSE keretek data: sorokként érkeznek, de egyetlen hálózati chunk több keretet is tartalmazhat, vagy egy keretet két chunkra oszthat, ezért a részleges sorokat pufferelned kell ahelyett, hogy feltételeznéd, minden chunk teljes üzenet:

 1async function streamCompletion(messages, onToken) {
 2  const response = await fetch("/api/chat", {
 3    method: "POST",
 4    headers: { "Content-Type": "application/json" },
 5    body: JSON.stringify({ messages })
 6  });
 7
 8  const reader = response.body.getReader();
 9  const decoder = new TextDecoder();
10  let buffer = "";
11
12  while (true) {
13    const { value, done } = await reader.read();
14    if (done) break;
15
16    buffer += decoder.decode(value, { stream: true });
17    const lines = buffer.split("\n");
18    buffer = lines.pop();              // keep the trailing partial line
19
20    for (const line of lines) {
21      if (!line.startsWith("data: ")) continue;
22      const payload = line.slice(6).trim();
23      if (payload === "[DONE]") return;
24
25      try {
26        const json = JSON.parse(payload);
27        const token = json.choices?.[0]?.delta?.content;
28        if (token) onToken(token);
29      } catch {
30        // ignore keep-alive comments and malformed partial frames
31      }
32    }
33  }
34}

A buffer.split("\n") után következő lines.pop() a lényeges részlet: minden hiányos sort megőriz, amíg a következő chunk be nem fejezi. A JSON.parse try/catch-be burkolása életben tartja a ciklust, amikor egy keep-alive megjegyzés vagy egy félig fogadott keret érkezik. Az onToken callback ezután minden töredéket hozzáfűz a DOM-hoz, így a szöveg abban a pillanatban jelenik meg, amint a modell előállítja.


A késleltetés mérése és benchmarkolása

Nem optimalizálhatod azt, amit nem mértél meg. Minden változtatás előtt és után rögzítsd a Time to First Tokent és a teljes generálási időt, hogy egy javulást a megfelelő okhoz tudj rendelni. A TTFT mintavételezésének leggyorsabb módja a curl, ahol a time_starttransfer jó közelítése annak, amikor az első bájt eléri a klienst:

1curl -w "TTFT: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
2  -X POST https://your-worker.example.com/chat \
3  -H "Content-Type: application/json" \
4  -d '{"messages":[{"role":"user","content":"Hello"}]}' \
5  -o /dev/null -s

Alkalmazásszintű számokhoz közvetlenül a kliensoldali parsert instrumentáld. Bélyegezd meg az órát, amikor a kérés elindul, és újra, amikor az első token megérkezik:

1const start = performance.now();
2let firstTokenAt = null;
3
4await streamCompletion(messages, (token) => {
5  if (firstTokenAt === null) firstTokenAt = performance.now();
6  render(token);
7});
8
9console.log(`TTFT: ${Math.round(firstTokenAt - start)}ms`);

Minden mérést végezz el többször, és egyetlen minta helyett vedd a mediánt, mivel a hálózati szórás és a hidegindítások eltorzíthatják az egyszeri leolvasásokat. Az alábbi táblázat szemléltető tartományokat ad arra, hogy egy jól viselkedő globális kérés esetén tipikusan hová megy az idő; tekintsd ezeket összehasonlítási mintának, ne fix értékeknek, mert a saját számaid a régiótól, a modelltől és a prompt méretétől függenek.

SzakaszTipikus hozzájárulásA te kontrollod alatt?
Hálózati átvitel (klienstől edge-ig)10–60 msIgen — az edge útválasztás lerövidíti
Middleware-feldolgozás az edge-en1–15 msIgen — tartsd karcsún a workert
Time to First Token (hideg prompt)400–1200 msRészben — a caching élesen csökkenti
Time to First Token (cache-elt előtag)100–400 msIgen — prompt cachinggel
Tokenenkénti generálás10–50 ms/tokenNem — a modell és a hardver határozza meg

A két sor, amelyet érdemes alaposan megnézni, a cache-elt és a hideg TTFT értékei. Ez a különbség a legnagyobb egyetlen nyereség, amely a legtöbb alkalmazás számára elérhető, ezért van a prompt caching az optimalizálási lista élén. A generálási sebesség ezzel szemben a szolgáltató által rögzített, így az egyszerűbb kérések kisebb modellhez irányítása az egyetlen elérhető emelő.


Lépésről lépésre optimalizálási munkafolyamat

A szoftveralkalmazásod sebességének optimalizálásához kezdd a statikus rendszerutasítások és a dinamikus felhasználói bemenetek szétválasztásával. Ez a felosztás lehetővé teszi, hogy tisztán célozd meg a cache belépési pontjait.

Ezután aktiváld a prompt caching flageket az API-payloadjaidban, hogy a modellszolgáltató a memóriában tárolja a szöveges tokenjeidet.

Mindig konfiguráld a válasz-streaminget standard SSE végpontokkal. Könnyűsúlyú frontend parserek írásával, amelyek a chunkokat érkezésükkor dolgozzák fel, javítod a felhasználó által érzékelt teljesítményt. Ezután alakíts ki modell-tartalék útvonalakat: az alapszintű ügyfélbemeneteket irányítsd kisebb modellekhez, a nagyobb, gondolkodó modelleket pedig tartsd fenn a fejlett feladatokhoz. Végül profilozd a hálózati ugrásokat, hogy megerősítsd, a serverless workerek csökkentik az átviteli késleltetéseket. Az adatbázis-optimalizálás részleteiért nézd meg útmutatónkat a WordPress kontra egyedi webfejlesztésről .


Gyakori buktatók és hibaelhárítás

Néhány hiba újra és újra felbukkan, amikor a csapatok először vezetik be a streaminget és a cachinget. A tünet felismerése órányi találgatást takarít meg.

TünetValószínű okMegoldás
A cache_read_input_tokens nullán maradEgy időbélyeg, UUID vagy munkamenet-azonosító a cache töréspontja előtt helyezkedik el, így az előtag minden kérésnél megváltozikMozgasd az összes dinamikus tartalmat a statikus blokk mögé; bármely JSON-t determinisztikusan szerializálj
A tokenek egyszerre érkeznek, nem fokozatosanEgy közbülső proxy vagy CDN pufferolja a választKüldd a Cache-Control: no-transform és X-Accel-Buffering: no fejléceket; győződj meg róla, hogy a text/event-stream content type be van állítva
A stream félúton megszakadA worker azelőtt tért vissza, hogy az upstream törzs befejeződött volna, vagy elérte a max_tokens értéketAdd vissza közvetlenül a response.body-t ahelyett, hogy a teljes szövegre várnál; növeld a max_tokens értéket
Az első token lassú a caching ellenéreA statikus előtag a szolgáltató minimális cache-elhető hossza alatt vanVond össze az utasításokat, hogy a cache-elt blokk átlépje a nagyjából 1024 tokenes küszöböt
A kliens parsere egyes chunkokon hibát dobEgy keret két hálózati chunkra oszlottPufferold a részleges sorokat a fent bemutatott módon, és burkold a JSON.parse-t try/catch-be

Egy alattomosabb csapda az edge-en magán történő pufferolás. Ha a workerben await response.text()-et hívsz, mielőtt visszatérnél, csendben visszaalakítottál egy streaming választ blokkolóvá. Mindig közvetlenül add tovább a stream törzsét. Hasonlóképpen figyelj a worker CPU-korlátaira: a middleware-ben végzett kérésenkénti nehéz munka közvetlenül hozzáadódik a TTFT-hez, ezért tartsd minimálisan az autorizációs és útválasztási logikát, és halassz el minden költséges műveletet.


Éles üzemi megfontolások

Egy streaming demó böngészőben való futtatása egyszerű; valódi forgalom alatt megbízhatóan üzemeltetni néhány további védőmechanizmust igényel.

Állíts be ésszerű kérési időkorlátot az upstream hívásra, hogy egy elakadt szolgáltatói kapcsolat ne tarthasson nyitva egy workert korlátlan ideig, és párosítsd ezt egy újrapróbálkozással, amely egy második szolgáltatóra vagy egy kisebb modellre vált, amikor az elsődleges időtúllépést szenved. Mivel a prompt caching kis felárat számít fel a cache-írásokra és nagy kedvezményt a cache-olvasásokra, csak akkor térül meg, ha egy előtagot újrahasznosítanak; egy néhány percenkénti háttérbeli ping memóriában tart egy aktív rendszerpromptot anélkül, hogy minden felhasználói kérésnél fizetni kellene az újraírásáért.

Instrumentálj folyamatosan, ne csak az induláskor. Naplózd a TTFT-t és a másodpercenkénti tokenszámot kérésenként, és riasztj, amikor a medián elmozdul, mivel egy szolgáltatóoldali visszalépés vagy a prompt méretének változása ott jelenik meg először. Végül tartsd tiszteletben a szolgáltató rátakorlátait: egyidejű streamek hulláma átlépheti ezeket, ezért sorba rendezd vagy elegánsan dobd el a terhelést ahelyett, hogy a kéréseket csendben hagynád meghiúsulni. Ezek az intézkedések egy gyors prototípust olyan alkalmazássá alakítanak, amely gyors marad, amikor számít.


Legfontosabb tanulságok

  • Célozd meg a Time to First Tokent (TTFT) és az átviteli időt az LLM-késleltetés csökkentéséhez.
  • Használd ki a prompt cachinget a modell-API-kon, hogy megkerüld a rendszerszintű utasításfeldolgozási többletterhelést.
  • Használj válasz-streaminget a tokenek valós idejű kézbesítéséhez, javítva az érzékelt sebességet.
  • Telepítsd az API middleware-t serverless edge futtatókörnyezetekre a globális hálózati útvonalak lerövidítéséhez.
  • Irányítsd az egyszerűbb felhasználói lekérdezéseket könnyűsúlyú modellekhez a végrehajtási sebesség optimalizálása érdekében.
  • Állíts be teljesítményfigyelő eszközöket a késleltetés folyamatos elemzéséhez és csökkentéséhez valós felhasználói körülmények között.

Gyakran ismételt kérdések (GYIK)

Hogyan csökkenthetem az LLM-késleltetést éles üzemben? Az LLM-késleltetés éles üzemi csökkentéséhez érdemes prompt cachinget megvalósítanod a statikus utasításokhoz, engedélyezned a token-streaminget, és edge workereket telepítened a kérésútválasztás optimalizálásához. Serverless orchestrációs futtatókörnyezetek globális kliensekhez közelebbi telepítésével a fejlesztők megkerülnek több hálózati útválasztási ugrást, és valós időben kézbesítik az első válasz-tokent.

Mi a prompt caching? A prompt caching egy olyan API-funkció, amely a feldolgozott szöveges állapotokat a szerver memóriájában tárolja, lehetővé téve, hogy az ugyanazt az előtagot használó későbbi kérések sokkal gyorsabban fussanak. A nagy utasításadathalmazok rendszerszintű parsing ciklusának megkerülésével ez az optimalizáció akár nyolcvan százalékkal csökkenti a Time to First Tokent (TTFT).

Befolyásolja a modell mérete a késleltetést? Igen, a kisebb modellek tokengenerálási sebessége sokkal gyorsabb, ami ideálissá teszi őket olyan egyszerű feladatokhoz, ahol a késleltetés elsődleges szempont. Az egyszerű osztályozási vagy kinyerési kérések specializált edge modellekhez irányítása gyors átfutási időt biztosít, miközben a sűrű modelleket a gondolkodó feladatokhoz tartja fenn.

Hogyan segít a Server-Sent Events (SSE) streaming az érzékelt késleltetés csökkentésében? Az SSE streaming valós időben, összeállításuk pillanatában küldi a szöveges kimeneti tokeneket a modell hosztjáról a kliens képernyőjére. Bár ez nem csökkenti a teljes végrehajtási időtartamot, minimalizálja a Time to First Tokent (TTFT), és reszponzív, aktív alkalmazásfelületet nyújt a felhasználónak.

Hogyan cache-elhetem a dinamikus LLM-válaszokat az edge-en? A dinamikus válaszokat az edge-en KV-adatbázisok vagy Redis-példányok segítségével cache-elheted rövid TTL (Time to Live) korlátokkal. A dinamikus válaszok cache-elése ismétlődő felhasználói lekérdezések vagy gyakori ügyfélszolgálati szándékok esetén hatékony, teljesen megelőzve a modellszolgáltató felé irányuló hálózati hívásokat.