Проблема: команда тонет в коде
Вернёмся к нашей тройке «аналитик → писатель → критик». В чистом Python каждый агент — это вызов Agent(...) с многострочными role, goal, backstory, а каждая задача — Task(...) с длинным description и expected_output. Для трёх агентов и трёх задач это уже десятки строк, где что описывает команду и как её запускают перемешано.
Проблем несколько: тексты ролей и задач трудно читать среди кода; их нельзя поправить, не трогая логику; не-программист (продакт, доменный эксперт) не может отредактировать промпт роли, не боясь сломать скрипт. Это нарушение принципа «разделяй конфигурацию и код» — того же, ради чего мы выносили .env и настройки в модуле 01.
«Какие у команды роли и задачи» — это конфигурация: данные, которые меняются часто и должны быть читаемы. «Как собрать Crew и запустить» — это код: логика, которая меняется редко. CrewAI поощряет держать их раздельно: YAML для описания, Python для сборки. Так система становится понятнее и тем, кто пишет код, и тем, кто правит промпты.
Структура: agents.yaml и tasks.yaml
CrewAI-проект (создаётся командой crewai create crew <name>) кладёт описания в два YAML-файла внутри папки config/. Код в отдельном файле их подхватывает и собирает команду.
analyst:
role: >
Аналитик рынка {topic}
goal: >
Собрать точные факты и цифры по теме {topic} с источниками
backstory: >
Ты дотошный аналитик с 8-летним стажем. Никогда не утверждаешь
без подтверждения и всегда даёшь источник.
writer:
role: >
Редактор-копирайтер
goal: >
Превратить факты в ясный структурированный текст
backstory: >
Опытный редактор, ценит простоту и режет воду.
research_task:
description: >
Собери ключевые факты и цифры по теме {topic}.
expected_output: >
Маркированный список из 5–7 фактов с источниками.
agent: analyst # имя агента из agents.yaml
write_task:
description: >
Напиши короткий обзор по собранным фактам.
expected_output: >
Связный текст на 2–3 абзаца.
agent: writer
context:
- research_task # вход — результат предыдущей задачи
Прочитай эти файлы — и сразу понятно, что делает команда: роли описаны человеческим языком, задачи с ожидаемым результатом, зависимости через context. Никакого Python-шума. Заметь и {topic} — это плейсхолдеры, которые подставятся из inputs при запуске (как в прошлых уроках).
Код, который подхватывает YAML
Связывает YAML и запуск тонкий Python-файл с декоратором @CrewBase. Он автоматически читает оба файла, а ты лишь помечаешь методы декораторами @agent, @task, @crew — CrewAI подставляет в них конфигурацию по имени.
from crewai import Agent, Task, Crew, Process
from crewai.project import CrewBase, agent, task, crew
@CrewBase
class ContentCrew:
"""Команда: аналитик + писатель."""
agents_config = "config/agents.yaml" # пути к конфигам
tasks_config = "config/tasks.yaml"
@agent
def analyst(self) -> Agent:
return Agent(config=self.agents_config["analyst"]) # роль из YAML
@agent
def writer(self) -> Agent:
return Agent(config=self.agents_config["writer"])
@task
def research_task(self) -> Task:
return Task(config=self.tasks_config["research_task"])
@task
def write_task(self) -> Task:
return Task(config=self.tasks_config["write_task"])
@crew
def crew(self) -> Crew:
return Crew(agents=self.agents, tasks=self.tasks, # авто-собранные списки
process=Process.sequential)
# Запуск
result = ContentCrew().crew().kickoff(inputs={"topic": "рынок электромобилей 2025"})
Обрати внимание: код стал тонким и однотипным — он лишь «склеивает» имена из YAML. Вся суть (роли, задачи, тексты) живёт в конфигурации. Списки self.agents и self.tasks CrewAI собирает автоматически из помеченных методов — порядок задач для sequential берётся из порядка @task.
Что это даёт
Документация CrewAI продвигает YAML-конфигурацию как основной подход (а crewai create сразу создаёт эту структуру). Не воспринимай её как «лишний слой»: для любой команды сложнее одной-двух ролей разделение «YAML-описание + тонкий код» окупается читаемостью и поддерживаемостью. Прямой Python-вызов оставляй для совсем быстрых экспериментов.
Переменные и динамика
Плейсхолдеры {topic} в YAML — это та же интерполяция из inputs, что в коде. Они делают конфигурацию шаблоном: один и тот же YAML обслуживает разные темы, проекты, языки — конкретика приходит в kickoff(inputs=...).
# {topic} в YAML подставляется при каждом запуске
crew = ContentCrew().crew()
crew.kickoff(inputs={"topic": "электромобили"})
crew.kickoff(inputs={"topic": "облачные сервисы"})
crew.kickoff(inputs={"topic": "рынок труда в IT"})
# одна конфигурация, разные входы — без правки YAML и кода
Типичные ошибки
Ключ агента/задачи в YAML и имя метода в @agent/@task должны совпадать — CrewAI связывает их по имени. Опечатка — и конфиг не подхватится.
YAML чувствителен к отступам (только пробелы, не табы). Кривой отступ ломает парсинг всего файла. Проверяй структуру; многострочные тексты оформляй через > или |.
Если в YAML есть {topic}, а в inputs его не передали, подстановка не сработает. Все плейсхолдеры конфигурации должны приходить из kickoff(inputs=...).
YAML — для описания (роли, задачи, тексты), а не для логики. Условия, ветвления, выбор процесса — это код. Не пытайся «программировать» в конфиге.
Шпаргалка
ИДЕЯ: описание команды → YAML, сборка/запуск → тонкий Python
(принцип «разделяй конфигурацию и код»)
СТРУКТУРА (crewai create crew ):
config/agents.yaml — роли: role / goal / backstory
config/tasks.yaml — задачи: description / expected_output / agent / context
crew.py — @CrewBase + @agent / @task / @crew
СВЯЗЫВАНИЕ:
ключ в YAML == имя метода в коде (совпадение по имени!)
Agent(config=self.agents_config["analyst"])
Task(config=self.tasks_config["research_task"])
ПЛЕЙСХОЛДЕРЫ:
{topic} в YAML → подставляется из kickoff(inputs={"topic": ...})
один YAML → много запусков с разными входами
ПЛЮСЫ: читаемость · правки без кода · доступно не-кодерам · git-diff
ГРАБЛИ:
• имя в YAML = имя метода
• YAML-отступы (пробелы, не табы); многострочно → > или |
• плейсхолдеры должны приходить из inputs
• в YAML — описание, НЕ логика
Практическое задание
Переведи команду на YAML:
Задание: вынеси команду в конфигурацию
- Создай проект через
crewai create crew(или вручную папкуconfig/с двумя YAML). Перенеси тройку «аналитик → писатель → критик» из прошлых уроков вagents.yamlиtasks.yaml. - Напиши тонкий
crew.pyс@CrewBaseи методами@agent/@task/@crew. Убедись, что имена совпадают с ключами YAML. - Используй плейсхолдер
{topic}и запусти команду черезkickoff(inputs={"topic": ...})для двух разных тем — без правки YAML. - Сравни читаемость: открой YAML и оцени, насколько проще понять команду, чем по чистому Python из прошлых уроков.
- Намеренно сломай отступ в YAML и опечатайся в имени метода — разбери ошибки, которые получишь. Это закрепит правила связывания.
- Со звёздочкой: добавь третью роль (критик) и третью задачу в YAML, ничего не меняя в логике
crew.pyкроме регистрации метода — почувствуй, как легко растёт команда (привет масштабируемости).
Что дальше
YAML делает команды читаемыми, но Crew остаётся линейной/иерархической оркестрацией. Для сложных, событийных сценариев с ветвлениями и состоянием у CrewAI есть отдельный механизм — Flows. Это последний урок раздела CrewAI.