Звичайно, ось стаття, написана у вашому стилі, заснована на наданій розшифровці відео:
Агенти в дії: як ШІ перетворює відповіді на ваші запити
Привіт, друзі! Ліла Гарт з вами, і я завжди в захваті від того, як людський інтелект продовжує дивувати та захоплювати. Нещодавно я звернула увагу на відео, яке вразило мене глибиною підходу до створення інтелектуальних систем. Мова піде про те, як об’єднати силу кількох штучних інтелектів для створення відповіді на потреби користувачів, використовуючи саме те, що треба, і нічого зайвого.
Чи траплялося вам стикатися з морем даних у вашому VectorDB, використовуючи їх для генеративного пошуку? Певне, ви відчували, що контекст, який надається вашій LLM для вражаючих результатів, дещо недосконалий. Вона просто витягує дані, які зовсім не стосуються вашого запиту. Що ж, саме це і хотілося розібрати!
Почнімо з самого початку. Нам розповідають про практичний приклад, у якому поєднуються:
- Категоризація запитів.
- Вилучення контексту з VectorDB.
- Генерація відповідей природною мовою – але все це з використанням багатоагентного підходу.
І все це крок за кроком.
Крок 1: Занурення у світ коду
Перше, з чого починаємо, це клонування репозиторію на наш локальний пристрій. Далі ми переходимо до каталогу UI, щоб встановити всі необхідні залежності. Хоча з UI ми працювати не будемо, важливо знати, що він реалізований з використанням React та TypeScript. Це те, що показує кінцевий результат у вашому браузері.
Одразу хочу відзначити Carbon components – чудову оболонку для створення інтерфейсу. Це спрощує роботу, особливо для тих, хто не є надто досвідченим в передній розробці. Раджу з ними ознайомитись, особливо якщо плануєте змінювати інтерфейс програми.
Ось, нарешті, ми встановили залежності. Нам залишається лише скопіювати .env.example та створити .env як у клієнта, так і на серверній стороні. Ці файли містять важливу інформацію для налаштування.
Далі, щоб зробити програму більш особистою, можна змінити назву програми та брендинг. У цьому прикладі застосовується назва “Агенти в дії!”.
Отже, з UI ми на сьогодні завершили. Переходимо до API, яке написано на Python. Створюємо віртуальне середовище з назвою aiagentic, активуємо його та встановлюємо всі залежності. Тут нам знадобиться терпіння, оскільки цей процес може зайняти деякий час. Ми встановлюємо CrewAI та Watsonx.ai.
Коли залежності встановлені, ми копіюємо .env.example та розміщуємо його як .env в API. Всередині цього файлу містяться необхідні рядки підключення для Watsonx.ai.
Для отримання цих даних, вам потрібно перейти до Cloud, відкрити Watson Studio, а потім IBM watsonx. Далі – у Prompt Lab, де у верхньому правому куті ви знайдете “view code”, та побачите cURL команду з усіма основними даними, потрібними для налаштування API.
Отже, звідси ми отримуємо:
- BASE URL.
- PROJECT ID.
- API KEY.
API ключ треба створити окремо в розділі IAM, в підрозділі API keys. Створюємо новий ключ, називаємо його AGENTIC та копіюємо його.
Тепер API налаштовано, отже, можна переходити до створення гілки.
Крок 2: Запуск служб
Ми створюємо нову гілку з назвою one-step. Нам потрібно буде запустити усі наші сервіси.
Ми маємо три сервіси:
- FastAPI.
- React UI.
- Express Server.
Спочатку запускаємо Uvicorn, який підготує FastAPI. Потім переходимо до UI, де запускаємо клієнт та сервер. Команди для цього можна знайти в репозиторії.
Чекаємо, поки Uvicorn підготує FastAPI, та переходимо до браузера, щоб побачити, як виглядає UI.
І ось перед нами чат-вікно з парою кнопок. На перший погляд, все просто, але на бекенді все набагато цікавіше.
Якщо зайти в API directory, там знаходяться декілька папок, які нас цікавлять, та текстовий файл questions.txt. Далі ми вставляємо відповідь у вікно чату.
Коли ми натиснемо “Відправити”, бекенд має виконати таке:
- Категоризувати запит.
- Вибрати потрібні дані з відповідної колекції VectorDB та ChromaDB.
- Передати їх у налаштований промпт.
- Повернути гарну відповідь.
Але спочатку перевіримо, як це працює. Спробуємо запустити скрипт, який знаходиться в API scripts, під назвою process document script.
Він потрібен для створення ChromaDB VectorDB. В папці docs є три текстових файли: accounting, billing та technical. Мета в тому, щоб виділити окремі теми, та не “змішувати” їх між собою. Уявіть, у вас є велика документація, і коли ви робите запит до VectorDB, cosine similarity distance буде однаковим для даних, які не мають стосунку до вашого запиту.
Отже, скрипт перебирає всі файли з папки docs. Для кожного файлу створюється нова колекція та зберігаються вбудовування. Скрипт перевірить, чи є колекції. Якщо немає, то їх буде створено: account, billing та technical.
Перш ніж ми почнемо роботу, нам потрібно категоризувати запит. І саме тут ми створимо нашого першого агента, агента категоризації.
У маршруті agentic route ми бачимо коментарі, де описано, що мають робити агенти: категоризація запиту, вилучення контексту та генерація відповіді.
Почнемо з імпортування фреймворку CrewAI.
Нам знадобляться такі класи:
- agent
- task
- crew
- process
- LLM
Тепер нам потрібно створити нашу першу LLM.
З документації беремо параметри: model, temperature, max tokens та рядки підключення.
Для прикладу будемо використовувати Granite 3.8 billion. Додаємо “watsonx” до назви моделі.
Temperature – 0.7.
Max tokens – 50.
Нам також потрібні рядки підключення для Watson: API key, project ID та URL.
URL.
API key – з файлу .env.
Project ID.
Тепер ми можемо інтегрувати все це у клас CrewAI LLM.
Отже, ми створили LLM, а тепер створюємо агента категоризації. Називаємо його Collection Selector.
Роль агента – Collection Selector , мета – аналізувати запити користувачів та визначати найвідповіднішу колекцію ChromaDB. Backstory – він експерт з класифікації запитів, який направляє питання у правильний домен.
Розберемо параметри:
- verbose – true, щоб бачити логи.
- allow delegation – false (ми не використовуємо делегування).
- max iterations – стандартне значення 20 (у нас проста задача, тому можна залишити так).
- brain – категоризаційний LLM, який використовує Granite.
Отже, в нас є агент з мізками, роллю, та бекграундом. Тепер створимо завдання.
Для завдання важливо задати agent, description, output JSON.
Далі нам потрібен prompt.
Ми звертаємось до агента з проханням визначити найкращу категорію, повернути лише одне слово. Ми пропонуємо визначення категорій, щоб дати агенту більше свободи.
У нашому випадку ми потребуємо чіткого формату відповіді, тому ми зазначаємо, що відповідь буде у форматі JSON об’єкта з полем category зі значенням technical, billing або account.
Для output JSON потрібна модель Pydantic.
Ми визначаємо модель CategoryResponse, яка містить поле category з переліком можливих значень. Додали опис, оскільки, є підозра, що агент дивиться на опис моделей.
Тепер, коли у нас є агент та задача, створимо команду.
Нам потрібний агент, завдання, process та verbosity.
Спочатку додаємо агента. Далі додаємо завдання категоризації.
Verbose = true.
Process має значення sequential (покроковий процес).
Отже, ми підготували команду, даємо їй старт.
Ми очікуємо отримати JSON об’єкт з полем category.
Ми витягуємо категорію з відповіді.
Перевіряємо, чи все працює.
Відправляємо наявний запит, та сподіваємось отримати category technical.
Чудово! Тепер ми бачимо, що робить агент.
Ми можемо побачити запит, який ми передали з UI.
Отримуємо остаточну відповідь в потрібному форматі.
Отже, ми створили базову категоризацію та агента, і тепер можемо рухатися далі.
Крок 3: Поглиблюємо пайплайн
Переходимо до наступного етапу.
Тепер нам потрібно отримати дані з VectorDB.
Для цього ми використовуємо схожий процес, як і в попередньому кроці.
Створюємо нового LLM, retriever LLM. Йому знадобиться більше токенів. Ми залишаємо 1000, все інше – без змін.
Додаємо нового агента та нове завдання.
Тепер різниця буде в тому, що використовується інструмент, про який ми поговоримо.
Агент-провідник повинен отримати категорію, яку він отримав від агента категоризації, та передати її у функцію для запиту VectorDB.
Створюємо новий інструмент, який називаємо query collection tool.
Визначаємо його.
На вхід він приймає category.
На вхід він приймає query to embed.
Повертає dictionary.
Інструмент для запитів ChromaDB базуватиметься на категорії, та повертатиме відповідні документи.
Для реалізації нам знадобиться ще один компонент: Watsonx.ai embeddings.
Далі ми беремо категорію, яка повернулася після виконання категоріїзаційного завдання, та використовуємо її для запиту VectorDB.
У нас є функція, на виконання якої ми покладаємось.
Отже, тепер є інструмент, тому ми можемо подивитися, що робить агент retrieval.
Агент отримує запит з маршруту.
Має вихід. Нам не потрібно хвилюватися про вихідний JSON.
Тут потрібно додатково додати контекст. Ми надаємо доступ до завдання категоризації та її виводу.
Тепер агент знає, як ми отримуємо категорію, і саме це ми повідомляємо агенту.
Завдання агента: подивись на категорію, подивись на запит, використай цю функцію, виклич її та поверни контекст.
Додаємо нового агента до команди. Додаємо нове завдання.
Маємо print out category result.
Перевіряємо.
Отримуємо потрібну категорію.
Агент отримав результат RAG.
Використав категорію.
Подав її у колекцію ChromaDB.
Запитав.
Повертає контекст для запиту.
Ми фактично отримали все, що потрібно для останнього агента.
Маємо категорію, запит, та контекст. Весь цей набір даних допоможе отримати відповідь.
Використання функцій та інструментів в агентах – дуже круто!
Ми завершили з агентом retrieval, і переходимо до наступного.
Крок 4: Фінальний акорд – створення відповіді
Ось ми і на останньому етапі застосунку! Створимо агента, який формуватиме гарну відповідь для користувача.
Робимо все майже те саме.
Створюємо окремі LLM для кожного з агентів.
Тут важливим є зміна кількості токенів. Звісно, нам потрібно більше місця для відповіді.
Також ми можемо використовувати різні моделі в Watson.ai, та змінювати параметри.
Отже, нам потрібні:
- Агент генерації.
- Остання задача.
- Ще один інструмент.
Останній інструмент – це те, як ми знаходимо промпт.
У проєкті ви можете використовувати accelerator. Знайдіть watsonx.ai RAG, і він надасть вам цей accelerator. В ньому є шаблони промптів, які написали ті, то навчали моделі.
Ми копіюємо prompt, та інтерполюємо контекст, отриманий від ChromaDB, у контекст та питання.
Створюємо останній інструмент.
Він бере контекст та запит, та відправляє їх у промпт.
Останнє, що нам потрібно, – модель Pydantic для виведення, оскільки ми тепер відправляємо все це у UI.
Це потрібно для того, щоб вихід був у форматі JSON.
Його має містити категорії та відповідь.
Оголошуємо модель FinalResponse.
Отже, додаємо останнього агента у команду та надаємо йому кінцеве завдання.
Тестуємо, чи все працює.
Гарна відповідь є!
Отримуємо категорію.
Надсилаємо її до retrieval, який повертає контекст з RAG, який, в свою чергу, буде використаний агентом.
Агент інтерполює ці дані у промпт.
Все працює!
З відповіддю все добре.
Відповідь містить контекст та інформацію.
Ми створили багатоагентний пайплайн!
Давайте підсумуємо:
Ми побудували бекенд до агентного RAG чат-бота, який може ідентифікувати категорію запитів, націлювати правильну колекцію ChromaDB, інтерполювати запит у контексті у власному промпті та генерувати відповідь природною мовою.
За цією програмою та процесом, запрошуємо вас дослідити додаткові випадки використання, налаштувати UI та поекспериментувати з фреймворком CrewAI.
Почніть з коду, розважайтесь та створіть щось круте!