Узнайте, как создавать и развертывать агентов LLM, использующих инструменты, с помощью моделей JumpStart Foundation от AWS SageMaker

Узнайте, как создавать и развертывать агентов LLM с помощью JumpStart Foundation от AWS SageMaker

Большие модели языка (LLM) – это программы, которые расширяют возможности автономных LLM с помощью 1) доступа к внешним инструментам (API, функциям, вебхукам, плагинам и т. д.) и 2) возможности планирования и выполнения задач самостоятельно. Часто LLM’ы должны взаимодействовать с другими программными продуктами, базами данных или API для выполнения сложных задач. Например, административный чат-бот, который планирует встречи, потребует доступа к календарям и электронной почте сотрудников. Обладая доступом к инструментам, агенты LLM могут стать более мощными – за счет дополнительной сложности.

В этой статье мы представляем агентов LLM и демонстрируем, как создавать и развертывать агента LLM для электронной коммерции с использованием Amazon SageMaker JumpStart и AWS Lambda. Агент будет использовать инструменты для предоставления новых возможностей, таких как ответы на вопросы о возвратах (“Обработан ли мой возврат rtn001?”) и предоставления обновлений о заказах (“Можете ли вы сказать мне, отправлен ли заказ 123456?”). Для реализации этих новых возможностей необходимо, чтобы LLM’ы извлекали данные из нескольких источников данных (orders, returns) и выполняли augmented generation (RAG).

Для работы агента LLM мы используем модель Flan-UL2, развернутую как точку доступа SageMaker, и используем инструменты для извлечения данных, построенные с помощью AWS Lambda. Агент может быть интегрирован с Amazon Lex и использоваться в качестве чат-бота на веб-сайтах или в AWS Connect. Мы завершаем статью рассмотрением вопросов, которые следует учесть перед развертыванием агентов LLM в производственной среде. Для полностью управляемого опыта по созданию агентов LLM, AWS также предоставляет агенты для функции Amazon Bedrock (в предварительной версии).

Краткий обзор архитектур агентов LLM

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

Что же означает для LLM выбор инструментов и планирование задач? Существует множество подходов (например, ReAct, MRKL, Toolformer, HuggingGPT и Transformer Agents) к использованию LLM с инструментами, и прогресс происходит быстро. Но одним из простых способов является подача LLM списком инструментов и просьбой определить, 1) требуется ли инструмент для удовлетворения запроса пользователя и, если да, 2) выбрать соответствующий инструмент. Такая подсказка обычно выглядит следующим образом и может содержать примеры few-shot для повышения надежности LLM в выборе правильного инструмента.

‘’’
Ваша задача - выбрать инструмент для ответа на вопрос пользователя. У вас есть доступ к следующим инструментам.

search: поиск ответа в FAQ
order: заказ товаров
noop: инструмент не требуется

{примеры few-shot}

Вопрос: {input}
Инструмент:
‘’’

