مدیریت جلسات برای Live API

Gemini Live API جریان‌های پیوسته‌ای از صدا یا متن به نام جلسات (session) را پردازش می‌کند. شما می‌توانید چرخه حیات جلسات را از اولین دست‌دهی (handshake) تا پایان دادن به آن مدیریت کنید.

محدودیت برای جلسات

برای Live API ، یک جلسه به یک اتصال پایدار اشاره دارد که در آن ورودی و خروجی به طور مداوم از طریق یک اتصال پخش می‌شوند.

اگر جلسه از هر یک از محدودیت‌های زیر فراتر رود، اتصال قطع می‌شود. البته توجه داشته باشید که Live API گزینه‌هایی (به زیر مراجعه کنید) برای مدیریت این محدودیت‌های مربوط به جلسه ارائه می‌دهد.

  • پنجره‌ی زمینه‌ی جلسه به ۱۲۸ هزار توکن محدود شده است.

    با توجه به این محدودیت پنجره زمینه، در اینجا حداکثر طول تقریبی جلسات بر اساس روش‌های ورودی آمده است:

    • جلسات ورودی فقط صوتی به ۱۵ دقیقه محدود می‌شوند.
    • ورودی ویدیو + صدا به ۲ دقیقه محدود می‌شود.
  • مدت زمان اتصال به حدود 10 دقیقه محدود شده است.

    حدود ۶۰ ثانیه قبل از پایان اتصال ، اعلانی مبنی بر قطع شدن اتصال دریافت خواهید کرد.

در اینجا چند گزینه برای مدیریت محدودیت‌های مربوط به جلسه وجود دارد:

شروع یک جلسه

برای مشاهده‌ی قطعه کد کامل که نحوه‌ی شروع یک جلسه را نشان می‌دهد، به راهنمای شروع به کار با Live API مراجعه کنید.

به‌روزرسانی اواسط جلسه

مدل‌های Live API از قابلیت‌های پیشرفته زیر برای به‌روزرسانی‌های میان‌دوره‌ای پشتیبانی می‌کنند:

به‌روزرسانی‌های تدریجی محتوا را اضافه کنید

شما می‌توانید در طول یک جلسه فعال، به‌روزرسانی‌های افزایشی اضافه کنید. از این برای ارسال ورودی متن، ایجاد زمینه جلسه یا بازیابی زمینه جلسه استفاده کنید.

  • برای متن‌های طولانی‌تر، توصیه می‌کنیم یک خلاصه پیام واحد ارائه دهید تا پنجره متن برای تعاملات بعدی آزاد شود.

  • برای متن‌های کوتاه، می‌توانید تعاملات نوبت به نوبت را برای نمایش توالی دقیق رویدادها، مانند قطعه کد زیر، ارسال کنید.

سویفت

// 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,
);

وحدت

// 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 به عنوان ارائه دهنده API خود استفاده کنید.

شما می‌توانید دستورالعمل‌های سیستم را در طول یک جلسه فعال به‌روزرسانی کنید. از این برای تطبیق پاسخ‌های مدل، به عنوان مثال برای تغییر زبان پاسخ یا تغییر لحن، استفاده کنید.

برای به‌روزرسانی دستورالعمل‌های سیستم در اواسط جلسه، می‌توانید محتوای متنی را با نقش system ارسال کنید. دستورالعمل‌های به‌روز شده سیستم تا پایان جلسه معتبر خواهند بود.

سویفت

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');
}

وحدت

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}");
}

فشرده‌سازی پنجره زمینه

برای مشاهده محتوا و کد مخصوص ارائه‌دهنده در این صفحه، روی ارائه‌دهنده API Gemini خود کلیک کنید.

پنجره زمینه جلسه Live API داده‌های پخش‌شده بلادرنگ (۲۵ توکن در ثانیه (TPS) برای صدا و ۲۵۸ TPS برای ویدیو) و همچنین سایر محتوا، از جمله ورودی‌های متنی و خروجی‌های مدل را ذخیره می‌کند. همه مدل‌های Live API دارای محدودیت پنجره زمینه جلسه ۱۲۸ هزار توکن هستند.

به طور پیش‌فرض، به دلیل محدودیت پنجره زمینه، در اینجا حداکثر طول تقریبی جلسات بر اساس روش‌های ورودی آمده است:

  • جلسات ورودی فقط صوتی به ۱۵ دقیقه محدود می‌شوند.
  • ورودی ویدیو + صدا به ۲ دقیقه محدود می‌شود.

در جلسات طولانی مدت، با پیشرفت مکالمه، تاریخچه توکن‌های صوتی و/یا تصویری جمع می‌شود. اگر این تاریخچه از حد مجاز مدل فراتر رود، مدل ممکن است دچار توهم شود، سرعتش کم شود یا جلسه به اجبار خاتمه یابد.

