Головна / Статті / Розуміння штучних інтелектуальних агентів через аналогію мозок-палець

Розуміння штучних інтелектуальних агентів через аналогію мозок-палець

Дізнайтеся, як ШІ з великими масивами даних, інструменти та їх виконавці взаємодіють, проаналізувавши архітектуру агента через аналогію з замовленням їжі, а потім створіть мінімальну реалізацію агента.

1513 слів

Огляд

Ймовірно, ви стикалися з такими термінами, як використання інструментів, або з думкою, що агенти — це просто LLM, підключені до інструментів. Замість того, щоб одразу переходити до визначень, у цій статті використовується знайома повсякденна ситуація для пояснення того, що насправді відбувається всередині AI-агента. По ходу ви побачите, як LLM, інструменти та щось, що називається виконавцем інструментів, взаємодіють між собою. Цей текст призначений для розробників, які хочуть справді зрозуміти механізми роботи агента, а не просто повторювати термінологію; далі ви побачите, як створити мінімального агента, щоб побачити його реалізацію на практиці.

Аналогія

Усе починається з того, що ваш мозок наказує пальцю запустити додаток для замовлення їжі щоб ви могли переглянути ресторани поблизу. Ви торкаєтесь іконки, і на екрані з’являється список ресторанів.

Потім ваш мозок читає назви ресторанів, які відображаються на екрані, та спрямовує ваш палець на певний ресторан, щоб відкрити його меню. Після цього ваш мозок аналізує статті меню та наказує пальцю торкнутися кнопки „Додати“ поруч із стравами, які ви бажаєте, щоб додати їх до кошика.

Як тільки це зроблено, ваш мозок перевіряє все, що є у кошику, щоб переконатися, що нічого не бракує, а потім наказує пальцю торкнутися „Замовити“.

Нарешті, мозок розпізнає, що ціль досягнута, як тільки бачить екран підтвердження замовлення, і в цей момент взаємодія між мозком та пальцем завершується.

Аналогія в мові агентів

Зверніть увагу на щось важливе протягом усієї цієї послідовності: сам мозок ніколи не виконував жодної дії безпосередньо — він лише інтерпретував надходжену інформацію та вказував пальцю, що робити далі. Це майже точно відповідає способу роботи ШІ-агента. 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 містить інформацію про інструмент, який викликається — його назву та аргументи, — причому ці дані змінюються залежно від того, який інструмент викликається: назва ресторану, ідентифікатор статті меню чи щось зовсім інше. Ключовий момент полягає у тому, що коли ШІ повідомляє виконавцю, який інструмент потрібно запустити, воно надає точні, структуровані дані, наприклад назву інструменту 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;
  }
}

Те, що варто помітити у псевдокоді

  1. Назва reactAgent стосується патерну запитів ReAct (Reason and Act), у якому LLM вирішує, який інструмент викликати, спостерігає за результатом цього виклику, а потім визначає, чи потрібно запустити інший інструмент, чи завдання вже завершене та чи можна зупинити цикл.
  2. Зверніть увагу на цикл while(true). Саме тут агенти відрізняються від умовної логіки, яку зазвичай пишуть у мовах на кшталт Java чи Python. Замість того, щоб жорстко кодувати виклики функцій у гілках if-else чи циклах for, ви надаєте LLM набір інструментів — кожен з них має назву та опис — і дозволяєте самому LLM на етапі виконання вирішувати, який інструмент викликати далі, які аргументи передати та коли робота завершена і цикл має закінчитися.
  • Проте виробничі системи насправді не спираються на примітивний цикл while(true); його використовують тут лише для ілюстрації основної поведінки агента у простому коді. На практиці слід використовувати фреймворки оркестрації, такі як LangGraph. Навіть із таким фреймворком стандартною практикою є обмеження глибини рекурсії, щоб ШІ не могло викликатися нескінченно — неконтрольований цикл може призвести до помилок, марної витрати токенів та зайвих витрат.
  • Перевірка response.isFinalAnswer у псевдокоді свідчить про те, що агент дійшов до повної відповіді та подальші виклики інструментів не потрібні. Після цього агент повертає користувачеві узагальнену відповідь замість того, щоб запускати ще один інструмент.
  • Ви, можливо, також помітили рядок userInput = response + result, де об’єднаний результат подається назад у LLM як response = llm(userInput) під час наступної ітерації. Це відбувається тому, що кожен виклик LLM є безстановим — він не зберігає жодної інформації про попередні кроки, навіть у межах однієї сесії чи взаємодії з користувачем. Тому щоразу, коли інструмент завершує виконання, необхідно пересилати повну історію розмови: системний запит, який описує, як повинен поводитися агент, початкове запитання користувача, попередню відповідь ШІ з пропозицією використання інструменту та результат, отриманий цим інструментом. Потім LLM обробляє всю цю послідовність, щоб визначити, чи досягнуто мети, чи потрібні додаткові виклики інструментів.
  • Схема послідовності виконання LLM та інструментів

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

    Описаний процес чітко демонструє взаємодію: LLM пропонує виклик, виконавець його здійснює, результат повертається до LLM, який або пропонує ще один виклик, або завершує цикл остаточною відповіддю.

    Код з GitHub

    Якщо ви хочете самостійно запустити цей приклад та спостерігати за роботою агента, у вас є репозиторій із початковим кодом.

    Пов’язана література

  • Прогресивне відкриття інструментів для AI-агентів у масштабі — Пояснює, чому великі каталоги інструментів погіршують продуктивність AI-агентів, та як прогресивне відкриття інструментів за допомогою маніфестів та схем типу just-in-time це вирішує.
  • Виклик Claude, GPT та Gemini через кінцеві точки, сумісні з OpenAI — Дізнайтеся, які функції підтримують сумісні з OpenAI шари Anthropic та Gemini, де вони безпопередньо відкидають певні можливості, та коли доцільно направляти всі три сервіси через один шлюз.