Проблема: команда тонет в коде

Вернёмся к нашей тройке «аналитик → писатель → критик». В чистом 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/. Код в отдельном файле их подхватывает и собирает команду.

100%
колёсико — масштаб  ·  зажать и тянуть — перемещение
config/agents.yaml роли: role / goal / backstory config/tasks.yaml задачи: description / expected_output КОНФИГУРАЦИЯ (что за команда) crew.py @CrewBase подхватывает YAML КОД (как собрать) Crew kickoff() описание команды в YAML + тонкий код сборки → работающий Crew
config/agents.yaml — роли команды
yaml
analyst:
  role: >
    Аналитик рынка {topic}
  goal: >
    Собрать точные факты и цифры по теме {topic} с источниками
  backstory: >
    Ты дотошный аналитик с 8-летним стажем. Никогда не утверждаешь
    без подтверждения и всегда даёшь источник.

writer:
  role: >
    Редактор-копирайтер
  goal: >
    Превратить факты в ясный структурированный текст
  backstory: >
    Опытный редактор, ценит простоту и режет воду.
config/tasks.yaml — задачи команды
yaml
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 подставляет в них конфигурацию по имени.

crew.py — сборка из YAML
python
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.

Что это даёт

читаемость
Команда видна как на ладони: открыл YAML — понял роли и задачи без чтения кода.
правки без кода
Поправить промпт роли или текст задачи = отредактировать YAML. Логику запуска не трогаешь.
доступно не-кодерам
Доменный эксперт или продакт правит роли в YAML, не боясь сломать Python.
git-дружелюбно
Изменения промптов видны в diff построчно — удобно ревьюить и откатывать.
YAML — рекомендуемый способ CrewAI

Документация CrewAI продвигает YAML-конфигурацию как основной подход (а crewai create сразу создаёт эту структуру). Не воспринимай её как «лишний слой»: для любой команды сложнее одной-двух ролей разделение «YAML-описание + тонкий код» окупается читаемостью и поддерживаемостью. Прямой Python-вызов оставляй для совсем быстрых экспериментов.

Переменные и динамика

Плейсхолдеры {topic} в YAML — это та же интерполяция из inputs, что в коде. Они делают конфигурацию шаблоном: один и тот же YAML обслуживает разные темы, проекты, языки — конкретика приходит в kickoff(inputs=...).

Один YAML — много запусков
python
# {topic} в YAML подставляется при каждом запуске
crew = ContentCrew().crew()

crew.kickoff(inputs={"topic": "электромобили"})
crew.kickoff(inputs={"topic": "облачные сервисы"})
crew.kickoff(inputs={"topic": "рынок труда в IT"})
# одна конфигурация, разные входы — без правки YAML и кода

Типичные ошибки

Ошибка 1: имя в YAML ≠ имя метода

Ключ агента/задачи в YAML и имя метода в @agent/@task должны совпадать — CrewAI связывает их по имени. Опечатка — и конфиг не подхватится.

Ошибка 2: сломанный YAML-отступ

YAML чувствителен к отступам (только пробелы, не табы). Кривой отступ ломает парсинг всего файла. Проверяй структуру; многострочные тексты оформляй через > или |.

Ошибка 3: плейсхолдер без значения

Если в YAML есть {topic}, а в inputs его не передали, подстановка не сработает. Все плейсхолдеры конфигурации должны приходить из kickoff(inputs=...).

Ошибка 4: логика, заехавшая в YAML

YAML — для описания (роли, задачи, тексты), а не для логики. Условия, ветвления, выбор процесса — это код. Не пытайся «программировать» в конфиге.

Шпаргалка

YAML конфигурация CrewAI — всё в одном месте
text
ИДЕЯ: описание команды → 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:

Задание: вынеси команду в конфигурацию

  1. Создай проект через crewai create crew (или вручную папку config/ с двумя YAML). Перенеси тройку «аналитик → писатель → критик» из прошлых уроков в agents.yaml и tasks.yaml.
  2. Напиши тонкий crew.py с @CrewBase и методами @agent/@task/@crew. Убедись, что имена совпадают с ключами YAML.
  3. Используй плейсхолдер {topic} и запусти команду через kickoff(inputs={"topic": ...}) для двух разных тем — без правки YAML.
  4. Сравни читаемость: открой YAML и оцени, насколько проще понять команду, чем по чистому Python из прошлых уроков.
  5. Намеренно сломай отступ в YAML и опечатайся в имени метода — разбери ошибки, которые получишь. Это закрепит правила связывания.
  6. Со звёздочкой: добавь третью роль (критик) и третью задачу в YAML, ничего не меняя в логике crew.py кроме регистрации метода — почувствуй, как легко растёт команда (привет масштабируемости).

Что дальше

YAML делает команды читаемыми, но Crew остаётся линейной/иерархической оркестрацией. Для сложных, событийных сценариев с ветвлениями и состоянием у CrewAI есть отдельный механизм — Flows. Это последний урок раздела CrewAI.