Управление токенами: Стратегии подсчета и оптимизация затрат
Введение: Экономика токена в эпоху Gemini 3
Добро пожаловать на урок, который может сэкономить вам или вашей компании тысячи долларов. Когда мы переходим от экспериментов к продакшену, магия нейросетей сталкивается с суровой реальностью бухгалтерии. В экосистеме Gemini 3, обладающей колоссальным контекстным окном (до 2 миллионов токенов и выше), управление токенами перестает быть просто технической деталью. Это фундамент архитектуры.
Раньше, в эпоху GPT-3.5 или ранних BERT-моделей, мы считали токены, чтобы «влезть» в лимит. Сегодня, работая с Gemini 1.5 Pro или Flash (которые лежат в основе Gemini 3 API), мы считаем токены, чтобы оптимизировать латентность и затраты. Загрузить всю «Войну и мир» в промпт теперь технически возможно, но всегда ли это экономически оправдано?
В этом уроке мы разберем:
- Как именно Gemini «видит» текст, изображения и видео (спойлер: это не всегда очевидно).
- Использование
countTokensAPI для предварительного анализа. - Революционную фичу: Context Caching и её влияние на юнит-экономику.
- Стратегии выбора между длинным контекстом и RAG (Retrieval-Augmented Generation).
Анатомия токена: Текст и Мультимодальность
Чтобы управлять расходами, нужно понимать единицу измерения. В текстовых моделях токен — это часть слова. Для английского языка 1000 токенов — это примерно 750 слов. В русском языке из-за особенностей морфологии и кириллицы коэффициент может быть чуть менее выгодным, но современные токенизаторы (как SentencePiece, используемый в Gemini) значительно оптимизированы.
Мультимодальная арифметика
Gemini — нативно мультимодальная модель. Это значит, что она не преобразует картинку в текст (как это делают модели типа «image-to-text» перед подачей в LLM), она «видит» изображение как набор токенов. Как это тарифицируется?
- Изображения: В Gemini изображения потребляют фиксированное количество токенов, независимо от их размера (до определенного предела). Обычно это 258 токенов за изображение. Это важно учитывать: загрузка 10 сканов документов «весит» 2580 токенов + текст промпта.
- Видео: Видео не разбивается на кадры 1-к-1. Gemini сэмплирует видеоряд (обычно 1 кадр в секунду) и не обрабатывает аудиодорожку отдельно, если вы не укажете это явно. Одна секунда видео может стоить около 263 токенов (видео + аудио). Часовое видео в контексте — это сотни тысяч токенов.
- Аудио: Аудиофайл конвертируется в токены по длительности. Примерно 1 секунда аудио ≈ 32 токена.
Важно: Эти цифры могут меняться с обновлениями API, поэтому жестко «хардкодить» их в калькуляторы затрат на клиенте — плохая практика. Всегда используйте динамический подсчет через API.
import google.generativeai as genai
import os
# Настройка API ключа
genai.configure(api_key=os.environ["GEMINI_API_KEY"])
# Выбор модели (например, Gemini 1.5 Flash для быстрого подсчета)
model = genai.GenerativeModel('gemini-1.5-flash')
# Пример текста и мультимодального контента
text_prompt = "Проанализируй этот график и сделай вывод о трендах."
# Предположим, у нас есть загруженное изображение (объект file)
# image_file = ...
# 1. Простой подсчет токенов для текста
response_text = model.count_tokens(text_prompt)
print(f"Токенов в тексте: {response_text.total_tokens}")
# 2. Подсчет токенов для мультимодального запроса (текст + изображение)
# В реальном коде вместо 'image_data' вы передадите объект изображения
# response_multi = model.count_tokens([text_prompt, image_data])
# print(f"Токенов всего: {response_multi.total_tokens}")
# ЗАЧЕМ ЭТО НУЖНО?
# Вы можете реализовать проверку перед отправкой запроса:
# if response.total_tokens > BUDGET_LIMIT:
# raise CostExceededError("Запрос слишком дорогой")
Стратегия 1: Context Caching (Кэширование контекста)
Это, пожалуй, самая важная особенность для оптимизации затрат в экосистеме Gemini. Представьте ситуацию: вы создаете бота-юриста, который должен отвечать на вопросы по Гражданскому кодексу. Кодекс огромен.
Классический подход: Вы отправляете весь текст кодекса в каждом запросе.
Результат: Вы платите за обработку миллионов токенов каждый раз, когда пользователь спрашивает «Как оформить дарение?».
Подход с Context Caching: Вы загружаете кодекс один раз и получаете cache_key. Модель «запоминает» этот контекст.
Результат: Последующие запросы стоят копейки, так как вы платите только за новый промпт (вопрос пользователя) и хранение кэша (что значительно дешевле повторной обработки).
Экономика кэширования
Кэширование выгодно, если:
- У вас большой контекст (обычно от 32k токенов).
- Вы делаете к этому контексту много запросов в течение короткого времени.
В Gemini кэш имеет TTL (Time to Live). Вы платите за создание кэша (обычная цена инпута) и за время хранения (почасовая оплата), но использование кэшированных данных в запросах стоит значительно дешевле (часто скидка до 75-90% по сравнению с обычной передачей токенов).
from google.generativeai import caching
import datetime
# Предположим, у нас есть большой файл 'manual.txt'
path_to_large_file = 'company_handbook.txt'
# 1. Загрузка файла в File API (предварительный шаг)
remote_file = genai.upload_file(path=path_to_large_file)
# 2. Создание кэша
# Мы указываем модель, для которой кэш будет валиден
cache = caching.CachedContent.create(
model='models/gemini-1.5-pro-001',
display_name='Company Handbook Cache',
system_instruction='Ты HR-ассистент. Отвечай только на основе этого документа.',
contents=[remote_file],
ttl=datetime.timedelta(minutes=60) # Кэш живет 1 час
)
print(f"Кэш создан: {cache.name}")
# 3. Использование кэша в модели
model_with_cache = genai.GenerativeModel.from_cached_content(cached_content=cache)
# Этот запрос будет ОЧЕНЬ дешевым и быстрым
response = model_with_cache.generate_content("Как оформить отпуск?")
print(response.text)
# В конце работы (или по таймеру) можно обновить TTL или удалить кэш
# cache.delete()
Стратегия 2: Длинный контекст vs RAG
С появлением окна в 1-2 миллиона токенов возникает соблазн отказаться от векторных баз данных (RAG) и просто «кидать всё в контекст». Давайте разберем, когда это работает, а когда — сжигает бюджет.
Когда использовать длинный контекст (Long Context)?
- Сложный анализ связей: Когда ответ требует понимания всего документа целиком (например, «Найди противоречия между главой 1 и главой 10 в этом договоре»). RAG может вытащить куски, но потерять глобальную связь.
- Единоразовые задачи: Если вам нужно один раз проанализировать книгу, дешевле загрузить её целиком, чем строить инфраструктуру векторного поиска.
- QA по видео: Загрузить часовое видео и спросить «На какой минуте спикер упомянул конкурентов?» — идеальный кейс для нативного видео-токенизатора.
Когда использовать RAG?
- Масштаб Enterprise: Если ваша база знаний — это 100 000 документов. Даже 2 млн токенов не хватит.
- Цена за запрос: Если у вас 10 000 пользователей в минуту задают простые вопросы. Кэширование помогает, но RAG всё еще может быть дешевле для точечных извлечений.
- Латентность: Поиск по вектору + генерация на малом контексте быстрее, чем обработка гигантского промпта (хотя Gemini Flash очень быстрая, физику не обманешь).
Золотая середина: Гибридный подход. Используйте RAG, чтобы найти 10-20 наиболее релевантных документов, которые в сумме дают 50-100к токенов, и скармливайте их Gemini. Это дает точность длинного контекста без необходимости загружать всю библиотеку Конгресса.
Оптимизация системных инструкций
Системный промпт (System Instruction) передается с каждым запросом. Если он длинный, это постоянный налог на ваши токены.
Техники сжатия:
- Удалите вежливость: Модели не нужны «пожалуйста» и «будь добр».
- Используйте примеры (Few-Shot) экономно: Вместо 10 примеров дайте 2 кардинально разных.
- Формат данных: Если вы просите JSON, используйте TypeScript-подобные определения интерфейсов вместо словесного описания схемы. Модели отлично понимают код, и он компактнее текста.
Пример сжатия:
Было: «Пожалуйста, проанализируй входящее сообщение пользователя. Если оно содержит грубость, то верни статус ошибки. Если сообщение доброе, верни статус успех. Формат должен быть JSON с полем status...»
Стало: Task: Sentiment Analysis. Output: JSON { status: "error" | "success" }. Criteria: error if rude.
Вы разрабатываете систему поддержки для онлайн-школы. У вас есть 50 учебников в формате PDF (каждый по 200 страниц). Студенты задают вопросы круглосуточно. <br><br>Задание: <br>1. Рассчитайте примерное количество токенов для одного учебника (считайте 1 стр = 400 слов).<br>2. Предложите архитектуру: использовать ли Context Caching или RAG? Обоснуйте выбор с точки зрения затрат, если каждый студент делает в среднем 5 запросов за сессию.
Вы используете Context Caching в Gemini. Вы создали кэш из документации на 500k токенов. Срок жизни (TTL) истек. Что произойдет при попытке сделать запрос к этому кэшу?