Качество работы LLM — функция от качества контекста на входе. Это утверждение звучит банально, однако зачастую разработчики оптимизируют модель, выбирая между GКачество работы LLM — функция от качества контекста на входе. Это утверждение звучит банально, однако зачастую разработчики оптимизируют модель, выбирая между G

Слепое пятно LLM-разработки: контекст за пределами кода

2026/03/15 18:15
12м. чтение
Для обратной связи или замечаний по поводу данного контента, свяжитесь с нами по адресу [email protected]
10dd95726bf0fa807b1cb0bb1a648e04.png

Качество работы LLM — функция от качества контекста на входе. Это утверждение звучит банально, однако зачастую разработчики оптимизируют модель, выбирая между GPT, Claude, Gemini и прочими, и промпт, но не контекст в целом. Между тем, разница между "агент с правильным контекстом" и "агент без контекста" — не 20% и не 50%. Эта разница находится в дистанции вариантов между "решил задачу за 5 минут" и "потратил час, сломал два сервиса, и результат пришлось откатить из-за массы новых проблем".

Я solo-разработчик. В моей экосистеме десятки актуальных проектов: платформа из десятков микросервисов, AI-инференс кластер на неспецифическом железе типа mac studio и dgx spark, масса shared-библиотек, инфраструктура на нескольких физических и десятках виртуальных хостов.

Последний год "пишу" код почти исключительно через LLM и Cursor. Начинал с deepseek на уровне "подскажи как написать функцию для ..." и дошел до полноценной оркестрации на Claude 4.6: я формулирую задачу, агент анализирует условия и кодовую базу, обсуждаем архитектурный план, агент пишет код и тесты, запускает тесты, исправляет ошибки, получает от меня обратную связь по результатам ручной проверки.

Это работает хорошо, когда агент глубоко понимает контекст. И катастрофически плохо, когда контекста недостаточно. Эта статья — про то, как я решаю проблему контекста системно.

Оговорка о применимости

Описанная методология разрабатывалась и обкатывалась на одной из наиболее сильных моделей для работы с кодом — Claude 4.6 Opus с контекстным окном в миллион токенов. Это важно зафиксировать: большое окно контекста означает, что агент физически способен "увидеть" knowledge base, а сильные аналитические способности модели позволяют извлечь из неё пользу, а не утонуть в шуме.

Даже на такой модели разница между "с workbench" и "без workbench" оказалась существенной — и именно это стало основанием для формализации подхода. Если структурированный контекст заметно улучшает и без того сильную модель, можно предположить, что для менее мощных моделей — с меньшим окном или слабее — он может быть ещё важнее: у них меньше способности компенсировать отсутствие контекста "сообразительностью".

Однако практической проверки на open source моделях или моделях с меньшим окном контекста я не проводил. Вероятно, потребуется адаптация: более компактные документы, приоритизация контекста, возможно — автоматическая выборка релевантных фрагментов вместо подключения всей knowledge base. Это остаётся открытым вопросом, и если у кого-то из читателей есть опыт подобных экспериментов — это интересно обсудить.

Проблема: эфемерная память

У LLM-агентов нет долговременной памяти. Это фундаментальное свойство архитектуры на текущем уровне развития технологий: каждый чат — изолированный контекст, который исчезает после завершения сессии. Cursor Rules и system prompts дают агенту характер (конвенции, стиль, ограничения), но не дают знаний о системе — историю решений, архитектуру, состояние проектов.

Для одного проекта это терпимо: ключевая часть кодовой базы помещается в контекст, README описывает основные моменты, агент ориентируется используя небольшой объем контекстного окна и времени на вызов инструментов. Но когда проектов десятки и они связаны — каждая сессия начинается с фазы ориентации, на которую уходят лишние токены и время. Агент не знает без дополнительных усилий:

  • Что проект использует шину данных для коммуникации, а не REST

  • Что два месяца назад был отвергнут Redis в пользу NATS KV Store и почему

  • Что один из проектов намеренно остановлен из-за ограничений используемой БД

  • Что другой проект — это legacy, который находится в процессе замены

  • Какие shared-библиотеки существуют и какая кодовая база их использует

Отсутствие системного контекста порождает четыре класса ошибок:

