Контекстный инжиниринг для LLM: управление агентскими системами в продакшн | AiManual
AiManual Logo Ai / Manual.
02 Янв 2026 Гайд

Контекстный инжиниринг: как избежать хаоса в продакшн-системах с LLM

Практическое руководство по контекстному инжинирингу для стабильной работы LLM-агентов в продакшне. Реальные проблемы и работающие решения.

Контекстный хаос: когда ваши агенты начинают жить своей жизнью

Помните ту статью про агентов, которые тупят и забывают инструкции? Молитесь, чтобы она осталась для вас просто интересным чтением. Потому что если ваши LLM-агенты в продакшне начали вести себя странно — поздравляю, вы попали в контекстный ад.

Разработчики приходят ко мне с одинаковыми историями. Вчера агент прекрасно отвечал на вопросы клиентов. Сегодня он начал советовать покупать конкурентов. На тестовых данных всё работает идеально. В продакшне — непредсказуемый хаос. Промпты те же, модели те же, код не менялся. Что пошло не так?

Контекст съел вашу систему. И я сейчас не про token limit.

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

Почему контекст ломает всё

У LLM нет памяти. Нет состояния. Нет понимания «сессии» в человеческом смысле. Каждый запрос — это новая вселенная, где модель видит только то, что вы ей скормили в этом конкретном промпте.

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

Модель пытается найти паттерны в этом супе. И находит. Только не те, которые вы хотели.

1 Диагностика: ваш контекст болен?

Проверьте эти симптомы:

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

Если хотя бы два пункта совпали — у вас проблемы с контекстным инжинирингом. Не с промптами. Не с моделью. С контекстом.

Архитектура контекста: как не утонуть в токенах

Первый и самый очевидный совет — «используйте RAG». Второй и самый бесполезный. Потому что RAG не решает проблему управления контекстом. Он её усугубляет.

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

💡
Проблема не в количестве информации. Проблема в её структуре. Сырые тексты из RAG для LLM — это как пытаться найти иголку в стоге сена, предварительно перемешав стог бетономешалкой.

2 Стратификация контекста: разделяй и властвуй

Нельзя сваливать всё в одну кучу. Контекст нужно структурировать. Я использую четыре слоя:

Слой Что содержит Приоритет
Системный Роль агента, основные инструкции, ограничения Всегда первый, никогда не удаляется
Сессионный Цель текущей сессии, состояние диалога Обновляется, но не удаляется полностью
Оперативный Результаты последних действий, текущий контекст Циклический буфер, старые данные удаляются
Референсный Данные из RAG, справочная информация Фильтруется и сжимается перед добавлением

Давайте посмотрим, как это работает в коде. Сначала — как НЕ надо делать:

# ПЛОХО: всё в одну кучу
context = [
    system_prompt,
    *history,
    rag_results,
    current_question,
    "Пожалуйста, ответь на вопрос выше"
]

response = llm.generate(context)

Теперь правильный подход:

# ХОРОШО: стратифицированный контекст
class StratifiedContext:
    def __init__(self, llm):
        self.llm = llm
        self.system_layer = []
        self.session_layer = []
        self.operational_layer = []
        self.reference_layer = []
        
    def add_to_system(self, instruction):
        # Системный слой — только самое важное
        if len(self.system_layer) > 5:
            # Сжимаем старые инструкции
            self.compress_system_layer()
        self.system_layer.append(instruction)
        
    def add_to_reference(self, rag_chunks):
        # Не просто добавляем, а фильтруем и сжимаем
        compressed = self.compress_rag_chunks(rag_chunks)
        # Оставляем только самые релевантные
        self.reference_layer = compressed[:3]  # максимум 3 чанка
        
    def build_context(self):
        # Собираем слои в правильном порядке
        return [
            "# СИСТЕМНЫЕ ИНСТРУКЦИИ",
            *self.system_layer,
            "\n# ТЕКУЩАЯ СЕССИЯ",
            *self.session_layer,
            "\n# ОПЕРАТИВНЫЙ КОНТЕКСТ",
            *self.operational_layer[-5:],  # только последние 5
            "\n# СПРАВОЧНАЯ ИНФОРМАЦИЯ",
            *self.reference_layer
        ]

Контекстная амнезия и как с ней бороться

Самая большая проблема в агентских системах — потеря контекста между агентами. Агент А что-то узнал, передал результат агенту Б, а тот начинает с чистого листа.

