Привет! В этой статье я детально разберу основные фреймворки для AI-агентов, попробую их побенчить и детально распишу их плюсы и минусы. Если вы подступались к агентам, то первым вопросом наверняка стало «а на чем их делать?». Отовсюду все говорят про langchain и десяток других фреймворков, звучат аббревиатуры типа MCP и A2A, какие-то Swarmы и CrewAI, мультиагентность и самое всякое разное.
Давайте попробуем все это разложить по полочкам, потестировать, замерить и собрать материал, который поможет за раз во всем разобраться. А в качестве задачи мы возьмем мой проектик, который я с удовольствием поделываю в качестве развлекухи по ночам: сложный выбор товаров на маркетплейсах LLMкой.
Сразу к делу.
Что будем тестировать: LangChain, LangGraph, AutoGen, CrewAI, OpenAI Swarm, LlamaIndex, MetaGPT, ControlFlow, Haystack, Phidata, Pydantic AI, smolagents, DSPy, SuperAGI, Semantic Kernel, Claude Agent SDK
Не будем: low-code/no-code
Под такой большой список необходимо хорошо подготовить задачу и ровно этим мы сначала займемся.
Задача интересная и сильно повлияла на то, во что вылился подбор и оценки фреймворка, но она долгая и может быть не всем интересна, поэтому при желании можно сразу перейти к оценке в конце статьи.
Выбираем газонокосилку на маркетплейсе
В качестве задачи мы попробуем выбрать газонокосилку на одном из маркетплейсов. В реальной жизни мой агентик посложнее, но для бенчмаркинга агентов его можно упростить до качественно-минимального и одновременно оставить ему как мультиагентность, так и полезную функциональность.
Наша система будет состоять из оркестратора и трех ролей под ним:
Анализатор характеристик товаров
Анализатор отзывов к ним
Решала, который принимает цену товара, а так же выводы от первых двух
Важной частью любого агента является память. Поэтому мы ее добавим в нашу схему, и в этой памяти будет лежать один важный факт, который необходимо будет учесть в выборе.

В качестве подопытного товара мы возьмем газонокосилку — как идеальное сочетание следующих факторов: у товара есть объективная часть (это электроника с кучей конкретных характеристик), субъективная (отзывы) и это выбор пониженного уровня дофаминности. Про последнее стоит пояснить детальнее — есть вещи, которые нам нравится выбирать (любимый ноут, страны для поездки или что-то уютненькое для дома), но газонокосилку выбирать, скорее всего, никому не нравится, поэтому подбор таких товаров можно и нужно перекладывать на агентов.
Но про дизайн и flow этого серьезного бенчмарка стоит рассказать подробнее.
Итак, мы будем решать одну и ту же задачу на разных фреймворках. На входе у нас есть три претендента, их характеристики и отзывы — данные, промпты и служебный код в этой части будут общими, а агентная обвязка будет уже уникальная под фреймворк.

Я некоторое время на старте карьеры разрабатывал CRM и мне очень понравилась ключевая идея о том, что большая часть покупок продиктована страхом сделать неправильный выбор и весь маркетинг направлен именно на убеждение в правильности выбора вооот этого товара. Покупая что-либо, мы хотим не столько купить самое лучшее, сколько боимся купить «не то».
Это будет ключевой идеей нашего встроенного ханипота. Из трех товаров я подобрал два таких, которые «не то», и которые должны логично отвалиться в процессе нашего выбора. Один из них должен точно отвалиться в результате анализа характеристик, другой — в результате отзывов. И мы хотим, чтобы это было проделано более интеллектуально (про это — ниже), в конце концов за что я плачу LLMкам.
Я взял три реальных газонокосилки, запарсил их реальные характеристики и отзывы, а затем немножко изменил их характеристики и названия, чтобы они были неизвестными для LLM — чтобы решение принимаось именно на переданных мной данных, что мы дополнительно и пропишем в промпте.
У нас есть идеально подходящая GreenForks GF7A114 (ту, что агент в итоге должен выбрать), проводная несамоходная Takita LDM4393 (которую агент должен выкинуть по характеристикам) и Mosch BRD9401S (в отзывах которой за кучей позитива явно следует ее применимость именно для маленьких участков).
Помните я в начале писал про память? Она пригодится нам имеенно тут — оркестратор должен в нее сходить на старте и передать сохраненные ценные факты дальше. Наш агент по характеристикам должен сам догадаться, что если ему был передан факт использований кем-угодно из семьи, то значит наличие проводов или отсутствие самоходности — это сразу красный флаг для товара.

