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

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

В статье разберём, что это такое, чем она отличается от промпт-инжиниринга, RAG и MCP и какие приёмы помогают агенту не путаться в длинных сценариях.

С подготовкой статьи помог:

Иван Родин

AI-инженер в Andersen Lab, преподаватель на расширенном курсе «Data Scientist» в Нетологии

Что такое контекстная инженерия простыми словами

Anthropic определяет контекст так: 

«Context refers to the set of tokens included when sampling from a large-language model (LLM)». 

То есть контекст — это набор токенов, который передаётся LLM.

В этот набор входит не только сообщение пользователя. Там могут быть системные инструкции, история сообщений, документы из внешних источников, описания инструментов, которые модель может вызвать (tools), результаты вызова, данные из памяти и всё остальное, что приложение добавило в запрос к модели.

Для контекстной инженерии Anthropic даёт определение: «the set of strategies for curating and maintaining the optimal set of tokens during LLM inference». То есть набор приёмов, которые помогают собрать и поддерживать оптимальный контекст во время работы модели.

Ключевое слово здесь — «оптимальный». Anthropic пишет, что хороший контекст — это «the smallest possible set of high-signal tokens». Минимальный набор полезных токенов, который повышает шанс получить нужный результат.

Чем контекстная инженерия отличается от промпт-инжиниринга

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

Термин стал распространяться именно на фоне развития AI-агентов. В отличие от разового запроса, агент делает цепочку шагов. Поэтому перед каждым вызовом приходится заново решать, какие документы, инструменты, история и результаты прошлых шагов попадут в контекст LLM.

Контекстная инженерия vs RAG vs MCP: в чём разница

RAG, MCP и контекстную инженерию часто упоминают рядом, потому что все три термина встречаются в LLM-приложениях и агентских сценариях. Но это разные понятия. Агент может работать без RAG, не использовать MCP. Разберём это подробнее.

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

MCP — это протокол, который стандартизирует подключение модели к внешним данным и инструментам. Через MCP-сервер приложение может дать агенту доступ к инструментам (тулам), ресурсам и промптам (tools, resources и prompts). Например, агент может выполнить поиск в интернете или файловой системе, запустить определённую функцию или программу и обработать эти результаты. 

То есть MCP отвечает за канал доступа: откуда агент может получать данные и какие действия может выполнять.

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

Если коротко: RAG приносит знания, MCP подключает источники и инструменты, а контекстная инженерия решает, как всё это собрать в контекст для следующего шага агента.

Из чего состоит контекст LLM-агента

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

Он собирается из разных источников: пользователь пишет запрос, команда заранее задаёт правила и инструменты, а сам агент во время работы подтягивает данные.

Разберём эти слои чуть подробнее.

Пользовательский запрос

Это текущая задача, с которой человек приходит к агенту: вопрос, команда, описание проблемы или просьба выполнить действие. Запрос задаёт направление для ответа. 

Системный промпт

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

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

Tools

Tools (тулы) — это инструменты, которые модель может вызвать: например, поиск по базе, запрос к API, чтение файла или создание задачи в трекере.

Модель выбирает инструмент по тому, как он описан в контексте. Поэтому важны название, описание и параметры. Если у нескольких тулов похожие названия и размытые docstring — строки документации с описанием функции или инструмента, — модель будет хуже понимать, что выбрать.

Few-shot примеры

Few-shot — это несколько примеров прямо в промпте: как должна выглядеть хорошая цепочка действий или итоговый ответ.

Такие примеры помогают модели повторить нужный паттерн. Но это не место для списка всех edge cases — нестандартных ситуаций, на которых логика может сломаться. Обычно достаточно 2–3 типовых примеров: как выбрать инструмент, что делать при ошибке, как оформить результат.

Данные из RAG

RAG добавляет в контекст внешние знания: фрагменты документации, статьи из базы знаний, куски wiki или README из репозитория.

Здесь важны не только сами документы, но и их объём, свежесть и связь с текущей задачей. Если RAG достал не тот фрагмент, модель может принять его за полезный контекст и построить ответ не на тех данных.

История сообщений и tool calls

Tool calls — это прошлые вызовы инструментов и их результаты.

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

Память

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

Память не обязательно целиком лежит в контекстном окне. Часто она хранится отдельно и подгружается, когда нужна для ответа.

