При подготовке урока сценарий взял две выгрузки учебной кофейни «Зерно», из Директа и из Метрики, и за 54 секунды выдал отчёт собственнику. Все цифры в отчёте совпали с теми, что посчитал код. А вывод был неверный: разницу в одну конверсию, 53 против 52, модель назвала «падением эффективности». Собственник, прочитав такое, начнёт что-то чинить, хотя чинить нечего. В этом уроке вы соберёте недельный отчёт, в котором цифры считает код, а модель их только пересказывает, и научите её отличать перемену от шума.
Чему научитесь в этом уроке:
• принять два файла через форму n8n и разобрать их в двух параллельных ветках;
• посчитать неделю к неделе кодом: расход, клики, CTR (долю кликнувших), конверсии, цену конверсии, визиты;
• написать промпт, где модель пересказывает готовые цифры и не раздувает мелкие колебания;
• сохранить посчитанные недели в таблицу данных, чтобы слайд урока 4.6 брал их по расписанию сам.
Бухгалтер считает, директор пересказывает
В нормальной компании отчёт делают двое. Бухгалтер сводит цифры и отвечает за каждую копейку. Директор берёт его таблицу и говорит собранию по-человечески: «неделя ровная, вот что делаем дальше». Если поручить директору ещё и считать, он округлит, перепутает недели и добавит пару цифр «для убедительности».
В сценарии бухгалтер это узел Code, кусок кода на JavaScript, который n8n выполняет как есть. Он считает одинаково при каждом запуске. Директор это модель: она хорошо пишет связный текст и плохо складывает. Этот принцип вы уже применяли в треке 2, в уроке «Отчёт собственнику»: там модель в одном прогоне из четырёх написала «закрыто 6 задач» при нуле закрытых. Здесь та же схема, только данные приходят из рекламы и сайта.
Схема сценария
Сценарий при подготовке назывался «Т3 прогон 4.4: отчёт по Директу и Метрике». Узлы по порядку:
- Form Trigger «Загрузка выгрузок». Это веб-форма, которую n8n показывает по ссылке. В ней два поля-файла:
direct_csvиmetrika_csv. - Extract From File «Директ» и Extract From File «Метрика». Узел превращает файл CSV в строки таблицы. Оба формат CSV, разделитель «,». Оба подключены прямо к форме, параллельно.
- Merge «Обе выгрузки», режим Append. Ждёт обе ветки и складывает их строки в один поток.
- Code «Цифры недели». Считает две недели и разницу между ними.
- Basic LLM Chain «Отчёт собственнику». Модель пишет текст по готовым цифрам. При подготовке урока это была
google/gemini-3.6-flashчерез CloseRouter. - Data Table «В таблицу цифр». Записывает посчитанные недели в таблицу данных «Цифры недели». Подключён к «Цифрам недели» второй стрелкой, рядом с моделью. Зачем он нужен, ниже.

