Главная / Статьи

Инжиниринг промптов или инжиниринг контекста, механизмов и циклов? Отладка ИИ-агентов по слоям

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

Издатель: REACTAPP.TOP14 мин чтения3236 слов

Источники: Prompt Engineering vs Context Engineering vs Harness Engineering vs Loop Engineering: Why Your Agent Breaks and Which Layer Actually Broke It

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

Четыре уровня ИИ-агента в кратком изложении

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

Большинство дорогостоящих сбоев агентов возникают из-за устранения проблем в неправильном из этих слоёв.

Когда демо-версия работает, а продакшн — нет

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

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

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

PACT: ассоциативная помощь для запоминания четырех слоев

Компактный способ запомнить эти слои во время инцидента — PACT: Prompt, Awareness, Control, Trajectory. Каждое слово соответствует определенному вопросу:

  • Prompt: была ли задача четко определена?
  • Awareness: получил ли модель информацию, необходимую для выполнения этого шага?
  • Контроль: может ли среда выполнения безопасно и надежно выполнить то, о чем просит модель?
  • Траектория: движется ли процесс, повторяющийся снова и снова, к завершению, которое можно проверить?

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

Как появились эти уровни и почему важен порядок

Эти термины появились примерно в таком порядке, по мере того как агенты обретали новые возможности:

  • Инжиниринг промптов (примерно с 2022 по 2024 год) был первым навыком: формулировка запросов, примеры, ограничения и шаблоны для работы с небольшим количеством примеров с целью одного вызова модели.
  • Инженерия контекста (примерно с 2024 по 2025 год) стала важной темой, когда агенты начали одновременно обрабатывать полученные документы, историю разговоров и определения инструментов. Вопросы сместились от способа сформулировки запроса к тому, что на самом деле видит модель. Компании Anthropic, LangChain и Chroma способствовали распространению этого подхода среди специалистов, а комментарии Андрея Карпати помогли включить его в более широкие инженерные дискуссии.
  • Инженерия управления ресурсами (начало 2026 года) получила приоритет, когда у агентов появился доступ к файловой системе, возможность выполнять команды терминала и длительные операции. Внимание сосредоточилось на диапазоне действий агента и на его поведении после неудачного вызова инструмента. Работа OpenAI над Codex сделала этот аспект ключевым для кодирующих агентов; их описание инженерии управления ресурсами с использованием Codex является полезным основным источником информации.
  • Инженерия циклов (середина 2026 года) — это самая новая категория. Даже при наличии соответствующей инфраструктуры всё равно необходимо определить, что делать на каждой итерации и когда прекратить процесс: наблюдать, действовать, проверять, повторять или останавливаться. IBM предоставляет пояснения по инженерии циклов, если вам нужна дополнительная информация.

Указанные даты относятся к моменту, когда эти термины стали популярными, а не к официальным вехам; к моменту написания этого текста терминология всё ещё находится в стадии формирования. Важно отметить, что ничего не было заменено — каждый новый уровень добавлялся поверх предыдущего, поскольку каждое увеличение автономности требовало собственной системы управления.

Инженерия промптов: локальный контракт

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

В кодинговом агенте промпт для проверки кода может выглядеть следующим образом:

SYSTEM: You are a code reviewer.
Given a diff, output ONLY valid JSON:
{"issues": [{"line": int,
"severity": "low|medium|high", "note": str}]}
No prose. No markdown fences.
If there are no issues, return {"issues": []}.

Этот промпт устанавливает локальный контракт. Он назначает роль, описывает процесс преобразования (разницу входных и выходных данных, список выявленных проблем), фиксирует структуру вывода до уровня названий полей и допустимых значений степени серьезности, а также определяет сценарий пустого входа, чтобы последующая обработка никогда не сталкивалась с прозой или отсутствием ключей.

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

Инжиниринг контекста: кураторство в рамках бюджета

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

Создатель контекста для кодингового агента может извлекать кандидаты, переориентировать их по значимости и сжимать историю операций:

def build_context(query, full_history, kb):
    relevant = retrieve(query, kb, top_k=8)
    reranked = rerank(relevant, query)[:3]
    summary = summarize_if_long(
        full_history, max_tokens=800
    )
    return {
        "docs": reranked,
        "history": summary,
        "query": query,
    }

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

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

Инжиниринг контекста — это нечто большее, чем RAG

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

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

Инженерия использования ресурсов: граница между намерением и результатом

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

Пример обёртки для вызова инструмента иллюстрирует эту идею:

def call_tool(tool_name, args, retries=2):
    for attempt in range(retries + 1):
        try:
            result = TOOLS[tool_name](**args)
            log_trace(tool_name, args, result, status="ok")
            return result
        except ToolError as e:
            log_trace(tool_name, args, str(e), status="failed")
            if attempt == retries:
                return {"error": str(e), "recoverable": False}
            args = repair_args(args, e)

