Skip to content

Высокодоступное планирование: Ротация, фиксированные учётные записи, липкие сессии и повторные попытки при сбоях

После использования Antigravity Tools в качестве локального AI-шлюза некоторое время вы неизбежно столкнётесь с одной и той же проблемой: чем меньше учётных записей, тем чаще 429/401/invalid_grant, чем больше учётных записей, тем менее понятно «какая учётная запись работает», а коэффициент попадания в кеш падает.

В этом уроке будет чётко объяснено планирование: как оно выбирает учётную запись, что такое «липкая сессия», когда происходит принудительная ротация, и как с помощью «режима фиксированной учётной записи» сделать планирование управляемым.

Что вы сможете сделать после изучения

  • Понять, что на самом деле делают три режима планирования Antigravity Tools в реальных запросах
  • Знать, как генерируется «отпечаток сессии (session_id)» и как он влияет на липкое планирование
  • Включить/выключить «режим фиксированной учётной записи» в GUI и понять, какие логики планирования он перекрывает
  • При встрече 429/5xx/invalid_grant знать, как система отметит ограничение частоты, как повторит попытку и когда ротирует

Ваша текущая проблема

  • Claude Code или OpenAI SDK внезапно дают 429 при работе, а при повторной попытке меняют учётную запись, коэффициент попадания в кеш падает
  • Несколько клиентов параллельно выполняют задачи, часто «попираются» друг на друга статусы учётных записей
  • Вы хотите устранять неполадки, но не знаете, какая учётная запись обслуживает текущий запрос
  • Вы хотите использовать только «самую стабильную учётную запись», но система постоянно ротирует

Когда использовать этот подход

  • Вам нужно сбалансировать «стабильность (меньше ошибок)» и «попадание в кеш (одна учётная запись)»
  • Вы хотите, чтобы один и тот же диалог как можно дольше использовал одну и ту же учётную запись (уменьшая колебания Prompt Caching)
  • Вы хотите выполнить тестирование цвета/устранение неполадок, зафиксировав все запросы на одной учётной записи

🎒 Подготовка перед началом

  1. Подготовьте минимум 2 доступные учётные записи (чем меньше пул учётных записей, тем меньше пространства ротации)
  2. Служба обратного прокси запущена (на странице «API Proxy» виден статус Running)
  3. Вы знаете, где находится файл конфигурации (если вам нужно вручную изменить конфигурацию)

Сначала пройдите урок о конфигурации

Если вы ещё не знакомы с gui_config.json и какие конфигурации поддерживают горячее обновление, сначала посмотрите Конфигурация полностью: AppConfig/ProxyConfig, место сохранения на диск и семантика горячего обновления.

Основная идея: через какие «уровни планирования» пройдёт один запрос

Планирование — это не «одиночный переключатель», а несколько механизмов, наложенных друг на друга:

  1. SessionManager сначала даёт запросу отпечаток сессии (session_id)
  2. При каждой повторной попытке Handlers требуют, чтобы TokenManager принудительно ротировал (attempt > 0)
  3. TokenManager затем выбирает учётную запись по: фиксированная учётная запись → липкая сессия → окно 60s → ротация
  4. При встрече 429/5xx будет записана информация об ограничении частоты, при последующем выборе учётной записи такие учётные записи будут активно пропущены

Что такое «отпечаток сессии (session_id)»?

Отпечаток сессии — это «по возможности стабильный Session Key», используемый для привязки нескольких запросов одного и того же диалога к одной и той же учётной записи.

В запросах Claude приоритет:

  1. metadata.user_id (явно передано клиентом и не пусто и не содержит префикса "session-")
  2. Первое «достаточно длинное» пользовательское сообщение выполняет хеширование SHA256, затем усекается до sid-xxxxxxxxxxxxxxxx

Соответствующая реализация: src-tauri/src/proxy/session_manager.rs (у Claude/OpenAI/Gemini есть своя логика извлечения).

Маленькая деталь: почему смотреть только на первое пользовательское сообщение?