1. Повторение отвергнутых решений. Без истории решений агент зачастую предлагает то, что уже было рассмотрено и отвергнуто. Из сессии в сессию. "Давайте используем Redis для кэширования" — мы уже это обсуждали два месяца назад, вот почему не Redis.

2. Нарушение неявных контрактов. В распределённой системе изменение в одном сервисе может сломать несколько других. Агент без информации о топологии зависимостей может изменить формат сообщения, не зная, что его читают потребители вне контекста текущей сессии.

3. Потеря времени на ориентацию. Без навигационных документов существенная часть сессии уходит на рекогносцировку: "какие файлы отвечают за X", "где конфигурация Y", "как деплоится Z".

4. Generic-код вместо идиоматического. Без знания конвенций проекта агент пишет в стиле "среднего по больнице": camelCase вместо snake_case, axios вместо project-specific api_request(), console.log вместо structured logger.

Cursor Rules (.cursor/rules/) частично решают проблему — проектные конвенции, anti-patterns, стек. Но rules — это про один проект. Всё иначе, когда нужно, чтобы агент понимал систему целиком: как проекты связаны, какие решения приняты, что в каком состоянии.

Принципы контекста

Контекст должен быть постоянным (persistent), структурированным (structured) и находиться рядом с кодовой базой (co-located).

Если контекст теряется между сессиями — ему нужно обеспечить долговременное хранение. Если контекст хранится хаотично — его нужно структурировать. Если контекст лежит в отдельном инструменте (wiki, Notion, Google Docs) — LLM-агент его не видит. Значит, контекст должен лежать рядом с кодом, в формате, который агент может прочитать.

Из этих принципов вытекает следующий вариант решения: один git-репозиторий с документацией по всей системе, подключаемый вторым (или дополнительным) корнем в IDE.

Я назвал его workbench. Он подключается еще одним корнем в каждый workspace через .code-workspace файл:

{ "folders": [ { "name": "front-app", "path": "/path/to/generic/front-app" }, { "name": "workbench", "path": "/path/to/meta/workbench" } ] }

Агент видит и код текущего проекта, и весь контекст — в одном окне. Не нужно переключаться, не нужно copy-paste, не нужно "прочитай этот документ из Notion".

Архитектура базы знаний: два измерения организации

Документация различается по двум независимым параметрам, и оба влияют на то, как её организовать.

Scope — масштаб применимости. Одни документы касаются конкретного проекта: его бэклог, план миграции, заметки по расследованию бага. Другие — пересекают границы проектов: карта серверов, справочник shared-библиотек, архитектурные решения, затрагивающие несколько сервисов. Если кросс-проектное знание лежит внутри одного проекта, остальные его не видят.

Lifecycle — скорость устаревания. Бэклог проекта устаревает за недели по мере реализации. Описание протокола взаимодействия — возможно, за месяцы. Архитектурное решение сохраняет актуальность годами. Если свалить документы с разным жизненным циклом в одну папку, быстро станет невозможно понять, чему доверять: актуален ли этот план, или это артефакт прошлого периода.

На практике эти два измерения коррелируют: проектная документация чаще бывает быстроживущей, а кросс-проектная — долгоживущей. Но совпадение не полное: стратегический план по конкретному проекту может жить месяцами, а кросс-проектный бэклог обновлений зависимостей — устаревать за недели. Тем не менее, для верхнеуровневой структуры scope оказывается более надёжным критерием: он определяет, где искать документ, в то время как lifecycle определяет, насколько ему доверять.

Отсюда основное разделение — по scope:

workbench/
├── projects/<name>/ Документация конкретного проекта
│ ├── service-alpha/ Архитектура, бэклоги, планы
│ ├── frontend/ UI планы, improvements
│ └── compute-engine/ Migration plan, протокол

├── domains/ Кросс-проектные знания
│ ├── platform/ Реестр, топология, CI, решения
│ ├── infrastructure/ Железо, модели, инциденты
│ └── engineering/ Практики разработки

├── tools/ Скрипты валидации и автоматизации
├── workspaces/ .code-workspace файлы
└── .cursor/rules/ Глобальные cursor rules

