Yayınlanma tarihi: 21 Ocak 2025
Aktarılan LLM yanıtı, artımlı ve sürekli olarak yayınlanan verilerden oluşur. Akış verileri, sunucu ve istemciden farklı görünür.
Sunucudan
Aktarılan yanıtların nasıl göründüğünü anlamak için Gemini'den curl
komut satırı aracını kullanarak bana uzun bir şaka anlatmasını istedim. Gemini API'ye yapılan aşağıdaki çağrıyı düşünün. Bunu denerseniz URL'deki {GOOGLE_API_KEY}
değerini Gemini API anahtarınızla değiştirmeyi unutmayın.
$ 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."}]}]}'
Bu istek, aşağıdaki (kısaltılmış) çıkışı etkinlik akışı biçiminde günlüğe kaydeder.
Her satır data:
ile başlar ve ardından mesaj yükü gelir. Belirli bir biçim kullanmak önemli değildir. Önemli olan metin parçalarıdır.
//
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}}
İlk yük JSON'dur. Vurgulanan candidates[0].content.parts[0].text
bölümüne daha yakından bakın:
{
"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
}
}
İlk text
girişi, Gemini'nin yanıtının başlangıcıdır. Daha fazla text
girişi ayıkladığınızda yanıt, yeni satırla sınırlandırılır.
Aşağıdaki snippet'te, modelden gelen nihai yanıtı gösteren birden fazla text
girişi gösterilmektedir.
"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?\""
...
Ancak T-rex şakaları yerine modelden biraz daha karmaşık bir şey isterseniz ne olur? Örneğin, Gemini'den bir sayının çift mi yoksa tek mi olduğunu belirleyen bir JavaScript işlevi oluşturmasını isteyin. text:
parçaları biraz farklı görünüyor.
Çıkış artık JavaScript kod bloğundan başlayarak Markdown biçimini içeriyor. Aşağıdaki örnekte, öncekiyle aynı ön işleme adımları yer almaktadır.
"```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"
...
İşleri daha da zorlaştırmak için işaretlenmiş öğelerin bazıları bir parçada başlar ve başka bir parçada biter. İşaretçilerden bazıları iç içe yerleştirilmiş. Aşağıdaki örnekte, vurgulanan işlev iki satır arasında bölünmüştür: **isEven(
ve number) function:**
. Bu iki değer birleştirildiğinde sonuç **isEven("number) function:**
olur. Yani biçimlendirilmiş Markdown çıktısı almak istiyorsanız her bir parçayı bir Markdown ayrıştırıcıyla ayrı ayrı işleyemezsiniz.
Müşteriden
MediaPipe LLM gibi bir çerçeveyle istemcide Gemma gibi modeller çalıştırırsanız akış verileri bir geri çağırma işlevi aracılığıyla gelir.
Örneğin:
llmInference.generateResponse(
inputPrompt,
(chunk, done) => {
console.log(chunk);
});
Prompt API ile ReadableStream
üzerinde iterasyon yaparak akış verilerini parçalar halinde alırsınız.
const languageModel = await self.ai.languageModel.create();
const stream = languageModel.promptStreaming(inputPrompt);
for await (const chunk of stream) {
console.log(chunk);
}
Sonraki adımlar
Aktarılan verileri nasıl etkili ve güvenli bir şekilde oluşturacağınızı mı merak ediyorsunuz? LLM yanıtlarını oluşturmayla ilgili en iyi uygulamalarımızı okuyun.