Более сложные подходы включают использование специализированного LLM, который может непосредственно декодировать “вызовы API” или “использование инструментов”, таких как GorillaLLM. Такие настроенные LLM обучаются на наборах данных спецификации API для распознавания и прогнозирования вызовов API на основе инструкций. Часто для этих LLM требуется некоторая метаданные о доступных инструментах (описания, yaml или JSON-схема для их входных параметров), чтобы выдавать вызовы инструментов. Такой подход используется агентами для Amazon Bedrock и функций OpenAI. Обратите внимание, что LLM’ы, как правило, должны быть достаточно большими и сложными, чтобы обладать способностью выбора инструментов.

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

  1. Запрос пользователя – Программа принимает ввод пользователя, например, “Где мой заказ 123456?” от некоторого клиентского приложения.
  2. Планирование следующего действия и выбор инструментов – Затем программа использует предложение, чтобы LLM сгенерировал следующее действие, например, “Используйте таблицу заказов с помощью OrdersAPI.” LLM получает запрос на выбор имени инструмента, такого как OrdersAPI, из предопределенного списка доступных инструментов и их описаний. В качестве альтернативы LLM может быть настроен на прямое создание вызова API с входными параметрами, такими как OrdersAPI(12345).
    1. Обратите внимание, что следующее действие может или не может включать использование инструмента или API. Если нет, LLM может отвечать на запросы пользователя без учета дополнительного контекста от инструментов или просто возвращать готовый ответ, например, “Я не могу ответить на этот вопрос.”
  3. Разбор запроса инструмента – Затем нам нужно разобрать и проверить предсказание инструмента/действия, предложенное LLM. Валидация необходима, чтобы убедиться, что имена инструментов, API и параметры запроса не являются вымышленными и что инструменты правильно вызываются в соответствии с спецификацией. Для этого разбора может потребоваться отдельный вызов LLM.
  4. Вызов инструмента – После того, как убедились в правильности имени инструмента(ов) и параметров запроса, мы вызываем инструмент. Это может быть HTTP-запрос, вызов функции и так далее.
  5. Разбор вывода – Ответ от инструмента может потребовать дополнительной обработки. Например, вызов API может дать длинный JSON-ответ, из которого интересны только некоторые поля для LLM. Извлечение информации в чистом, стандартизированном формате может помочь LLM более надежно интерпретировать результат.
  6. Интерпретация вывода – Исходя из вывода от инструмента, LLM снова получает запрос на его осмысление и принятие решения о том, может ли он сгенерировать окончательный ответ пользователю или требуются дополнительные действия.
  7. Завершение или переход к шагу 2 – Возврат окончательного ответа или ответа по умолчанию в случае ошибок или превышения времени ожидания.

Различные фреймворки агентов выполняют предыдущий поток программы по-разному. Например, ReAct объединяет выбор инструмента и генерацию окончательного ответа в одну подсказку, вместо использования отдельных подсказок для выбора инструмента и генерации ответа. Кроме того, эта логика может быть выполнена в один проход или выполнена в цикле while («цикл агента»), который завершается, когда генерируется окончательный ответ, возникает исключение или истекает время ожидания. Что остается постоянным, так это то, что агенты используют LLM в качестве центрального элемента для оркестрации планирования и вызовов инструментов до завершения задачи. Далее мы покажем, как реализовать простой цикл агента, используя службы AWS.

Обзор решения

В этом блоге мы реализуем агента LLM для поддержки электронной коммерции, который предоставляет две функции, основанные на инструментах:

  • Инструмент получения статуса возврата – Отвечает на вопросы о статусе возврата, такие как “Что происходит с моим возвратом rtn001?”
  • Инструмент получения статуса заказа – Отслеживает статус заказов, такие как “Каков статус моего заказа 123456?”

Агент эффективно использует LLM в качестве маршрутизатора запросов. Учитывая запрос (“Каков статус заказа 123456?”), выберите соответствующий инструмент получения для запроса в нескольких источниках данных (то есть возвраты и заказы). Мы осуществляем маршрутизацию запросов, позволяя LLM выбирать среди нескольких инструментов получения, которые отвечают за взаимодействие с источником данных и извлечение контекста. Это расширяет простой шаблон RAG, который предполагает наличие одного источника данных.

Оба инструмента получения являются функциями Lambda, которые принимают идентификатор (orderId или returnId) в качестве входных данных, извлекают объект JSON из источника данных и преобразуют JSON в строку, подходящую для использования LLM. В реальном сценарии источник данных может представлять собой высоко масштабируемую базу данных NoSQL, такую как DynamoDB, но данное решение использует простой словарь Python с образцовыми данными для демонстрационных целей.

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

