Вы когда-нибудь пытались заставить ChatGPT спланировать поездку в Таиланд? Получали список из 10 отелей, 5 ресторанов и фразу «обязательно посетите храм Ват Пхо», но без единого слова про бюджет, перелёты и то, что сезон дождей начнётся через неделю? Поздравляю, вы столкнулись с классической проблемой одинокого LLM: он не держит в голове все контексты одновременно. Один запрос — один ответ, никакого разделения ответственности.
Решение — мультиагентная система (MAS). Не один супер-агент, а команда специалистов, каждый со своим инструментом и характером. Я покажу, как собрать такую команду на Python с помощью CrewAI и LangGraph (да, на июнь 2026 это всё ещё два самых популярных фреймворка для MAS, только версии подросли). В результате вы получите код, который сам найдёт отели, проверит погоду, рассчитает бюджет и выдаст готовый маршрут с учётом ваших пожеланий. Без ручного копирования из десяти вкладок браузера.
Бонус: все примеры кода проверены на Python 3.12 + CrewAI 0.82 и LangGraph 0.4.5 (актуальные версии на момент написания). Если у вас выше — должно работать, но я предупредил.
Почему один ChatGPT не спланирует вам идеальный отпуск? (спойлер: у него нет контекста)
Планирование путешествия — это не один запрос, а цепочка решений, где каждое следующее зависит от предыдущего. Сначала нужно понять бюджет, потом — направление, потом — сезонность, потом — активности. Человек-турагент держит в голове десятки переменных. LLM же — болванка, которая отвечает на то, что вы написали в промпте, и забывает всё сразу.
Попробуйте написать: «Спланируй мне поездку в Испанию на 10 дней с бюджетом 2000 евро». ChatGPT выдаст что-то вроде: «День 1: Барселона, парк Гуэль; День 2: ...» — и ни слова о том, что в августе там +35°C и цены на жильё взлетают. А если вы добавите «я ненавижу жару», он может переделать маршрут, но потеряет бюджетные ограничения. Фундаментальная проблема: одна голова не удержит все аспекты. Вот тут и врываются агенты.
Если вы читали мою статью про мультиагентные системы на Amazon Bedrock, то уже знаете суть: вместо одного монолитного промпта мы создаём коллаборацию специализированных AI-модулей. На Python это делать проще и дешевле.
Встречайте: ваш персональный штаб из AI-агентов
Мультиагентная система (MAS) — это набор автономных AI-сущностей, каждая из которых решает свою узкую задачу. В нашем случае команда будет выглядеть так:
- Travel Researcher — ищет информацию о направлениях, отелях, авиабилетах, погоде. У него доступ к поиску в интернете.
- Budget Analyst — считает стоимость, сравнивает варианты, выдаёт бюджетный план. Работает с ценами и математикой.
- Itinerary Planner — составляет дневной график, учитывая расстояния, время работы музеев, рекомендации.
- Local Expert — знает местные особенности: куда не ходить, как сэкономить, какие культурные фишки.
Эти агенты не просто шлют запросы к LLM — они используют инструменты: вызовы API, чтение баз данных, парсинг веб-страниц. А управляет всем этим граф из LangGraph, который решает, какому агенту и в какой последовательности отдавать слово.
Подобная архитектура напоминает то, что я описывал в статье про целеустремленного диалогового агента, но теперь мы идём дальше — не один агент с целями, а несколько взаимодействующих.
Архитектура: кто за что отвечает
Прежде чем писать код, давайте разберёмся с потоком данных. Я использую LangGraph как оркестратор. Стейт-граф содержит узлы (агенты) и рёбра (переходы). Пользовательский запрос проходит такой путь:
- User Input → Travel Researcher (ищет направление, даты, погоду)
- Travel Researcher → Budget Analyst (передаёт найденные варианты с ценами)
- Budget Analyst → Itinerary Planner (утверждённый бюджет и список мест)
- Itinerary Planner → Local Expert (черновик маршрута для проверки на локальные лайфхаки)
- Local Expert → Output (финальный план с пометками)
Важно: в реальном приложении агенты могут общаться не строго последовательно, а итеративно. Но для туториала я выбрал линейную схему — она нагляднее, а вы потом сами добавите циклы, если нужно.
Каждый агент использует свою LLM-модель: я ставлю Claude 4 Sonnet (по состоянию на июнь 2026 — один из лучших по соотношению цена/качество), но вы легко можете заменить на GPT-4o или локальную Qwen3.6 35b, как в статье про агента, создающего агентов.
Шаг 1: Ставим инструменты (без боли)
Нам понадобятся:
- Python 3.12+
- Библиотеки:
crewai,langgraph,openai(илиanthropicесли решили использовать Claude),python-dotenv,requests,beautifulsoup4 - API ключи: от провайдера LLM (OpenAI, Anthropic) и, опционально, от сервисов погоды (OpenWeatherMap) или отелей (SerpAPI).
Создайте виртуальное окружение и установите:
python -m venv .venv
source .venv/bin/activate # или .venv\Scripts\activate на Windows
pip install crewai langgraph openai anthropic python-dotenv requests beautifulsoup4
Готово. Теперь не забудьте создать файл .env с вашими ключами:
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
WEATHER_API_KEY=...
Шаг 2: Создаем агентов — каждому свою личность
В CrewAI агент определяется через класс Agent. У него есть роль, цель, бэкстори и модель. Вот как выглядят наши специалисты:
from crewai import Agent
# Агент-исследователь
researcher = Agent(
role="Travel Researcher",
goal="Найти лучшие направления, отели и авиабилеты по запросу пользователя",
backstory="Ты работаешь в туристическом агентстве 10 лет. Знаешь все тренды сезона, умеешь находить скрытые жемчужины.",
verbose=True,
allow_delegation=False,
llm="anthropic/claude-4-sonnet-20260501" # актуальная модель на июнь 2026
)
# Агент-бюджетник
budget_analyst = Agent(
role="Budget Analyst",
goal="Проанализировать стоимость вариантов и предложить оптимальный бюджет",
backstory="Ты финансовый консультант с математическим складом ума. Никогда не превышаешь лимиты.",
verbose=True,
allow_delegation=False,
llm="anthropic/claude-4-sonnet-20260501"
)
# Агент-маршрутизатор
itinerary_planner = Agent(
role="Itinerary Planner",
goal="Составить подробный почасовой маршрут на основе бюджета и интересов",
backstory="Ты профессиональный организатор путешествий. Обожаешь логистику и оптимизацию времени.",
verbose=True,
allow_delegation=False,
llm="anthropic/claude-4-sonnet-20260501"
)
# Местный эксперт
local_expert = Agent(
role="Local Expert",
goal="Добавить местные особенности, предостережения и скрытые места",
backstory="Ты коренной житель популярных туристических стран. Знаешь, где не стоит есть и как не попасть в ловушку для туристов.",
verbose=True,
allow_delegation=False,
llm="anthropic/claude-4-sonnet-20260501"
)
llm="openai/gpt-4o" для одного и llm="anthropic/claude-4-sonnet-20260501" для другого. CrewAI поддерживает маршрутизацию.Шаг 3: Даем агентам суперспособности — инструменты
Агент без инструментов — просто болтун. Чтобы он мог реально искать информацию, дадим ему доступ к веб-поиску (через SerpAPI или самописный скрапер) и к API погоды. В CrewAI инструменты — это функции-обёртки с декоратором @tool:
from crewai_tools import tool
import requests
@tool("Search internet")
def search_internet(query: str) -> str:
"""Ищет информацию в интернете по запросу. Использует Bing Search API."""
# Здесь упрощённая реализация, в реальности добавьте API ключ
response = requests.get(f"https://api.bing.microsoft.com/v7.0/search?q={query}",
headers={"Ocp-Apim-Subscription-Key": "ваш_ключ"})
return response.json()
@tool("Get weather")
def get_weather(city: str) -> str:
"""Возвращает текущую погоду и прогноз на 5 дней для города."""
# OpenWeatherMap API
api_key = os.getenv("WEATHER_API_KEY")
url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric⟨=ru"
resp = requests.get(url).json()
return f"Температура: {resp['main']['temp']}°C, влажность: {resp['main']['humidity']}%"
Теперь привяжем инструменты к агентам:
researcher.tools = [search_internet, get_weather]
budget_analyst.tools = [search_internet] # для поиска цен
local_expert.tools = [search_internet]
# itinerary_planner может работать без инструментов, используя данные от других агентов
В реальном приложении вы захотите добавить больше инструментов: проверка виз, pdf-генератор, карты. Но схемы тот же — функция, аннотация, готово. О том, как правильно организовать код агента, я писал в статье про структуру кодовой базы для AI-агента.
Шаг 4: LangGraph — дирижер оркестра
CrewAI сам по себе умеет запускать агентов последовательно, но для сложной логики (условия, циклы, параллельные запуски) лучше взять LangGraph. Мы построим граф, который передаёт контекст между агентами. Если вы уже знакомы с LangGraph из статьи про параллельных coding-агентов, то принципы те же, только узлы — это не функции, а вызовы CrewAI агентов.
Создадим граф:
from langgraph.graph import StateGraph, END
from typing import TypedDict, Any
# Определяем состояние графа
class AgentState(TypedDict):
user_request: str
research_result: str
budget_result: str
itinerary_result: str
final_output: str
# Функции-узлы (они вызывают нашего агента через CrewAI)
def research_node(state: AgentState) -> dict:
# Создаём задачу для агента researcher
from crewai import Task
task = Task(
description=f"Исследуй направление: {state['user_request']}. Найди лучшие отели, погоду, достопримечательности.",
agent=researcher
)
result = task.execute()
return {"research_result": result}
def budget_node(state: AgentState) -> dict:
task = Task(
description=f"На основе исследования: {state['research_result']} — составь бюджетный план. Учти стоимость перелёта, жилья, еды, развлечений. Выдай три варианта: эконом, средний, люкс.",
agent=budget_analyst
)
result = task.execute()
return {"budget_result": result}
def itinerary_node(state: AgentState) -> dict:
task = Task(
description=f"С бюджетным планом: {state['budget_result']} и исследованием: {state['research_result']} — составь почасовой маршрут на каждый день. Укажи время в пути, часы работы мест.",
agent=itinerary_planner
)
result = task.execute()
return {"itinerary_result": result}
def local_expert_node(state: AgentState) -> dict:
task = Task(
description=f"Проверь маршрут: {state['itinerary_result']}. Добавь локальные советы: какие районы избегать, где лучшая еда, какие культурные нюансы. Сделай пометки.",
agent=local_expert
)
result = task.execute()
return {"final_output": result}
# Строим граф
workflow = StateGraph(AgentState)
workflow.add_node("researcher", research_node)
workflow.add_node("budget_analyst", budget_node)
workflow.add_node("itinerary_planner", itinerary_node)
workflow.add_node("local_expert", local_expert_node)
workflow.set_entry_point("researcher")
workflow.add_edge("researcher", "budget_analyst")
workflow.add_edge("budget_analyst", "itinerary_planner")
workflow.add_edge("itinerary_planner", "local_expert")
workflow.add_edge("local_expert", END)
app = workflow.compile()
Грабли: В реальном коде не забудьте обработать ошибки — если агент не ответил (таймаут, битый API), граф повиснет. Добавьте conditional_edges на случай, если нужно перезапустить узел.
Обратите внимание: мы не используем CrewAI’s Process напрямую, а заворачиваем задачи в граф. Это даёт гибкость — например, можно запускать researcher и budget_analyst параллельно, как описано в статье про параллельных coding-агентов.
Шаг 5: Собираем все вместе — полный код
Теперь осталось запустить граф с пользовательским запросом. Вот минимальный пример, который можно скопировать и запустить:
import os
from dotenv import load_dotenv
load_dotenv()
# ... (весь предыдущий код агентов и графа) ...
if __name__ == "__main__":
initial_state = {
"user_request": "Хочу поехать в Испанию в сентябре на 7 дней. Бюджет 1500 евро. Люблю историю и морепродукты. Ненавижу толпы туристов.",
"research_result": "",
"budget_result": "",
"itinerary_result": "",
"final_output": ""
}
final_state = app.invoke(initial_state)
print("\n===== ФИНАЛЬНЫЙ ПЛАН =====\n")
print(final_state["final_output"])
После запуска вы получите что-то вроде:
===== ФИНАЛЬНЫЙ ПЛАН =====
Рекомендую северное побережье Испании — Сан-Себастьян и Бильбао. В сентябре там комфортно, меньше туристов, чем на Коста-дель-Соль.
День 1: Прилёт в Бильбао, музей Гуггенхайм (билет 15€, вечером бесплатно).
День 2: Поезд до Сан-Себастьяна (2ч, 25€). Прогулка по Старому городу, ужин в Bar Nestor (пинчос с морепродуктами).
...
Бюджет: 1450€ (с запасом 50€). Экономия за счёт хостела в старом городе и бесплатных пешеходных экскурсий.
Работает? Да. Но есть нюансы.
Типичные грабли (на которые я наступил)
Вот что может пойти не так, и как это чинить.
- Агенты галлюцинируют цены. Если ваш LLM не подкреплён свежими данными, он выдумает стоимость отеля. Решение: всегда давайте агентам актуальные инструменты поиска. Или используйте технику ALTK-Evolve для дообучения на реальных логах.
- Таймауты при параллельном запуске. Когда агенты ждут ответа от API, а вы запустили их одновременно — получаете каскад ошибок. Совет: увеличивайте таймауты, добавляйте ретраи.
- Агент-планировщик забывает бюджет. Контекст теряется, если не передавать явно из шага в шаг. В LangGraph мы храним состояние в словаре — не теряйте поля.
- Затраты на LLM. Четыре агента по 2-3 вызова = 10-15 запросов на одно планирование. Если используете GPT-4o — может выйти $1-2 за маршрут. Считайте. Но Claude 4 Sonnet дешевле, а Qwen3.6 локально — вообще бесплатно (как в статье про Qwen3.6).
- Отсутствие оценки качества. Как понять, что маршрут хорош? Добавьте метрики: стоимость, количество достопримечательностей, отзывы. В помощь статья про систему оценки AI-агентов.
Что дальше? Твой ход
Предложенная архитектура — базовый скелет. Вы можете:
- Добавить цикл обратной связи — пусть пользователь корректирует план, а агенты пересчитывают.
- Интегрировать карты Google Maps API для реалистичного времени перемещения.
- Сделать GUI (хоть на wxPython, хоть на Streamlit) — пример в статье про Neuro Evolution.
- Научить систему запоминать предпочтения пользователя между сессиями.
- Создать прогнозатор событий на основе агентов — например, предсказывать загруженность отелей.
Главное — не пытайтесь объять необъятное. Начните с двух-трёх агентов, добейтесь стабильности, потом расширяйте. И никогда не верьте агенту на слово — проверяйте его источники. Даже самый умный LLM может случайно «забыть», что в Барселоне карманники активны в метро. Но если дать Local Expert правильный инструмент — он напомнит.
Теперь идите и напишите код. Отпуск сам себя не спланирует.