Фрилансер ведёт три учебных клиента: кофейню «Зерно», барбершоп «Бритва» и студию йоги «Прана». Все трое выдуманы для курса. Раньше на каждого пришлось бы собирать свой сценарий в n8n и потом править три копии одного и того же. При подготовке урока хватило одного сценария и одной таблицы: модель написала по черновику каждому клиенту, а узел с кодом проверил, что в пост кофейни не попала «Бритва» и что все цены взяты из фактов нужного клиента. Все три черновика прошли проверку с первого раза. Потом мы подсунули проверке нарочно испорченный текст, и она его пропустила. Об этом тоже расскажу.
Чему научитесь в этом уроке:
• хранить брендбуки нескольких клиентов строками одной таблицы;
• собрать один сценарий, который пишет черновик каждому активному клиенту;
• проверять кодом чужие бренды и цифры вне фактов;
• проверять саму проверку текстом с заведомой ошибкой.
Повар и карточки рецептов
Представьте повара, который готовит обеды для трёх соседних ресторанов. Кухня одна, плита одна, руки одни. Разное только в карточках: у каждого ресторана своя карточка с рецептом, порцией и подачей. Повар берёт карточку, готовит по ней, кладёт блюдо на поднос с названием ресторана. Если завтра появится четвёртый ресторан, он не строит вторую кухню. Он заводит четвёртую карточку.
В конвейере кухня это сценарий n8n, а карточки это строки таблицы. Каждая строка хранит короткий брендбук клиента из урока «Брендбук как инструкция агента»: тон, факты, канал и тему поста. Сценарий проходит по строкам и пишет каждому клиенту по его карточке.

