Понимание искусственных интеллектуальных агентов с помощью аналогии мозг-палец
Изучите, как великие языковые модели, инструменты и исполнители инструментов взаимодействуют, сопоставив архитектуру агента с аналогией заказа еды, затем создайте минимальную реализацию агента.
Обзор
Вероятно, вы сталкивались с такими терминами, как использование инструментов, или с идеей о том, что агенты — это просто большие языки моделей, подключенные к инструментам. Вместо того чтобы сразу переходить к определениям, в этой статье используется знакомая повседневная ситуация для объяснения того, что на самом деле происходит внутри ИИ-агента. По мере чтения вы увидите, как взаимодействуют большой язык модели, инструменты и так называемый исполнитель инструментов. Эта статья написана для разработчиков, которые хотят по-настоящему понять механизмы работы агента, а не просто повторять термины; далее вы узнаете, как создать минимальный агент, чтобы увидеть его реализацию на практике.
Аналогия
Представьте, что вы заказываете еду через приложение для доставки. Рассмотрение этого обычного действия покажет, как ваш мозг и пальцы сотрудничают с приложением для оформления заказа, а затем мы соотнесем каждый шаг с терминологией агентов.
Всё начинается с того, что мозг приказывает пальцу открыть приложение для заказа еды чтобы вы могли просмотреть рестораны поблизости. Палец нажимает на иконку, и на экране появляется список ресторанов.
Затем мозг проходит по названиям ресторанов, отображаемым на экране, и направляет палец нажать на конкретный ресторан, чтобы открыть его меню. После этого мозг анализирует позиции меню и приказывает пальцу нажать кнопку «Добавить» рядом с теми блюдами, которые вы хотите, добавляя их в корзину.
Как только это сделано, мозг проверяет всё, что находится в корзине, чтобы убедиться, что ничего не пропало, а затем указывает пальцу нажать «Оформить заказ».
Наконец, мозг распознаёт, что цель достигнута, как только видит экран подтверждения заказа, и в этот момент взаимодействие между мозгом и пальцем прекращается.
Аналогия в языке агентов
Обратите внимание на важный момент на протяжении всей этой последовательности: сам мозг никогда не выполнял ни одной действия напрямую — он лишь интерпретировал поступающую информацию и указывал пальцу, что делать дальше. Это почти полностью соответствует способу работы ИИ-агента. LLM выполняет роль мозга; такие действия, как просмотр ресторанов, открытие меню, добавление товаров в корзину и оформление заказа, являются инструментами, с использованием которых мозг умеет работать; а палец соответствует исполнителю инструмента, компоненту, который фактически выполняет действие.
Когда вы создаёте агента для конкретной цели, вы определяете набор инструментов и передаёте этот список ЯЗЫКУ БОЛЬШИХ МОДЕЛЕЙ, который выступает в роли мозга для принятия решений. (Далее символ -> будет использоваться для обозначения перехода управления к следующему шагу.) Когда пользователь задаёт агенту задачу, процесс выглядит следующим образом: ЯЗЫК БОЛЬШИХ МОДЕЛЕЙ анализирует текущий шаг или оставшуюся работу и выбирает наиболее подходящий инструмент —> затем передаёт этот инструмент исполнителю, прося его запустить его и доложить о результатах —> ЯЗЫК БОЛЬШИХ МОДЕЛЕЙ читает эти результаты и проверяет, удовлетворяют ли они запросу пользователя. Если да, процесс прекращается на этом этапе; если нет, ЯЗЫК БОЛЬШИХ МОДЕЛЕЙ выбирает следующий подходящий инструмент на основе последних результатов, и цикл повторяется до тех пор, пока ЯЗЫК БОЛЬШИХ МОДЕЛЕЙ не определит, что задача полностью выполнена и дальнейшие вызовы инструментов не требуются.
Реализация
После того как концепция сформулирована, следующим шагом является создание небольшого рабочего агента, способного оформлять заказ на еду в соответствии с запросом пользователя. Приведённые ниже фрагменты кода показывают реальный путь выполнения агентом, а в конце приведена ссылка на полный репозиторий.
Инструменты
get_restaurants() {
// In production, replace with an API call such as GET /api/v1/restaurants
return list of restaurants;
}
get_menu(restaurantName) {
// In production, replace with an API call such as GET /api/v1/restaurants/${restaurantName or restaurantId}/menu
return menuItems;
}
add_to_cart(sessionId, menuItemId) {
// In production, replace with an API call such as POST /api/v1/cart
return updatedCart;
}
place_order(sessionId) {
// In production, replace with an API call such as POST /api/v1/order
return orderDetails;
}
Обратите внимание, что эти инструменты представляют собой всего лишь обычные функции, подобные тем, которые используются в повседневном прикладном коде — в них нет никакой специальной рамочной структуры для агентов или логики, специфичной для LLM. В реальной производственной среде каждый инструмент также имел бы имя, описание и определённую схему входных данных, описывающую ожидаемые данные. Именно на это имя и описание опирается LLM, чтобы определить, какой инструмент наилучшим образом соответствует запросу пользователя.
Выполняющий инструменты модуль
toolExecutor(toolCall) {
const tool = toolNameMap[toolCall.name];
return tool.execute(toolCall.arguments);
}
Сам исполнитель инструмента — это просто ещё одна обычная функция. Его аргумент toolCall содержит информацию о вызываемом инструменте — его название и аргументы, — причём эта информация варьируется в зависимости от того, какой именно инструмент вызывается: название ресторана, ID позиции меню или что-то совершенно другое. Ключевой момент заключается в том, что когда большая языковая модель указывает исполнителю, какой инструмент нужно запустить, она передаёт точные, структурированные данные, такие как название инструмента get_menu с аргументом {restaurantName: "Spicy Pizza"}. Нет необходимости вручную извлекать или анализировать эту информацию из необработанного текстового вывода большой языковой модели.
Агент
// Give all the tools to the LLM
llm = OpenAILLM.bindTools([get_restaurants, get_menu, add_to_cart, place_order])
// Take the user query to run the agent loop
reactAgent(userInput) {
while (true) {
response = llm(userInput);
if (response.isFinalAnswer) {
return response.answer;
}
result = toolExecutor(response.toolCall);
userInput = response + result;
}
}
Что стоит обратить внимание в псевдокоде
- Название
reactAgentотносится к шаблону подсказок ReAct (Reason and Act), при котором большая языковая модель определяет инструмент, который необходимо вызвать, наблюдает за результатом этого вызова, а затем решает, требуется ли запустить ещё один инструмент или задача завершена и цикл может прекратиться. - Обратите внимание на цикл
while(true). Именно здесь агенты отличаются от условной логики, которую обычно используют в языках вроде Java или Python. Вместо того чтобы жёстко задавать вызовы функций в ветках if-else или циклах for, вы предоставляете большой языковой модели набор инструментов — каждый из которых имеет имя и описание — и позволяете самой модели во время выполнения решать, какой инструмент вызвать дальше, какие аргументы передать и когда работа завершена и цикл должен прекратиться.
while(true); он используется здесь исключительно для иллюстрации основного агентского поведения в простом коде. На практике следует использовать фреймворки оркестрации, такие как LangGraph. Даже с подобным фреймворком стандартной практикой является ограничение глубины рекурсии, чтобы LLM нельзя было вызывать бесконечно — неограниченный цикл может привести к ошибкам, расточительству токенов и ненужным затратам.response.isFinalAnswer в псевдокоде указывает на то, что агент пришел к полному ответу и дальнейшие вызовы инструментов не требуются. После этого агент возвращает пользователю краткий ответ вместо того, чтобы запускать еще один инструмент.userInput = response + result, при которой объединённый результат возвращается в LLM через response = llm(userInput) в следующей итерации. Это происходит потому, что каждый вызов LLM является безсостоянийным — он не сохраняет информацию о предыдущих шагах, даже в рамках одной сессии или взаимодействия с пользователем. Следовательно, каждый раз после завершения выполнения инструмента необходимо пересылать полную историю разговора: системное указание, описывающее поведение агента, первоначальный запрос пользователя, предыдущий ответ ИИ с рекомендацией использования инструмента и результат, полученный этим инструментом. Затем LLM обрабатывает всю эту последовательность, чтобы определить, достигнута ли цель или требуются дополнительные вызовы инструментов.Диаграмма последовательности выполнения LLM и инструментов
На приведённой ниже диаграмме показано, как LLM выбирает следующий инструмент, как его исполнитель запускает этот инструмент, и как этот цикл повторяется до тех пор, пока LLM не придёт к выводу, что задача завершена и дальнейшее выполнение инструментов не требуется.
Описанный процесс чётко демонстрирует взаимодействие: LLM предлагает вызов, исполнитель его выполняет, результат возвращается к LLM, который либо предлагает ещё один вызов, либо завершает цикл окончательным ответом.
Код на GitHub
Если вы хотите самостоятельно запустить этот пример и наблюдать за работой агента, доступен репозиторий с исходным кодом.
Связанная литература
- Понимание различий между элементами и сообщениями в API ответов OpenAI — Объясняется, как API ответов OpenAI переорганизует результаты работы модели в элементы вместо сообщений, и почему это изменение имеет значение для вызова инструментов и рабочих процессов с использованием агентов.
- Понимание ИИ-агентов: цели, инструменты, память и цикл действий агента — Простое для новичков объяснение того, чем ИИ-агенты отличаются от чат-ботов, с описанием основных компонентов, цикла принятия решений, уровней автономии и практических применений.