Вы думаете: "Ну так передавайте весь контекст!" Нельзя. Потому что тогда у вас будет interpretation drift на стероидах.

Решение — контекстные снимки (snapshots). Каждый агент создаёт сжатое резюме того, что он узнал. Не сырые данные. Не полный контекст. Резюме.

class Agent:
    def create_context_snapshot(self):
        """Создаёт сжатый снимок контекста для передачи другому агенту"""
        
        prompt = f"""
        Ты — агент {self.role}. 
        Ты узнал следующую информацию в ходе текущей задачи:
        
        {self.get_operational_context()}
        
        Создай краткое резюме (максимум 3 предложения) самой важной информации, 
        которая нужна следующему агенту для продолжения работы.
        Игнорируй технические детали, оставь только суть.
        """
        
        summary = self.llm.generate(prompt)
        return {
            "agent": self.role,
            "summary": summary,
            "timestamp": time.time()
        }

Это работает лучше, чем передача сырого контекста. Почему? Потому что LLM лучше справляются с обработкой структурированных резюме, чем с анализом сырых диалогов.

Токены дорогие: как экономить без потери качества

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

Вот что работает на практике:

3 Динамическое сжатие контекста

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

def compress_conversation_history(history, current_focus):
    """
    Сжимает историю диалога с учётом текущего фокуса задачи.
    
    :param history: список сообщений [{"role": "user/assistant", "content": "..."}]
    :param current_focus: на чём сейчас сфокусирована задача
    :return: сжатая история
    """
    
    compression_prompt = f"""
    Ты — компрессор контекста. Твоя задача — сократить историю диалога, 
    сохранив только информацию, релевантную текущему фокусу: {current_focus}
    
    История диалога:
    {history}
    
    Инструкции по сжатию:
    1. Удали все приветствия, прощания и формальности
    2. Сохрани факты, решения и действия
    3. Удали повторяющуюся информацию
    4. Объедини похожие идеи
    5. Максимальная длина результата — 200 слов
    
    Верни только сжатую версию, без дополнительных комментариев.
    """
    
    return llm.generate(compression_prompt)

Этот подход даёт сжатие в 3-5 раз без потери ключевой информации. Но есть нюанс: нужно делать это асинхронно, параллельно с основным выполнением задачи.

Контекстные ловушки: что убивает вашу систему

Есть три смертных греха контекстного инжиниринга. Избегайте их как огня.

Грех 1: Смешивание уровней абстракции. Нельзя класть в один контекст технические инструкции по API и философские размышления о цели проекта. LLM запутается.

Грех 2: Контекстное загрязнение. Когда каждый агент добавляет в контекст свои внутренние мысли, отладочную информацию, промежуточные вычисления. Через 10 итераций контекст превращается в свалку.

Грех 3: Слепая конкатенация. Просто склеивать всё подряд — самый быстрый путь к катастрофе. Если вы делаете context += new_info без разбора — готовьтесь к сюрпризам.

Продакшн-паттерны: что работает в реальных системах

Теория — это хорошо. Но что работает на практике? Вот паттерны, которые я использую в продакшн-системах:

Паттерн 1: Контекстные шлюзы

Перед тем как добавить что-то в контекст, это что-то должно пройти через шлюз. Шлюз решает: добавлять, сжать или отклонить.

class ContextGateway:
    def __init__(self, max_tokens_per_layer):
        self.max_tokens = max_tokens_per_layer
        
    def evaluate_addition(self, new_content, layer_type):
        """Оценивает, стоит ли добавлять контент в контекст"""
        
        evaluation_prompt = f"""
        Оцени релевантность следующего контента для слоя {layer_type}:
        
        Контент: {new_content}
        
        Верни JSON:
        {
            "should_add": true/false,
            "priority": 1-10,
            "suggested_compression": "как сжать, если нужно",
            "reason": "почему такое решение"
        }
        """
        
        decision = llm.generate(evaluation_prompt, parse_json=True)
        return decision

Паттерн 2: Контекстные версии

Контекст меняется со временем. То, что было важным час назад, может быть нерелевантным сейчас. Храните версии контекста и умейте откатываться.