Таблица «Клиенты фрилансера»
В n8n таблицы данных хранятся прямо в кабинете, как в уроке 3.2. Создайте новую: Personal → Data tables → Create data table, имя «Клиенты фрилансера». Колонок семь, все текстовые (string):
- client: название клиента, например Кофейня «Зерно». Название бренда стоит в ёлочках внутри ячейки: код проверки ищет имя между ёлочками. Вокруг всей ячейки кавычек не ставьте, иначе код вытащит не то имя и может перестать ловить чужой бренд;
- voice: тон: «тёплый, на «вы», без восклицаний, коротко»;
- facts: факты одной строкой: адрес, часы, цены, что есть в продаже;
- channel: куда пойдёт пост. В прогоне это были условные подписи вроде «ТГ @zerno_test»;
- topic: тема ближайшего поста;
- active: «да» или «нет». Клиент ушёл в отпуск или поставил работу на паузу: меняете «да» на «нет», и сценарий его пропускает. Строку удалять не нужно.
- signup: как записаться или купить: ссылка, телефон или «через бота». Зачем она нужна, видно ниже, в разделе о прогоне.
Три учебные строки из прогона:
- Кофейня «Зерно»: тон тёплый, на «вы», без восклицаний; факты «Тверь, ул. Трёхсвятская; работаем 8:00–21:00; фильтр-кофе Эфиопия Иргачеффе 220 ₽; булочки с корицей»; тема «новый сорт Эфиопия в фильтре».
- Барбершоп «Бритва»: тон дерзкий, на «ты», с юмором, без мата; факты «Тверь, пр. Чайковского; стрижка 1500 ₽; борода 800 ₽; запись через бота, работаем до 22:00»; тема «стрижка + борода по будням до 16:00 со скидкой 10%».
- Студия йоги «Прана»: тон спокойный, на «вы», бережный, без обещаний похудения; факты «Тверь, ул. Советская; утренние классы 7:30; первое занятие бесплатно; коврики выдаём»; тема «утренний класс для новичков».
Сценарий из четырёх узлов
Порядок узлов: Manual Trigger (старт вручную) → Data Table с именем «Активные клиенты» → Basic LLM Chain «Черновик клиента» → Code «Проверка бренда».
Узел Data Table читает строки таблицы. В нём выбрана операция Get, таблица «Клиенты фрилансера», условие active = да и Return All, то есть вернуть все подходящие строки, а не первую. Дальше каждая строка идёт через модель отдельно.
В «Черновике клиента» системное сообщение общее для всех клиентов:
Ты копирайтер-фрилансер. Напиши один пост для клиента ниже, 400–700 знаков, простой текст без звёздочек и решёток.
Правила:
- Строго тон клиента.
- Цены, адреса, часы работы — только из «Фактов», слово в слово. Чего нет в фактах — не пиши.
- В конце — один понятный призыв к действию из фактов (прийти, записаться).
А в сообщение пользователя подставляется строка таблицы. Это выражение n8n, вставьте его в поле Prompt (User Message) целиком:
{{ "Клиент: " + $json.client + "\nТон: " + $json.voice + "\nФакты (только они): " + $json.facts + "\nКанал: " + $json.channel + "\nТема поста: " + $json.topic }}
Правила, одинаковые для всех, живут в системном сообщении. Всё, что отличает клиента, приходит из его строки. Новый клиент меняет таблицу, а сценарий остаётся прежним.
Проверка бренда кодом
Модель может перепутать карточки: написать в пост кофейни цену стрижки или название соседа. Глазами это легко пропустить, когда клиентов трое и постов много. Узел Code проверяет два правила механически. Первое: в посте нет имени другого клиента. Второе: каждая цифра в посте есть в фактах или теме этого клиента. Идея та же, что в уроке «Защита бренда и тест промпта», только теперь фактов несколько наборов.
// Проверка кодом: нет чужих брендов, нет цифр не из фактов клиента
const all = $('Активные клиенты').all().map(i => i.json);
return $input.all().map((it, i) => {
const c = all[i], text = String(it.json.text || '');
const issues = [];
for (const o of all) if (o.client !== c.client) {
const name = o.client.match(/«(.+)»/)?.[1];
// Ищем по основе: «Бритва», «Бритве», «Бритвой» — без последней буквы
const stem = name && name.length > 4 ? name.slice(0, -1) : name;
if (stem && text.toLowerCase().includes(stem.toLowerCase())) issues.push('чужой бренд: ' + name);
}
const own = (c.facts + ' ' + c.topic).replace(/(\d)[\s ](?=\d{3})/g, '$1');
const nums = (text.replace(/(\d)[\s ](?=\d{3})/g, '$1').match(/\d+(?:[:.,]\d+)?/g) || []);
const extra = nums.filter(n => !own.includes(n));
if (extra.length) issues.push('цифры не из фактов: ' + extra.join(', '));
return { json: { client: c.client, channel: c.channel, знаков: text.length, проверка: issues.length ? issues.join('; ') : 'ОК', text } };
});
На выходе у каждого черновика есть клиент, канал, число знаков, поле «проверка» и сам текст. В поле «проверка» стоит «ОК» или перечень нарушений.
Что вышло в прогоне
Запуск дал три черновика, у всех «ОК». Тон держался: кофейня на «вы», барбершоп на «ты» с юмором, йога бережно. Цены, адреса и часы модель взяла из фактов своего клиента.
Нашлась одна мелочь. Пост йоги закончился словом «Запишитесь…», а как записаться, в фактах не сказано. Системное сообщение требует призыв к действию, и модель его дала, но читателю непонятно, куда идти. Поэтому в таблице есть колонка signup. В прогоне её не было, вывод сделан по этому посту. Чтобы модель её видела, допишите поле в конец выражения сообщения пользователя:
{{ "Клиент: " + $json.client + "\nТон: " + $json.voice + "\nФакты (только они): " + $json.facts + "\nКанал: " + $json.channel + "\nТема поста: " + $json.topic + "\nКак записаться: " + $json.signup }}
В прогоне курса это поле не запускали. После правки посмотрите в черновиках, ведёт ли призыв туда, что записано в колонке signup.
Проверка проверки
Три «ОК» на чистых данных ничего не доказывают: проверка, которая всегда отвечает «ОК», выглядит точно так же. Поэтому мы подсунули ей текст с ошибкой: «стрижка в Бритве» в посте другого клиента. Первая версия кода его не поймала. Она искала точное слово «Бритва», а в тексте стояло «Бритве», в другом падеже.
Исправили так: проверка ищет основу имени, без последней буквы и без учёта больших и маленьких букв. Эта строчка с комментарием есть в коде выше. После правки на подложных текстах ловятся и чужой бренд в падеже, и чужая цена 250. Эти подложные тексты гоняли вне n8n, отдельно от сценария.
Проверку проверяйте текстом с ошибкой. Возьмите готовый черновик, впишите в него имя другого клиента в любом падеже и цену, которой нет в фактах, и пропустите через узел. Если проверка ответила «ОК», она сломана.
Следующий шаг: публикация по каналам
В прогоне собирали только черновики, публикаций по клиентам не было. Связать сценарий с публикацией из урока «Одобрение и публикация» можно так: в колонке channel хранить номер канала клиента (начинается с -100), а в узле публикации подставлять его из строки вместо постоянного номера. Одобрение каждого поста при этом оставьте, как в уроке 3.6. В прогоне курса эту связку не проверяли, начните с одного тестового канала. В миссию этого урока публикация не входит.
Если не получилось
- Пришёл один черновик вместо трёх. Проверьте в узле Data Table, что включено Return All, и что у всех нужных клиентов в колонке active стоит ровно «да».
- Проверка ругается на чужой бренд, хотя его нет. Основа короткого имени может совпасть с обычным словом. Посмотрите, какое имя назвала проверка, и сравните с текстом.
- «Цифры не из фактов» на время или цену, которые есть в фактах. Запишите их в таблице так же, как модель пишет в тексте: «8:00», а не «8.00».
- В ответе модели пусто, проверка падает. Посмотрите выход «Черновика клиента»: текст должен лежать в поле text. Если поле называется иначе, поправьте
it.json.textв коде. - Проверка отвечает «ОК» даже на подложном тексте. Посмотрите ячейки client: в ёлочках должно стоять только название бренда, без кавычек вокруг всей ячейки.
Контрольный вопрос. Студия йоги закрылась на месяц на ремонт. Как поставить её на паузу в конвейере?
Подсказка: Строка должна сохраниться, чтобы через месяц вернуть клиента одним изменением.
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Проверка бренда вернула «ОК» на всех трёх черновиках. Что из этого можно заключить о самой проверке?
Подсказка: Как отличить исправную проверку от той, что всегда отвечает одно и то же?
На курсе задания проверяются автоматически. Подобрать курс
Контрольный вопрос. Что в этом конвейере хранится в строке клиента, а не в общем системном сообщении? Выберите все подходящие.
Выберите все верные варианты.
Подсказка: В строку попадает то, чем один клиент отличается от другого.
На курсе задания проверяются автоматически. Подобрать курс
Задание. МИССИЯ «Три карточки на одной кухне». Создайте таблицу данных с 2–3 клиентами: своими или выдуманными. Колонки: client, voice, facts, channel, topic, active и signup (как записаться или купить); signup допишите в сообщение пользователя. Соберите сценарий из четырёх узлов урока и запустите. Затем возьмите один черновик, впишите в него имя другого клиента в другом падеже и цифру, которой нет в фактах, и пропустите через узел проверки. Приложите: (1) скриншот таблицы; (2) черновики с полем «проверка»; (3) подложный текст и ответ проверки на него; (4) одну фразу: что пришлось поправить в таблице или коде. Принято, если: в таблице не меньше двух клиентов и колонка active; черновиков столько же, сколько активных клиентов; у каждого черновика есть поле «проверка»; в черновиках призыв ведёт туда, что записано в signup; на подложном тексте проверка нашла чужой бренд в падеже и лишнюю цифру; в таблице нет персональных данных реальных людей.
Подсказка: Чтобы убедиться, что пауза работает, поставьте одному клиенту «нет» в active и запустите ещё раз: черновиков должно стать меньше.
✅ Готово, если: программа запускается без ошибок и выводит то, что просят в задании.
На курсе задания проверяются автоматически. Подобрать курс
Что дальше
Конвейеров становится больше, а с ними растут расходы на модель и число мест, где может сломаться качество. В уроке 5.3 соберём недельный разбор: раз в неделю сценарий считает расход, остаток баланса и пишет короткую сводку.
Итог:
• клиенты хранятся строками одной таблицы, сценарий один на всех;
• колонка active ставит клиента на паузу без удаления;
• код проверяет чужие бренды по основе имени и цифры вне фактов клиента;
• проверку проверяют текстом с заведомой ошибкой.