Текущее состояние

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

Scratchpad — это рабочие заметки агента: что он уже сделал, какие гипотезы проверил, какие данные получил и что осталось уточнить. Например: «проверил статус задачи через API», «не нашёл запись в базе», «нужно запросить комментарии за последнюю неделю».

Часть состояния можно держать в контексте, а часть — хранить отдельно и подключать, когда она нужна для следующего шага.


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

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

Chroma в отчёте Context Rot проверила 18 моделей, включая GPT-4.1, Claude 4, Gemini 2.5 и Qwen3, и показала: при росте используемого контекста качество может проседать даже на простых задачах. Поэтому «поместилось в окно» не равно «помогло агенту».

Почему агент начинает ошибаться: четыре сценария сбоя контекста

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

Дрю Брейниг, стратег в Overture Maps Foundation и автор практических материалов о контекстной инженерии для O’Reilly, в статье How Long Contexts Fail выделяет четыре типичных сбоя: context poisoning, context distraction, context confusion и context clash. Для разработчика это удобная карта логов: по ней проще понять, почему агент ошибается.

Context poisoning — отравление контекста

В контекст попала ошибка, и агент начал обращаться с ней как с фактом.

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

Что искать в логах: один и тот же ложный факт повторяется несколько шагов подряд. Например, агент снова обращается к несуществующей таблице, старому endpoint или выдуманному статусу, хотя tool call уже показал, что этого нет.

Context distraction — отвлечение на длинный контекст

Нужная информация есть в контексте, но теряется среди старой истории и промежуточных результатов.

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

Что искать в логах: модель игнорирует свежий tool result, возвращается к предыдущему сценарию или ведёт себя так, будто важного фрагмента не было во входе.

Context confusion — путаница из-за лишних вариантов

В контексте слишком много похожих инструментов, документов или инструкций, и модель выбирает не то.

Например, несколько тулов делают почти одно и то же, называются похоже и описаны слишком общо. Модель не понимает, какой инструмент нужен сейчас, и начинает перебирать варианты. С документами из RAG происходит то же самое: лишний похожий фрагмент может увести ответ в сторону.

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

Для таких сценариев полезно смотреть на бенчмарки function calling, например, Berkeley Function Calling Leaderboard: они проверяют, насколько точно модели выбирают и вызывают функции.

Context clash — конфликт внутри контекста

Разные части контекста противоречат друг другу, а правила приоритета не заданы.

Например, системная инструкция требует брать данные из CRM, пользователь просит свериться с таблицей, RAG приносит старую документацию, а tool возвращает свежий статус из базы. Если не указать, какой источник главнее, модель может смешать всё сразу.

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

Близкую проблему разбирали Microsoft Research и Salesforce в исследовании LLMs Get Lost In Multi-Turn Conversation: в многошаговых диалогах модели часто слишком рано фиксируют предположения и потом продолжают на них опираться.

Здесь помогает не просто сокращение контекста, а явные правила приоритета: свежий tool result важнее старой истории, системная инструкция важнее пользовательской догадки, актуальный ответ API важнее устаревшего документа.

Что делать с контекстом дальше

Когда в логах понятно, где сломался контекст, следующий вопрос: как лучше собрать его перед новым вызовом модели. Для этого можно опереться на подход, который описывает LangChain. LangChain — это open-source экосистема для разработки LLM-приложений и агентов. В гайде по context engineering они сводят работу с контекстом к четырём действиям: write, select, compress и isolate. 

Это звучит абстрактно, но на практике всё просто: что сохранить, что выбрать, что сжать и что вынести в отдельный контекст.

Write — сохранить важное

Не всё нужно держать прямо в контекстном окне. Часть информации лучше записывать во внешнее состояние: summary, результаты шагов, найденные факты, пользовательские настройки.

Например, агент проверил задачу в трекере: нашёл статус, ответственного и последний комментарий клиента. Дальше не обязательно передавать модели весь лог вызовов. Достаточно сохранить короткое состояние:

Задача PROJ-142 открыта.
Ответственный — Анна.
Последний комментарий от клиента был 12 июня.
Нужно проверить макет.

Так агент не теряет важные факты, но не тащит за собой всю историю.

Select — выбрать нужное