Какие выгрузки брать и как их скачать из кабинетов, разобрано в уроке «Данные маркетолога: выгрузки». Для тренировки подойдут учебные файлы курса direct.csv и metrika.csv: они повторяют формат настоящих выгрузок.
Ошибка первой сборки: почему ветки параллельные
В первой версии узлы стояли цепочкой: форма, потом «Директ», потом «Метрика». Логично на вид: сначала один файл, потом другой. Сценарий упал на «Метрике» с ошибкой expects binary 'metrika_csv', то есть узел ждал файл metrika_csv и не нашёл его.
Причина простая. Форма отдаёт оба файла первому узлу после себя. «Директ» разбирает свой файл и передаёт дальше уже строки таблицы, а сами файлы формы на этом теряются. «Метрике» нечего читать. Это как передать курьеру два конверта, а он вскрыл первый и отдал коллеге только листы из него, без второго конверта.
Исправление: оба узла подключаются прямо к форме, каждый берёт свой файл, а Merge «Обе выгрузки» ждёт, пока закончат оба. Если в вашем сценарии узел ругается на отсутствующий файл, первым делом проверьте, от какого узла к нему идёт стрелка.
Код «Цифры недели»
Этот код работал при подготовке урока. Вставьте его в узел Code целиком. Узлы выгрузок должны называться ровно «Директ» и «Метрика»: код находит их по имени.
// Неделя к неделе: цифры считает код
const d = $('Директ').all().map(i => i.json), m = $('Метрика').all().map(i => i.json);
// Числа из Директа бывают с пробелами и запятой: «1 234,56»
const num = v => Number(String(v).replace(/[\s ]/g, '').replace(',', '.')) || 0;
// Столбцы ищем по началу имени: «Расход» и «Расход, ₽», «Конверсии» и «Конверсии (цель)»
const col = (rows, prefix) => Object.keys(rows[0] || {}).find(k => k.startsWith(prefix));
const weeks = [['2026-09-28','2026-10-04'],['2026-10-05','2026-10-11']];
// Директ пишет «День», Метрика — «Дата визита»; строка «Итого» отсеивается по дате
const day = r => r['День'] || r['Дата'] || r['Дата визита'] || '';
const inW = (r, w) => day(r) >= w[0] && day(r) <= w[1];
const sum = (rows, prefix) => { const k = col(rows, prefix); return k ? rows.reduce((s, r) => s + num(r[k]), 0) : null; };
const out = weeks.map(w => { const dr = d.filter(r => inW(r, w)), mr = m.filter(r => inW(r, w));
const cost = sum(dr, 'Расход'), clicks = sum(dr, 'Клики'), conv = sum(dr, 'Конверси'), shows = sum(dr, 'Показы');
return { неделя: w[0] + '…' + w[1], дней: new Set(dr.map(day)).size, расход: Math.round(cost), клики: clicks,
ctr: shows ? (clicks / shows * 100).toFixed(2) : 'нет столбца «Показы»', конверсии: conv,
цена_конверсии: conv ? Math.round(cost / conv) : null, визиты: sum(mr, 'Визиты') }; });
const delta = (a, b) => b ? ((a - b) / b * 100).toFixed(0) + '%' : '—';
const [p, c] = out;
const text = 'Прошлая неделя: ' + JSON.stringify(p) + '\nЭта неделя: ' + JSON.stringify(c) + '\nИзменение: расход ' + delta(c.расход, p.расход) + ', конверсии ' + delta(c.конверсии, p.конверсии) + ', цена конверсии ' + delta(c.цена_конверсии, p.цена_конверсии) + ', визиты ' + delta(c.визиты, p.визиты);
return [{ json: { text, weeks: out } }];
Что в нём стоит знать без программирования:
- Столбцы ищутся по началу имени. В настоящем Директе столбец называется «Расход, ₽», а в учебном файле поначалу был просто «Расход». Код по точному имени дал бы нули на настоящей выгрузке, поэтому он ищет всё, что начинается с «Расход».
- Дата берётся из «День» (так пишет Директ) или из «Дата визита» (так пишет Метрика). В строке «Итого» на месте даты пусто (Директ) или слово «Итого и средние» (Метрика), в неделю она не попадает и в подсчёт не идёт.
- Если в выгрузке Директа нет столбца «Показы», вместо CTR будет надпись «нет столбца «Показы»». CTR это доля людей, которые увидели объявление и кликнули; без числа показов её не посчитать. Столбец добавляется в «Группировки и метрики» отчёта Директа.
- Поле
днейпоказывает, сколько дней с данными попало в неделю. По нему модель скажет, если неделя неполная.
Даты недель заданы руками. Строка const weeks = [['2026-09-28','2026-10-04'],['2026-10-05','2026-10-11']]; подобрана под учебные файлы. Для своих выгрузок замените четыре даты: первая пара это прошлая неделя, вторая последняя полная неделя, с понедельника по воскресенье. Например, если вы выгружаете в среду 14 октября, последняя полная неделя с 5 по 11 октября, а прошлая с 28 сентября по 4 октября. В учебных файлах даты записаны как 2026-09-28; если в вашей выгрузке они выглядят иначе, код неделю не найдёт. Такой вариант в прогоне курса не проверяли: сверьте вид даты в своём файле до запуска.
Что посчитал код
Два слова из урока 4.1. Конверсия здесь значит действие после рекламы, которое выбрано целью в Директе; у «Зерна» это «построил маршрут в Картах». Цена конверсии это расход, делённый на число таких действий: 10 994 ₽ / 52 ≈ 211 ₽. На учебных файлах вышло так:
- расход: 10 654 → 10 994 ₽ (+3%);
- клики: 833 → 800;
- CTR: 3,61 → 3,32%;
- конверсии: 53 → 52;
- цена конверсии: 201 → 211 ₽ (+5%);
- визиты на сайт: 1228 → 1216.
Сценарий отработал за 54 секунды и потратил 494 токена. Цифры в тексте отчёта совпали с кодом, тут модель не подвела. Ошибка была в словах.
Узел «В таблицу цифр»: цифры для слайда
Отчёт вы запускаете формой, когда скачали выгрузки. А слайд из урока 4.6 мы поставим на расписание: в понедельник утром он соберётся сам. Файлов у него нет, поэтому цифры ему оставляет этот сценарий. При каждом запуске он дописывает посчитанные недели строкой в таблицу данных, а слайд берёт оттуда последнюю строку.
Создайте таблицу: Personal → Data tables → Create data table, имя «Цифры недели», две колонки period и weeks, обе с типом string (текст). Добавьте узел Data Table с действием Insert (добавить строку), назовите его «В таблицу цифр» и протяните к нему вторую стрелку от «Цифр недели». От одного узла пойдут две стрелки: к модели и к таблице. Поля заполните выражениями:
- period:
{{ $json.weeks[1].неделя }} - weeks:
{{ JSON.stringify($json.weeks) }}
В period попадает подпись текущей недели, в weeks обе недели целиком, записанные одной строкой текста. После этой правки сценарий запустили формой с учебными файлами в формате настоящих выгрузок: в каждой неделе 7 дней из 7, строка в таблицу «Цифры недели» записана.
Шум: когда «меньше» ещё не «хуже»
Посмотрите на конверсии: 53 и 52. Одна конверсия разницы. В кофейне за неделю один человек мог просто не построить маршрут, потому что шёл дождь. Модель назвала это «падением эффективности», а при повторном прогоне, после правки форматов файлов, снова написала про «снижение эффективности». И в запуске после добавления таблицы цифр то же: «эффективность немного снизилась».
Модель не знает, какая разница для вашего бизнеса существенная. Ей нужен порог, записанный словами. Возьмём такой: изменение меньше 10% или меньше 5 штук считается шумом. Конверсии изменились на одну штуку, расход на 3%, цена конверсии на 5%: по этому порогу всё это шум. В уроке 4.5 этот порог проверим на тех же цифрах.
Вторая правка: в исходном промпте CTR не был в списке обязательных строк, хотя именно он изменился сильнее остальных. Его стоит назвать явно, чтобы собственник видел и его.
Промпт «Отчёт собственнику»
Так было в прогоне, в системном сообщении узла:
Ты маркетолог-аналитик кофейни. По цифрам двух недель (уже посчитаны, не меняй их) напиши отчёт собственнику, простым текстом без звёздочек и разметки, не длиннее 8 строк: главное одной фразой; расход, конверсии и цену конверсии с изменением; визиты; одна рекомендация на следующую неделю. Если в неделе меньше 7 дней данных, так и скажи. Не придумывай цифр, которых нет.
Вариант с порогом шума и обязательной строкой CTR:
Ты маркетолог-аналитик кофейни. По цифрам двух недель (уже посчитаны, не меняй их) напиши отчёт собственнику, простым текстом без звёздочек и разметки, не длиннее 8 строк: главное одной фразой; расход, конверсии и цену конверсии с изменением; CTR; визиты; одна рекомендация на следующую неделю.
Порог шума: если показатель изменился меньше чем на 10% или меньше чем на 5 штук, пиши «без изменений» и не называй это ни ростом, ни падением.
Если в неделе меньше 7 дней данных, так и скажи. Не придумывай цифр, которых нет.
Что проверено, а что нет. Во всех запусках прогона работал промпт «как было», и все три раза модель назвала ровную неделю снижением. Промпт с порогом и строкой CTR в прогоне курса не запускали. Запустите его на учебных файлах и сверьте: ни одна строка не должна называться ростом или падением.
Сообщение пользователя в узле модели: {{ $json.text }}. Это строка, которую собрал код: две недели и изменения.
Куда отправить отчёт
Отправить отчёт в Telegram можно так же, как в треке 2, в уроке «Отчёт собственнику». Сам сценарий по расписанию не запускается: ему нужен свежий файл из кабинета. Запускайте его формой раз в неделю, когда скачали выгрузки. Заодно он обновит таблицу «Цифры недели» для слайда.
Если не получилось
- Ошибка expects binary ‘metrika_csv’ или ‘direct_csv’. Узел выгрузки подключён не к форме, а к другому узлу. Подключите оба узла прямо к форме и соедините их в Merge.
- Все цифры нули. Проверьте разделитель «,» в узлах выгрузок, названия узлов «Директ» и «Метрика» и даты в строке
weeks: если неделя не совпала с датами файла, считать нечего. - Вместо CTR надпись «нет столбца «Показы»». Добавьте «Показы» в отчёт Директа и скачайте выгрузку заново.
- Модель меняет цифры или добавляет свои. Сравните отчёт с выходом узла «Цифры недели». Если расходится, запустите ещё раз; повторяется, смените модель.
- Модель всё равно пишет «падение» при разнице в 2–3%. Проверьте, что порог шума стоит в системном сообщении. Порог можно перенести и в код, так сделаем в уроке 4.5: тогда модель получит готовую пометку «без изменений» у каждой строки.
- «В таблицу цифр» ругается на колонку. Названия колонок в узле и в таблице «Цифры недели» должны совпадать буква в букву: period и weeks.
Контрольный вопрос. В сценарии форма отдаёт два файла, а узлы «Директ» и «Метрика» стоят друг за другом. «Метрика» падает с ошибкой, что не видит файл. Почему?
Подсказка: Подумайте, что именно передаёт дальше узел, который разбирает файл в таблицу.
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Конверсии за неделю: 53 и 52. В промпте порог шума: меньше 10% или меньше 5 штук. Как отчёт должен описать конверсии?
Подсказка: Посчитайте разницу в штуках и сравните с порогом.
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Что в сценарии недельного отчёта делает код, а не модель? Выберите все подходящие.
Выберите все верные варианты.
Подсказка: Всё, что можно посчитать и проверить калькулятором, отдают тому, кто не ошибается в счёте.
На курсе задания проверяются автоматически. Подобрать курс
Задание. МИССИЯ «Понедельничный отчёт». Соберите в n8n сценарий: форма с двумя файлами, параллельно «Директ» и «Метрика», Merge «Обе выгрузки», Code «Цифры недели», модель «Отчёт собственнику» с порогом шума и строкой CTR, а второй стрелкой от «Цифр недели» Data Table «В таблицу цифр». Запустите на учебных файлах или на своих выгрузках (тогда поменяйте даты недель в коде). Приложите: (1) скриншот сценария; (2) выход узла «Цифры недели»; (3) текст отчёта; (4) одну фразу: какие показатели модель назвала «без изменений» и совпадает ли это с порогом; (5) скриншот таблицы «Цифры недели» с новой строкой. Принято, если: оба узла выгрузок подключены к форме параллельно; цифры считает код, а не модель; каждое число в отчёте есть в выходе «Цифры недели»; в отчёте есть CTR; изменения меньше 10% или меньше 5 штук не названы ни ростом, ни падением; отчёт не длиннее 8 строк, без разметки; в таблице «Цифры недели» после запуска есть строка с period и weeks; в приложенных файлах нет персональных данных клиентов.
Подсказка: Если цифры нули, сначала сверьте даты недель в коде с датами в файле.
✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.
На курсе задания проверяются автоматически. Подобрать курс
Что дальше
Отчёт сказал, что неделя ровная. Следующий вопрос: что поменять, чтобы цифры сдвинулись заметно, больше порога шума. В уроке 4.5 из этих же цифр получатся три гипотезы, у каждой своя метрика и срок проверки.
Итог:
• цифры недели считает код, модель только пересказывает;
• две выгрузки разбираются в параллельных ветках и сходятся в Merge;
• порог шума в промпте не даёт назвать разницу в одну конверсию падением;
• даты недель в коде меняйте под свои файлы;
• узел «В таблицу цифр» при каждом запуске оставляет недели в таблице «Цифры недели» для слайда 4.6.
