ToolCallingAgent проти CodeAgent у локальних моделях Qwen2.5 14B
ToolCallingAgent проти CodeAgent у smolagents на Mac M4: швидкість та точність маршрутизації з використанням локальних моделей Qwen2.5 14B instruct та coder при різних температурах.
Джерела: ToolCallingAgent vs. CodeAgent: Which Performs Better on a Local LLM?
Налаштування локальних агентів швидко виявляють слабкі місця. Ця машина була базовим Mac з процесором Apple M4 та 16 ГБ об’єднаної пам’яті; у неї не було можливості виконання обчислень у хмарі та додаткової VRAM для роботи в критичних ситуаціях, тому навіть помірний розмір вікна контексту міг спричинити заміну пам’яті. Два стилі агентів з бібліотеки smolagents — ToolCallingAgent та CodeAgent — були протестовані на двох моделях, які працювали локально: qwen2.5-coder:14b та qwen2.5:14b-instruct. Обидві мають об’єм 14 мільярдів параметрів та однакову базову архітектуру, і обидві працювали на одному пристрої.
- Qwen2.5:14b-instruct — це універсальна модель у серії 14B, налаштована на обробку різноманітних інструкцій та діалогів, що дозволяє їй ефективно виконувати команди.
- qwen2.5-coder:14b використовує ту саму основну архітектуру, але пройшла додаткову попередню підготовку на великій кількості коду та фінішну налаштування, спрямовану саме на роботу з кодом.
З огляду на настільки обмежений бюджет на обладнання не очікувалося, що будь-яка з конфігурацій буде відзначатися особливими якостями. Більш цікавим було питання про те, де саме кожна з них має слабкі місця, та чи може вибір іншого типу агента послабити ці обмеження.
Конфігурація
Було проведено тестування при температурах 0, 0,1, 0,3 та 0,6 для обох типів агентів у рамках однієї задачі: знайти п’ять найкращих піцерій у Сіетлі, перевірити час очікування в кожній з них та порекомендувати лише ті, які відповідають встановленому клієнтом порогу. Функції, які обчислюють час очікування та порівнюють його з порогом, є детермінованими.
@tool
def get_wait_time(restaurant_name: str) -> int:
"""Current wait in minutes for a restaurant. Deterministic, not a live lookup."""
@tool
def restaurants_in_wait_limit(wait_time: int, wait_threshold: int) -> bool:
"""True if the wait is within the customer's threshold."""
Детерміністичний підхід обраний навмисно. Пошук у реальному часі дозволив би моделі припустити ймовірний час очікування та продовжити роботу. Примусовий виклик функції перевіряє те, що тут має значення: чи керується агент інструментом замість того, щоб вигадувати значення, та чи залишається це таким, коли змінюються параметри температури чи тип агента.
Відстежувалися три показники: затримка, чи завершилася операція, та точність маршрутизації, яка визначається як частка всієї послідовності інструментів, виконана правильно під час кожного виклику. Розглядайте ці цифри як інструмент діагностики, адже це не є формальним критерієм оцінки.
У чому різниця між двома агентами
За допомогою ToolCallingAgent кожен крок генерує один виклик інструменту у форматі JSON. Модель надає аргументи, фреймворк виконує інструмент, після чого починається наступний крок. П’ять ресторанів та дві функції дають загалом десять окремих викликів, кожен з яких є новою можливістю пошкодити структурований результат.
CodeAgent обирає інший підхід та створює фрагмент коду на Python, який виконується одним кроком. Один цикл може охопити всі ресторани та викликати обидві функції всередині нього. Правильний цикл є правильним для всіх з них під час цього виконання, тому рішення приймається один раз, а не десять.
Результати
На моделі Qwen2.5:14b-instruct
Обидва агенти показали гарні результати. CodeAgent зберігав точність маршрутизації 1,00 при будь-якій температурі, а ToolCallingAgent залишався в межах від 0,95 до 1,00. У правильності виконання не було значних відмінностей.
Швидкість показувала іншу картину. ToolCallingAgent працював приблизно вдвічі повільніше — близько п’яти хвилин на кожен запуск, на відміну від приблизно двох з половиною хвилин у CodeAgent. Причина криється у структурі роботи. ToolCallingAgent оплачує виклик нової моделі на кожному кроці, знову надсилаючи контекст розмови та генеруючи текст з нуля щоразу. CodeAgent оплачує це лише один раз. На локальному комп’ютері, де кожна генерація і так є повільною, такі додаткові витрати неможливо ігнорувати.
На Qwen2.5-coder:14b
Тут два агента різко відійшли один від одного. ToolCallingAgent так і не досяг 50 відсотків точності маршрутизації при жодній температурі, залишаючись у діапазоні від 0,40 до 0,50. Він працював швидше, ніж на моделі для виконання інструкцій, але це не було добрим знаком. Він працював швидко тому, що здався. Як тільки потік даних було втрачено, він припинив відправляти запити та завершив роботу раніше, виконавши менше завдань.
CodeAgent переміг беззаперечно, досягнувши точності маршрутизації 1,00, що дорівнює найкращим показникам. Це очікувано, адже він просить модель-кодувальника створювати код на Python, а не структурований JSON.
Що можна з цього зробити
Перевага CodeAgent у використанні циклів є реальною. У моделі instruct, де обидві моделі показали показник 1,00 у маршрутизації, блокування завдань зробило CodeAgent вдвічі швидшим за ToolCallingAgent.
Qwen2.5:14b-instruct видається надійним універсалом, який добре справляється як із запитами до структурованого JSON, так і з простим кодом. Qwen2.5-coder:14b краще використовувати для складних завдань з кодування, оскільки він може бути ненадійним у створенні структурованого JSON та у підтримці цього рівня якості протягом серії запитів.
Відкрите питання
Залишається ще одне запитання. Агенти відрізняються двома аспектами: CodeAgent об’єднує свою роботу в одну програму та записує код на Python, а не у структурованому форматі JSON. Наступний експеримент міг би розглянути ці відмінності, змусивши CodeAgent виконувати структуровані виклики інструментів, при цьому залишаючись у режимі пакетної обробки. Результат дозволить з’ясувати, чи перевага походить переважно від використання циклів, чи від того, що моделі вважають створення коду простішим, ніж серію довгих викликів JSON.