В случае с отзывами все попроще — негативные отзывы владельцев больших участков должны позволить агенту выкинуть товар из кандидатов.
Класс? Класс! Чтобы не потратить бюджет маленькой страны, я ограничил отзывы 20 штуками на каждый.
Вот пример mock-данных. Они в данном замере будут статические, чтобы исключить влияние времени и задержек при их получении.
Исходные данные: товары
PRODUCTS = {
"greenforks_gf7a114": {
"name": "GREENFORKS GF7A114 40V",
"price": 32990,
"brand": "GreenForks",
"type": "Самоходная аккумуляторная",
"voltage": "40V",
"battery_capacity": "4.0 Ah",
"batteries_included": 2,
"cutting_width": 46,
"cutting_height_min": 25,
"cutting_height_max": 80,
"height_positions": 7,
"grass_collector": 60,
"weight": 24,
"self_propelled": True,
"mulching": True,
"side_discharge": True,
"motor_type": "Бесщеточный"
},
"takita_ldm4393": {
"name": "Takita LDM4393",
"price": 34990,
"brand": "Takita",
"type": "Несамоходная проводная",
"voltage": "230V",
"battery_capacity": None,
"batteries_included": 0,
"cutting_width": 46,
"cutting_height_min": 30,
"cutting_height_max": 90,
"height_positions": 6,
"grass_collector": 55,
"weight": 29,
"self_propelled": False,
"mulching": True,
"side_discharge": True,
"motor_type": "Коллекторный"
}
"mosch_brd9401s": {
"name": "Mosch BRD9401S",
"price": 27990,
"brand": "Mosch",
"type": "Самоходная аккумуляторная",
"voltage": "36V",
"battery_capacity": "5.0 Ah",
"batteries_included": 2,
"cutting_width": 33,
"cutting_height_min": 25,
"cutting_height_max": 75,
"height_positions": 5,
"grass_collector": 40,
"weight": 18,
"self_propelled": True,
"mulching": false,
"side_discharge": False,
"motor_type": "Бесщеточный"
}
}
Исходные данные: отзывы
REVIEWS = {
"greenforks_gf7a114": {
"average_rating": 4.4,
"total_reviews": 20,
"reviews": [
{
"rating": 5,
"text": "Всем доброго дня!!! Приобрёл данный аккумуляторный агрегат, и честно говоря был приятно удивлён))) искал специально такую газонокосилку, где бы было 2 аккумулятора по 4Ам. С задачей газонокосилка справилась отлично!!! взяла траву высотой ~ 60-80см.... а это ну прям ооочень хороший показатель.... но в связи с тем, что было мокро - а значит и травушка тяжелее, и забивается всё мульчей - да и как я уже говорил ранее траву взял высокую.... разрядились акб через 8 минут. НО!!! В принципе меня всё устроило.",
"pros": "Отличная мощность, берет высокую траву",
"cons": "Аккумуляторы заряжаются долго, быстро разряжаются на мокрой траве"
},
{
"rating": 5,
"text": "Это чудо какое то. Батарейки хватает не на очень долго, но в запас купил и все",
"pros": "Отличное качество работы",
"cons": "Время работы от аккумулятора ограничено"
},
{
"rating": 4,
"text": "Косилка очень классная. Косит отлично. Правда аккумуляторы заряжаются долго. Все довольны.",
"pros": "Отлично косит",
"cons": "Долгая зарядка"
},
................................
]
},
"takita_ldm4393": {
"average_rating": 4.6,
"total_reviews": 20,
"reviews": [
{
"rating": 5,
"text": "Отличная косилка! Скосил 12 соток и еще силы остались!",
"pros": "Много",
"cons": "Не обнаружено"
},
{
"rating": 5,
"text": "Легче других, но косит не хуже. Жене удобно управлять. Травосборник вместительный.",
"pros": "Легкая, удобная для женщин, большой травосборник",
"cons": ""
},
{
"rating": 4,
"text": "Хорошая модель, но цена могла бы быть ниже.",
"pros": "Быстрая работа",
"cons": "Цена"
},
................................
]
},
"mosch_brd9401s": {
"average_rating": 4.3,
"total_reviews": 20,
"reviews": [
{
"rating": 5,
"text": "Самая легкая из всех! 18 кг - для женщины идеально. Маневреная и легко поворачивается.",
"pros": "Очень легкая, маневренная",
"cons": "Узкий захват и маленькая площадь"
},
{
"rating": 4,
"text": "За такую цену отличный вариант. Да, захват 33см маловат, но зато удобно между клумбами маневрировать.",
"pros": "Цена, маневренность между препятствиями, но полоса скашивания так себе",
"cons": ""
},
{
"rating": 3,
"text": "Для маленького участка норм. На большой площади устанешь из-за узкого захвата. Но работает хорошо.",
"pros": "Хорошее качество среза",
"cons": "Не подходит для больших участков"
},
................................
]
}
}
Первый заход был вот таким: все что можно общее — выносим в общее, а затем конкретную агентную обвязку пишем на конкретном фреймворке.
Пробуем!