В исходном коде явно написано «хешировать только содержимое первого пользовательского сообщения, не смешивая имя модели или временной метки», цель — заставить несколько запросов одного диалога по возможности генерировать один и тот же session_id, тем самым повышая коэффициент попадания в кеш.

Приоритет выбора учётной записи TokenManager

Основной вход TokenManager:

  • TokenManager::get_token(quota_group, force_rotate, session_id, target_model)

Что он делает можно понять по приоритету:

  1. Режим фиксированной учётной записи (Fixed Account): если в GUI включён «режим фиксированной учётной записи» (настройка рантайма), и эта учётная запись не ограничена частотой, не защищена квотой, будет использована напрямую.
  2. Липкая сессия (Session Binding): если есть session_id и режим планирования не PerformanceFirst, будет с приоритетом повторно использоваться учётная запись, привязанная к этой сессии.
  3. Повторное использование глобального окна 60s: если session_id не передано (или привязка ещё не успешна), в не PerformanceFirst будет как можно дольше повторно использоваться «последняя использованная учётная запись» в течение 60 секунд.
  4. Ротация (Round-robin): если ни одно из вышеперечисленных не применимо, учётная запись выбирается по глобальному самовозрастающему индексу ротации.

Кроме того, есть два «невидимых правила», которые сильно влияют на ощущения:

  • Учётные записи сначала сортируются: ULTRA > PRO > FREE, в одном уровне приоритет — учётные записи с более высоким остатком квоты.
  • Сбой или ограничение частоты будут пропущены: учётные записи, которые уже пытались и неуспешно, войдут в коллекцию attempted; помеченные как ограниченные частотой учётные записи будут пропущены.

В чём разница между тремя режимами планирования

В конфигурации вы увидите: CacheFirst / Balance / PerformanceFirst.

Взяв за основу «реальную ветку TokenManager на стороне бэкенда», их ключевая разница только в одной: включена ли липкая сессия + повторное использование окна 60s.

  • PerformanceFirst: пропускает липкую сессию и повторное использование окна 60s, напрямую идёт по ротации (и продолжает пропускать ограниченные частотой/защищённые квотой учётные записи).
  • CacheFirst / Balance: оба включают липкую сессию и повторное использование окна 60s.

О max_wait_seconds

Во фронтенде/структуре конфигурации есть max_wait_seconds, и в UI он позволяет регулировать только в CacheFirst. Но текущая логика планирования на стороне бэкенда только ветвится по mode, не читает max_wait_seconds.

Как повторные попытки и «принудительная ротация» связываются

В обработчиках OpenAI/Gemini/Claude используется похожий режим обработки повторных попыток:

  • Первая попытка: force_rotate = false
  • Вторая и последующие: force_rotate = true (attempt > 0), TokenManager пропустит повторное использование липкости, напрямую найдёт следующую доступную учётную запись

При встрече ошибок 429/529/503/500 и т. д.:

  • обработчик вызовет token_manager.mark_rate_limited(...), чтобы записать эту учётную запись как «ограниченную частотой/перегруженную», при последующем планировании будут активно пропускать её.
  • В пути совместимости с OpenAI также будет пытаться разобрать RetryInfo.retryDelay или quotaResetDelay из JSON ошибки, подождать небольшое время, затем продолжить повторную попытку.

Следуйте за мной: настройте планирование на «управляемый»

Шаг 1: Сначала подтвердите, что у вас действительно есть «пул учётных записей»

Почему Независимо от того, насколько продвинуто планирование, если в пуле только 1 учётная запись, выбирать не из чего. Многие проблемы «ротация не работает/липкая сессия не ощущается» имеют корнем слишком мало учётных записей.

Действия Откройте страницу «Accounts», подтвердите, что как минимум 2 учётные записи находятся в доступном состоянии (не disabled / proxy disabled).

Вы должны увидеть: минимум 2 учётные записи могут нормально обновлять квоту, а после запуска обратного прокси active_accounts не равно 0.

Шаг 2: Выберите режим планирования в GUI

Почему Режим планирования определяет, будет ли один и тот же диалог как можно дольше использовать одну и ту же учётную запись, или каждый раз ротацию.

