يعالج Gemini Live API تدفقات مستمرة من الصوت أو النص تُعرف باسم الجلسات. يمكنك إدارة دورة حياة الجلسة، بدءًا من المصافحة الأولية وصولاً إلى الإنهاء السلس.
حدود الجلسات
في Live API، تشير الجلسة إلى اتصال مستمر يتم فيه بث الإدخال والإخراج بشكل مستمر عبر اتصال.
إذا تجاوزت الجلسة أيًا من الحدود التالية، يتم إنهاء الاتصال. يُرجى العِلم أنّ Live API يوفّر بعض الخيارات (الموضّحة أدناه) للتعامل مع هذه الحدود المتعلقة بالجلسة.
تقتصر _**قدرة استيعاب الجلسة**_ على 128 ألف رمز مميّز.
بسبب هذا الحدّ الأقصى لقدرة الاستيعاب، إليك الحدّ الأقصى التقريبي لأطوال الجلسات استنادًا إلى طرق الإدخال:
- تقتصر الجلسات التي تستخدِم إدخال الصوت فقط على
15 دقيقة . - تقتصر الجلسات التي تستخدِم إدخال الفيديو والصوت على
دقيقتَين .
- تقتصر الجلسات التي تستخدِم إدخال الصوت فقط على
يقتصر طول الاتصال على 10 دقائق تقريبًا. ستتلقّى إشعارًا _بانتهاء الاتصال_ قبل
60 ثانية تقريبًا من انتهاء الاتصال.
في ما يلي بعض الخيارات للتعامل مع الحدود المتعلقة بالجلسة:
يمكنك ضغط قدرة استيعاب الجلسة لكي يحافظ الخادم تلقائيًا على حجم السياق ضمن الحدّ المسموح به.
يمكنك استئناف الجلسة لمنع فقدان سياق المحادثة أثناء حالات انقطاع الشبكة القصيرة أو بعد تلقّي إشعار بانتهاء الاتصال.
بدء جلسة
يُرجى الانتقال إلى دليل البدء في Live API للاطّلاع على مقتطف كامل يوضّح كيفية بدء جلسة.
تعديل الجلسة في منتصفها
تتوافق نماذج Live API مع الإمكانات المتقدّمة التالية لـ تعديلات منتصف الجلسة:
تعديل تعليمات النظام (لـ Vertex AI Gemini API فقط)
إضافة تعديلات تدريجية على المحتوى
يمكنك إضافة تعديلات تدريجية أثناء جلسة نشطة. استخدِم هذه الميزة لإرسال إدخال نصي أو إنشاء سياق الجلسة أو استعادة سياق الجلسة.
بالنسبة إلى السياقات الأطول، ننصحك بتقديم ملخّص لرسالة واحدة لتحرير قدرة الاستيعاب للتفاعلات اللاحقة.
بالنسبة إلى السياقات القصيرة، يمكنك إرسال تفاعلات اتّجاهات مفصّلة لتمثيل التسلسل الدقيق للأحداث، مثل المقتطف أدناه.
Swift
// Define initial turns (history/context).
let turns: [ModelContent] = [
ModelContent(role: "user", parts: [TextPart("What is the capital of France?")]),
ModelContent(role: "model", parts: [TextPart("Paris")]),
]
// Send history, keeping the conversational turn OPEN (false).
await session.sendContent(turns, turnComplete: false)
// Define the new user query.
let newTurn: [ModelContent] = [
ModelContent(role: "user", parts: [TextPart("What is the capital of Germany?")]),
]
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.sendContent(newTurn, turnComplete: true)
Kotlin
Not yet supported for Android apps - check back soon!
Java
Not yet supported for Android apps - check back soon!
Web
const turns = [{ text: "Hello from the user!" }];
await session.send(
turns,
false // turnComplete: false
);
console.log("Sent history. Waiting for next input...");
// Define the new user query.
const newTurn [{ text: "And what is the capital of Germany?" }];
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
newTurn,
true // turnComplete: true
);
console.log("Sent final query. Model response expected now.");
Dart
// Define initial turns (history/context).
final List turns = [
Content(
"user",
[Part.text("What is the capital of France?")],
),
Content(
"model",
[Part.text("Paris")],
),
];
// Send history, keeping the conversational turn OPEN (false).
await session.send(
input: turns,
turnComplete: false,
);
// Define the new user query.
final List newTurn = [
Content(
"user",
[Part.text("What is the capital of Germany?")],
),
];
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
input: newTurn,
turnComplete: true,
);
Unity
// Define initial turns (history/context).
List turns = new List {
new ModelContent("user", new ModelContent.TextPart("What is the capital of France?") ),
new ModelContent("model", new ModelContent.TextPart("Paris") ),
};
// Send history, keeping the conversational turn OPEN (false).
foreach (ModelContent turn in turns)
{
await session.SendAsync(
content: turn,
turnComplete: false
);
}
// Define the new user query.
ModelContent newTurn = ModelContent.Text("What is the capital of Germany?");
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.SendAsync(
content: newTurn,
turnComplete: true
);
تعديل تعليمات النظام في منتصف الجلسة
| لا يتوفّر هذا الخيار إلا عند استخدام Vertex AI Gemini API كمزوّد واجهة برمجة التطبيقات. |
يمكنك تعديل تعليمات النظام أثناء جلسة نشطة. استخدِم هذه الميزة لتكييف ردود النموذج، مثلاً لتغيير لغة الرد أو تعديل النبرة.
لتعديل تعليمات النظام في منتصف الجلسة، يمكنك إرسال محتوى نصي باستخدام دور system. ستظل تعليمات النظام المعدَّلة سارية المفعول طوال الفترة المتبقية من الجلسة.
Swift
await session.sendContent(
[ModelContent(
role: "system",
parts: [TextPart("new system instruction")]
)],
turnComplete: false
)
Kotlin
Not yet supported for Android apps - check back soon!
Java
Not yet supported for Android apps - check back soon!
Web
Not yet supported for Web apps - check back soon!
Dart
try {
await _session.send(
input: Content(
'system',
[Part.text('new system instruction')],
),
turnComplete: false,
);
} catch (e) {
print('Failed to update system instructions: $e');
}
Unity
try
{
await session.SendAsync(
content: new ModelContent(
"system",
new ModelContent.TextPart("new system instruction")
),
turnComplete: false
);
}
catch (Exception e)
{
Debug.LogError($"Failed to update system instructions: {e.Message}");
}
ضغط قدرة الاستيعاب
|
انقر على مزوّد Gemini API لعرض المحتوى والرمز البرمجي الخاصَّين بالمزوّد على هذه الصفحة. |
تخزِّن Live API قدرة استيعاب جلسة البيانات التي يتم بثها في الوقت الفعلي (25 رمزًا مميّزًا في الثانية للصوت و258 رمزًا مميّزًا في الثانية للفيديو) بالإضافة إلى المحتوى الآخر ، بما في ذلك الإدخالات النصية ونتائج النموذج. تحتوي جميع نماذج Live API على حدّ أقصى لقدرة استيعاب الجلسة يبلغ 128 ألف رمز مميّز.
بسبب هذا الحدّ الأقصى لقدرة الاستيعاب، إليك الحدّ الأقصى التقريبي لأطوال الجلسات استنادًا إلى طرق الإدخال:
- تقتصر الجلسات التي تستخدِم إدخال الصوت فقط على
15 دقيقة . - تقتصر الجلسات التي تستخدِم إدخال الفيديو والصوت على
دقيقتَين .
في الجلسات الطويلة، مع تقدّم المحادثة، يتراكم سجلّ الرموز المميّزة الصوتية و/أو المرئية. إذا تجاوز هذا السجلّ الحدّ الأقصى للنموذج، قد يقدّم النموذج معلومات غير صحيحة أو يصبح بطيئًا أو قد يتم إنهاء الجلسة قسرًا.
لإتاحة جلسات أطول، يمكنك تفعيل ضغط قدرة الاستيعاب من خلال ضبط الحقل contextWindowCompression كجزء من LiveGenerationConfig. عند تفعيل هذه الميزة، يستخدم الخادم آلية نافذة منزلقة لتجاهل أقدم الأدوار تلقائيًا أو تلخيصها للحفاظ على حجم السياق ضمن الحدود التلقائية أو المحدّدة. لا يتم تجاهل تعليمات النظام وستظل دائمًا في بداية قدرة الاستيعاب.
من منظور المستخدم، يتيح ذلك مدة جلسة غير محدودة نظريًا لأنّه تتم إدارة "الذاكرة" باستمرار.
يمكنك ضبط آلية النافذة المنزلقة بالإضافة إلى عدد الرموز المميّزة التي تؤدي إلى الضغط اختياريًا (راجِع الإعدادات والقيم المتاحة أدناه). في ما يلي بعض الاعتبارات العالية المستوى بشأن استخدام هذه الإعدادات:
سيؤدي ضبط
targetTokensعلى قيمة منخفضة جدًا إلى تحرير مساحة أكبر في السياق للتدفقات المستمرة، ولكنّ النموذج "سينسى" بسرعة الأدوار الأقدم في المحادثة.سيؤدي ضبط
targetTokensعلى قيمة أقرب إلىtriggerTokensإلى الاحتفاظ بمزيد من الذاكرة، ولكن سيؤدي ذلك إلى تشغيل إجراءات الضغط بشكل متكرر أكثر بكثير.
| الإعداد | القيمة التلقائية للنافذة المنزلقة إذا لم يتم ضبطها في الإعداد | القيمة الصغرى | القيمة القصوى |
|---|---|---|---|
triggerTokensطول السياق قبل بدء الضغط |
80% من الحدّ الأقصى لقدرة استيعاب النموذج | 5000 | 128000 |
targetTokensالعدد المستهدَف من الرموز المميّزة التي يجب الاحتفاظ بها |
50% من قيمة triggerTokens
|
0 | 128000 |
Swift
// Initialize the Gemini Developer API backend service
let liveModel = FirebaseAI.firebaseAI(backend: .googleAI()).liveModel(
modelName: "gemini-2.5-flash-native-audio-preview-12-2025",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig: LiveGenerationConfig(
responseModalities: [.audio],
contextWindowCompression: ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: SlidingWindow(
targetTokens: 2000,
)
)
)
)
Kotlin
// Initialize the Gemini Developer API backend service
val liveModel = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
modelName = "gemini-2.5-flash-native-audio-preview-12-2025",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig = liveGenerationConfig {
responseModality = ResponseModality.AUDIO,
contextWindowCompression = ContextWindowCompressionConfig(
triggerTokens = 10000,
slidingWindow = SlidingWindow(targetTokens = 2000)
)
}
)
Java
// Initialize the Gemini Developer API backend service
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.googleAI()).liveModel(
"gemini-2.5-flash-native-audio-preview-12-2025",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
new LiveGenerationConfig.Builder()
.setResponseModality(ResponseModality.AUDIO)
.setContextWindowCompression(
new ContextWindowCompressionConfig(10000, new SlidingWindow(2000))
)
.build()
);
Web
const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });
const liveModel = getLiveGenerativeModel(ai, {
model: "gemini-2.5-flash-native-audio-preview-12-2025",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig: {
responseModalities: [ResponseModality.AUDIO],
contextWindowCompression: {
triggerTokens: 10000,
slidingWindow: {
targetTokens: 2000,
},
},
},
});
Dart
final _liveModel = FirebaseAI.googleAI().liveGenerativeModel(
model: 'gemini-2.5-flash-native-audio-preview-12-2025',
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
liveGenerationConfig: LiveGenerationConfig(
responseModalities: [ResponseModalities.audio],
contextWindowCompression: ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: SlidingWindow(targetTokens: 2000),
),
),
);
Unity
var liveModel = FirebaseAI.GetInstance(FirebaseAI.Backend.GoogleAI()).GetLiveModel(
modelName: "gemini-2.5-flash-native-audio-preview-12-2025",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
liveGenerationConfig: new LiveGenerationConfig(
responseModalities: new[] { ResponseModality.Audio },
contextWindowCompression: new ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: new SlidingWindow(targetTokens: 2000)
)
)
);
اكتشاف وقت انتهاء الجلسة
الحدّ الأقصى لمدة اتصال WebSocket واحد ومستمر هو تقريبًا
يوضّح المثال التالي كيفية اكتشاف إنهاء الاتصال الوشيك من خلال الاستماع إلى إشعار بانتهاء الاتصال:
Swift
for try await response in session.responses {
switch response.payload {
case .goingAwayNotice(let goingAwayNotice):
// Prepare for the session to close soon
if let timeLeft = goingAwayNotice.timeLeft {
print("Server going away in \(timeLeft) seconds")
}
}
}
Kotlin
for (response in session.responses) {
when (val message = response.payload) {
is LiveServerGoAway -> {
// Prepare for the session to close soon
val remaining = message.timeLeft
logger.info("Server going away in $remaining")
}
}
}
Java
session.getResponses().forEach(response -> {
if (response.getPayload() instanceof LiveServerResponse.GoingAwayNotice) {
LiveServerResponse.GoingAwayNotice notice = (LiveServerResponse.GoingAwayNotice) response.getPayload();
// Prepare for the session to close soon
Duration timeLeft = notice.getTimeLeft();
}
});
Web
for await (const message of session.receive()) {
switch (message.type) {
...
case "goingAwayNotice":
console.log("Server going away. Time left:", message.timeLeft);
break;
}
}
Dart
Future _handleLiveServerMessage(LiveServerResponse response) async {
final message = response.message;
if (message is GoingAwayNotice) {
// Prepare for the session to close soon
developer.log('Server going away. Time left: ${message.timeLeft}');
}
}
Unity
foreach (var response in session.Responses) {
if (response.Payload is LiveSessionGoingAway notice) {
// Prepare for the session to close soon
TimeSpan timeLeft = notice.TimeLeft;
Debug.Log($"Server going away notice received. Remaining: {timeLeft}");
}
}
استئناف جلسة
تتيح Live API استئناف الجلسة لمنع فقدان سياق المحادثة. تحتوي كل جلسة على معرّف، ويمكن استخدامه بالطرق التالية:
الحفاظ على جلسة قبل بلوغ الحدّ الأقصى لوقت الاتصال
الحدّ الأقصى لمدة اتصال WebSocket واحد ومستمر هو تقريبًا
10 دقائق . يمكنك اكتشاف وقت انتهاء الاتصال من خلال الاستماع إلى إشعار بانتهاء الاتصال ، و ثم تمديد الجلسة من خلال إنشاء اتصال جديد باستخدام معرّف الجلسة.استئناف جلسة بعد انقطاع الاتصال مباشرةً
إذا انتهى الاتصال أو انقطع قبل الحدّ الأقصى لوقت الاتصال (مثلاً، التبديل من شبكة Wi-Fi إلى شبكة 5G)، يحتفظ الخادم بحالة الجلسة لمدة
10 دقائق تقريبًا. خلال هذه الفترة، يمكنك استئناف الجلسة من خلال إنشاء اتصال جديد باستخدام معرّف الجلسة.استئناف جلسة بعد فترة زمنية طويلة
بعد انتهاء الاتصال، يحتفظ الخادم بحالة الجلسة لبضع ساعات. خلال هذه الفترة، يمكنك استئناف الجلسة من خلال إنشاء اتصال جديد باستخدام معرّف الجلسة. يُرجى العِلم أنّ هذه الفترة تختلف بالنسبة إلى مزوّدَي Gemini API : Gemini Developer API هي
ساعتان | Vertex AI Gemini API هي24 ساعة .
يكون خيار استئناف الجلسة غير مفعَّل تلقائيًا. لتفعيل استئناف الجلسة، مرِّر إعدادات استئناف فارغة عند إنشاء اتصال جديد. عند تفعيل هذه الميزة، يرسل الخادم بشكل دوري تعديلات تحتوي على معرّف استئناف الجلسة. إذا تم قطع اتصال الجلسة، يمكنك إعادة الاتصال وتمرير هذا المعرّف لاستئناف الجلسة مع الحفاظ على سياقها.
يوضّح المثالان التاليان خيارَين لاستئناف الجلسة:
Swift
// Local variable to save the active session handle
var activeSessionHandle: String?
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = try await liveModel.connect(
sessionResumption: SessionResumptionConfig()
)
// Start receiving responses
for try await message in session.responses {
// Check for new session handles inside your message handling loop
switch message.payload {
case let .sessionResumptionUpdate(updateMessage):
guard let newHandle = updateMessage.newHandle, updateMessage.resumable else {
continue
}
activeSessionHandle = newHandle
print("SessionResumptionUpdate: handle \(newHandle)")
// ... handle other LiveServerMessage types ...
default:
break
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if let handle = activeSessionHandle {
session = try await liveModel.connect(
sessionResumption: SessionResumptionConfig(handle: handle)
)
}
// Option 2: Resume the session directly on an existing session object
if let handle = activeSessionHandle {
try await session.resumeSession(
sessionResumption: SessionResumptionConfig(handle: handle)
)
}
Kotlin
// Local variable to save the active session handle
var activeSessionHandle: String? = null
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = liveModel.connect(
sessionResumption = SessionResumptionConfig()
)
// Start receiving responses
session.receive().collect { message ->
// Process other received response types...
// Check for new session handles inside your message handling loop
if (message is LiveSessionResumptionUpdate) {
if (message.resumable == true && message.newHandle != null) {
activeSessionHandle = message.newHandle
Log.d("TAG", "SessionResumptionUpdate: handle ${message.newHandle}")
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
activeSessionHandle?.let { handle ->
session = liveModel.connect(
sessionResumption = SessionResumptionConfig(handle = handle)
)
}
// Option 2: Resume the session directly on an existing session object
activeSessionHandle?.let { handle ->
session.resumeSession(
sessionResumption = SessionResumptionConfig(handle = handle)
)
}
Java
For Java, session resumption is not yet supported. Check back soon!
Web
// Local variable to save the active session handle
let activeSessionHandle = null;
// Initialize the session. Passing an empty object requests the server to send SessionResumptionUpdate
let session = await liveModel.connect({});
// Start receiving responses
for await (const message of session.receive()) {
// Process other received response types...
// Check for new session handles inside your message handling loop
if (message.type === 'sessionResumptionUpdate') {
if (message.resumable && message.newHandle) {
activeSessionHandle = message.newHandle;
console.log(`SessionResumptionUpdate: handle ${activeSessionHandle}`);
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (activeSessionHandle) {
session = await liveModel.connect({
handle: activeSessionHandle
});
}
// Option 2: Resume the session directly on an existing session object
if (activeSessionHandle) {
await session.resumeSession({
handle: activeSessionHandle
});
}
Dart
// Local variable to save the active session handle
String? _activeSessionHandle;
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var _session = await _liveModel.connect(
sessionResumption: SessionResumptionConfig(),
);
// Start receiving responses
await for (final message in _session.receive()) {
// Process other received response types...
// Check for new session handles inside your message handling loop
if (message is SessionResumptionUpdate &&
message.resumable != null &&
message.resumable!) {
_activeSessionHandle = message.newHandle;
log('SessionResumptionUpdate: handle ${message.newHandle}');
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (_activeSessionHandle != null) {
_session = await _liveModel.connect(
sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
);
}
// Option 2: Alternatively, resume the session directly on an existing session object
if (_activeSessionHandle != null) {
await _session.resumeSession(
sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
);
}
Unity
// Local variable to save the active session handle
string activeSessionHandle = null;
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = await liveModel.ConnectAsync(
sessionResumption: new SessionResumptionConfig()
);
// Start receiving responses
await foreach (var response in session.ReceiveAsync())
{
// Process other received response types...
// Check for new session handles inside your message handling loop
if (response.Message is LiveSessionResumptionUpdate updateMessage)
{
if (updateMessage.Resumable == true && !string.IsNullOrEmpty(updateMessage.NewHandle))
{
activeSessionHandle = updateMessage.NewHandle;
Debug.Log($"SessionResumptionUpdate: handle {activeSessionHandle}");
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (!string.IsNullOrEmpty(activeSessionHandle)) {
session = await liveModel.ConnectAsync(
sessionResumption: new SessionResumptionConfig(activeSessionHandle)
);
}
// Option 2: Resume the session directly on an existing session object
if (!string.IsNullOrEmpty(activeSessionHandle)) {
await session.ResumeSessionAsync(
sessionResumption: new SessionResumptionConfig(activeSessionHandle)
);
}