[Перевод] Создание эффективных агентов

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

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

Что такое агенты?

Термин «агент» можно определить несколькими способами. Некоторые клиенты определяют агентов как полностью автономные системы, которые работают независимо в течение длительного времени, используя различные инструменты для выполнения сложных задач. Другие используют этот термин для описания более регламентированных реализаций, следующих предопределённым воркфлоу (рабочим процессам). В Anthropic мы классифицируем все эти вариации как агентные системы, но проводим важное архитектурное различие между воркфлоу и агентами:

  • Воркфлоу — это системы, где LLM и инструменты оркестрируются через предопределённые пути в коде.

  • Агенты, с другой стороны, — это системы, где LLM динамически направляют собственные процессы и использование инструментов, сохраняя контроль над тем, как они выполняют задачи.

Ниже мы подробно рассмотрим оба типа агентных систем. В Приложении 1 («Агенты на практике») мы описываем две области, где клиенты обнаружили особую ценность в использовании таких систем.

Когда (и когда не) использовать агентов

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

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

Когда и как использовать фреймворки

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

  • LangGraph от LangChain;

  • AI Agent фреймворк Amazon Bedrock;

  • Rivet, конструктор рабочих процессов LLM с drag and drop интерфейсом;

  • Vellum, ещё один GUI-инструмент для создания и тестирования сложных рабочих процессов.

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

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

Смотрите наш cookbook для примеров реализации.

Базовые компоненты, воркфлоу и агентов

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

Базовый компонент: Расширенный LLM

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

Дополненный LLM

Дополненный LLM

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

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

Воркфлоу: Цепочка промптов

Цепочка промптов разбивает задачу на последовательность шагов, где каждый вызов LLM обрабатывает вывод предыдущего. Вы можете добавить программные проверки (см. «gate» на диаграмме ниже) на любых промежуточных этапах, чтобы убедиться, что процесс все еще идет по плану.

Воркфлоу цепочки промптов

Воркфлоу цепочки промптов

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

Примеры, где цепочка промптов полезна:

  • Генерация маркетингового текста с последующим переводом на другой язык.

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

Воркфлоу: Роутинг

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

Воркфлоу роутинг

Воркфлоу роутинг

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

Примеры, где роутинг полезен:

  • Передача различных типов запросов службы поддержки (общие вопросы, запросы на возврат средств, техническая поддержка) в различные нисходящие процессы, промпты и инструменты.

  • Роутинг простых/общих вопросов к младшим моделям, таким как Claude 3.5 Haiku, и сложных/необычных вопросов к более старшим моделям, таким как Claude 3.5 Sonnet, для оптимизации стоимости и скорости.

Воркфлоу: Параллелизация

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

  • Декомпозиция: Разбиение задачи на независимые подзадачи, выполняемые параллельно.

  • Консенсус: Многократное выполнение одной и той же задачи для получения разнообразных выводов.

    Воркфлоу параллелизация

    Воркфлоу параллелизация

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

Примеры, где параллелизация полезна:

  • Декомпозиция

    • Реализация ограничений (guardrails), где одна модель обрабатывает пользовательские запросы, в то время как другая проверяет их на наличие неприемлемого контента или запросов. Это обычно работает лучше, чем когда один и тот же вызов LLM обрабатывает и ограничения (guardrails), и основной ответ.

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

  • Консенсус:

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

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

Воркфлоу: Оркестратор-исполнители (orchestrator-workers)

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

Воркфлоу оркестратор-исполнителей

Воркфлоу оркестратор-исполнителей

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

Примеры, где оркестратор-исполнители полезны:

  • Решения для программирования, которые вносят сложные изменения в несколько файлов одновременно.

  • Поисковые задачи, включающие сбор и анализ информации из нескольких источников на предмет возможной релевантной информации.

Воркфлоу: Оценщик-оптимизатор (evaluator-optimizer)

В воркфлоу оценщик-оптимизатор один вызов LLM генерирует ответ, в то время как другой обеспечивает оценку и обратную связь в цикле (feedback in a loop).

Воркфлоу оценщика-оптимизатора

Воркфлоу оценщика-оптимизатора

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

Примеры, где оценщик-оптимизатор полезен:

  • Литературный перевод, где есть нюансы, которые LLM-переводчик может не уловить изначально, но где LLM-оценщик может хорошо покритиковать.

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

Агенты

Агенты появляются в продакшене по мере развития ключевых возможностей LLM — понимания сложных входных данных, рассуждений и планирования, надежного использования инструментов и восстановления после ошибок. Агенты начинают свою работу либо с команды, либо с интерактивного обсуждения с пользователем. Когда задача ясна, агенты планируют и работают независимо, потенциально возвращаясь к человеку за дополнительной информацией или оценкой. Во время выполнения критически важно, чтобы агенты получали «ground truth» из окружения на каждом шаге (такие как результаты вызова инструментов или выполнения кода) для оценки своего прогресса. Агенты могут приостанавливаться для получения обратной связи от человека на контрольных точках или при столкновении с блокерами. Задача часто завершается по достижении цели, но также обычно включает условия остановки (например, максимальное количество итераций) для поддержания контроля.

