تاريخ النشر: 21 كانون الثاني (يناير) 2025
يتألّف ردّ النموذج اللغوي الكبير الذي يتم ببث مباشر من بيانات يتم بثّها بشكل متزايد ومستمر. تختلف بيانات البث عن بيانات الخادم والعميل.
من الخادم
لفهم شكل الردّ الذي يتم بثه، طلبت من Gemini إخباري بأحد القصص المضحكة باستخدام أداة سطر الأوامر curl
. راجِع المثال التالي على طلب Gemini API. إذا جرّبت ذلك، احرص على استبدال
{GOOGLE_API_KEY}
في عنوان URL بمفتاح Gemini API.
$ 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."}]}]}'
يسجِّل هذا الطلب الإخراج التالي (المقتطع) بتنسيق بث الأحداث.
يبدأ كل سطر بـ data:
متبوعًا بحمولة الرسالة. ليس التنسيق المحدد مهمًا في الواقع، ولكن المهم هو أجزاء النص.
//
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}}
الحِمل الأول هو ملف JSON. ألقِ نظرة عن كثب على النقاط المميّزة التالية:
candidates[0].content.parts[0].text
:
{
"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
}
}
تمثل إدخالة text
الأولى بداية ردّ Gemini. عند استخراج
مزيد من إدخالات text
، يكون الردّ مُحدَّدًا بفاصل سطر جديد.
يعرض المقتطف التالي إدخالات متعددة من text
، والتي تعرض الردّ
النهائي من النموذج.
"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?\""
...
ولكن ماذا يحدث إذا طلبت من النموذج شيئًا
أكثر تعقيدًا قليلاً بدلاً من نكات عن الديناصورات؟ على سبيل المثال، اطلب من Gemini إنشاء دالة JavaScript
لتحديد ما إذا كان الرقم زوجيًا أو فرديًا. تبدو أجزاء text:
مختلفة قليلاً.
يحتوي الإخراج الآن على تنسيق Markdown، ويبدؤه بوحدة رمز JavaScript. يتضمّن العيّنة التالية خطوات المعالجة المُسبَقة نفسها كما في السابق.
"```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"
...
لزيادة الصعوبة، تبدأ بعض العناصر التي تم وضع علامات عليها في قطعة واحدة وينتهي بها المطاف في قطعة أخرى. بعض العلامات مُدمجة. في المثال التالي، يتم تقسيم الدوال المميّزة بين سطرَين:
**isEven(
وnumber) function:**
. ويكون الناتج بعد الدمج هو
**isEven("number) function:**
. وهذا يعني أنّه إذا أردت إخراج ملف ملف markdown منسَّق، لا يمكنك معالجة كل قطعة بشكلٍ فردي باستخدام منظِّم Markdown.
من العميل
في حال تشغيل نماذج مثل Gemma على العميل باستخدام إطار عمل مثل MediaPipe LLM، يتم نقل بيانات البث من خلال دالة استدعاء.
على سبيل المثال:
llmInference.generateResponse(
inputPrompt,
(chunk, done) => {
console.log(chunk);
});
باستخدام Prompt API،
يمكنك الحصول على بيانات البث على شكل أجزاء من خلال تكرار
ReadableStream
.
const languageModel = await self.ai.languageModel.create();
const stream = languageModel.promptStreaming(inputPrompt);
for await (const chunk of stream) {
console.log(chunk);
}
الخطوات التالية
هل تتساءل عن كيفية عرض البيانات التي يتم بثها بأداء جيد وآمن؟ اطّلِع على أفضل الممارسات لعرض الردود المستندة إلى الذكاء الاصطناعي (LLM).