Перед каждым вызовом модели нужно решить, что ей показать сейчас.

У агента может быть доступ к истории, памяти, базе знаний и десяткам tools. Но для конкретного шага обычно нужна только часть этого набора.

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

Select снижает шум: чем меньше лишних вариантов видит модель, тем выше шанс, что она выберет правильное действие.

Compress — сжать длинное

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

Вместо десяти сообщений обсуждения можно оставить короткое summary:

Пользователь выбирает CRM.
Вариант A исключили из-за цены.
Остались B и C.
Нужно проверить интеграцию с телефонией и экспорт данных.

Хорошее сжатие не просто укорачивает текст. Оно сохраняет то, что нужно для следующего шага: цель, ограничения, проверенные факты и открытые вопросы.

Isolate — вынести отдельно

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

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

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

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

Практика: собираем контекст для ответа перед релизом

Разберём условный пример и покажем на нём сам принцип: как из доступных данных собрать оптимальный контекст для следующего вызова модели.

Возьмём задачу чуть сложнее, чем «покажи статус задачи», но без лишней архитектуры. Допустим, агент помогает подготовиться к релизу. Пользователь спрашивает:

Что с фичей PAY-482? Можно включать её в релиз?

Чтобы ответить, модели нужно понять, что это за фича, кто за неё отвечает, есть ли блокеры и что осталось проверить.

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

Ниже — упрощённый пример на Python с MCP Python SDK.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("release-assistant")

FEATURES = {
    "PAY-482": {
        "title": "Новый сценарий оплаты картой",
        "owner": "Анна",
        "planned_release": "2026-06-28",
        "status": "ready_for_qa",
        "last_comment": "Нужно перепроверить мобильный сценарий оплаты",
    }
}

BLOCKERS = {
    "PAY-482": [
        {
            "id": "BUG-911",
            "severity": "high",
            "title": "Повторная оплата создаёт два списания",
            "status": "fixed_waiting_retest",
        }
    ]
}


@mcp.resource("feature://{feature_id}")
def get_feature(feature_id: str) -> str:
    feature = FEATURES.get(feature_id)

    if not feature:
        return "Feature not found"

    return (
        f"Feature: {feature_id}\n"
        f"Title: {feature['title']}\n"
        f"Owner: {feature['owner']}\n"
        f"Planned release: {feature['planned_release']}\n"
        f"Status: {feature['status']}\n"
        f"Last comment: {feature['last_comment']}"
    )


@mcp.tool()
def get_blockers(feature_id: str) -> list[dict]:
    return BLOCKERS.get(feature_id, [])


if __name__ == "__main__":
    mcp.run(transport="stdio")

В этом коде важны не детали MCP, а то, какие данные агент может получить перед вызовом модели.

  1. FEATURES — условное хранилище фич. В реальном проекте вместо словаря был бы запрос в трекер, например, Jira или внутреннюю систему.

  2. BLOCKERS — список проблем, которые мешают релизу. В нашем примере у фичи есть баг с высокой критичностью: повторная оплата создаёт два списания. Статус fixed_waiting_retest означает, что разработчики уже внесли исправление, но QA ещё не подтвердили, что проблема ушла.

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

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

Теперь посмотрим, какой контекст можно собрать из этих данных.

Плохой вариант — передать модели всё подряд: весь релизный бэклог, все баги проекта, всю историю комментариев и все доступные инструменты. Формально информации много, но для ответа на вопрос про PAY-482 большая часть будет шумом.

Более аккуратный контекст выглядит так:

Feature: PAY-482
Title: Новый сценарий оплаты картой
Owner: Анна
Planned release: 2026-06-28
Status: ready_for_qa
Last comment: Нужно перепроверить мобильный сценарий оплаты

Blockers:
BUG-911 — high — Повторная оплата создаёт два списания — fixed_waiting_retest

Instruction:
Подготовь короткий статус по фиче.
Ответь в трёх пунктах: текущий статус, риски, следующий шаг.
Если есть блокер без ретеста, не пиши, что фичу можно включать в релиз.

Здесь остался только рабочий минимум: нужная фича, её владелец, ближайшая дата релиза, последний важный комментарий и блокер, который влияет на решение.

