Когда я только начинал пользоваться локальными агентами, я писал им как очень вежливому коллеге: «Please carefully analyze the project, find the best possible solution». Сейчас я всё чаще пишу инструкции телеграфом:
Fix empty password validation in AuthScreen Done == AuthScreen tests pass Don't change public API Don't know? -> Read relevant files / google it Stuck? -> ask me
Грамматика страдает, агент – нет. Ему не нужны артикли, предлоги и красивые обороты, если смысл однозначен. Это один из примеров контекстной гигиены в ежедневной работе.
Меня зовут Андрей Жаров, я iOS-разработчик из компании Doubletapp, и в этой статье мы рассмотрим, как управлять контекстным окном и экономить токены. Данный материал является расширением темы про контекст из статьи «Как я перестал писать убер-промпты и стал формировать инфраструктуру». Читать их можно в любом порядке, но если вы новичок, то рекомендую ознакомиться сначала с первой статьёй по ссылке выше.

Содержание
Что такое гигиена контекста
Удобно мыслить о контексте как о трёх слоях.
Первый слой – постоянные правила: архитектурные решения, границы безопасности, предпочтительные инструменты.
Второй – рабочий набор конкретной задачи: несколько файлов, дифф, ошибка, лог-кусок, скриншот, конкретный URL документации.
Третий – эпизодические шумные данные: длинные логи, промежуточные tool outputs, большие таблицы, внешние документы и поисковая выдача.
Гигиена начинается там, где вы перестаёте смешивать эти слои в один суп и начинаете управлять ими отдельно:
Фиксировать самое важное в постоянных правилах.
Рабочий набор конкретной задачи держать отдельными файлами на диске для чтения по необходимости, а не принудительно всегда.
Из шумных данных выносить только самое важное и не тянуть за собой пустые логи.
Самая важная часть – это не только убрать лишнее, но и подсветить важное. Так, например, лучше класть длинные данные в начало, а вопрос – в конец. Это помогает пройти через «шум» длинного документа. Академическая работа Lost in the Middle показывает ту же проблему с другой стороны: нейронки, которые мы используем в работе, читают данные токен за токеном с начала в конец и хуже используют информацию, если она спрятана в середине длинного контекста.
В поиске баланса между краткостью, важностью и полезностью приложенных для формирования ответа нейросетью данных и кроется вся суть так называемой гигиены контекста.
Держи команды машиночитаемыми
Начнём с понимания, кому мы это вообще всё пишем. Современные пользователи часто слишком «волшебно» воспринимают компьютеры и телефоны, думая, что они какие-то живые, добрые, злые, хорошие, уставшие. Это часть нашей человеческой натуры, но, к сожалению, это нас сильно подводит в вопросе работы с нейросетями, которые понимают и думают на нашем языке, но не являются людьми.
Это машины, а не коллеги. Нейронке нет разницы по смыслу между «Please, say to me, is our code okay?» и «code is okay?» и даже больше – первое тратит намного больше токенов и утяжеляет когнитивную нагрузку на искусственный интеллект, потому что это ещё надо распарсить, откинуть лишнее, копнуть и увидеть суть. Мы, люди, легко глазом откидываем лишнюю воду из приветствий и пожеланий, машины – нет.
И лучше каждую команду нейронке формировать предельно минималистично и структурированно, например:
Task: <одно действие> Done: <проверка результата> Context: <файлы / логи / ссылки> Rules: - <ограничение 1> - <ограничение 2> If stuck: <что делать>
Task: fix empty password validation in AuthScreen Done: AuthViewModelTests pass + new empty password test Context: - AuthScreen.swift - AuthViewModel.swift - AuthViewModelTests.swift Rules: - don't change backend API - don't touch registration - minimal patch If stuck: ask with exact blocker
Это не единственный формат. Можно писать свой. Важно, чтобы формат сообщения, написанного для машины, был написан в первую очередь для машины, и структурирован для упрощения чтения и понимания машиной.
Краткость – сестра таланта
Вы уже, наверное, слышали про скилл, который заставляет нейронку формировать не длинные ответы, а писать как неандерталец, очень тупо и коротко. Вместо «Баг является фундаментальной проблемой в данной системе, с ним не работает отправка сообщения в сервис аналитики» нейронка пишет: «баг мешать аналитике» – примерно так. И это действительно экономит много выходных токенов, но магия в том, что на вход это тоже работает! Оцените, насколько ёмкие по смыслу конструкции ниже и как сильно они короче, чем если бы мы их писали развёрнуто и грамматически правильно:
run tests after code-changes in loop: while tests failed: fix code and run tests else: exit fixing loop
read AuthScreen + tests find empty password bug's reason
if unsure -> ask if blocked -> show why don't know? -> google it google don't know? -> ask me
Укороченный английский удобен ещё и потому, что большинство агентских инструментов, документации, ошибок и команд всё равно живут на английском, нейронка тратит меньше токенов и меньше переключается между языками, но на русском можно так же:
почини валидацию пустого пароля готово = тест проходит API не менять если непонятно -> спроси
Главное правило: режь вежливость и мишуру, оставляй смысл. Не надо превращать команду в загадку. «auth bug fix pls» – слишком мутно. «fix empty password validation in AuthScreen, done = test passes» – уже достаточно коротко и достаточно точно. Ты пишешь не инструкцию коллеге, а псевдокод для машины.
Одна задача – один done-критерий
Агенту вредно давать задачу в стиле «посмотри всё и сделай нормально». Он начнёт сам выбирать масштаб. Иногда это полезно, но чаще вы получаете лишнее чтение файлов, случайный рефакторинг и длинный цикл исправлений.
Неудачный запрос:
Посмотри auth flow, там что-то не так с логином, поправь аккуратно, проверь всё.
Лучше:
Task: fix login when password is empty Done: unit test covers empty password and passes Rules: - don't change backend API contract - don't touch registration flow
Done-критерий нужен не для красоты. Он закрывает агенту вопрос «когда остановиться?». Без него модель может продолжать улучшать соседние места, потому что «так будет правильнее».
Хорошие done-критерии:
done = test passes done = failing test passed after code fixes done = ui matches design done = no errors done = answer contains root cause + minimal patch
Плохие done-критерии:
done = сделай хорошо done = чтобы было красиво done = чтобы не сломалось done = сам поймёшь
Если проверка объективна, агенту проще работать. Если проверка мутная, агент начинает угадывать ваш вкус, и почти всегда это происходит рандомно – не учите его понимать задачу за вас, поймите её сами и опишите ему.
Кто мы, откуда, куда мы идём
Локальный агент умеет читать проект сам, но это не значит, что ему надо начинать с раскопок по всему репозиторию. Не стоит писать «Где-то в auth сломалась кнопка, посмотри проект», лучше:
Bug: login button stays disabled for valid email + password Start here: - AuthScreen.swift - AuthViewModel.swift - AuthViewModelTests.swift Done: existing auth tests pass + add regression test
Координаты не обязаны быть точными до строки. Достаточно дать агенту стартовую область:
start from CheckoutView likely related to PaymentState error from log below
look at files changed in last commit bug appears after that commit don't scan unrelated modules unless needed
Это снижает объём чтения, уменьшает шум в контексте и ускоряет первый полезный шаг. Агент всё ещё может расширить поиск, если стартовая гипотеза не подтвердилась, но он не начинает с хаотичного обхода всего проекта.
Разделяй и властвуй
Когда в одном абзаце смешаны просьба, лог, догадки, ограничения и эмоции, агенту приходится самому разбирать, что является командой, а что просто фоном:
Вот лог, кажется проблема в токене, но может и нет, раньше работало, я менял AuthService, ещё вот тикет, поправь, только API не трогай, и тесты не забудь
Лучше так:
<task> Fix 401 in login flow. </task> <context> Changed recently: AuthService.swift Likely related: token refresh </context> <evidence> Log: POST /login returns 401 when password="" Ticket: AUTH-142 </evidence> <rules> - don't change backend API contract - add regression test </rules> <done> Auth tests pass. </done>
XML-теги не обязательны. Можно писать и обычными заголовками:
Task: Fix 401 in login flow. Evidence: POST /login returns 401 when password="". Rules: - don't change API contract - add regression test Done: Auth tests pass.
Смысл в том, что агенту не нужно угадывать структуру вашего сообщения. Вы уже структурировали вход, а значит получите скорее всего и структурированный вывод. Для длинных документов полезен ещё один приём: попросить сначала вытащить релевантные цитаты, а уже потом действовать.
Step 1: extract relevant quotes from attached spec. Step 2: propose minimal code change. Don't edit files before Step 1 is done.
Модели хуже держат внимание, когда важная информация спрятана где-то в середине большой простыни. Поэтому важное надо маркировать, повторять в конце или выносить в отдельный блок evidence. Особенно важно это для AGENTS.md или CLAUDE.md, раздутый файл базовых инструкций быстро превращается в свалку. Агент читает его постоянно, даже когда конкретное правило не относится к задаче:
# CLAUDE.md (<- отправляется на КАЖДОМ вызове) - Описание как у нас запускаются тесты (надо раз в спринт) - Описание как устроены коммиты и гит проекта, важные запреты (надо всегда) - Описание как оформлять PR review (надо при сдаче фичи) - Описание что делать при миграции БД (надо раз в год на мажорных апдейтах)
Здесь поможет простое распределение:
Нужно почти всегда -> AGENTS.md / CLAUDE.md
Нужно иногда -> skill
Нужно только сейчас -> prompt
Нужно сохранить после задачи -> markdown artifact в репозитории
Нужно один раз и больше никогда -> не сохранять вообще.
Пример исправленной структуры:
# CLAUDE.md (<- отправляется на КАЖДОМ вызове) - Описание как устроены коммиты и гит проекта, важные запреты (надо всегда) # .claude/skills/unit-test/SKILL.md (<- подключается ТОЛЬКО когда нужно) - Описание как у нас запускаются тесты (надо раз в спринт) # .claude/skills/pr-review/SKILL.md (<- подключается ТОЛЬКО когда нужно) - Описание как оформлять PR review (надо при сдаче фичи) # .claude/skills/DB-migration/SKILL.md (<- подключается ТОЛЬКО когда нужно) - Описание что делать при миграции БД (надо раз в год на мажорных апдейтах)
Так вы не заставляете агента каждый раз читать инструкцию по миграции базы, когда он просто красит кнопку. Хороший постоянный файл – короткий и тонкий. Он не должен быть энциклопедией проекта. Его задача – задать базовые рельсы:
# CLAUDE.md Project: iOS app, Swift, MVVM. Before final answer: run unit tests when code changed. Don't change public API without explicit approval. Don't edit generated files. Prefer minimal patches over broad refactors. If task needs rare workflow, check available skills.
С глаз долой, из сердца вон
Старый чат кажется полезной памятью, но часто становится мусором. В нём остаются старые цели, отменённые решения, промежуточные ошибки, ваши прошлые «нет, не так» и куски логов, которые уже не относятся к делу. Если новая задача не связана с предыдущей, начинайте новый сеанс или делайте /clear кода, когда:
задача завершена;
следующая задача из другой области;
старый контекст не нужен для будущего решения;
агент начал ссылаться на то, что уже неактуально.
Когда использовать лучше использовать /compact:
задача длинная;
контекст ещё нужен;
детали можно сжать до summary;
вы готовы проверить, что summary не потерял важные запреты.
Когда выгружать в текстовый артефакт:
решение понадобится позже;
это архитектурная договорённость;
это список известных ограничений;
это результат исследования, который жалко потерять после
/clear.
Пример команды:
Summarize current decisions into docs/agent-notes/auth-refresh.md Include: - accepted decisions - rejected options - open questions - files touched Don't add new recommendations.
Мастер на все руки
Основной агент должен держать в голове задачу, решение и ограничения. Не надо заставлять его одновременно читать 2000 строк логов, три страницы документации, issue-тред и код.
Как оркестратор работает, делая всё сам:
Сам читает 12 логов, находит паттерны, смотрит документацию, проверяет security rules, возвращается и исправляет баг. К моменту, когда вернулся исправлять баг, уже переполнился контекст, он его сжал и забыл половину того, что читал ранее.
Как оркестратор работает, делегируя задачи:
Запускает log-reader-agent -> получает краткий пересказ только того, что нужно.
Запускает doc-reader-agent -> задаёт нужные вопросы по документации.
Понимает, что код требует скилла безопасности -> загружает code-writer-agent, делегирует ему написать код, используя /secutiry-rules.
Перепроверяет сборку через скрипт assemble-project.sh, видит ошибки, запускает code-researcher-agent, просит разобраться, в чём дело, делегирует процесс чистки кодовой базы, снова code-writer-agent.
Отдаёт код на валидацию пользователю.
Пушит в remote repo через git-агента или git-скилл.
Оркестратор всё ещё также пишет код и принимает важные решения, но теперь поток его «мыслей» не засорён работой, которую он делает, что позволяет ему эффективнее понимать задачу и видеть её на макроуровне – как тимлид в живой человеческой команде, который эффективен как раз потому, что он в контексте процессов, а не в контексте реализации.
Просто делай – просто будет
Агенты лучше работают с простыми прямыми промптами, особенно если задача тоже простая. Не нужно plan mode или OpenSpec использовать всегда и везде по-умолчанию. Это хорошее решение для больших задач, для мелких намного лучше работает банально попросить что-то сделать, например:
Покрасить кнопку? (просто заменить цвет напрямую в коде)
Малая задача, лучше просто попроситьПодвинуть кнопку?
Уже посложнее, если UI комплексный, то могут быть конфликты, можно попробовать через встроенный в Claude Code plan mode, а можно и просто написать «сделать».Добавить уже свёрстанный экран в приложение?
Определённо задача среднего калибра, надо разобраться, как работает навигация, идеально через plan mode, OpenSpec может быть излишен, но тоже можно.Сверстать по дизайну экран и добавить?
Сложная большая задача, надо и дизайн посмотреть, и сверстать, и интегрировать, и ничего не сломать по пути, лучше всего через OpenSpec уже.
Избегайте по возможности цифровой бюрократии, чтение виртуальных бумажек и текста мешает агенту точно так же, как вас бесит чтение настоящих бумажек, если задача не подразумевает такого масштаба. Вы же не хотите заполнять 50 страниц договора, чтобы просто купить пирожок?
Eval-Driven Development
Любая статистика и аналитика касательно вашего использования лимитов, агента и инструментария – это операционные метрики, а не просто интересные циферки. И Anthropic, и OpenAI настаивают на eval-driven development – это методология создания ПО, при которой разработка управляется количественными метриками и автоматическими тестами, а не интуицией или визуальной проверкой. Я писал об этом в статье «Как я перестал писать убер-промпты...» в разделе про мета-промптинг, но не давал там явное определение.
Стартовый набор метрик, которые стоит собирать в рамках работы над одной задачей:
количество затраченных на задачу токенов (позволяет потом считать соотношение сложности задачи с реальными затраченными на неё ресурсами)
количество автоматических компактизаций (высокое число сигнализирует о частом переполнении контекста, возможно, что-то стоит декомпозировать)
прочитанное/изменённое количество файлов (позволит ловить ситуации, когда агент читает сильно больше, чем ему реально нужно, и засоряет контекст)
количество пойманных prompt injections (позволит не только предотвращать атаки, но и понимать, откуда они пришли)
Метрики можно и нужно калибровать под ваш конкретный проект и ваши потребности. Для улучшения системы недостаточно сильного желания и энтузиазма, нужны данные и сбор метрик – это сбор таких данных.
Реальные примеры
Anthropic: одна retrieval-подсказка подняла long-context recall с 27% до 98%
В эксперименте с Claude 2.1 Anthropic добавили всего одну фразу – «Here is the most relevant sentence in the context» – и получили скачок качества с 27% до 98%. Подсветить важное часто полезнее, чем просто дать больше контекста.
OpenAI: Sora for Android за 28 дней с Codex
OpenAI описывает реальный запуск Android-приложения за 28 дней командой из четырёх инженеров с Codex; отдельно они упоминают пользу ~/.codex/AGENTS.md, где было описано, где лежат локальные репозитории и что в них находится. Это «учебник» того, как внешний к модели контекст надо сначала организовать в системе, а потом уже ожидать качества от агента.
OpenAI: текстовые артефакты лучше инструкций на словах
Команда OpenAI прямо писала, что им пришлось «проталкивать всё больше контекста в репозиторий», чтобы агент мог продумать его, а не жить на сообщениях из Slack и устных договорённостях. Это практически важнее любой промпт-магии: если знание не достижимо для агента, оно технически не существует в проекте.
Ограничения и открытые вопросы
У этой темы нет универсальных чисел. Ни Anthropic, ни OpenAI не дают «магического» размера промпта, количества проб и ошибок, порога compaction или единственного правильного соотношения между количеством команд и правил. Их общая позиция – подбирать это через живые метрики на живом проекте. Поэтому любые конкретные пороги в продакшене должны считаться не best practice вообще, а best practice для вашего проекта вашего репозитория.
Вторая открытая зона – структура и масштабируемость. Не надо строить систему на надежде, что «модель сама всё аккуратно продумает внутри». Лучше требовать внешние артефакты – планы, TODO, цитаты, line references, test evidence и summaries – потому что они контролируемы, сравнимы и пригодны для последующей самооценки.
Лучшая гигиена контекста – это умение сделать контекст тонким, проверяемым, структурированным и объяснимым в первую очередь для машины, а не для человека.