class VersionedContext:
    def __init__(self):
        self.versions = []
        self.current_version = 0
        
    def save_version(self, context, metadata):
        """Сохраняет версию контекста"""
        snapshot = {
            "version": self.current_version,
            "context": copy.deepcopy(context),
            "metadata": metadata,
            "timestamp": time.time(),
            "hash": self._calculate_hash(context)
        }
        self.versions.append(snapshot)
        self.current_version += 1
        
        # Храним только последние 10 версий
        if len(self.versions) > 10:
            self.versions.pop(0)
            
    def rollback(self, version):
        """Откатывается к предыдущей версии контекста"""
        for v in self.versions:
            if v["version"] == version:
                return v["context"]
        return None

Паттерн 3: Контекстные теги

Помечайте каждый кусок контекста тегами: "факт", "инструкция", "предположение", "результат". Это помогает фильтровать и реорганизовывать контекст на лету.

def tag_context_chunk(chunk):
    """Автоматически тегирует кусок контекста"""
    
    tagging_prompt = f"""
    Проанализируй следующий текст и определи его тип:
    
    Текст: {chunk}
    
    Возможные типы:
    - FACT: объективный факт, данные
    - INSTRUCTION: инструкция, что делать
    - ASSUMPTION: предположение, гипотеза
    - RESULT: результат выполнения
    - METADATA: мета-информация, не влияющая на задачу
    - NOISE: шум, можно удалить
    
    Верни только тип тега.
    """
    
    tag = llm.generate(tagging_prompt).strip()
    return {"content": chunk, "tag": tag, "timestamp": time.time()}

Мониторинг и отладка: как понять, что контекст сломался

Вы не можете ждать, пока пользователи пожалуются. Нужно мониторить здоровье контекста в реальном времени.

Метрики, которые я отслеживаю:

  • Контекстная энтропия: как быстро растёт беспорядок в контексте
  • Коэффициент сжатия: насколько эффективно сжимается история
  • Тэг-распределение: какой процент контекста — полезная информация vs шум
  • Контекстный дрейф: как меняется семантика контекста со временем
class ContextMonitor:
    def calculate_entropy(self, context):
        """Вычисляет энтропию контекста (грубая оценка)"""
        # Простая эвристика: чем больше уникальных слов на токен, тем выше энтропия
        words = re.findall(r'\w+', str(context))
        unique_words = set(words)
        
        if len(words) == 0:
            return 0
            
        return len(unique_words) / len(words)
    
    def check_health(self, context):
        """Проверяет здоровье контекста"""
        entropy = self.calculate_entropy(context)
        
        metrics = {
            "entropy": entropy,
            "token_count": self.count_tokens(context),
            "tag_distribution": self.get_tag_distribution(context),
            "health_score": 0
        }
        
        # Вычисляем оценку здоровья
        if entropy > 0.8:
            metrics["health_score"] -= 30
        if metrics["token_count"] > 8000:
            metrics["health_score"] -= 20
        
        metrics["health_score"] = max(0, 100 + metrics["health_score"])
        
        return metrics

Локальные модели vs облачные: есть ли разница для контекста?

Да. Огромная. Локальные модели через Ollama часто имеют меньший эффективный контекст, чем заявлено. То, что работает с GPT-4 с контекстом 128K, сломается с локальной моделью на 8K.

Но есть и плюс: с локальными моделями вы можете делать то, что с облачными слишком дорого. Например, постоянная перекомпрессия контекста или множественные проходы для его очистки.

💡
Если вы используете локальные LLM, ознакомьтесь с этой статьей про оптимизацию llama.cpp. Задержки в 3 минуты убивают любую интерактивную систему.

Что делать сейчас: чек-лист на сегодня

  1. Проверьте, нет ли в вашем контексте смешения уровней абстракции
  2. Внедрите хотя бы базовую стратификацию (системный слой отдельно от оперативного)
  3. Начните тегировать контекст — это самый быстрый способ понять, что в нём происходит
  4. Установите лимиты на каждый слой контекста и соблюдайте их
  5. Добавьте мониторинг энтропии контекста в ваши дашборды

Контекстный инжиниринг — это не про написание идеальных промптов. Это про управление информационным потоком в системе, которая по своей природе не имеет памяти. Это про создание искусственной памяти там, где её нет. Про поддержание порядка в хаосе токенов.

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

Если через месяц ваши агенты снова начнут странно себя вести — не удивляйтесь. Просто вернитесь к этому руководству и проверьте, не нарушили ли вы какие-то принципы. Контекст имеет свойство загрязняться. Даже у самых дисциплинированных LLM.