Итоговая картиночка процесса:

Вроде бы солидно? Солидно!
И получилось то, что на всех фреймворках выбор отработал правильно, каждая реализация выбрала именно ту газонокосилку, которую выбрать нужно было. В качестве первого вывода — это еще одно напоминание о том, что в LLM-based проекта очень важным является дизайн и глубина предметной подготовки. Но и здесь важно сделать оговорку, что чем сложнее сценарий, тем больше будет фреймворкошной специфики.
Но, погодите. Если все фреймворки справились с задачей, то что насчет циферок? А вот — ну я же обвесил нужными циферками процесс.

Начал визуализировать все, что получилось.


Начав строить разные графики и радуясь, что вот теперь-то я забенчил всю эту агентную ораву, в какой-то момент я поймал себя на важной инженерной мысли — а что, собственно, я сейчас вообще сделал?

Типовые данные, типовые промпты, очень много общего кода и совсем немного самого фреймворка. Да разве ж это честно?
Попробуем зайти с другой стороны: у нас уже есть хороший документ систем-дизайна, так пусть по нему в самых лучших нюансах каждого фреймворка и будет написана реализация. И вот тогда, вот тогда...
Но посмотрев парочку framework-best-based реализаций, сильно покопавшись в их документации, я понял одну крамольную вещь — не все фреймворки одинаковые и, кажется, сравнивать их на одной задаче совсем нельзя.
Продолжая «строительную» тему газнокосилок — у нас тут есть швейцарский нож, молоток, зубило, шуруповерт и много чего еще — и вот эту агентную сову я пытаюсь натянуть на AI-глобус и посчитать одинаково.
Это нечестно. Главный вывод от всего проделанного — нельзя забенчить все фреймворки одной простой задачей. Здесь более уместно SBS (side-by-side) с возможным расширением участников (другими словами, сравнивать друг с другом больше двух). получается, что для полного-полного бенчмарка нужно найти подходящие классы задач, а затем под каждый класс тестировать наиболее релевантный этому классу набор фреймворков.
Целью этой статьи было дать наиболее полное представление обо всех-всех фреймворках, а если померить за раз не получилось, значит нужен другой подход.
Поэтому я стал думать о том, как максимально емко представить каждый из фреймворков и через несколько итераций, проб и ошибок, решил разбить их по следующим характеристикам:
Production-ready
Оказалось, что часть фреймворков вообще не позиционируют себя, как более-менее готовые к серьезному проду решения. Изучение концептов, обучение, ресерч или микро-проектики — да, но не прод. Не так важно, за сколько фреймворк порешал задачу если у него нет retries, evals и всякого-другого для реальной жизниФилософия (или англицизм Core Concepts)
Чем руководствовались авторы фреймворка и что легло в основуМультиагентность
Насколько хорошо мы можем подключаться разные сущности и устраивать взаимодействие между нимиЛучшее примение
Autogen придумывался как фреймворк для «в споре рождается истина». Когда наш flow не подразумевает спора, то ценность замеров околонулевая, а многие вещи будут оверкиломЛегкость реализации
Ммм, как будто бы уже похоже, но пока не то. Так, ну, в конце концов нас интересует именно тяжелый прод, поэтому давайте пойдем в сторону выявление проблем LLMок в реальном проде. Основные проблемы: неправильный вызов инструментов, галлюцинации самих LLM, объяснимость, контроль токенов/цены, зацикливание и прочее подобное неприятное.
Поэтому пересоберем наши критерии на следующие прод-based:
Production-Ready (стабильность, деплой)
Observability & Debugging (трейсинг, логи, понимание решений)
Мультиагентность (координация, паттерны общения)
Простота разработки (порог входа, DX [developer experience])
Error Handling & Reliability (retry, fallback, resilience)
По этим пунктам мы как будто бы даже можем выставить явную оценку. И радар-чарт кажется наиболее уместной визуализацией. Скажу честно, что выставление оценок не обошлось без десятка разных deep research у разных флагманских LLM с агрегацией всего этого уже мной на основе личного опыта (я много занимаюсь агентами, но иметь личный тяжелый прод на каждом фреймворке кажется невыполнимым условием). Если где-то есть что добавить, то буду рад внести исправления.
Оценка фреймворков по продо-применимости