На этом примере видно, как работают приёмы из предыдущего раздела.

  1. Select: агент выбирает только данные по PAY-482, а не весь релизный бэклог.

  2. Compress: вместо длинной истории обсуждения в контекст попадает один последний комментарий, который влияет на следующий шаг.

  3. Write: после ответа можно сохранить короткое состояние: «PAY-482 ждёт ретест BUG-911, включать в релиз пока нельзя». Если пользователь продолжит диалог, агенту не придётся заново восстанавливать всё из сырых данных.

  4. Isolate: если нужно подробно разобрать BUG-911, это можно сделать отдельным шагом. Основному агенту не обязательно видеть всю историю бага — достаточно вернуть вывод: исправление есть, но ретест ещё не пройден.

Итоговый ответ модели на таком контексте может быть таким:

1. Текущий статус: PAY-482 готова к QA, владелец — Анна.

2. Риск: есть блокер BUG-911 с высокой критичностью. Исправление уже внесли, но ретест ещё не пройден.

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

Что проверить, если агент всё равно ошибается

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

Вот что ещё важно для корректного ответа:

  1. Качество источников. Если в базе знаний лежит старая инструкция, агент может достать её через RAG и уверенно использовать в ответе. Поэтому для важных сценариев нужны даты обновления, приоритеты источников и правило, что делать при конфликте: например, свежий ответ API важнее старого документа.

  2. Поведение tools. Хорошее описание не поможет, если инструмент возвращает слишком общий результат, не сообщает об ошибке явно или смешивает несколько сущностей в одном ответе. В логах должно быть видно, какой tool вызван, с какими параметрами и что он вернул.

  3. Проверка на типовых сценариях. Если агент работает только на одном красивом демо, рано говорить о надёжности. Нужны тесты (evals): что он делает при устаревшем документе, пустом результате поиска, конфликте источников, похожих tools и длинной истории.

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

Кто на рынке занимается контекстной инженерией и сколько за это получает

Отдельной профессии «контекстный инженер» нет. Но похожие обязанности уже встречаются в вакансиях AI Engineer, ML Engineer, LLM Engineer и backend-разработчиков, которые внедряют LLM в продукт.

В таких ролях могут ждать, что специалист умеет работать с RAG, настраивать tool calls, управлять памятью агента, собирать контекст из разных источников, тестировать агентные сценарии и разбираться, почему модель дала неправильный ответ.

Зарплатная вилка зависит от роли, уровня и компании — тут всё как обычно. На июль 2026 года Хабр Карьера показывает среднюю зарплату специалиста AI около 190 000 ₽, а ML-разработчика — около 229 000 ₽.

☝️ Пара советов от эксперта

Сначала попробуйте готовых агентов

Перед тем как делать своих AI-агентов, стоит самому поработать с Claude Code, Cursor, Codex или GitHub Copilot.

Посмотрите, какие тулы они используют, где ошибаются, как учитывают пользовательские инструкции, что меняется после подключения MCP-серверов. Так проще понять реальные ограничения агентов и увидеть, как их обходят в уже работающих продуктах.

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

Собирайте агентов для pet-проектов

Следующий шаг — сделать своего агента на небольшой задаче. Не нужно сразу строить сложную систему. Можно начать с ассистента, который анализирует заметки на компьютере, помогает с календарём, собирает summary по документам или ищет нужные файлы.

Pet-проекты хорошо показывают, из чего на практике состоит агентский сценарий. Если опыта в разработке мало, можно начать с make.com или n8n — сервисов, где простые автоматизации собираются из готовых блоков без полноценного backend.

В статье мы остались на прикладном слое — как собирать контекст, чтобы агент не путался. Дальше начинается инженерия вокруг него: RAG с векторными базами, архитектура агентов, мониторинг качества и деплой. Этому учат на курсе «Специалист по ИИ» для действующих IT-специалистов — программа рассчитана на тех, у кого уже есть опыт в разработке.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Как вы боретесь с деградацией агента на длинном контексте?
50%Сжимаю историю в саммари2
0%Отбираю только нужные tools и данные0
25%Выношу подзадачи в отдельный контекст1
0%Задаю правила приоритета источников0
0%Пока никак — просто расширяю окно0
25%Не строю агентов1
Проголосовали 4 пользователя. Воздержались 2 пользователя.