Как ставить задачи LLM-агентам: от абстракции к детерминированному результату
Раскрываю секреты эффективного взаимодействия с LLM-агентами, чтобы они работали как опытные разработчики.
Что такое LLM-агенты?
Это инструмент, который принимает на вход набор токенов и генерирует на выходе последовательность токенов (слов, изображений и т.д.). Важно отметить, что у LLM по умолчанию нет памяти между вызовами: каждый чат формирует новый контекст, хотя существуют системные промпты и проекты, позволяющие сохранять контекст.
Отличие LLM от LLM-агентов
В основе LLM-агентов лежат те же базовые LLM (например, open-source QN или DeepSeek). Однако агенты обладают дополнительными возможностями:
- Описание инструментов: Агент знает, какие инструменты ему доступны.
- Использование инструментов: Он умеет передавать контекст при каждом вызове LLM и выполнять последовательность действий для достижения результата.
Принцип работы агентов: Reason and Act. Этот паттерн, популярный во фреймворке LangChain, заключается в следующем:
- Reasoning (размышление): Агент анализирует задачу, думает, какие инструменты использовать и строит предположения.
- Act (действие): Вызывает выбранный инструмент.
- Получение результата: Инструмент возвращает результат.
- Валидация: Агент проверяет, как результат действия изменил реальный мир (например, файловую систему) и получил ли он новое знание.
Этот процесс повторяется, формируя "траектории" действий. Концепция Chain of Thoughts усиливает этот подход, позволяя LLM рассуждать и проверять каждый шаг. Более продвинутая техника Tree of Thoughts (SpreeLsoot) подразумевает построение нескольких траекторий (асинхронный граф DAG), выполнение их параллельно и выбор лучшего результата на основе сравнения.
Популярные LLM-агенты
Такие инструменты, как Cloud Code, Cursor, Junie, работают на основе описанных принципов Reason and Act, Chain of Thoughts и SpreeLsoot, позволяя выполнять сложные задачи: от идентификации в Telegram до написания кода, его проверки и тестирования.
Почему агенты "выдают не то"?
Представим задачу: «Добавить уведомления в Telegram при создании заказа в интернет-магазине на Python.»
В начале работы агент имеет лишь:
- Системный промпт с его ролью и общими указаниями (если он вообще заполнен).
- Промпт по формату результата (если описан).
- Контекст нескольких файлов, с которыми он работал ранее (техническое ограничение, контекст быстро заполняется).
Многие разработчики не уделяют должного внимания системным промптам. Важно подчеркнуть, что роль агента (например, «опытный разработчик») критически важна, так как она отсеивает неподходящие решения и влияет на качество генерируемого кода.
Пример не оптимальной траектории
Агент может построить траекторию, которая приведет к результату, но с серьезными побочными эффектами. Например, он может синхронно вызывать API Telegram в основном потоке обработки заказа. Это приведет к тому, что:
- При недоступности API Telegram, заказы будут потеряны.
- К каждому заказу добавится 2 секунды задержки.
Для агента такой результат будет считаться удовлетворительным, но для реального проекта это неприемлемо.
Основные причины, по которым агенты "выдают не то":
- Абстрактная задача: Недостаточная детализация задачи вынуждает агента принимать слишком много решений самостоятельно, что увеличивает вероятность ошибки.
- Недостаточный контекст: Агент не знает архитектуру проекта, принятые решения, стиль кода, ожидания разработчика. Он опирается на данные, на которых был обучен в интернете, что не всегда соответствует специфике проекта.
- "Стажер в первый день": Агент похож на талантливого, но неопытного стажера. Он умеет программировать, но не знает особенностей вашего проекта и ваших ожиданий.
- Потеря контекста: Из-за технических ограничений (размер контекстного окна) агент может "забыть" предыдущие инструкции, если контекст закончится, и начать двигаться в неправильном направлении.
Структурирование, контекст и контроль
1. Превращаем абстрактные задачи в измеримые и проверяемые
Вместо абстрактной задачи, необходимо предоставить агенту развернутое описание с ограничениями и ожидаемым результатом. Например, для задачи с Telegram-уведомлениями:
- Условие: Если API Telegram недоступен, должна использоваться очередь.
- Критерий успеха: Работа с API очереди не должна увеличивать общее время обработки заказа.
Такая задача содержит: цель, границы (что можно и нельзя), метрики успеха, и описание артефактов, которые должны быть получены на каждом шаге. Чем лучше описаны шаги и способы их проверки, тем точнее будет результат.
Пример декомпозиции задачи
Сложную задачу можно разбить на атомарные шаги:
- Дизайн архитектуры: Результат — документация по интеграции с Telegram.
- Имплементация: Создание нового модуля.
- Интеграция: Встраивание модуля в процесс оформления заказа.
- Тестирование: Написание тестов.
- Валидация: Проверка ключевых метрик (что не сломался основной сценарий).
Критерии успеха для каждого шага критически важны. Они дают агенту ориентиры для проверки и помогают ему строить более точные цепочки рассуждений и действий.
2. Структурированный промптинг и шаблоны
LLM обучены на структурированных данных (XML, HTML, YAML, JSON). Поэтому агенты лучше воспринимают задачи, представленные в структурированном формате. Это помогает им четко понимать ограничения, действия и критерии.
Универсальный шаблон задачи. Создайте универсальный шаблон задачи (YAML, JSON), который вы будете использовать для всех комплексных задач. Это позволяет стандартизировать процесс и каждый раз формулировать задачи понятным для агента образом.
Делегирование LLM. Вы можете попросить одну LLM-ку (или самого агента) заполнить этот шаблон на основе вашего абстрактного запроса. Это экономит время и позволяет получить структурированную задачу, которую затем можно дополнить и передать агенту.
3. Управление контекстом проекта: MemoryBank
Проблема отсутствия контекста проекта (архитектура, кодовая база) решается с помощью MemoryBank. Это специальные файлы (например, .md), которые автоматически загружаются при начале сессии агента и предоставляют ему актуальные знания о проекте. Важно, что даже если модель была обучена на кодовой базе, знания быстро устаревают, поэтому динамический MemoryBank незаменим.
В MemoryBank можно описать:
- Общая структура проекта: Интернет-магазин на Python FastAPI, количество пользователей, пиковая нагрузка, архитектура (монолит).
- Принятые решения: Например, использование асинхронных фоновых задач.
- Технический стек: Используемые библиотеки, фреймворки. Это поможет агенту понять, что Telegram-уведомления должны быть асинхронными.
- Стиль кода и стандарты: Как генерировать код, хранить токены (например, в .env файлах), именования.
- Конкретные примеры: Как используются очереди, как хранятся секреты.
Разветвленная файловая структура MemoryBank позволяет агенту навигироваться и загружать только нужные подмножества знаний для конкретной задачи, оптимизируя контекст (например, только раздел orders, если задача касается заказов).
4. Сохранение промежуточных результатов и артефактов
Агенты часто сталкиваются с проблемой потери контекста из-за его ограниченного размера. Это приводит к тому, что незавершенные задачи "обрываются".
Проблема потери контекста. Агент может предложить какое-то решение, но в процессе работы контекст заканчивается. Он просит "запустить компакт" или говорит, что "conversation слишком большой". В этот момент вся проделанная работа теряется.
Решение: Явное сохранение промежуточных результатов на файловую систему. Просите агента сохранять:
- План решения: в .md файл.
- Новый модуль: в соответствующий файл.
- Конфиги: в .yaml или .json.
- Неочевидные артефакты: Отчеты о прохождении тестов, патчи изменений.
Файлы — это постоянная память агента. Организация артефактов в папочной структуре (например, для каждого запуска агента своя папка) позволяет:
- Сравнивать траектории: Оценивать работу разных промптов или подходов.
- Отказоустойчивость: При сбое агент может возобновить работу с последнего сохраненного шага, используя артефакты как входные данные.
Рекомендуемые форматы для артефактов:
- JSON: Для передачи структурированных данных между шагами.
- Markdown (.md): Для человекочитаемых описаний и документации.
- Patch/Diff: Недооцененный формат для сохранения последовательности изменений файла в текстовом виде. Агент формирует патч, а затем специальный инструмент применяет его одним действием, что снижает риск ошибок.
- YAML: Для конфигов и системных настроек.
5. Явное описание шагов и пайплайнов
Прописывание шагов (pipelines) позволяет явно определить, что агент должен получить на каждом этапе, а также входные и выходные данные для каждого шага. Это дает следующие преимущества:
- Воспроизводимость: Четко прописанная траектория обеспечивает стабильный результат.
- Параллельное выполнение: Агент может запускать долгие задачи параллельно, сокращая время выполнения.
- Отказоустойчивость: В случае сбоя агент может перезапустить работу с конкретного шага, используя сохраненные артефакты.
- Прозрачность: Позволяет понять текущее состояние комплексной задачи и отследить прогресс.
Автоматические проверки
Типичные ошибки агентов:
- Потеря контекста между шагами.
- Неполное применение изменений (особенно при работе с патчами).
- Игнорирование ограничений проекта.
- Неправильная валидация промежуточных результатов.
Как помочь агенту избежать этих ошибок:
- Явная передача контекста: Через файлы, с возможностью остановки при потере контекста.
- Работа с патчами: Сохранять патчи отдельно и применять их одной командой.
- Проверка ограничений: Просить агента проверять ограничения на каждом шаге.
- Автоматические тесты: Самое мощное средство.
Агенты и автотесты
Агенты прекрасно умеют пользоваться интерпретаторами Python/JavaScript, писать скрипты проверок и автотесты. Они могут:
- Сравнивать результаты проверок: Запускать тест, сохранять "бейслайн", применять изменения, запускать тест снова и сравнивать результаты.
- Создавать отчеты с доказательствами: Для подтверждения выполнения задачи.
Для задачи с Telegram-уведомлениями, агент может написать тест, который измеряет задержку при N запросах, а затем проверить, что после изменений метрики не ухудшились.
Прописанные критерии успеха (например, "производительность улучшилась или не изменилась") помогают агенту не только выполнить задачу, но и написать конкретный тест, запустить его, проанализировать числовые результаты и составить отчет. Это повышает прозрачность и позволяет нам лучше понять, на основе чего агент сделал вывод о выполнении критериев.
Как ставить задачу агенту как стажёру.
- Цель: Конкретная и измеримая.
- Контекст: Достаточный, но не избыточный.
- Стандарты: Описаны (стиль кода, именования).
- Шаги: Конкретные, без большого пространства для творчества.
- Артефакты: Описаны для каждого шага (проверки, результаты).
- Критерии успеха: Ясные, желательно с цифрами.
- Автоматические проверки: Указан способ валидации (например, какой тест написать).
Чек-листы — еще один недооцененный формат для агентов. Они хорошо работают с текстовыми чек-листами, могут проверять пункты и ставить отметки.
LLM как помощник для улучшения задач
Вы можете использовать другую LLM-ку, чтобы она проанализировала вашу задачу по предложенному чек-листу, указала на отсутствующие элементы и предложила улучшения.
Использование LLM и агентов как инструмент, как IDE. Чем более открыто ставить задачу, тем менее детерминированный получится результат.
Два подхода:
- Открытая постановка (исследовательский процесс): Подходит, когда мы сами не знаем, какой результат хотим получить, и используем LLM для поиска идей, исследования.
- Жесткая траектория (инструментальный подход): Идеален, когда мы точно знаем, что нам нужно, много раз решали подобную задачу и хотим получить максимально эффективный результат.
LLM как судья
Существует общепризнанный способ валидации: LLM as a judge. В контейнерах запускаются разные агенты (или одна модель с разными траекториями/промптами). Полученные результаты затем передаются более развитой LLM (например, если работали с Qwen 3.2b, валидирует более крупная LLaMA). Судья сравнивает результаты по заданным критериям и определяет, какая траектория или параметры были лучше.
Этот подход использовался, например, при тренировке моделей DeepSeek.
Чек-лист эффективной постановки задач для LLM-агентов
Следуйте этим шагам, чтобы получать детерминированные и качественные результаты от ваших агентов.
Подготовка задачи
Определить конкретную и измеримую цель. Избегайте абстракций, четко формулируйте, что должен сделать агент.
Описать границы и ограничения задачи. Укажите, что можно делать, а что нельзя (например, "использовать очередь, если API недоступно").
Указать метрики успеха и критерии валидации. Как будет измеряться успех задачи, например, "не увеличивать время обработки заказа".
Использовать структурированный формат для задачи (YAML, JSON, Markdown) для лучшего восприятия агентом.
Управление контекстом и траекторией
Предоставить достаточный, но не избыточный контекст (MemoryBank). Описать архитектуру, техстек, стандарты, примеры кода в MD-файлах.
Определить явные шаги или пайплайны выполнения задачи. Разбить большую задачу на атомарные, последовательные действия.
Описать входные и выходные артефакты для каждого шага. Что агент должен получить и сохранить на каждом этапе (план, код, конфиги, отчеты).
Просить агента сохранять промежуточные результаты на файловую систему. Использовать файлы (MD, JSON, Patch) как постоянную память для отказоустойчивости.
Верификация и контроль
Требовать написания автоматических тестов. Для проверки логики и подтверждения выполнения критериев успеха.
Использовать LLM для улучшения постановки задач. Позволить другой LLM анализировать и предлагать улучшения для вашей задачи по чек-листу.