Вот некоторые дополнительные детали о ключевых компонентах:

  1. Конечная точка вывода LLM – Основой программы агента является LLM. Мы будем использовать модель Flan-UL2 из SageMaker JumpStart foundation model hub для легкого развертывания. SageMaker JumpStart упрощает развертывание конечных точек вывода LLM на выделенных экземплярах SageMaker.
  2. Оркестратор агента – Оркестратор агента оркестрирует взаимодействие между LLM, инструментами и приложением клиента. Для нашего решения мы используем функцию AWS Lambda для управления этим потоком и используем следующие вспомогательные функции.
    • Планировщик задач (инструментов) – Планировщик задач использует LLM для предложения одного из 1) запроса возврата, 2) запроса заказа или 3) отсутствия инструмента. Мы используем только инженерию подсказок и модель Flan-UL2 без настройки.
    • Анализатор инструментов – Анализатор инструментов гарантирует, что предложение инструмента от планировщика задач является допустимым. Важно отметить, что мы гарантируем, что можно разобрать только один orderId или returnId. В противном случае мы отвечаем стандартным сообщением.
    • Диспетчер инструментов – Диспетчер инструментов вызывает инструменты (функции Lambda), используя допустимые параметры.
    • Анализатор вывода – Анализатор вывода очищает и извлекает соответствующие элементы из JSON в читаемую человеком строку. Эта задача выполняется как самим инструментом получения, так и оркестратором.
    • Интерпретатор вывода – Задачей интерпретатора вывода является 1) интерпретация вывода от вызова инструмента и 2) определение, может ли быть удовлетворен запрос пользователя или требуются дополнительные шаги. Если последнее, генерируется отдельный окончательный ответ и возвращается пользователю.

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

Оркестратор агента

Ниже приведена сокращенная версия цикла агента внутри функции-ламбда оркестратора агента. Цикл использует вспомогательные функции, такие как task_planner или tool_parser, для модуляризации задач. Цикл здесь спроектирован таким образом, чтобы работать максимум два раза, чтобы предотвратить зависание агента в бесконечном цикле.

#.. импорты ..
MAX_LOOP_COUNT = 2 # остановить цикл агента после максимум 2 итераций
# ... определения вспомогательных функций ...
def agent_handler(event):
    user_input = event["query"]
    print(f"ввод пользователя: {user_input}") 
    
    final_generation = ""
    is_task_complete = False
    loop_count = 0 

    # начало цикла агента
    while not is_task_complete and loop_count < MAX_LOOP_COUNT:
        tool_prediction = task_planner(user_input)
        print(f"предсказание инструмента: {tool_prediction}")  
        
        tool_name, tool_input, tool_output, error_msg = None, None, "", ""

        try:
            tool_name, tool_input = tool_parser(tool_prediction, user_input)
            print(f"название инструмента: {tool_name}") 
            print(f"ввод инструмента: {tool_input}") 
        except Exception as e:
            error_msg = str(e)
            print(f"ошибка разбора инструмента: {error_msg}")  
    
        if tool_name is not None: # если выбран и разобран допустимый инструмент 
            raw_tool_output = tool_dispatch(tool_name, tool_input)
            tool_status, tool_output = output_parser(raw_tool_output)
            print(f"статус инструмента: {tool_status}")  

            if tool_status == 200:
                is_task_complete, final_generation = output_interpreter(user_input, tool_output) 
            else:
                final_generation = tool_output
        else: # если не выбран и разобран допустимый инструмент, либо вернуть сообщение по умолчанию, либо сообщение об ошибке
            final_generation = DEFAULT_RESPONSES.NO_TOOL_FEEDBACK if error_msg == "" else error_msg
    
        loop_count += 1

    return {
        'statusCode': 200,
        'body': final_generation
    }

Планировщик задач (предсказание инструмента)

Оркестратор агента использует планировщик задач для предсказания инструмента по вводу пользователя. Для нашего агента LLM мы будем использовать промпт-инжиниринг и few-shot prompting для обучения LLM этой задаче в контексте. Более сложные агенты могут использовать откалиброванный LLM для предсказания инструмента, что выходит за рамки этого поста. Промпт выглядит следующим образом:

tool_selection_prompt_template = """
Ваша задача - выбрать подходящие инструменты для удовлетворения пользовательского ввода. Если для ответа не требуется инструмент, выберите "no_tool"

Доступные инструменты:

returns_inquiry: База данных информации о статусе определенного возврата, будь то ожидающий, обработанный и т. д.
order_inquiry: Информация о статусе определенного заказа, такая как статус доставки, продукт, сумма и т. д.
no_tool: Для ответа на пользовательский ввод инструмент не требуется.

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

Примеры:
user: "Каковы ваши рабочие часы?"
tool: no_tool

user: "Отправлен ли заказ 12345?"
tool: order_inquiry

user: "Был ли обработан возврат ret812?"
tool: returns_inquiry

user: "Сколько дней у меня есть на возврат заказов?"
tool: returns_inquiry

user: "Какова общая сумма заказа 38745?"
tool: order_inquiry

user: "Могу ли я вернуть мой заказ 38756 в соответствии с политикой магазина?"
tool: order_inquiry

user: "Привет"
tool: no_tool

user: "Вы ИИ?"
tool: no_tool

user: "Какая погода?"
tool: no_tool

user: "Какой статус возврата для заказа 12347?"
tool: order_inquiry

user: "Какой статус возврата для возврата ret172?"
tool: returns_inquiry

ввод пользователя: {}
инструмент:
"""

Диспетчер инструментов

Механизм диспетчера инструментов работает посредством логики if/else для вызова соответствующих функций-ламбда в зависимости от имени инструмента. Ниже приведена реализация вспомогательной функции tool_dispatch. Она используется внутри цикла агента и возвращает необработанный ответ от функции-ламбда инструмента, который затем очищается функцией output_parser.

def tool_dispatch(tool_name, tool_input):
    #...
     
    tool_response = None 

    if tool_name == "returns_inquiry":
        tool_response = lambda_client.invoke(
            FunctionName=RETURNS_DB_TOOL_LAMBDA,
            InvocationType="RequestResponse",
            Payload=json.dumps({
              "returnId": tool_input  
            })
        )
    elif tool_name == "order_inquiry":
        tool_response = lambda_client.invoke(
            FunctionName=ORDERS_DB_TOOL_LAMBDA,
            InvocationType="RequestResponse",
            Payload=json.dumps({
                "orderId": tool_input
            })
        )
    else:
        raise ValueError("Недопустимый вызов инструмента")
        
    return tool_response

Развертывание решения

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

  • Доступ к консоли управления AWS через пользователя, который может запускать стеки AWS CloudFormation
  • Знакомство с навигацией по консолям AWS Lambda и Amazon Lex
  • Flan-UL2 требует один экземпляр типа ml.g5.12xlarge для развертывания, что может потребовать увеличения лимитов ресурсов через заявку в службу поддержки. В нашем примере мы используем регион us-east-1, поэтому, пожалуйста, убедитесь, что увеличили квоту на услуги (при необходимости) в регионе us-east-1.

Развертывание с использованием CloudFormation – Вы можете развернуть решение в регионе us-east-1, нажав на кнопку ниже:

Развертывание решения займет около 20 минут и создаст стек LLMAgentStack, который:

  • развернет конечную точку SageMaker с использованием модели Flan-UL2 из SageMaker JumpStart;
  • развернет три функции Lambda: LLMAgentOrchestrator, LLMAgentReturnsTool, LLMAgentOrdersTool;
  • развернет бот AWS Lex, который можно использовать для тестирования агента: Sagemaker-Jumpstart-Flan-LLM-Agent-Fallback-Bot.

Тестирование решения

Стек развертывает бот Amazon Lex с именем Sagemaker-Jumpstart-Flan-LLM-Agent-Fallback-Bot. Бот можно использовать для полного тестирования агента. Вот дополнительное подробное руководство по тестированию ботов AWS Amazon Lex с интеграцией Lambda и общее описание работы интеграции. Но вкратце, бот Amazon Lex – это ресурс, который предоставляет удобный пользовательский интерфейс для общения с агентом LLM, работающим внутри функции Lambda, которую мы построили (LLMAgentOrchestrator).