Теперь добавим каждому философию и лучшую применимость. Пока я собирал информацию мне показалось важным добавить сюда зрелость/adoption. От зрелости зависит множество важных вещей, например, уже готовая поддержка MCP.
Маленькая вводная про MCP — это не фреймворк, а именно протокол — то есть, это способ отправки и обработки запросов. Это очень удобно, если агенту нужно ходить в самые разные системы и тогда через две строчки кода у вас уже есть готовый коннектор ко всему, но MCP — это все-таки инженерный оверхед над обычными запросами, поэтому он не всем и не всегда нужен, но это я попробую разобрать потом в отдельной статье.
В контексте фреймворков — прицепить MCP можно к любому фреймворку, и чем более зрелый фреймворк, тем вероятнее, что с mcp или a2a или другим протоколом все уже хорошо и сделано за нас.
Еще есть такая штука, как гибкость. Я долго думал куда ее добавить — радар-чарты или же таблицу, как ее вообще оценивать — штука-то очень субьективная и очень зависит от поставленной задачи. Поэтому пусть она будет в таблице.
Итоговая таблица:

В качестве бейзлайна для универсального агента хорошо подойдет LangChain. Для RAG - LlamaIndex. Для быстрой проверки командной работы агентов — CrewAI.
Выводы
Что же мы имеем на выходе? Бенчмарки и оценка таких сложных вещей как агенты и фреймворки — очень сложная тема, вся статья была проделана в соло одним человеком, поэтому наверняка есть множество вещей, которые я пропустил (объединения, ребрендинг или матюризацию фреймворков), не учел и которые можно было бы сделать лучше или более наглядно. Но на момент сейчас — мне стало сильно понятнее а что там вообще происходит и, надеюсь, вам тоже. Я бы с большим удовольствием прочитал бы эту статью сам, вместо того чтобы угробить на нее много часов ?
Вот самое важное, что я узнал в процессе и чтобы хотел зафиксировать:
Фреймворков много, но далеко не все из них вообще готовы к проду.
Опять же, при всем разнообразии, куча фреймворков либо нишевые, либо не подходят по другим условиям и при вопросе «какой фреймворк выбрать для моих AI-агентов» шорт-лист сводится к довольно небольшому списку, немного разному в зависимости от потребностей.
Фреймворки нельзя сравнить все со всеми, требуется более специфичное попарное сравнение между собой на конкретных классах задач.
LangChain как самое сбалансированное решение на старте никуда не делся, он как был так и остался. А если нужен вау-эффект для демо на новые погоны, то сгодится CrewAI.
И самый важный совет, который дали Anthropic еще в до-хайп-агентную эпоху: все, что можно сделать без агентов, стоит делать без агентов.
И в качестве пятничного мемасика: как я себя чувствую, когда люди, едва знакомые с разработкой и LLM, говорят что им надо срочно сделать ИИ-агента:

Спасибо!
P.S.: мне нравится писать всякое разное, но большие статьи отнимают очень-очень много времени, поэтому мне очень хочется делиться более короткими заметочками в своем мини-канальчик в тг Agentic World и буду очень рад вашей подписке ?
Мои другие статьи:
Rai220
Я бы еще популярность в сообществе бы добавил. Можно грубо оценить по количеству звездочек на github:
LangChain - 117k
AutoGen - 50k
LlamaIndex - 44k
CrewAI - 39k
Semantic Kernel - 26k
Smolagents - 23k
Google ADK - 13k