Проверка кодом пропустила все три гипотезы с пометкой «ОК». Одна из них обещала поднять конверсии с 52 до 62 «за 14 дней». Только 52 конверсии кофейня «Зерно» набирает за одну неделю, а за две недели их выйдет около 104, даже если ничего не менять. Такая гипотеза засчиталась бы успешной сама. Вторая предлагала посты в канале и собиралась мерить их кликами в Директе, на которые посты никак не влияют. В этом уроке вы соберёте сценарий, который пишет гипотезы по цифрам недели, и научите код ловить обе ошибки.
Чему научитесь в этом уроке:
• отличать настоящее изменение цифр от обычных колебаний (шума);
• проверять идею способом «до/после», когда разделить гостей на группы нельзя;
• получать от модели гипотезы в виде JSON с понятными полями;
• проверять гипотезы кодом: база, срок, связь «где меняем → какую цифру смотрим», слишком большая и слишком маленькая цель.
Сначала отсеять шум
В уроке 4.4 код посчитал две недели кофейни. Расход 10 654 → 10 994 ₽, клики 833 → 800, доля кликнувших (CTR) 3,61 → 3,32%, конверсии 53 → 52, цена конверсии 201 → 211 ₽, визиты на сайт 1228 → 1216. Модель в отчёте назвала разницу в одну конверсию «падением эффективности». Если строить гипотезу на таком «падении», вы будете чинить то, что не ломалось.
Представьте весы в ванной: сегодня они показывают на 200 граммов больше, чем вчера. Это не значит, что вы поправились, это обычное колебание. С недельными цифрами так же. Поэтому первый узел сценария до всякой модели помечает каждую цифру: если она изменилась меньше чем на 10% или меньше чем на 5 штук, вывод «без изменений (шум)». На цифрах «Зерна» под этот порог попали все шесть строк, даже CTR с его −8% и цена конверсии с +5%. Это правильный ответ: за эту неделю ничего не сломалось и ничего не выросло.
Порог 10% и 5 штук выбран для учебных цифр одной кофейни. Для своего бизнеса его можно сдвинуть, но держите одно правило: порог задаёт код, а модель только читает готовую пометку.
Одно изменение за раз
Врач, который подбирает лечение, меняет одно лекарство за раз. Если сменить три сразу и пациенту стало лучше, неизвестно, какое из них помогло. Если хуже, неизвестно, какое отменять.
Крупные сайты поступают ещё строже. Они делят посетителей пополам в один и тот же день: одна половина видит старое объявление, другая новое, и разница между половинами показывает, что сработало. Такую проверку называют A/B-тестом (вариант A против варианта B). У одной кофейни с недельными цифрами такого деления нет: гости одни и те же, и половину из них не спрячешь от поста в канале. Поэтому вместо A/B остаётся проверка «до/после»: неделя до изменения против недели после, и меняется только одна вещь.
Отсюда находка прогона: две гипотезы на один канал в одну неделю мешают друг другу. Если на той же неделе в канале выйдут и серия постов, и сбор фото гостей, а визиты вырастут, вы не узнаете, что из двух сработало. Запускайте их по очереди.