Агенты могут справляться со сложными задачами, но их реализация часто проста. Обычно это просто LLM, использующие инструменты на основе обратной связи от среды в цикле. Поэтому крайне важно четко и продуманно разрабатывать наборы инструментов и их документацию. Мы расширяем лучшие практики разработки инструментов в Приложении 2 («Промпт-инженерия ваших инструментов»).

Автономный агент

Автономный агент

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

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

Примеры, где агенты полезны:

Следующие примеры взяты из наших собственных реализаций:

  • Агент для программирования для решения задач SWE-bench, которые включают правки многих файлов на основе описания задачи;

  • Наша эталонная реализация «computer use», где Claude использует компьютер для выполнения задач.

Общий процесс работы агента для программирования

Общий процесс работы агента для программирования

Комбинирование и настройка этих паттернов

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

Заключение

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

При внедрении агентов мы стараемся следовать трем основным принципам:

  1. Поддерживать простоту в архитектуре вашего агента.

  2. Отдавать приоритет прозрачности, явно показывая этапы планирования агента.

  3. Тщательно прорабатывать интерфейс взаимодействия агента с компьютером (ACI) через подробную документацию и тестирование инструментов.

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

Благодарности

Авторы: Erik Schluntz и Barry Zhang. Эта работа основана на нашем опыте создания агентов в Anthropic и ценных идеях, которыми поделились наши клиенты, за что мы им глубоко благодарны.

Приложение 1: Агенты на практике

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

A. Клиентская поддержка (customer support)

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

  • Взаимодействия поддержки естественным образом следуют потоку (flow) разговора, требуя при этом доступа к внешней информации и действиям;

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

  • Действия, такие как возвраты или обновление тикетов, могут обрабатываться программно;

  • Успех может быть четко оценен через определенные пользователем решения.

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

B. Агенты для программирования

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

  • Решения с кодом проверяемы через авто-тесты;

  • Агенты могут итерировать решения, используя результаты тестов как обратную связь;

  • Проблемное пространство хорошо определено и структурировано;

  • Качество результата может быть измерено объективно.

В нашей собственной реализации агенты теперь могут решать реальные проблемы GitHub в бенчмарке SWE-bench Verified на основе только описания пул-реквеста. Однако, хотя автоматизированное тестирование помогает проверить функциональность, человеческая проверка остается критически важным для обеспечения соответствия решений более широким системным требованиям.

Приложение 2: Промпт-инжиниринг ваших инструментов

Независимо от того, какую агентную систему вы создаете, инструменты, вероятно, будут важной частью вашего агента. Инструменты (tools) позволяют Claude взаимодействовать с внешними сервисами и API, указывая их точную структуру и определение в нашем API. Когда Claude отвечает, он включит блок использования инструмента в ответе API, если планирует вызвать инструмент. Определениям и спецификациям инструментов следует уделять столько же внимания при промпт-инжиниринге, как и вашим общим промптам. В этом кратком приложении мы описываем, как проводить промпт-инжиниринг ваших инструментов.

Часто существует несколько способов указать одно и то же действие. Например, вы можете указать редактирование файла, написав diff, или переписав весь файл. Для structured output вы можете вернуть код внутри markdown или внутри JSON. В программировании такие различия являются косметическими и могут быть без потерь преобразованы из одного формата в другой. Однако некоторые форматы гораздо сложнее для написания LLM, чем другие. Написание diff требует знания количества изменяющихся строк в заголовке чанка перед написанием нового кода. Написание кода внутри JSON (по сравнению с markdown) требует дополнительного экранирования переносов строк и кавычек.

Наши предложения по выбору форматов инструментов следующие:

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

  • Держите формат близким к тому, что модель видела естественно встречающимся в тексте в интернете.

  • Исключите лишнюю работу по форматированию: ни подсчёта тысяч строк кода, ни возни с экранированием строк в написанном коде.

Одно эмпирическое правило — подумать о том, сколько усилий вкладывается в интерфейсы человек-компьютер (HCI), и планировать вложить столько же усилий в создание хороших интерфейсов агент-компьютер (ACI). Вот несколько мыслей о том, как это сделать:

  • Поставьте себя на место модели. Очевидно ли, как использовать этот инструмент, основываясь на описании и параметрах, или вам нужно было бы тщательно об этом подумать? Если да, то это, вероятно, верно и для модели. Хорошее определение инструмента часто включает примеры использования, редкие кейсы (edge cases), требования к формату ввода и четкие границы с другими инструментами.

  • Как вы можете изменить имена параметров или описания, чтобы сделать вещи более очевидными? Думайте об этом как о написании отличной документации для джуниор разработчика в вашей команде. Это особенно важно при использовании множества похожих инструментов.

  • Тестируйте, как модель использует ваши инструменты: Запускайте множество примеров входных данных в нашем workbench, чтобы увидеть, какие ошибки делает модель, и итерируйте.

  • Внедрите защиту от ошибок (пока-ёкэ) в ваши инструменты. Измените аргументы так, чтобы было сложнее делать ошибки.

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

© Habrahabr.ru