Cara LLM melakukan streaming respons

Dipublikasikan: 21 Januari 2025

Respons LLM yang di-streaming terdiri dari data yang dikeluarkan secara bertahap dan berkelanjutan. Data streaming terlihat berbeda dari server dan klien.

Dari server

Untuk memahami tampilan respons yang di-streaming, saya meminta Gemini untuk menceritakan lelucon panjang menggunakan alat command line curl. Pertimbangkan panggilan berikut ke Gemini API. Jika Anda mencobanya, pastikan untuk mengganti {GOOGLE_API_KEY} di URL dengan kunci Gemini API Anda.

$ curl "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:streamGenerateContent?alt=sse&key={GOOGLE_API_KEY}" \
      -H 'Content-Type: application/json' \
      --no-buffer \
      -d '{ "contents":[{"parts":[{"text": "Tell me a long T-rex joke, please."}]}]}'

Permintaan ini mencatat output berikut (yang dipangkas), dalam format aliran peristiwa. Setiap baris dimulai dengan data: yang diikuti dengan payload pesan. Format konkret sebenarnya tidak penting, yang penting adalah potongan teks.

//
data: {"candidates":[{"content": {"parts": [{"text": "A T-Rex"}],"role": "model"},
  "finishReason": "STOP","index": 0,"safetyRatings": [{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HATE_SPEECH","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HARASSMENT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_DANGEROUS_CONTENT","probability": "NEGLIGIBLE"}]}],
  "usageMetadata": {"promptTokenCount": 11,"candidatesTokenCount": 4,"totalTokenCount": 15}}

data: {"candidates": [{"content": {"parts": [{ "text": " walks into a bar and orders a drink. As he sits there, he notices a" }], "role": "model"},
  "finishReason": "STOP","index": 0,"safetyRatings": [{"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HATE_SPEECH","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_HARASSMENT","probability": "NEGLIGIBLE"},{"category": "HARM_CATEGORY_DANGEROUS_CONTENT","probability": "NEGLIGIBLE"}]}],
  "usageMetadata": {"promptTokenCount": 11,"candidatesTokenCount": 21,"totalTokenCount": 32}}
Setelah menjalankan perintah, potongan hasil akan di-streaming.

Payload pertama adalah JSON. Lihat lebih dekat candidates[0].content.parts[0].text yang disoroti:

{
  "candidates": [
    {
      "content": {
        "parts": [
          {
            "text": "A T-Rex"
          }
        ],
        "role": "model"
      },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": [
        {
          "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HATE_SPEECH",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_HARASSMENT",
          "probability": "NEGLIGIBLE"
        },
        {
          "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
          "probability": "NEGLIGIBLE"
        }
      ]
    }
  ],
  "usageMetadata": {
    "promptTokenCount": 11,
    "candidatesTokenCount": 4,
    "totalTokenCount": 15
  }
}

Entri text pertama adalah awal respons Gemini. Jika Anda mengekstrak lebih banyak entri text, respons akan dibatasi dengan baris baru.

Cuplikan berikut menunjukkan beberapa entri text, yang menampilkan respons akhir dari model.

"A T-Rex"

" was walking through the prehistoric jungle when he came across a group of Triceratops. "

"\n\n\"Hey, Triceratops!\" the T-Rex roared. \"What are"

" you guys doing?\"\n\nThe Triceratops, a bit nervous, mumbled,
\"Just... just hanging out, you know? Relaxing.\"\n\n\"Well, you"

" guys look pretty relaxed,\" the T-Rex said, eyeing them with a sly grin.
\"Maybe you could give me a hand with something.\"\n\n\"A hand?\""

...

Namun, apa yang terjadi jika alih-alih meminta lelucon T-rex, Anda meminta model untuk melakukan sesuatu yang sedikit lebih kompleks. Misalnya, minta Gemini membuat fungsi JavaScript untuk menentukan apakah suatu angka genap atau ganjil. Chunk text: terlihat sedikit berbeda.

Output sekarang berisi format Markdown, dimulai dengan blok kode JavaScript. Contoh berikut mencakup langkah-langkah pra-pemrosesan yang sama seperti sebelumnya.

"```javascript\nfunction"

" isEven(number) {\n  // Check if the number is an integer.\n"

"  if (Number.isInteger(number)) {\n  // Use the modulo operator"

" (%) to check if the remainder after dividing by 2 is 0.\n  return number % 2 === 0; \n  } else {\n  "
"// Return false if the number is not an integer.\n    return false;\n }\n}\n\n// Example usage:\nconsole.log(isEven("

"4)); // Output: true\nconsole.log(isEven(7)); // Output: false\nconsole.log(isEven(3.5)); // Output: false\n```\n\n**Explanation:**\n\n1. **`isEven("

"number)` function:**\n   - Takes a single argument `number` representing the number to be checked.\n   - Checks if the `number` is an integer using `Number.isInteger()`.\n   - If it's an"

...

Untuk membuat masalah menjadi lebih menantang, beberapa item yang ditandai dimulai dalam satu bagian dan berakhir di bagian lain. Beberapa markup bertingkat. Dalam contoh berikut, fungsi yang ditandai dibagi menjadi dua baris: **isEven( dan number) function:**. Jika digabungkan, outputnya adalah **isEven("number) function:**. Artinya, jika Anda ingin menghasilkan output Markdown yang diformat, Anda tidak dapat memproses setiap bagian satu per satu dengan parser Markdown.

Dari klien

Jika Anda menjalankan model seperti Gemma di klien dengan framework seperti MediaPipe LLM, data streaming akan masuk melalui fungsi callback.

Contoh:

llmInference.generateResponse(
  inputPrompt,
  (chunk, done) => {
     console.log(chunk);
});

Dengan Prompt API, Anda mendapatkan data streaming sebagai potongan dengan melakukan iterasi pada ReadableStream.

const languageModel = await LanguageModel.create();
const stream = languageModel.promptStreaming(inputPrompt);
for await (const chunk of stream) {
  console.log(chunk);
}

Langkah berikutnya

Apakah Anda bertanya-tanya cara merender data yang di-streaming secara berperforma tinggi dan aman? Baca praktik terbaik kami untuk merender respons LLM.