Главная / Статьи

Перенос нагрузок Apps Script на сандбокс-среду Linux, управляемую Gemini Managed Agent.

Google Apps Script управляет средой Linux-сандбокса для агента Gemini: передача файлов в Drive с помощью ggsrun, обход ограничения в 50 МБ, запуск Playwright, FFmpeg и esbuild.

Издатель: REACTAPP.TOP13 мин чтения2934 слов

Источники: Taking Advantage of Gemini Managed Agents with Google Apps Script

Почему стоит сочетать Apps Script с Linux-сандбоксом

Google Apps Script — удобный инструмент для автоматизации работы в Google Workspace, однако это легковесная, ограниченная серверless-среда без доступа на уровне операционной системы. Это исключает выполнение множества более сложных задач. Контроль над сетью и протоколами на низком уровне ограничен. Нет браузера без графического интерфейса для отображения динамических страниц, нет возможности запуска нативных бинарников для транскодирования медиафайлов или обработки сигналов, отсутствуют современные компиляторы и инструменты сборки, а также существуют строгие ограничения на время выполнения и размер данных.

Gemini Managed Agents позволяют обойти эти ограничения. Будучи частью API Gemini v1beta Interactions and Environments, они дают разработчикам возможность создавать удаленные Linux-сандбоксы, которые могут самостоятельно выполнять код, запускать команды в оболочке и управлять пакетами. Сочетание их с CLI Google Workspace уже привлекло внимание сообщества.

Описанная здесь архитектура связывает эти два компонента. Apps Script управляет постоянно действующим Linux-контейнером с 4 ядрами CPU и 16 ГБ ОЗУ, в котором установлены Python 3.12, Node.js 22 и стандартные менеджеры пакетов (apt, npm, pip). Контейнер передает сгенерированные файлы непосредственно в Google Drive с помощью инструмента командной строки ggsrun. Поскольку файлы никогда не передаются обратно через ответ API, такая конструкция позволяет избежать ограничений по объему данных и дополнительных затрат, связанных с токенами, обеспечивая высокую производительность в облачной автоматизации.

Проблема возвращения бинарных файлов в формате Base64

