Сжигание токенов в AI-агентах: ошибка OpenCode и решение | AiManual
AiManual Logo Ai / Manual.
28 Янв 2026 Гайд

Как избежать сжигания миллионов токенов в AI-агентах: анализ ошибки OpenCode и гайд по контекстному кэшированию

Разбор ошибки OpenCode, где сожгли 45M токенов за 150 диалогов. Гайд по контекстному кэшированию, RAG и индексации для экономии на API AI-агентов. Актуально на

45 миллионов токенов в трубу: как OpenCode обанкротился на глупости

Это случилось в прошлом месяце. Команда OpenCode запустила своего код-агента в продакшен. Через неделю пришел счет: 45 миллионов токенов. 150 диалогов. Стоимость – несколько тысяч долларов. И все из-за одной архитектурной ошибки, которую совершает 9 из 10 разработчиков AI-агентов.

Агент был построен на Gemini 2.0 Pro (последняя стабильная версия на январь 2026). Каждый запрос пользователя – "допиши функцию", "найди баг" – отправлял в модель ВЕСЬ контекст репозитория. Весь код, всю историю чата, все системные промпты. Снова и снова. Это как пересылать энциклопедию Британника почтой каждый раз, когда нужно узнать столицу Франции.

Цифры пугают: один токен Gemini 2.0 Pro стоит $0.0000005 для ввода. 45 миллионов токенов – это $22.5 только за ввод. Умножьте на тысячи пользователей. Теперь понимаете масштаб?

Почему ваши агенты жрут токены как не в себя

Проблема в шаблонном мышлении. Мы берем пример из документации OpenAI или Anthropic, где в чат отправляется массив сообщений. User, assistant, system. И думаем: "Так и надо". Но в продакшене этот массив растет как снежный ком.

Каждый turn диалога – это вся предыдущая история плюс новый запрос. Если ваш агент анализирует код, то с каждым шагом контекст пухнет. Через 10 turns вы отправляете 10 версий одного и того же файла. Модель платит за обработку одинаковых данных многократно. Это не просто дорого – это технически тупо.

💡
Контекстное окно – это не склад для хранения всего подряд. Это оперативная память. Вы же не копируете всю базу данных в RAM при каждом запросе? С агентами та же логика.

И вот здесь многие идут по пути выгорания, пытаясь вручную обрезать контекст или изобретать хитрые схемы. Есть способ проще.

Контекстное кэширование: не магия, а просто умный кэш

В конце 2025 года Google анонсировал фичу context_caching для Gemini API. OpenAI добавила аналогичное в GPT-4.5. Суть: вы отправляете часть контекста (например, системный промпт или документацию) один раз, получаете cache_id, а в следующих запросах подставляете только этот ID. Модель знает, что уже видела этот текст, и не заряжает за его обработку.

Это не RAG. Это кэширование на уровне API провайдера. Разница принципиальная: RAG ищет релевантные куски в векторах, а context_caching говорит "этот кусок текста неизменен, запомни его". Идеально для системных инструкций, кодовой базы, документации – всего, что не меняется в течение сессии.

Подход Экономия токенов Сложность Когда использовать
Полный контекст каждый раз (как у OpenCode) 0% Низкая Никогда. Серьезно.
Контекстное кэширование API До 70% на статичных данных Средняя Системные промпты, базовая документация
RAG с индексацией До 90% на больших репозиториях Высокая Кодовая база, техдокументация, базы знаний

Комбинируя оба подхода, вы получаете агента, который не сжигает бюджет впустую. Давайте разберем, как это внедрить, на примере того же OpenCode.

1 Анализируем текущий поток контекста

Первое – аудит. Что вы отправляете в модель? Откройте логи вашего агента. Вы увидите три категории данных:

  • Статичное: Системный промпт ("Ты – помощник для написания кода..."), лицензии, конфигурационные файлы. Это кандидаты на context_caching.
  • Динамичное, но повторяющееся: Код файлов, которые не меняются в течение сессии. Тоже можно кэшировать.
  • Уникальное: Вопрос пользователя, новый код, ответы агента. Это отправляется всегда.
# Как НЕ надо делать
messages = [
    {"role": "system", "content": "Ты код-ассистент. Твои правила..."},  # 500 токенов
    {"role": "user", "content": "Вот мой код: {весь_файл.py}"},  # 2000 токенов
    {"role": "assistant", "content": "Я вижу проблему..."},
    {"role": "user", "content": "А теперь исправь функцию X"}  # И весь предыдущий контекст летит снова!
]
# Каждый turn – нарастающий итог. Кошмар.

2 Выбираем стратегию кэширования

Для статичных данных – используем нативный API. Для Gemini 2.0 это параметр tools.caching. Для OpenAI – cache_control. Кэш живет до 24 часов и привязан к API-ключу.

Для кода – гибридный подход. Если файл не менялся, кэшируем его хеш. При изменении – инвалидируем кэш. Тут поможет LiteLLM – библиотека, которая абстрагирует провайдеров и добавляет слой управления кэшем поверх.