Действия Перейдите на страницу «API Proxy», найдите карточку «Планирование и ротация учётных записей», выберите один из режимов:

  • Balance: значение по умолчанию, рекомендуется. В большинстве случаев стабильнее (липкая сессия + ротация при сбоях).
  • PerformanceFirst: высокий параллелизм, короткие задачи, вам важнее пропускная способность, чем попадание в кеш, выбирайте этот.
  • CacheFirst: если вы хотите, чтобы диалог фиксировал учётную запись, можно выбрать его (текущее поведение на стороне бэкенда мало отличается от Balance).

Если вы хотите вручную изменить конфигурацию, соответствующий фрагмент:

json
{
  "proxy": {
    "scheduling": {
      "mode": "Balance",
      "max_wait_seconds": 60
    }
  }
}

Вы должны увидеть: после переключения режима сразу записывается в gui_config.json, при работающей службе обратного прокси вступает в силу немедленно (без перезапуска).

Шаг 3: Включите «режим фиксированной учётной записи» (отключите ротацию)

Почему При устранении неполадок/тестировании цвета/или вы хотите «прибить» определённую учётную запись к определённому клиенту, режим фиксированной учётной записи — самый прямой способ.

Действия В той же карточке откройте «Режим фиксированной учётной записи», затем выберите учётную запись в выпадающем списке.

Не забудьте: этот переключатель доступен только когда служба обратного прокси Running.

Вы должны увидеть: последующие запросы будут с приоритетом использовать эту учётную запись; если она ограничена частотой или защищена квотой, откатится к ротации.

Фиксированная учётная запись — это настройка рантайма

Режим фиксированной учётной записи — это состояние рантайма (динамически устанавливается через GUI или API), не сохраняется в gui_config.json. После перезапуска службы обратного прокси фиксированная учётная запись вернётся в пустое (вернётся в режим ротации).

Шаг 4: При необходимости очистите «привязку сессии»

Почему Липкая сессия записывает session_id -> account_id в памяти. Если вы на одной машине выполняете разные эксперименты (например, переключение пулов учётных записей, переключение режимов), старая привязка может мешать вам наблюдать.

Действия В карточке «Планирование и ротация учётных записей» нажмите «Очистить привязки» в правом верхнем углу.

Вы должны увидеть: старые сессии будут снова распределены учётные записи (следующий запрос снова привяжется).

Шаг 5: Используйте заголовок ответа, чтобы подтвердить «какая учётная запись обслуживает»

Почему Вы хотите подтвердить, что планирование соответствует ожиданиям, самый надёжный способ — получить «идентификатор текущей учётной записи» с сервера.

Действия Отправьте не потоковый запрос на совместимую с OpenAI конечную точку, затем наблюдайте за заголовком X-Account-Email в ответе.

bash
  # Пример: минимальный запрос OpenAI Chat Completions
  # Обратите внимание: model должен быть доступен/маршрутизирован в вашей текущей конфигурации
curl -i "http://127.0.0.1:8045/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-REPLACE_ME" \
  -d '{
    "model": "gemini-3-pro-high",
    "stream": false,
    "messages": [{"role": "user", "content": "hello"}]
  }'

Вы должны увидеть: в заголовках ответа появляется следующее содержимое (пример):

text
X-Account-Email: [email protected]
X-Mapped-Model: gemini-3-pro-high

Контрольная точка ✅

  • Вы можете чётко сказать, какой из трёх механизмов: «фиксированная учётная запись», «липкая сессия», «ротация» перекрывает другой
  • Вы знаете, как получается session_id (приоритет metadata.user_id, иначе хеш первого пользовательского сообщения)
  • При встрече 429/5xx вы можете ожидать: система сначала запишет ограничение частоты, затем сменит учётную запись и повторит попытку
  • Вы можете использовать X-Account-Email для подтверждения, какая учётная запись обслуживает текущий запрос