Предположим, что среда тестирования генерирует крупные файлы — например, скриншоты высокого разрешения, аудиоформы или архивированный файл JavaScript — и их необходимо сохранить в Drive. Очевидным решением является возвращение необработанных байтов в виде строки Base64 в ответе API Gemini и декодирование её в Apps Script. Однако этот подход сталкивается с рядом проблем одновременно.

  • Функция UrlFetchApp в Apps Script ограничивает размер ответа 50 МБ.
  • Среда выполнения кода в Interactions API ограничивает размер буфера вывода, поэтому многомегабайтная строка Base64 может быть прервана на полпути.
  • У управляемых агентов установлен лимит в 200 000 токенов в минуту. Формат Base64 увеличивает размер бинарных данных примерно на треть, и в многократных сессиях предыдущие строки Base64 накапливаются в истории разговора, пока не исчерпается лимит ввода, после чего сразу появляются ошибки 429 Quota Exceeded.
  • Декодирование длинных строк в формате Base64 и создание объектов типа Drive blobs в Apps Script потребляют время выполнения и память скрипта.
  • На следующей диаграмме показано сравнение этого подхода с прямой передачей данных в реальном времени.

    Лучшим решением является использование инструмента ggsrun, написанного на языке Go, прямо внутри самой среды sandbox; при этом токен доступа OAuth вводится во время выполнения с помощью функции ScriptApp.getOAuthToken(). Затем среда sandbox передаёт бинарные данные в Drive по внутренней сети Google Cloud со скоростью свыше 2 МБ/с, тем самым обходя ограничения на память Apps Script, размер ответа и исчерпание квот на токены.

    Передача данных в реальном времени возможна в обоих направлениях

    Прямая передача данных из облака в облако также полезна для загрузки. Когда крупные внешние наборы данных, такие как изображения высокого разрешения, аудио, видео, файлы CSV или JSON объемом в несколько гигабайт, а также модели машинного обучения, должны попасть в сандбокс, их включение в запрос в формате Base64 или сериализованного текста практически мгновенно исчерпывает лимит токенов входных данных, что приводит к ошибке 429. С помощью ggsrun сандбокс сам загружает файл из Drive, и в запросе требуется лишь краткое указание вроде «загрузить целевой набор данных из Drive и проанализировать его». Использование токенов входных данных снижается практически до нуля, что предотвращает исчерпание лимитов скорости.

    Совместное использование одной постоянной песочницы ещё больше снижает затраты. Одна процедура настройки генерирует environmentId, который могут использовать проекты Apps Script, локальные рабочие станции Node.js, скрипты на Python и пайплайны CI/CD. Наборы данных, корпуса, библиотеки или заранее обученные модели, хранящиеся в папке /workspace/, становятся доступными для всех клиентов, поэтому никому не нужно перезагружать данные или повторять настройку при каждом использовании. Это сокращает время отклика, сетевую пропускную способность и общую нагрузку на API, к тому же задачи могут повторно использовать общие рабочие файлы и заранее установленные пакеты.

    На следующей диаграмме показана полная архитектура: Apps Script и локальные рабочие станции Node.js координируют работу в рамках одной постоянной песочницы с помощью общего environmentId, используя двунаправленную передачу данных и общие наборы данных для быстрой генерации контента.

    Архитектура делится на четыре части:

    • Несколько клиентов управляют одним контейнером. Приложения на базе облака, написанные с использованием Apps Script, работают с синхронным триггером и динамическим токеном OAuth, в то время как локальные рабочие станции на Node.js используют потоковую передачу данных в реальном времени по протоколу SSE и аутентификацию через gcloud.
    • Сандбокс хранит общедоступные наборы данных и инструменты сборки, такие как Playwright, FFmpeg и esbuild, что позволяет генерировать контент без повторной загрузки данных.
    • Команда ggsrun download передаёт крупные наборы данных из Drive в сандбокс в потоковом режиме, что избавляет от необходимости вставки данных в реальном времени и помогает соблюдать лимит в 200 тыс. TPM.
    • Команда ggsrun upload загружает готовые бинарные файлы в Drive со скоростью 2 МБ/с и выше, тем самым обходя ограничение объёма данных в 50 МБ и проблему обрезки вывода в стандартный вывод.

    Полный исходный код (классы Apps Script, клиенты потоковой передачи для Node.js, наборы тестов и логи выполнения) хранится в публичном репозитории проекта на GitHub.

    Настройка

    Сначала сгенерируйте ключ API в Google AI Studio. Он используется для аутентификации запросов к API Gemini v1beta Interactions and Environments. Затем создайте проект Apps Script двумя способами: либо отдельный проект на сайте script.google.com через раздел «Новый проект», либо проект, связанный с таблицей, документом или формой — для этого откройте соответствующий документ, выберите раздел «Расширения», а затем «Apps Script».

    Скопируйте два файла из репозитория в редактор:

    • ManagedAgentSandboxClient.js — это основной класс-клиент. Он управляет жизненным циклом среды тестирования и динамическими переменными окружения, хранит данные сессии в PropertiesService и применяет разумные механизмы повторных попыток при получении ответа 429.
    • tests.js — это основной набор тестов. Он охватывает настройку среды тестирования, проверку инструментов, обработку медиафайлов, веб-скрапинг и тестирование производительности.

    Далее откройте «Настройки проекта», затем «Свойства скрипта» и добавьте свойство с именем GEMINI_API_KEY, в котором будет храниться ключ. В конце убедитесь, что в манифесте (appsscript.json) указаны правильные диапазоны OAuth. Для вызовов UrlFetchApp требуется диапазон https://www.googleapis.com/auth/script.external_request, а диапазон https://www.googleapis.com/auth/drive необходим для создания целевых папок и загрузки файлов. Код, использующий существующие папки без вызова DriveApp.createFolder(), может обойтись диапазоном https://www.googleapis.com/auth/drive.file. Журналы выполнения каждого теста находятся в файле gas-src/execution-logs.md репозитория.

    Настройка общей среды выполнения

    Выполнение функции provisionSharedSandbox() запускает новый удаленный контейнер Linux, устанавливает инструменты командной строки и необходимые зависимости, настраивает пути к целевым дискам и сохраняет полученный environmentId в PropertiesService.

    В инфографике показаны четыре шага. Сначала Drive создает папку назначения с именем ManagedAgent_Artifacts_YYYYMMDD. Затем контейнер с 4 vCPU и 16 GB запускает через команду инициализации библиотеки ggsrun, ffmpeg, sox, jq, typescript, esbuild и Playwright с Chromium. После этого сандбокс проверяет установленные бинарные файлы и сообщает READY. Наконец, уникальный environmentId сохраняется в папке SHARED_SANDBOX_SESSION, чтобы последующие тесты и другие клиенты могли им воспользоваться. После этого вызов функции testListSandboxes() запрашивает API сред, чтобы подтвердить, что сандбокс активен, и возвращает его метаданные.

    Тест 1: пользовательские заголовки, которые перезаписывает Apps Script

    Первый тест показывает, чего не может сделать UrlFetchApp. Apps Script автоматически заменяет пользовательский заголовок User-Agent на строку-идентификатор прокси от Google, в то время как среда безопасности сохраняет любые заголовки, которые вы установили, поскольку она отправляет запросы через необработанные POSIX-сокеты и нативный curl.

    В диаграмме показано, как запрос с заголовком User-Agent: sample user agent направляется на адрес httpbin.org/anything. В среде Apps Script политика прокси платформы заменяет этот заголовок. В среде сандбокса инструмент curl сохраняет исходную строку без изменений. Затем встроенный скрипт на Python сравнивает полученные JSON-данные и выводит матрицу проверки. По сути, Apps Script отправляет запрос типа GET с пользовательским заголовком, сандбокс отправляет тот же запрос с использованием curl, и сравнение подтверждает, что Apps Script заменил значение на Mozilla/5.0 (compatible; Google-Apps-Script; beanserver; ...), тогда как сандбокс полностью сохранил исходное значение sample user agent.

    Тест 2: аутентификация в Drive изнутри сандбокса

    Этот тест проверяет аутентификацию в Drive и прямой доступ через ggsrun путем вставки нового токена OAuth из функции ScriptApp.getOAuthToken() в процесс выполнения на данном этапе.

    На первом этапе Apps Script извлекает токен и вставляет его в качестве переменной окружения GGSRUN_AT, что устраняет риск истечения срока действия токена через час. На втором этапе сандбокс генерирует файл верификации 00_ggsrun_verification.txt в папке /workspace/test2/ и загружает его с помощью команды ggsrun upload в режиме безблокирующего перезаписывания (--nc --cm OverwriteIfNewer -j). На третьем этапе команда ggsrun searchfiles ищет файлы в целевой папке и возвращает структурированные метаданные, подтверждающие наличие всех девяти файлов. Весь цикл создания, загрузки и проверки занял 12,1 секунды, и никакие конфиденциальные токены не сохранялись между сессиями.

    Тест 3: скрапинг без графического интерфейса с Playwright

    Далее автоматизированная сессия Chromium без графического интерфейса в среде сандбокса собирает динамический контент, отрендеренный с помощью JavaScript, и делает скриншоты в нескольких размерах окна просмотра.

    Скрипт Node.js Playwright открывает сайт с цитатами, отрендеренным на JavaScript (quotes.toscrape.com/js/), делает скриншоты всей страницы в размере рабочего стола (1280x800) и в режиме имитации iPhone (375x812), затем нажимает на элемент управления пагинацией, делает скриншот второй страницы в размере рабочего стола и извлекает цитаты в файл 02_Page2_Quotes.json. Размеры скриншотов составили примерно 92,5 КБ для версии рабочего стола, 51,6 КБ для мобильной версии и 171,9 КБ для второй страницы, плюс 4,1 КБ для файла JSON; в сумме все четыре файла занимают около 320 КБ. Одна команда ggsrun upload отправила все три PNG-файла и набор данных в формате JSON в Drive без какой-либо конвертации в Base64, причем весь процесс занял 20,4 секунды. Это пример рендеринга на стороне клиента, который Apps Script не может обработать нативно.

    Тест 4: синтез звука с использованием FFmpeg и SoX

    Четвертый тест запускает нативную обработку цифровых сигналов в сандбоксе, создавая многотоновую аккордовую гармонию с использованием FFmpeg и SoX.

    Три генератора синусоидальных волн с частотами 440 Гц (A4), 554,37 Гц (C#5) и 659,25 Гц (E5) смешиваются с помощью фильтра amix в FFmpeg в трехсекундный MP3-файл мажорного аккорда размером 73,4 КБ. Затем ffprobe извлекает метаданные потока в файл 03_Audio_Analysis.json объемом 1,8 КБ. Команда ggsrun upload отправляет файл 03_Chord_Major.mp3 и JSON-файл непосредственно в Drive. Время синтеза, извлечения метаданных и загрузки составило 9,1 секунды.

    Тест 5: парсинг TypeScript и сборка с помощью esbuild

    В этом тесте демонстрируется работа современных инструментов сборки JavaScript и TypeScript внутри сандбокса.

    Два набора инструментов работают с модулем TypeScript matrix.ts, который определяет генерические классы и интерфейсы и находится в папке /workspace/test5/. В первой ветке скрипт Node.js использует официальный API компилятора TypeScript для анализа дерева абстрактной синтаксической структуры и экспорта схем интерфейсов и методов в файл 04_TypeScript_AST.json объемом всего 152 байта. Во второй ветке esbuild собирает и минифицирует модуль в отдельный файл с использованием конструкции IIFE — 04_Matrix_Bundle.iife.js объемом 1,2 КБ, причем время сборки составляет всего 13 миллисекунд. Затем команда ggsrun upload отправляет оба результата в Drive, и вся процедура занимает 10,0 секунд.

    Тест 6: прямая загрузка в формате Base64 через Apps Script

    В этом тесте 10-тысячебайтный бинарный файл перемещается из среды тестирования в Drive двумя разными способами.

    В подходе A среда разработки генерирует 10 КБ бинарных данных из /dev/urandom и передаёт их в Drive с помощью ggsrun в течение одного этапа взаимодействия (freshInteraction: true). В подходе B среда разработки кодирует те же байты в формате Base64 и возвращает их в текстовом ответе API, после чего Apps Script декодирует этот строковый формат и сохраняет файл в Drive. Подход A был завершён за 16,20 секунды со скоростью 0,60 КБ/с и не потребовал использования процессорных ресурсов Apps Script. Подход B занял 32,13 секунды со скоростью 0,30 КБ/с, плюс ещё 1,23 секунды на работу процессора Apps Script; таким образом, подход A оказался в 1,98 раза быстрее. Кроме того, он позволяет избежать примерно 33-процентного увеличения размера данных из-за кодирования Base64, а также проблем исчерпания токенов, с которыми сталкиваются многократные сессии. Записанный отчёт выглядит следующим образом.

    ================================================================================
    PERFORMANCE BENCHMARK REPORT: 10,000 BYTES FILE TRANSFER TO GOOGLE DRIVE
    ================================================================================
    | Metric                       | Approach A: Direct ggsrun Upload | Approach B: Base64 via Gemini API -> GAS |
    | :--------------------------- | :------------------------------- | :--------------------------------------- |
    | Transfer Method              | Direct Sandbox-to-Drive (Go CLI) | Base64 Stream -> GAS -> Drive            |
    | Drive File Name              | benchmark_10kb_ggsrun.bin        | benchmark_10kb_gas.bin                   |
    | Verified File Size           | 10,000 bytes (9.77 KB)           | 10,000 bytes (9.77 KB)                   |
    | API Turns Required           | 1 Turn (Direct Offload)          | 1 Turn (Base64 Retrieval)                |
    | Local GAS Processing Time    | 0.00 s (Zero CPU overhead)       | 1.23 s (Base64 Decode & Blob Creation)   |
    | Total End-to-End Duration    | 16.20 s                          | 32.13 s                                  |
    | Effective Throughput         | 0.60 KB/s                        | 0.30 KB/s                                |
    | Performance Multiplier       | 1.98x FASTER                     | Baseline (Higher Latency & Token Usage)  |
    ================================================================================
    

    Стриминг через ggsrun происходил в 1,98 раза быстрее, исключал все затраты CPU и памяти, связанные с декодированием в Apps Script, и не потреблял никакой квоты на токены для общения. Для полезных данных объемом в несколько мегабайт именно этот прямой путь предотвращает появление ошибок 429 Quota Exceeded.

    Управление одним и тем же сандбоксом с локальной рабочей станции

    Чтобы показать, что один и тот же постоянный сандбокс Linux можно управлять как из Apps Script, так и с ноутбука, был создан клиент на Node.js с функцией стриминга Server-Sent Events на основе SDK @google/genai. Apps Script работает синхронно и блокирующим образом, собирая события агента в конце HTTP-запроса, в то время как локальный запуск обеспечивает разработчикам ряд возможностей, недоступных в Apps Script.

    • Постоянный просмотр хода выполнения. Шаги рассуждений (thought), команды оболочки (code_execution_call), вывод stdout и stderr из песочницы (code_execution_result) и текст модели (model_output) передаются в терминал в реальном времени с использованием цветов ANSI.
    • Гибкий рабочий процесс для разработки. Пromptы и инструментальные цепочки можно прототипировать, отлаживать и настраивать локально с мгновенной обратной связью, а затем переносить в автоматизированные триггеры Apps Script, которые работают без участия человека.
    • Простое обмен внутри песочницы. Введение идентификатора, сгенерированного во время настройки Apps Script, в поле ENVIRONMENT_ID в локальном файле .env позволяет подключить клиент к существующему контейнеру со всеми установленными пакетами, скомпилированными бинарниками и файлами рабочего пространства, без необходимости повторной установки.
  • Автоматическая обработка OAuth. Запускающий скрипт получает новые токены доступа к Google с помощью команды gcloud auth print-access-token и вставляет их в переменную GGSRUN_AT, что позволяет выполнять загрузку данных непосредственно в Drive так же, как это работает в Apps Script, без необходимости вручную копировать учетные данные.
  • Для запуска локальных тестов требуется четыре шага.

    1. Клонируйте репозиторий и выполните команду npm install внутри файла local-node.js-src.
    2. Скопируйте файл .env.example в .env и укажите три значения: ключ API как GEMINI_API_KEY, идентификатор среды с длительным сроком действия как ENVIRONMENT_ID, а также папку в Drive для записи данных как TARGET_FOLDER_ID.
    3. Запустите команду npm test или отдельный тест с помощью npm run test:1 до test:6 и наблюдайте за работой агента в реальном времени.
    4. По завершении выполните команду npm run test:teardown, чтобы удалить удаленную сандбокс-среду и освободить облачные ресурсы.

    Полные необработанные записи вместе с результатами прямой трансляции хранятся в файле local-node.js-src/execution-logs.md репозитория; они показывают те же функциональные результаты, что и выполнение кода в Apps Script.

    Шаблоны API для управляемых агентов

    Приведенные ниже шаблоны обобщают распространенные способы работы с API Gemini v1beta Interactions and Environments. Каждый из них отправляет запрос POST на один и тот же базовый конечный пункт.

    POST https://generativelanguage.googleapis.com/v1beta/interactions?key=${API_KEY}
    Content-Type: application/json
    

    В сценарии 1 одна постоянная песочница используется многими клиентами. Создайте удаленную среду один раз, установив environment.type в значение "remote", сохраните возвращаемый environment_id и отправляйте его в виде обычной строки в последующих запросах из Apps Script, Node.js, Python или задачи CI/CD.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Run task in shared container...",
      "environment": "environments/env-12345"
    }
    

    Сценарий 2 представляет собой изолированную среду для каждой запуска. Когда задаче требуется совершенно новая среда Linux, устанавливайте environment.type в значение "remote" при каждом вызове.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Execute client-specific isolated task...",
      "environment": {
        "type": "remote"
      }
    }
    

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

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Based on the previous output, proceed to step 2...",
      "environment": "environments/env-12345",
      "previous_interaction_id": "interaction-prev-67890"
    }
    

    В сценарии 4 используется песочница с новым контекстом с помощью опции freshInteraction. Укажите существующий environment_id и не указывайте previous_interaction_id. Все файлы и установленные инструменты в контейнере остаются прежними, в то время как история разговора сбрасывается до нуля токенов, что предотвращает исчерпание лимита скорости TPM.

    {
      "agent": "antigravity-preview-05-2026",
      "input": "Execute a completely new task in the existing sandbox...",
      "environment": "environments/env-12345"
    }
    

    Сравнение в одном взгляде

    Матрица резюме размещает различные подходы рядом друг с другом.

    Что это дает

    Сочетание Apps Script с Gemini Managed Agents позволяет преодолеть обычные ограничения серверно-независимой среды выполнения. Постоянная удаленная сандбокс-среда в сочетании с прямой передачей данных между облачным хранилищем и сандбоксом в обоих направлениях делает возможным выполнение задач, которые Apps Script в одиночку обработать не может, а также позволяет избежать ограничений по объему данных в API и квот на токены для взаимодействия.

    • Преодолеваются ограничения Apps Script. Задачи, требующие нативной среды Linux, такие как скрапинг с использованием безголового браузера Playwright, синтез звука с помощью FFmpeg и компиляция кода на TypeScript с использованием esbuild, теперь могут запускаться из Apps Script.
    • Размышления ИИ сочетаются с выполнением в Linux. Вместо запуска фиксированных внешних команд размышления Gemini работают вместе с настоящей оболочкой, что позволяет формировать команды динамически, выполнять код во время работы и корректировать свои действия в ходе сложных рабочих процессов.
    • Потоковая передача в обоих направлениях позволяет сократить количество токенов и объем данных. Загрузка результатов работы, а также извлечение крупных наборов данных из Drive в среду тестирования позволяют избежать включения данных в запросы и преобразования их в формат Base64, что снижает количество токенов входных и выходных данных, помогает соблюдать лимит в 50 МБ и квоту в 200 000 TPM.
    • Общие среды тестирования снижают затраты. Хранение общих наборов данных и инструментов в общей файловой системе контейнера исключает необходимость повторной загрузки и настройки для каждой задачи, что сокращает время задержки и потребление пропускной способности.
    • Это подтверждается тестами производительности. Прямая передача данных из облака в облако с использованием CLI была в 1,98 раза быстрее, чем загрузка данных в формате Base64 через API, причем не требовалась обработка на процессоре и не использовалась локальная память в Apps Script.