3 Интегрируем с API Gemini или OpenAI

Вот рабочий пример для Gemini 2.0 на январь 2026. Обратите внимание на параметр cached_content.

import google.generativeai as genai

# Настройка клиента с кэшированием
genai.configure(api_key="YOUR_KEY")
model = genai.GenerativeModel('gemini-2.0-pro')

# Шаг 1: Кэшируем системный промпт (делаем один раз за сессию)
cache_response = model.cache_content(
    contents=[{"role": "user", "parts": ["Ты экспертный код-ассистент..."]}],
    tools=[{"caching": {"mode": "ENABLED"}}]
)
cache_id = cache_response.cache_id

# Шаг 2: Используем в основном запросе
response = model.generate_content(
    contents=[
        {"role": "user", "parts": ["Проанализируй функцию:"]},
        {"role": "model", "parts": []},  # Место для кэшированного контента
        {"role": "user", "parts": ["def foo():\n    return 42"]}
    ],
    tools=[{"caching": {"mode": "READ_ONLY", "cache_id": cache_id}}]
)
# Модель получит системный промпт из кэша, а не из тела запроса

Для OpenAI GPT-4.5 логика похожа, но используйте параметр cache_control в запросе.

4 Настраиваем RAG для статичного кода

Context_caching не панацея. Если у вас 1000 файлов, кэшировать их все – неэффективно. Здесь нужна архитектура как у исследовательских агентов: индексация репозитория.

Используйте векторную базу (Chroma, Pinecone) для индексации файлов. Когда агент получает вопрос "Как работает функция X?", сначала ищите релевантные фрагменты кода через RAG, а затем отправляйте только их в контекст. Это сократит объем в 10-50 раз.

# Упрощенная схема гибридного агента
class EfficientCodeAgent:
    def __init__(self):
        self.cache_id = None  # ID кэшированного системного промпта
        self.vector_index = Chroma()  # Индекс кода
    
    def query(self, user_question, repo_context=None):
        # 1. RAG: находим релевантный код
        relevant_code = self.vector_index.similarity_search(user_question, k=3)
        # 2. Формируем компактный контекст
        context = "\n".join([doc.page_content for doc in relevant_code])
        # 3. Отправляем запрос с кэшированным системным промптом
        messages = [
            {"role": "user", "parts": [user_question]},
            {"role": "model", "parts": []},  # Кэш
            {"role": "user", "parts": [f"Релевантный код:\n{context}"]}
        ]
        # ... вызов модели с cache_id
        return response

5 Мониторим и оптимизируем

Внедрили – отлично. Теперь следите за метриками. Среднее количество токенов на запрос должно упасть в 2-3 раза. Используйте дашборды LiteLLM для отслеживания стоимости по провайдерам. Настройте алерты при аномальном росте.

Важный нюанс: кэшированный контент тоже учитывается в лимитах контекстного окна модели, но не тарифицируется повторно. То есть если ваше кэшированное системное сообщение – 1000 токенов, а контекстное окно Gemini 2.0 Pro – 1 млн токенов, то для расчета "вместимости" окна эти 1000 токенов учитываются, но платите вы за них только один раз.

Ошибки, которые вы сделаете (и как их избежать)

Я видел эти грабли десятки раз. Вот топ-3:

  1. Кэшировать динамичные данные. Кэш должен быть инвалидирован при изменении. Хешируйте контент и сравнивайте хеши перед использованием cache_id.
  2. Забыть про безопасность. Кэшированный системный промпт – такая же цель для промпт-инъекций, как и обычный. Не кэшируйте промпты, которые содержат чувствительные инструкции или могут быть переопределены пользователем.
  3. Слепо доверять RAG. Векторный поиск иногда пропускает критически важные фрагменты кода. Всегда добавляйте ручной механизм "force include" для ключевых файлов (например, main.py).

И да, ваш агент все еще уязвим для джейлбрейка, даже с кэшем. Безопасность – отдельная история.

Что будет дальше? Прогноз от инсайдера

К 2027 году контекстное кэширование станет стандартом де-факто. API провайдеры начнут тарифицировать не сырые токены, а "уникальные токены за сессию". Появятся специализированные базы данных для AI-контекста, которые будут делать то, что Redis для веб-сессий.

Но главный сдвиг – в мышлении. Разработчики перестанут думать об агентах как о "чат-интерфейсе к модели" и начнут строить их как полноценные stateful-системы. С сессиями, кэшем, индексами. Это уже не prompt engineering, это агентная инженерия.

Совет напоследок: если ваш агент сегодня работает с полным контекстом, остановите его. Прямо сейчас. Посчитайте, сколько он уже сжег денег. Затем внедрите хотя бы базовое кэширование системного промпта. Это займет час, а сэкономит тысячи. Не повторяйте ошибку OpenCode – они сейчас переписывают архитектуру с нуля, и это больно.