Напоминания о возможных ошибках

  1. Если в пуле только 1 учётная запись, не ожидайте, что «ротация спасёт вас» Ротация — это «выбрать другую учётную запись», если в пуле нет второй учётной записи, 429/invalid_grant будет возникать чаще.

  2. CacheFirst — это не «ждать всегда, пока не станет доступным» Текущая логика планирования на стороне бэкенда при ограничении частоты склоняется к развязыванию и переключению учётной записи, а не к долгосрочному блокирующему ожиданию.

  3. Фиксированная учётная запись не является абсолютно принудительной Если фиксированная учётная запись отмечена как ограниченная частотой или защищена квотой, система откатится к ротации.

Краткое содержание урока

  • Цепочка планирования: обработчик извлекает session_idTokenManager::get_token выбирает учётную запись → при ошибке attempt > 0 принудительная ротация
  • Два ваших самых часто используемых переключателя: режим планирования (включать ли липкую сессию/повторное использование 60s) + режим фиксированной учётной записи (напрямую указать учётную запись)
  • 429/5xx будут записаны как «состояние ограничения частоты», при последующем планировании эта учётная запись будет пропущена, пока не истечёт время блокировки

Предварительный просмотр следующего урока

Следующий урок мы посмотрим Маршрутизацию моделей: когда вы хотите предоставить «стабильное внешнее множество моделей», а также использовать подстановочные знаки/предустановленные стратегии, как настроить и устранять неполадки.


Приложение: Ссылка на исходный код

Нажмите, чтобы развернуть и просмотреть местоположение исходного кода

Дата обновления: 2026-01-23

ФункцияПуть к файлуНомер строки
Режим планирования и структура конфигурации (StickySessionConfig)src-tauri/src/proxy/sticky_config.rs1-36
Генерация отпечатка сессии (Claude/OpenAI/Gemini)src-tauri/src/proxy/session_manager.rs1-159
TokenManager: поля режима фиксированной учётной записи и инициализацияsrc-tauri/src/proxy/token_manager.rs27-50
TokenManager: основная логика выбора учётной записи (фиксированная учётная запись/липкая сессия/окно 60s/ротация/защита квоты)src-tauri/src/proxy/token_manager.rs470-940
TokenManager: invalid_grrant автоматически отключает и удаляет из пулаsrc-tauri/src/proxy/token_manager.rs868-878
TokenManager: запись ограничения частоты и очистка успешного APIsrc-tauri/src/proxy/token_manager.rs1087-1147
TokenManager: обновление конфигурации планирования / очистка привязок сессии / сеттер фиксированной учётной записиsrc-tauri/src/proxy/token_manager.rs1419-1461
ProxyConfig: определение полей планирования и значений по умолчаниюsrc-tauri/src/proxy/config.rs174-257
При запуске прокси синхронизируется конфигурация планированияsrc-tauri/src/commands/proxy.rs70-100
Команды Tauri, связанные с планированием (get/update/clear bindings/fixed account)src-tauri/src/commands/proxy.rs478-551
Обработчик OpenAI: session_id + принудительная ротация при повторной попыткеsrc-tauri/src/proxy/handlers/openai.rs160-182
Обработчик OpenAI: запись ограничения частоты 429/5xx + разбор повторной задержкиsrc-tauri/src/proxy/handlers/openai.rs349-367
Обработчик Gemini: session_id + принудительная ротация при повторной попыткеsrc-tauri/src/proxy/handlers/gemini.rs62-88
Обработчик Gemini: запись ограничения частоты 429/5xx и ротацияsrc-tauri/src/proxy/handlers/gemini.rs279-299
Обработчик Claude: извлечение session_id и передача в TokenManagersrc-tauri/src/proxy/handlers/claude.rs517-524
Разбор повторной задержки 429 (RetryInfo.retryDelay / quotaResetDelay)src-tauri/src/proxy/upstream/retry.rs37-66
Идентификация причин ограничения частоты и экспоненциальный откат (RateLimitTracker)src-tauri/src/proxy/rate_limit.rs154-279

Ключевая структура:

  • StickySessionConfig: структура конфигурации планирования (mode, max_wait_seconds)
  • TokenManager: пул учётных записей, привязка сессий, режим фиксированной учётной записи, трекер ограничения частоты
  • SessionManager: извлечение session_id из запроса