برای فعال کردن جلسات طولانی‌تر، می‌توانید فشرده‌سازی پنجره زمینه را با تنظیم فیلد contextWindowCompression به عنوان بخشی از LiveGenerationConfig فعال کنید. وقتی این گزینه فعال باشد، سرور از یک مکانیزم پنجره کشویی برای حذف خودکار قدیمی‌ترین چرخش‌ها یا خلاصه کردن آنها استفاده می‌کند تا اندازه زمینه را در محدوده پیش‌فرض یا مشخص شده حفظ کند. دستورالعمل‌های سیستم حذف نمی‌شوند و همیشه در ابتدای پنجره زمینه باقی می‌مانند.

از دیدگاه کاربر، این امر از نظر تئوری امکان ایجاد مدت زمان نامحدود برای جلسات را فراهم می‌کند، زیرا "حافظه" دائماً مدیریت می‌شود.

شما می‌توانید مکانیزم پنجره کشویی و همچنین تعداد توکن‌هایی که فشرده‌سازی را آغاز می‌کنند (به تنظیمات و مقادیر موجود در زیر مراجعه کنید) را پیکربندی کنید. در اینجا چند نکته مهم در مورد استفاده از این تنظیمات آورده شده است:

  • تنظیم بسیار پایین targetTokens فضای بیشتری برای جریان‌های پیوسته آزاد می‌کند، اما مدل به سرعت نوبت‌های قدیمی‌تر مکالمه را «فراموش» می‌کند.

  • تنظیم targetTokens نزدیک‌تر به triggerTokens حافظه بیشتری را حفظ می‌کند اما روال‌های فشرده‌سازی را بسیار بیشتر فعال می‌کند.

تنظیم پیش‌فرض برای پنجره کشویی اگر در پیکربندی تنظیم نشده باشد حداقل مقدار حداکثر مقدار
triggerTokens
طول متن قبل از شروع فشرده‌سازی
۸۰٪ از محدودیت پنجره زمینه مدل ۵۰۰۰ ۱۲۸۰۰۰
targetTokens
تعداد هدف توکن‌ها برای نگهداری
۵۰٪ از مقدار triggerTokens
  • اگر triggerTokens به طور صریح تنظیم نشده باشد، targetTokens به طور پیش‌فرض ۵۰٪ از مقدار پیش‌فرض triggerTokens را در نظر می‌گیرد.
  • مقدار targetTokens باید کمتر از مقدار triggerTokens باشد.
0 ۱۲۸۰۰۰

سویفت


// 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),
    ),
  ),
);

وحدت


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 مداوم حدود 10 دقیقه است. 60 ثانیه قبل از پایان اتصال، یک اعلان قطع اتصال برای کلاینت ارسال می‌شود که می‌تواند به شما در انجام اقدامات بیشتر (مثلاً با از سرگیری یک جلسه ) کمک کند.

مثال زیر نحوه تشخیص قریب‌الوقوع خاتمه اتصال را با گوش دادن به اعلان قطع اتصال نشان می‌دهد:

سویفت

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}');
  }
}

وحدت

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 دقیقه است. شما می‌توانید با گوش دادن به اعلان «قطع اتصال» ( going away notification) تشخیص دهید که چه زمانی یک اتصال در شرف پایان است و سپس با ایجاد یک اتصال جدید با استفاده از شناسه session، جلسه را تمدید کنید.

  • از سرگیری یک جلسه درست پس از قطع اتصال

    اگر اتصال قبل از حداکثر زمان مجاز اتصال قطع شود یا قطع شود (برای مثال، تغییر از WiFi به 5G)، سرور حالت جلسه را حدود 10 دقیقه نگه می‌دارد. در طول این پنجره، می‌توانید با ایجاد یک اتصال جدید با استفاده از دسته جلسه، جلسه را از سر بگیرید.

  • از سرگیری یک جلسه پس از یک دوره زمانی طولانی

    پس از پایان اتصال، سرور وضعیت جلسه را برای چند ساعت نگه می‌دارد. در طول این پنجره، می‌توانید با ایجاد یک اتصال جدید با استفاده از شناسه جلسه، جلسه را از سر بگیرید. توجه داشته باشید که این پنجره برای دو ارائه‌دهنده API Gemini متفاوت است: API توسعه‌دهنده Gemini 2 ساعت | API Vertex AI Gemini 24 ساعت است.

به طور پیش‌فرض، از سرگیری جلسه غیرفعال است. برای فعال کردن از سرگیری جلسه، هنگام برقراری اتصال جدید، یک پیکربندی از سرگیری خالی ارسال کنید. وقتی فعال باشد، سرور به صورت دوره‌ای به‌روزرسانی‌هایی حاوی یک هندل از سرگیری جلسه ارسال می‌کند. اگر جلسه قطع شود، می‌توانید دوباره متصل شوید و این هندل را ارسال کنید تا جلسه با متن دست نخورده از سر گرفته شود.

مثال‌های زیر دو گزینه برای از سرگیری جلسه را نشان می‌دهند:

سویفت

// 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!),
  );
}

وحدت

// 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)
  );
}