Сценарий из четырёх узлов
Сценарий в n8n: «Старт» (ручной запуск) → Code «Цифры и идеи» → Basic LLM Chain «Гипотезы» → Code «Проверка гипотез». Code (узел с короткой программой на JavaScript) считает, Basic LLM Chain (узел, который отправляет модели системное сообщение и вашу просьбу) пишет, второй Code проверяет то, что написала модель.
Первый узел, «Цифры и идеи». Цифры двух недель вписаны в него руками из отчёта урока 4.4: в прогоне курса гипотезы с таблицей «Цифры недели» не связывали, переносите шесть чисел сами, а три идеи взяты из разбора конкурента в уроке 4.2. Для своих данных замените числа в строках was (прошлая неделя) и now (эта неделя) и тексты в ideas.
// Цифры и идеи: цифры двух недель из урока 4.4 и идеи из разбора конкурента 4.2
const was = {расход:10654,клики:833,ctr:3.61,конверсии:53,цена_конверсии:201,визиты:1228};
const now = {расход:10994,клики:800,ctr:3.32,конверсии:52,цена_конверсии:211,визиты:1216};
const ideas = ['Серия постов «Закулисье: как открывается Зерно»','Сет-дегустация из двух мини-напитков','Сбор фото гостей в комментариях'];
// Порог шума: меньше 10% или меньше 5 штук — «без изменений»
const rows = Object.keys(now).map(k => { const d = now[k] - was[k]; const pct = was[k] ? d / was[k] * 100 : 0;
const noise = Math.abs(pct) < 10 || Math.abs(d) < 5;
return { метрика: k, было: was[k], стало: now[k], изменение_проц: +pct.toFixed(1), вывод: noise ? 'без изменений (шум)' : (d > 0 ? 'рост' : 'падение') }; });
return [{ json: { rows, ideas, was, now } }];
Гипотеза как карточка с полями
Фраза «попробуем сет-дегустацию» проверке не поддаётся: непонятно, что смотреть и когда подводить итог. Поэтому модель отдаёт каждую гипотезу как карточку в формате JSON (текст по образцу «поле: значение»). Поля такие: сама гипотеза в виде «если …, то …, потому что …», что меняем, где меняем, какую метрику смотрим, база (цифра сейчас), цель (какую цифру ждём), срок в днях и как поймём, что не сработало.
Системное сообщение узла «Гипотезы», итоговая версия после первого прогона:
Ты маркетолог кофейни «Зерно» (Тверь, одна точка). По таблице «неделя к неделе» и идеям ниже предложи ровно 3 гипотезы для проверки.
Правила:
- Не строй гипотезу на строке с выводом «без изменений (шум)» как на проблеме.
- Одна кофейня не может разделить гостей на две группы, поэтому проверка — «до/после» по неделям, одно изменение за раз.
- метрика — строго одно из: расход, клики, ctr, конверсии, цена_конверсии, визиты.
- база — значение этой метрики на текущей неделе из таблицы, без округления.
- где_меняем — строго одно из: "объявления Директа", "канал и соцсети". Объявления Директа влияют на: расход, клики, ctr, конверсии, цена_конверсии. Канал и соцсети — только на визиты.
- цель — значение метрики В СРЕДНЕМ ЗА НЕДЕЛЮ, которого ждём; изменение не больше 30% от базы.
- срок_дней — от 7 до 14; при сроке 14 итог считаем как среднее за неделю.
Ответ — только JSON-массив без пояснений и без ```: [{"гипотеза":"если …, то …, потому что …","что_меняем":"…","где_меняем":"…","метрика":"…","база":0,"цель":0,"срок_дней":14,"как_поймём_что_не_сработало":"…"}]
Сообщение пользователя собирает таблицу неделя к неделе и список идей:
{{ "Неделя к неделе:\n" + $json.rows.map(r => r.метрика + ": было " + r.было + ", стало " + r.стало + " (" + r.изменение_проц + "%) — " + r.вывод).join("\n") + "\n\nИдеи из разбора конкурента:\n" + $json.ideas.join("\n") }}
Главное в промпте три строки. Цель задана как среднее за неделю, а не сумма за срок. Поле «где_меняем» выбирается только из двух вариантов, и для каждого перечислены метрики, на которые он влияет. Изменение ограничено 30% от базы.
Прогон 1: три «ОК» и две ошибки
В первом прогоне поля «где_меняем» не было, а цель никто не уточнял. Код проверял только метрику из списка, базу и срок. Все три гипотезы прошли, но две были негодными.
- Цель как сумма. База 52 конверсии за неделю, цель 62 за 14 дней. За две недели без всяких изменений набирается около 104, так что цель выполнилась бы сама.
- Не та метрика. Гипотеза про посты в канале мерилась кликами Директа. Посты в канале на клики по рекламе не влияют: что бы ни случилось с кликами, к постам это отношения не имеет.
Обе ошибки модель сделала уверенно и в правильном формате. Формат проверка видела, а смысл нет.
Исправление: проверки кодом
После прогона 1 в промпт добавили поле «где_меняем» и правило «цель в среднем за неделю», а в код три проверки. Первая сверяет связь «где меняем → метрика»: объявления Директа влияют на расход, клики, CTR, конверсии и цену конверсии, канал и соцсети только на визиты. Вторая ловит цель дальше 30% от базы: такая цифра похожа на сумму за весь срок. Третья ловит цель ближе 10% к базе: она лежит в шуме, и успех от неуспеха не отличить.
// Проверка гипотез
const base = $('Цифры и идеи').first().json.now;
let raw = String($input.first().json.text || '').replace(/^\s*```(json)?/, '').replace(/```\s*$/, '');
let list; try { list = JSON.parse(raw); } catch (e) { return [{ json: { ok: false, ошибка: 'модель вернула не JSON', raw: raw.slice(0, 300) } }]; }
const allowed = Object.keys(base);
return list.map(h => { const issues = [];
if (!allowed.includes(h.метрика)) issues.push('метрика не из списка: ' + h.метрика);
else if (Number(h.база) !== base[h.метрика]) issues.push('база ' + h.база + ' ≠ факт ' + base[h.метрика]);
if (!(h.срок_дней >= 7 && h.срок_дней <= 14)) issues.push('срок ' + h.срок_дней + ' дн. вне 7–14');
const MAP = {'объявления Директа': ['расход','клики','ctr','конверсии','цена_конверсии'], 'канал и соцсети': ['визиты']};
if (!MAP[h.где_меняем]) issues.push('где_меняем не из списка: ' + h.где_меняем);
else if (!MAP[h.где_меняем].includes(h.метрика)) issues.push(h.где_меняем + ' не влияет на ' + h.метрика);
const b = Number(h.база), c = Number(h.цель);
if (b && Math.abs(c - b) / b > 0.3) issues.push('цель ' + c + ' дальше 30% от базы ' + b + ' — похоже на сумму за весь срок, а не среднее за неделю');
if (b && Math.abs(c - b) / b < 0.1) issues.push('цель в пределах шума (<10%)');
if (!h.цель || !h.что_меняем) issues.push('нет цели или изменения');
return { json: { ...h, проверка: issues.length ? issues.join('; ') : 'ОК' } }; });
Код снимает с ответа обёртку из трёх обратных кавычек, если модель её добавила. Если ответ не разбирается как JSON, код возвращает пометку «модель вернула не JSON» и первые 300 знаков ответа, чтобы вы увидели, что пришло.
Прогон 2
- Серия постов «Закулисье» в канале: визиты 1216 → 1338 за 7 дней. Проверка: «ОК». Цель выше базы на 10,03%, то есть на самой границе шума.
- Сет-дегустация в объявлениях Директа: конверсии 52 → 60 в среднем за неделю, срок 14 дней. Проверка: «ОК».
- Сбор фото гостей в комментариях: визиты 1216 → 1290. Проверка: «цель в пределах шума (<10%)», гипотеза отбракована.
Третья гипотеза отбракована правильно: рост на 74 визита укладывается в обычное колебание, и по нему нельзя понять, сработала идея или нет. К тому же она про тот же канал, что и первая, так что на одной неделе с ней её запускать нельзя.
Сами проверки по неделям «до/после» в прогоне курса не проводились: у учебных данных нет недели после изменения. Сценарий выдаёт план проверки, а итог вы увидите в следующем отчёте 4.4. Так петля и замыкается: отчёт → гипотеза → проверка → отчёт.
Если не получилось
- В выводе «модель вернула не JSON». Посмотрите поле raw. Если там пояснения перед массивом, проверьте, что в системном сообщении осталась строка «Ответ — только JSON-массив без пояснений».
- Все гипотезы с пометкой «база … ≠ факт …». Модель округлила базу или взяла прошлую неделю. Проверьте правило «база — значение этой метрики на текущей неделе из таблицы, без округления» и что в сообщении пользователя есть строки «было» и «стало».
- Модель получила пустую таблицу или «undefined» вместо цифр. Узел «Гипотезы» должен стоять сразу после «Цифры и идеи», а первый узел должен называться именно так: имя нужно второму коду.
- Все шесть строк снова «без изменений». Это нормальный результат: гипотезы тогда строятся на идеях, а не на «проблемах».
Контрольный вопрос. Конверсии за неделю 52. Гипотеза обещает 62 конверсии за 14 дней. Что с ней не так?
Подсказка: Сколько конверсий кофейня набирает за две обычные недели?
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Почему кофейня «Зерно» проверяет идеи способом «до/после», а не A/B-тестом?
Подсказка: Вспомните, что нужно для A/B-теста в один и тот же день.
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Какие гипотезы код «Проверка гипотез» отбракует при базе 1216 визитов? Выберите все верные варианты.
Выберите все верные варианты.
Подсказка: Посчитайте, на сколько процентов цель отличается от базы, и сверьте «где меняем» с метрикой.
На курсе задания проверяются автоматически. Подобрать курс
Задание. МИССИЯ «Одно лекарство за раз». Соберите в n8n сценарий из четырёх узлов: «Старт», «Цифры и идеи», «Гипотезы», «Проверка гипотез». Подставьте в «Цифры и идеи» цифры двух недель из своего отчёта урока 4.4 (или учебные) и три своих идеи. Запустите и выберите из гипотез с пометкой «ОК» одну, которую запустите первой. Приложите: (1) вывод узла «Цифры и идеи» (поле rows); (2) вывод узла «Проверка гипотез» по всем трём гипотезам; (3) одну-две фразы: какую гипотезу запускаете первой, какую откладываете и почему; (4) если хоть одна гипотеза была отбракована, напишите, за что. Принято, если: в сценарии есть все четыре узла; порог шума посчитан кодом, а не моделью; у каждой гипотезы заполнены поля метрика, база, цель, срок_дней, где_меняем; база совпадает с цифрой текущей недели; выбранная гипотеза прошла проверку «ОК»; в плане нет двух гипотез на один канал в одну неделю; персональные данные клиентов не указаны.
Подсказка: Если все три гипотезы прошли «ОК», поменяйте одной цель на сумму за 14 дней и убедитесь, что код её поймал.
✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.
На курсе задания проверяются автоматически. Подобрать курс
Что дальше
У вас есть цифры недели и план того, что проверяем дальше. В следующем уроке соберём из них один слайд «было/стало» для владельца, где шум не выдаётся ни за рост, ни за падение.
Итог:
• изменение меньше 10% или меньше 5 штук код помечает как шум, и гипотезу на нём не строят;
• одна кофейня проверяет идеи «до/после», одно изменение за раз; две гипотезы на один канал в одну неделю запускают по очереди;
• гипотеза приходит карточкой JSON: метрика, база, цель в среднем за неделю, срок 7–14 дней, где меняем;
• код ловит то, что пропускает формат: метрику не того канала, цель-сумму дальше 30% и цель в шуме ближе 10%.