projects/<name>/ — документация, привязанная к конкретному репозиторию: планы, бэклоги, логи рабочих сессий, заметки по расследованию проблем. При работе с конкретным сервисом агент заглядывает в его проектную папку за контекстом.

domains/<topic>/ — знания, пересекающие границы проектов: карта серверов, справочник библиотек, стратегические планы, архитектурные решения. Нужно агенту независимо от того, в каком проекте идёт работа.

Scope определяет навигацию: "как деплоить сервис X" — ищется в projects/X/, а "какие серверы вообще существуют" — в domains/platform/topology.md. А lifecycle определяет доверие: документ с пометкой "обновлён 3 месяца назад" в projects/ — повод для подозрения, в domains/ — скорее всего, нормально.

Единый реестр проектов

В системе из десятков сервисов знание о состоянии разработки каждого из них неизбежно рассыпается: версия — в package.json, сервер деплоя — в CI-конфигурации, статус — в голове разработчика. Агент не может собрать это из разрозненных источников за разумное время. Нужен один документ, агрегирующий ключевые факты по всем проектам.

В моём workbench эту роль выполняет Project Registry — таблица, где по каждому проекту собрано:

Поле

Что даёт агенту

Версия в репо vs версия в production

Видит рассинхронизацию

Сервер и способ деплоя

Знает куда и как деплоить

Наличие CI/CD

Знает, есть ли pipeline

Зависимости от shared-библиотек

Видит граф зависимостей

Статус: active / legacy / stopped

Не тратит время на неактуальный код

На практике это означает: задача "добавь streaming результатов в подсистему бэктестинга" не начинается с рекогносцировки. Агент смотрит в реестр и сразу видит, какие сервисы задействованы, на чём они написаны, где развёрнуты и как взаимодействуют. Без реестра та же ориентация занимала бы минуты вызовов инструментов и намного большее окно контекста.

Архитектурные диаграммы в текстовом формате

Визуализация архитектуры — стандартная практика. Но выбор формата определяет, кто её потребитель. draw.io создаёт бинарный файл — LLM его не прочитает. Mermaid — текстовый, но описывает структуру декларативно, а не визуально: чтобы понять диаграмму, её нужно отрендерить. Для knowledge base, ориентированной на LLM, нужен формат, который читается как текст и при этом передаёт топологию.

ASCII-диаграммы — компромисс, который работает:

frontend UI ──→ backend API ──→ orchestrator

┌───────────────────┼──────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ worker-1 │ │ worker-2 │ │ worker-3 │
│ 24 cores │ │ 512 cores│ │ 512 cores│
└──────────┘ └──────────┘ └──────────┘

У этого формата есть и другие достоинства помимо LLM-совместимости: diff-friendly в git, рендерится в любом контексте (терминал, чат, email), не зависит от внешних инструментов. В моём workbench несколько таких диаграмм — по основным подсистемам. Агент видит, как данные текут через систему, не задавая вопросов.

Память о принятых решениях: ADR

У каждого проекта — и тем более у системы из десятков проектов — есть история архитектурных развилок: что рассматривали, что выбрали, что отвергли и почему. У человека эта память живёт в голове, в истории переписок, в wiki. LLM не имеет доступа ни к чему из этого — и потому будет раз за разом предлагать варианты, которые уже были рассмотрены и отвергнуты. Причём каждый раз — убедительно аргументируя, потому что вариант может выглядеть сильным в изоляции, если не учитывать контекст конкретной системы: её ограничения, зависимости между компонентами, историю эксплуатации и причины, по которым альтернатива не подошла.

Architecture Decision Records (ADR) — способ сделать эту память явной и доступной. Суть формата — не в тяжёлой бюрократии, а в четырёх полях:

- Контекст — что происходило, какая проблема решалась
- Рассмотренные варианты — что оценивали, с плюсами и минусами
- Решение — что выбрали и почему
- Условия пересмотра — когда решение стоит переоценить

Последнее поле — ключевое. Без него ADR фиксирует прошлое, с ним — задаёт условия для будущего пересмотра. Пример:

# ADR-001: СУБД для аналитического pipeline ## Контекст Текущая СУБД не поддерживает оконные функции для near-realtime агрегации. ## Варианты A. Оптимизация текущей СУБД — ограничение фундаментальное, не решается настройкой B. ClickHouse + потоковый ETL — полноценный SQL, materialized views C. TimescaleDB — на порядок медленнее на аналитике тиковых данных ## Решение Выбран вариант B. ## Условия пересмотра Текущая СУБД добавит оконные функции и continuous aggregation.

Без ADR агент предложит "а давайте попробуем вариант C". С ADR — увидит, что C уже рассматривался, и при необходимости задаст правильный вопрос: "условия пересмотра не изменились?". Без ухода сессии в нежелательное пространство вариантов.

Несколько ретроспективных ADR по ключевым развилкам системы — и цикл "обсудить → забыть → обсудить заново" разорван.

Разделение по уровням значимости: от общего к частному

Есть знания, общие для всех проектов: стиль кода, подход к обработке ошибок, формат коммитов. И есть специфика конкретного проекта: какие API-обёртки использовать, какие паттерны запрещены в этой кодовой базе. Если смешать оба уровня в одном месте, при каждом новом проекте придётся заново описывать общие правила. Если разделить — общее наследуется автоматически.

В Cursor этот принцип реализуется через иерархию правил:

workbench/.cursor/rules/ → Общие для всех проектов workbench.mdc → Структура системы, навигация robust-implementation.mdc → Defensive coding, анализ blast radius project/.cursor/rules/ → Специфичные для проекта project-overview.mdc → Стек, модули, команды запуска anti-patterns.mdc → Что запрещено в этом проекте git-commits.mdc → Формат коммитов

Общие правила из workbench действуют в каждом workspace. Проектные могут ужесточить, но не ослабить. Пример общего правила:

> Не использовать console.log для ошибок. На фронтенде — console.error с префиксом модуля, на бэкенде — structured logger сервиса.

Пример проектного ограничения:

> Не вызывать fetch() напрямую из компонентов. Использовать обёртку api_request(), которая добавляет retry, нормализацию ошибок и заголовки авторизации.

Агент получает оба уровня и генерирует код, соответствующий конвенциям — без напоминаний.

Параллельные сессии и когнитивная нагрузка

При работе с LLM естественный ритм — несколько проектов параллельно: один в активном фокусе, в остальных агент работает автономно и ждёт ревью. Узкое место в этом процессе — не LLM, а человек. Нужно мгновенно отличать окна друг от друга, чтобы не отправить промпт не в тот проект и не сбиться с "потока".

Простое решение — визуальная кодировка workspace. В каждом .code-workspace задаётся уникальный цвет заголовка окна и статус-бара:

"workbench.colorCustomizations": { "titleBar.activeBackground": "#2d1f3d", "statusBar.background": "#2d1f3d" }

Цвета назначаются по ассоциации с проектом: фронтенд — фиолетовый (цвет UI), Rust-сервис — оранжевый, сервис автоматизации — зелёный. Приглушённые тёмные тона, различимые периферийным зрением. Взгляд на полоску внизу экрана — и контекст переключился. Эта мелочь экономит когнитивный ресурс, который лучше потратить на содержательное ревью.

Что это меняет на практике

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

Без knowledge base: "Расскажи про архитектуру подсистемы бэктестинга" → минуты на поиск по файлам, чтение разрозненных README, уточняющие вопросы.

С knowledge base: Агент открывает реестр, видит задействованные сервисы и их связи, читает топологию для понимания потоков данных, заглядывает в план проекта для деталей. Через короткое время он ориентируется и может работать.

Без ADR: "Может, перейдём на другую СУБД?" → повторение дискуссии, которая уже была три месяца назад, с теми же выводами. Или забег по старым "граблям".

С ADR: Агент видит, что альтернатива рассматривалась и отвергнута. Задаёт единственный нужный вопрос: «условия пересмотра не изменились?» — ответ занимает секунды.

При нескольких рабочих сессиях в день разница накапливается в часы. Это не абстрактная «продуктивность» — это конкретное время, которое уходит на решение задач вместо повторения пройденных шагов.

Для следующих частей есть наработки - как не дать knowledge base устареть: автоматическая валидация, агрегация бэклогов, жизненный цикл документов. Мета-ловушки рекурсивной оптимизации и как с ними бороться.

Источник

Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу [email protected] для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.