Введение: когда «всё работает» — вдруг перестаёт

Вы потратили недели на выточенный препромпт для Claude Opus. Агент знает контекст, уверенно вызывает инструменты, не галлюцинирует. Потом вы решаете перейти на self-hosted Ollama — ради приватности, экономии или независимости от вендора. И в первые же три минуты агент начинает вести себя как человек с амнезией: перечитывает файлы, которые уже обработал, переписывает готовую работу, зависает в петле повторных вызовов.

Это не баг конкретной модели. Это системная проблема, с которой сталкиваются все, кто переносит тяжёлые препромпты с облачных API на локальный инференс. Данный инженерный постмортем вскрывает реальные режимы отказа при переносе больших production-промптов с проприетарных API — и показывает, как с ними бороться.


Проблема №1: Контекстное окно — ваш главный враг

Клаудиные Opus или GPT-4 работают на огромных контекстных окнах — сотни тысяч токенов. Это создаёт у разработчиков ложное ощущение, что «большой препромпт — не проблема».

Self-hosted системы имеют значительно меньшие контекстные окна. Промпт плюс история сессии быстро превышают максимум — например, 65 тысяч токенов у типичного локального развёртывания.

На практике 35-килобайтный препромпт мгновенно поглощает 14% всего контекстного окна — и агент сразу начинает «сомневаться» в инструкциях: делает лишние вызовы инструментов, перечитывает файлы. Контекст насыщается за несколько циклов — иногда ещё до первого реального ответа.

⚠ Критическое предупреждение
Pо умолчанию Ollama выставляет крайне маленький контекст. Если не настроить num_ctx вручную в Modelfile — вы потеряете большую часть своего препромпта ещё до первого обмена с агентом.

Контекстную длину нужно явно задавать в Ollama. Значения по умолчанию катастрофически малы.

Пример минимального Modelfile:

FROM gemma3:27b

PARAMETER num_ctx 65536
PARAMETER num_predict 4096
PARAMETER rope_freq_base 1000000

SYSTEM """
[ВАШ ПРЕПРОМПТ ЗДЕСЬ]
"""

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


Проблема №2: Агентский тромбоз — петли и трэшинг

Когда вы пытаетесь использовать большие препромпты, хорошо работающие у облачных провайдеров, Ollama начинает «захлёбываться» уже через три минуты. Агент зависает в петлях повторных вызовов инструментов, перечитывает уже обработанные файлы, переписывает завершённую работу.

Это явление — не случайность, а закономерный симптом контекстного насыщения.

Системный промпт, безупречно работающий на GPT-4o или Claude Sonnet, может молча рассыпаться в Ollama. Инженеры, мигрирующие большие промпты на локальные LLM, регулярно сталкиваются с одним и тем же паттерном: деградация последовательности персонажа, частичное игнорирование многошаговых инструкций, обвал качества — без единого сообщения об ошибке. Модель выглядит рабочей, но перестаёт следовать правилам, которые «закопаны» в середине промпта.

Сигналы отказа, которые нужно мониторить

Вот признаки контекстного истощения, которые стоит отслеживать в логах: ошибки парсинга вызовов инструментов (tool-call parse failures). Разбор ответов инструментов вталкивает в контекст столько сырых данных, что уничтожает сессию — как прорыв трубы прямо на вечеринке.

Другие тревожные сигналы:

  • Агент снова и снова читает один и тот же файл
  • Переписывает код, который уже сгенерировал
  • Игнорирует инструкции из середины промпта
  • Отвечает неполными или обрезанными JSON-структурами

graph TD
    A[Большой препромпт 35KB] --> B{Контекст заполнен?}
    B -- Нет --> C[Нормальная работа агента]
    B -- Да --> D[Трэшинг и петли]
    D --> E[Повторные вызовы инструментов]
    D --> F[Перечитывание файлов]
    D --> G[Переписывание готового]
    E --> H[Ошибки парсинга tool-call]
    F --> H
    G --> H
    H --> I[Сессия уничтожена]


Проблема №3: Архитектура промпта не переносится 1-в-1

Это, пожалуй, самый болезненный сюрприз: то, что работает на Opus, требует фундаментального переосмысления для локальной модели.

Негативные инструкции работают хуже

Правило для self-hosted агентов: перечитывайте только нужный срез данных, сокращайте число вызовов инструментов на каждый шаг и — важнейшее — замените «не делай X» на позитивные директивы: «делай только Y».

Это не каприз — это следствие меньших параметров модели. 27B-модель менее устойчива к двойному отрицанию и длинным цепочкам запретов.

Монолитный промпт нужно разбить

Если вы планируете переносить агентов с Frontier Provider на self-hosted open weight системы — изучите разбивку препромптов на единицы «одна проблема / одно решение», по одной цели на каждую.

Реструктурируйте системный промпт по принципу «закладок»: критические инструкции — в начале и в конце, референсные данные — в середине.

💡 Практический совет
Проверьте «плотность инструкций» вашего промпта: сколько директив приходится на каждые 1000 токенов? Если цифра большая — модели с меньшим числом параметров будут терять инструкции из середины. Разбейте агента на специализированные под-агенты.

Управление состоянием сессии