Этот обёртывающий механизм не пытается решить задачу самостоятельно. Он определяет границу между тем, что запросил модель, и тем, что делает реальная система. Каждая попытка отслеживается вместе с её аргументами, результатом и статусом. При сбое запускается ограниченное количество повторных попыток с исправленными аргументами, и по истечении всех попыток возвращается структурированная ошибка с пометкой о невозможности восстановления; таким образом вызывающий код получает данные, с которыми можно работать, вместо исключения, прерывающего выполнение.

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

Инженерия циклов: контракт завершения

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

Минимальный контроллер выглядит следующим образом:

def run_loop(task, harness, max_iters=15, stall_limit=3):
    state = init_state(task)
    stalls = 0
    for i in range(max_iters):
        action = plan_next_step(state)
        result = harness.call_tool(action.tool, action.args)
        state = update_state(state, result)
        if is_goal_met(state):
            return state, "success"
        if made_no_progress(state):
            stalls += 1
            if stalls >= stall_limit:
                return state, "stalled — escalate"
        else:
            stalls = 0
    return state, "max iterations reached"

Здесь применяется несколько уровней ограничений. max_iters определяет максимальное количество итераций, is_goal_met позволяет завершить работу при достижении цели, а счётчик застоя отслеживает последовательные итерации без прогресса, сбрасываясь при возобновлении движения вперёд. После stall_limit итераций в состоянии застоя цикл возвращает специальный статус, требующий усиления мер, вместо того чтобы продолжать работу без действий. Каждый путь выхода содержит чёткую причину, что облегчает последующую классификацию запусков.

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

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

Четыре слоя рядом

  • Подсказка (P): содержит инструкцию. Типичная проблема: модель неправильно понимает намерение или возвращает данные неверного формата. Сначала следует проверить сам результат.
  • Контекст (A): содержит данные, готовые к использованию моделью. Типичная проблема: модель использует устаревшую, отсутствующую или отвлекающую информацию. Сначала следует проверить кадры контекста за каждый шаг.
  • Хаб (C): отвечает за выполнение и восстановление. Типичная проблема: ошибка при вызове инструмента, слепая попытка повтора или невозможность восстановления. Сначала следует проверить записи о сбоях в трассе выполнения инструмента.
  • Цикл (T): определяет ход выполнения и момент остановки. Типичная проблема: агент никогда не достигает конвергенции и никогда не останавливается. Сначала следует проверить повторные успешные вызовы с практически идентичными аргументами.
  • Как отличить ошибку инструментария от ошибки цикла

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

    1. Просмотреть трассу вызовов инструментов

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

    2. Поиск повторяющихся сбоев инструментов

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

    3. Проверьте, что может видеть модель

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

    4. Проверьте результат в конце

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

    Ориентир для принятия решений

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

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

    Пример из практики: рецензент pull-request, который не останавливается

    Представьте команду, выпускающую агента для кодирования, который проверяет pull-request. Тестирование проходит гладко. Однако в производственной среде некоторые проверки занимают более 40 минут на один pull-request, что приводит к неожиданным счетам.

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

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

    Это не проблема с запросом, не проблема с контекстом и не проблема с фреймворком; инструменты вели себя ровно так, как было запланировано. Это чисто баг в виде цикла. Пошаговый анализ позволяет прийти к такому выводу.

    Шаг 1: подтвердить работоспособность инструментов

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

    Шаг 2: сравнение состояния между итерациями

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

    Шаг 3: проверка на сходимость

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

    Шаг 4: обучение контроллера обнаружению застоя

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

    if progress_signature == previous_signature:
        stagnant_steps += 1
    else:
        stagnant_steps = 0
    
    if stagnant_steps >= 3:
        escalate("no measurable progress")
        stop()
    

    progress_signature может представлять собой что угодно, что отражает значимый прогресс, например набор неудачных тестов вместе с их сообщениями об ошибках. Если этот параметр не меняется, счетчик застоя увеличивается; после трех таких шагов контроллер передает информацию о причине и останавливается. Любые реальные изменения сбрасывают счетчик.

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

    Пример из практики: ограничение, исчезающее из контекста

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

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

    Фраза «модель забыла» никогда не является полным диагнозом. Важный вопрос заключается в том, что именно было предоставлено модели.

    Слои, а не замены

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

    Перефразировано с использованием PACT:

    • Запрос: определение инструкции.
    • Осведомленность: формирование состояния, на основе которого будет работать модель.
    • Контроль: обеспечение прозрачности выполнения, его ограничения и возможности восстановления.
    • Траектория: преобразование повторений в измеримый прогресс, заканчивающийся проверяемым результатом.

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

    Частые вопросы о слоях агентов

    Является ли инженерия механизмов управления просто другим названием для фреймворка агентов?

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

    Требуется ли инжиниринг циклов для ассистента с одним вопросом?

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

    Какой слой следует изучать в первую очередь?

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

    Может ли одна ошибка затрагивать несколько слоев?

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

    Чек-лист для следующего инцидента с агентом

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