Вот несколько примеров тестовых случаев, которые следует учесть:

  • Действительный запрос о заказе (например, “Какой товар был заказан для 123456?”)
    • Заказ “123456” является действительным, поэтому мы должны ожидать разумного ответа (например, “Травяное мыло”)
  • Действительный запрос о возврате (например, “Когда будет обработан мой возврат rtn003?”)
    • Мы должны ожидать разумного ответа о статусе возврата.
  • Не относящийся ни к возвратам, ни к заказам (например, “Какая погода в Шотландии прямо сейчас?”)
    • Вопрос, не относящийся ни к возвратам, ни к заказам, поэтому должен быть возвращен ответ по умолчанию (“Извините, я не могу ответить на этот вопрос.”)
  • Недействительный запрос о заказе (например, “Какой товар был заказан для 383833?”)
    • Идентификатор 383832 не существует в наборе данных заказов, поэтому мы должны грациозно обработать ошибку (например, “Заказ не найден. Пожалуйста, проверьте свой идентификатор заказа.”)
  • Недействительный запрос о возврате (например, “Когда будет обработан мой возврат rtn123?”)
    • Аналогично, идентификатор rtn123 не существует в наборе данных возвратов, поэтому должно быть выполнено грациозное завершение.
  • Не относящийся к возвратам запрос о возврате (например, “Какое влияние возврата rtn001 на мировой мир?”)
    • Этот вопрос, хотя и кажется относящимся к действительному заказу, является несущественным. LLM используется для фильтрации вопросов с несущественным контекстом.

Чтобы сами запустить эти тесты, вот инструкции.

  1. На консоли Amazon Lex (AWS Console > Amazon Lex) перейдите к боту под названием Sagemaker-Jumpstart-Flan-LLM-Agent-Fallback-Bot. Этот бот уже настроен на вызов функции Lambda LLMAgentOrchestrator при срабатывании намерения FallbackIntent.
  2. В левой панели навигации выберите Намерения.
  3. Выберите Построить в правом верхнем углу
  4. 4. Дождитесь завершения процесса построения. Когда он будет завершен, вы получите сообщение об успешном выполнении, как показано на следующем скриншоте.
  5. Протестируйте бота, введя тестовые случаи.

Очистка

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

  • На консоли AWS CloudFormation выберите стек с именем LLMAgentStack (или выбранным вами пользовательским именем).
  • Выберите Удалить
  • Убедитесь, что стек удален с консоли CloudFormation.

Важно: убедитесь, что стек успешно удален, убедившись, что конечная точка вывода Flan-UL2 удалена.

  • Чтобы проверить, перейдите на страницу AWS console > Sagemaker > Endpoints > Inference.
  • На странице должны быть перечислены все активные конечные точки.
  • Убедитесь, что sm-jumpstart-flan-bot-endpoint не существует, как показано на скриншоте ниже.

Соображения для продакшна

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

  • Выбор модели LLM для управления циклом агента: В решении, описанном в этой статье, мы использовали модель Flan-UL2 без донастройки для выполнения планирования задач или выбора инструмента. На практике использование LLM, донастроенного для прямого вывода запросов инструментов или API, может повысить надежность и производительность, а также упростить разработку. Мы могли бы донастроить LLM для задач выбора инструментов или использовать модель, которая прямо декодирует токены инструментов, такую ​​как Toolformer.
    • Использование донастроенных моделей также может упростить добавление, удаление и обновление инструментов, доступных агенту. При подходе, основанном только на подсказках, обновление инструментов требует изменения каждой подсказки в оркестраторе агента, таких как те, которые используются для планирования задач, разбора инструментов и отправки инструментов. Это может быть неудобно, и производительность может ухудшиться, если контексту LLM предоставляется слишком много инструментов.
  • Надежность и производительность: Агенты LLM могут быть ненадежными, особенно для сложных задач, которые невозможно выполнить за несколько циклов. Добавление проверок вывода, повторных попыток, структурирование выводов из LLM в формат JSON или yaml и применение тайм-аутов для предоставления аварийных выходов для LLM, застрявших в циклах, может повысить надежность.

Заключение

В этом сообщении мы исследовали, как создать агента LLM, который может использовать несколько инструментов с нуля, используя низкоуровневую инженерию подсказок, функции AWS Lambda и SageMaker JumpStart в качестве строительных блоков. Мы подробно рассмотрели архитектуру агентов LLM и цикл работы агента. Концепции и архитектура решения, представленные в этом блоге, могут быть применимы к агентам, использующим небольшое количество заранее определенного набора инструментов. Мы также обсудили несколько стратегий использования агентов в производстве. Агенты для Bedrock, которые находятся в предварительной версии, также обеспечивают управляемый опыт создания агентов с нативной поддержкой вызовов инструментов.