Агентам потребуется логировать состояние сессии на диск, чтобы обеспечить более частые передачи между сессиями. Это нетипично для облачных провайдеров с огромными окнами, но критично для локального инференса.


Проблема №4: Скрытая цена «дешёвого» self-hosting

Переход на Ollama мотивирован экономией и приватностью. Но у него есть невидимые издержки.

Сравнение: облако vs self-hosted

ПараметрClaude Opus / GPT-5 (API)Self-hosted Ollama
Контекстное окно200K–1M токенов32K–128K токенов
Настройка промптаМинимальнаяГлубокая реструктуризация
Данные сессийУходят провайдеруОстаются локально
Стоимость запросаPer-token billingCAPEX на железо
Стабильность агентаВысокаяТребует ручной настройки
Цензура / отказыВстроены в модельУправляется вами
LatencyЗависит от сетиПредсказуема локально

Один из главных активов, которые мы получаем от Frontier Providers — не модель, а большое контекстное окно. Они располагают железом для вашего инференса. И в результате получают доступ к данным вашей сессии.

Возможно, самая ценная информация — не ваши данные, а метаданные о ваших сессиях: паттерны запросов, стратегии промптинга, цепочки рассуждений.

Для стабильной высокообъёмной нагрузки локальный инференс позволяет избежать per-token затрат и сохраняет данные на своей машине. Для случайных задач облачный API зачастую дешевле с учётом железа и времени настройки. Точка безубыточности зависит от объёма и ценности приватности.

ℹ Аппаратный контекст
Автор оригинального постмортема использовал систему с 128 ГБ оперативной памяти на AMD Ryzen AI MAX+ 395, выделив 32 ГБ операционной системе и всё остальное — инференсу. Даже при такой конфигурации 35KB препромпт создаёт серьёзные проблемы.

Практический план миграции

На основе реальных уроков выстраивается следующий порядок действий:

Шаг 1: Аудит и измерение

  • Посчитайте токены вашего препромпта (не байты!)
  • Определите, сколько токенов занимает типичная сессия
  • Установите соотношение: промпт / окно контекста целевой модели

Запустите «канарейковые» диагностические промпты, чтобы измерить, где именно деградирует внимание модели по всему контекстному окну.

Шаг 2: Декомпозиция промпта

Монолитный 35KB промпт
Модуль А: Контекст задачи (5KB)
Модуль Б: Правила поведения (3KB)
Модуль В: Инструменты (4KB)
Модуль Г: Примеры (загружаются по запросу)

Каждый специализированный агент получает только свой модуль — не весь промпт целиком.

Шаг 3: Настройка Ollama

# Создаём Modelfile с правильными параметрами
ollama create my-agent -f ./Modelfile

# Проверяем, что контекст выставлен
ollama show my-agent --modelfile | grep num_ctx

Шаг 4: Мониторинг сигналов деградации

Добавьте в логи агента детектор этих паттернов:

FAILURE_SIGNALS = [
    "tool_call_parse_error",
    "repeated_file_read",    # один файл читается 2+ раза
    "rewrite_completed_block", # агент трогает готовые блоки
    "instruction_contradiction", # противоречие с ранними инструкциями
]

def detect_context_exhaustion(agent_log: list[str]) -> bool:
    return any(
        signal in entry 
        for entry in agent_log 
        for signal in FAILURE_SIGNALS
    )

Шаг 5: State persistence

Агент должен логировать состояние сессии на диск для поддержки частых передач. Перечитывайте только нужный срез — не всё состояние сразу.

📝 Пример структуры state-файла
{
  "session_id": "abc123",
  "completed_steps": ["read_repo", "analyze_deps"],
  "current_objective": "write_tests",
  "artifacts": {"tests_path": "./tests/unit/"},
  "context_tokens_used": 18400
}

При передаче новой сессии агент загружает только current_objective и artifacts — не всю историю.


Заключение: self-hosting — это не замена, это другая игра

Эта история о миграции промптов задела нерв у разработчиков, обеспокоенных vendor lock-in: сообщество делится собственными подводными камнями и подтверждает трудно добытые уроки автора.

Главный вывод прост, но его легко пропустить: большой препромпт — это не файл конфигурации, который можно скопировать из одной системы в другую. Это архитектурное решение, завязанное на конкретные характеристики инфраструктуры.

Переход на Ollama даёт реальные преимущества — приватность данных, предсказуемую latency, отсутствие per-token billing. Но он требует:

  1. Явной настройки контекста — дефолты Ollama для production непригодны
  2. Декомпозиции монолитного промпта — один агент, одна задача, один срез контекста
  3. Переписывания запретов в позитивные директивы — меньшие модели плохо держат длинные цепочки «не делай…"
  4. Реализации state persistence — сессии живут короче, передача должна быть явной
  5. Мониторинга сигналов деградации — context exhaustion не бросает исключений

Self-hosting меняет уравнение: промпты никогда не покидают ваш сервер, вы получаете стабильную производительность без API rate limits и контролируете расходы — никаких неожиданных счетов, когда команда увлекается AI.

Но за это вы платите инженерными усилиями. И чем больше был ваш исходный препромпт — тем больше этих усилий потребуется.