Итоговая работа: мини-конструктор «бриф, структура, тексты, код»
Зачем:Один большой запрос ломается там, где его не видно. После урока вы собираете конвейер из четырёх этапов с проверками между ними, понимаете, как устроен вызов модели по API (запрос, ключ, токены, ошибки), решаете, какие поля брифа уходят модели и когда нужна российская модель, и записываете проект своего мини-конструктора.
35 минут
Озвучено синтезом речи (Qwen3-TTS), голос не принадлежит человеку.
Конвейер «бриф, структура, тексты, код» — цепочка запросов к модели, где выход каждого этапа проверяет обычный код, прежде чем он станет входом следующего.
Один запрос или конвейер
На прошлых уроках вы поставили задачу модели и проверили результат. Теперь соберите это в конвейер: цепочку маленьких запросов, где результат каждого проверяется, прежде чем стать входом следующего. Это и есть мини-конструктор, то, что внутри любого ИИ-конструктора из первого урока, только вы видите все детали.
Зачем дробить. Один большой запрос «сделай сайт» ломается там, где его не видно: непонятно, на каком шаге появился выдуманный факт и что именно переделывать. В конвейере этапы короче и точнее, выход каждого можно проверить программой, ошибка видна там, где возникла, а повтор одного этапа стоит дешевле повтора всего. Авторы руководств по созданию агентов называют это приёмом «цепочки запросов» (prompt chaining) и советуют ставить программные проверки между шагами.
Четыре этапа
- Бриф. Вы выбираете, какие поля уйдут модели. Только публичное: кто вы, для кого, главное действие, разделы, предложения, подтверждения, тон. Телефон, почта и чужие личные данные остаются у вас. Выход: JSON из выбранных полей. Проверка: нет ли в нём контактов.
- Структура. Модель получает JSON и возвращает JSON со структурой: список разделов и подпись главной кнопки. Формат строгий, потому что его читает программа. Проверка: схема (разобрался ли JSON) и сверка с брифом (названия разделов точно такие же, лишних нет, подпись кнопки совпадает).
- Тексты. По одному разделу за запрос, только из фактов брифа и в вашем тоне (на примерах). Проверка фактов: каждое число и имя в тексте найдено в брифе, нет пустых формул («индивидуальный подход»).
- Код. Модель получает структуру и тексты и пишет HTML и CSS. Проверка кода: один
h1,lang,altу картинок, подписи у полей, нет внешних скриптов и «кнопок» изdiv. Это те же проверки, что вы делали руками на прошлом уроке, теперь программой.
Проверки между этапами это обычный код, а не ещё одна модель: он применяет точное правило, не устаёт и не «одобряет» ошибку уверенно. Модель-рецензент годится как дополнение, но не как единственные ворота.
Поиграйте на схеме. Это учебный режим: модель не запускается, а каждый этап собирает выход по правилу из вашего брифа, чтобы схема работала без сети и бесплатно. Но устройство то же: что входит, что выходит и как проверка отказывает. Включайте у каждого этапа «ошибку модели» и смотрите, что скажет проверка.
Модель здесь не запускается. Каждый этап собирает выход по написанному правилу из вашего брифа: так страница работает без сети и бесплатно. Настоящее здесь устройство конвейера: что входит в этап, что выходит и в каком формате, и как проверка (обычный код, а не ещё одна модель) отказывает, когда выход нарушил договор.
{
"who": "Что делает проект",
"forWhom": "Для кого",
"mainAction": "Оставить заявку",
"sections": [
"О проекте",
"Услуги",
"Контакты"
],
"items": [
"Услуга"
],
"proofs": []
} Проверка пройдена. В запросе только то, что станет публичным: личных контактов нет. Примерно 76 токенов на входе.
{
"sections": [
{
"title": "О проекте"
},
{
"title": "Услуги"
},
{
"title": "Контакты"
}
],
"cta": "Оставить заявку"
} Проверка пройдена. JSON разобран, разделы и подпись кнопки точно совпадают с брифом.
- О проекте. Что делает проект. Для кого: Для кого.
- Услуги. Услуга: Что это.
- Контакты. Чтобы «Оставить заявку», воспользуйтесь формой ниже.
Проверка пройдена. Каждое число есть в брифе, пустых формул нет.
<!doctype html>
<html lang="ru">
<head><meta charset="utf-8"><title>Проект</title></head>
<body>
<header><h1>Проект</h1></header>
<main>
<section>
<h2>О проекте</h2>
<p>Что делает проект. Для кого: Для кого.</p>
</section>
<section>
<h2>Услуги</h2>
<p>Услуга: Что это.</p>
</section>
<section>
<h2>Контакты</h2>
<p>Чтобы «Оставить заявку», воспользуйтесь формой ниже.</p>
</section>
<form action="https://example.ru/leads" method="post">
<p><label for="n">Имя</label> <input id="n" name="name" required></p>
<p><label for="p">Телефон</label> <input id="p" name="phone" type="tel" required></p>
<p><label><input type="checkbox" required> Согласен на обработку данных, <a href="/politika/">политика</a></label></p>
<button>Оставить заявку</button>
</form>
</main>
</body>
</html> В настоящем запуске между этапами идёт сетевой вызов: стоимость, время и случайные сбои. В учебном режиме их нет, но форма та же.
Проверьте себя: зачем проверять структуру на втором этапе, а не только готовый код на последнем?
Ошибка, пойманная на втором этапе (лишний раздел), обходится дёшево: переделывается один небольшой ответ. Та же ошибка в готовом коде означает переделывать тексты и код.
Что такое вызов модели по API
Когда вы пишете в окне конструктора, за кулисами происходит обычный запрос по HTTP, о котором вы знаете из части про серверы (у вас было и про REST, и про fetch). Только отвечает не страница, а модель.
- Запрос идёт методом POST на адрес провайдера (у Anthropic, OpenAI, OpenRouter, Яндекса, Сбера адреса и форматы свои).
- В теле запроса JSON: название модели, сообщения (инструкция
system, которая задаёт поведение, и заданиеuserс данными) и лимит длины ответа. - В заголовке ключ: ваш пропуск. По нему провайдер узнаёт, с кого брать деньги.
- Ответ тоже JSON: внутри текст, а рядом число использованных токенов.
Токены это куски текста, на которые модель режет слова; для русского примерно один токен на два-три символа. Платят за токены на входе и на выходе отдельно, а выходные обычно дороже, поэтому длинные ответы и многократные «исправь» стоят заметных денег. Учебник показывает оценку стоимости до каждого вопроса, и вам стоит делать так же в своём конвейере.
Ошибки бывают три вида: 401 или 403: ключ не подошёл; 429: слишком много запросов, подождите; 5xx: сбой на стороне провайдера, повторите позже. Конвейер должен уметь переждать и повторить, а не молча сломаться.
Ключ это секрет. Ему место в настройках у вас или в переменных окружения на сервере. Не в коде страницы, не в репозитории, не в архиве сайта, который вы скачиваете и отправляете в мир. Если ключ однажды попал в публичное место, его отзывают и выпускают новый. В учебнике ваш ключ хранится только в вашем браузере и уходит только провайдеру, которого вы выбрали, и только когда вы задаёте вопрос. А на опубликованном сайте запросы к модели идут через ваш серверный код или функцию, где ключ в настройках.
Проверьте себя: почему нельзя вызывать модель прямо из страницы сайта с вашим ключом внутри?
Весь код страницы виден посетителям, значит, ключ увидит каждый и сможет тратить ваши деньги. Запрос к модели делают с сервера или из функции, а страница обращается к ней.
Российские модели
Для проектов, которые работают с данными граждан России, есть российские языковые модели: GigaChat от Сбера и YandexGPT в Yandex AI Studio. У них свои API и документация (ссылки в источниках), русский язык для них родной, а обработка идёт по условиям российского провайдера. Что это даёт: юридически проще, когда данные граждан России не уходят за границу (вы помните правило локализации из урока про инфраструктуру). Чего не даёт: не снимает с вас обязанностей оператора персональных данных, не гарантирует, что качество окажется лучше на вашей задаче, и не отменяет чтения договора. Спросите у провайдера, где обрабатываются данные, используются ли они для обучения и как их удалить, и сравните качество на своих текстах: оно различается между моделями и между задачами.
Практический выбор такой. Если в запросе только публичное (а в хорошем конвейере так и должно быть), подойдёт любая модель. Если неизбежны персональные данные граждан России (например, ответы на письма клиентов), берите российский контур и обсудите его с юристом.
Для тех, кто хочет запустить по-настоящему
Устройство конвейера в учебнике показано в учебном режиме. Если хотите попробовать с настоящей моделью, вот минимальный сценарий на Node.js с моделью Anthropic. Это пример для запуска у себя (не в браузере и не на сайте): ключ и название модели берутся из переменных окружения, а структура и тексты проверяются программой. Формат ответов API может измениться, поэтому сверяйтесь с документацией провайдера (ссылки в источниках).
import { readFile, writeFile } from 'node:fs/promises';
const key = process.env.ANTHROPIC_API_KEY;
const model = process.env.MODEL;
if (!key || !model) throw new Error('Нужны переменные ANTHROPIC_API_KEY и MODEL');
async function ask(system, user) {
const res = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: { 'content-type': 'application/json', 'x-api-key': key, 'anthropic-version': '2023-06-01' },
body: JSON.stringify({ model, max_tokens: 4000, system, messages: [{ role: 'user', content: user }] })
});
if (!res.ok) throw new Error(`Ошибка ${res.status}`);
const data = await res.json();
return data.content.filter((b) => b.type === 'text').map((b) => b.text).join('');
}
const brief = JSON.parse(await readFile(process.argv[2], 'utf8'));
// Этап 1. Модели уходят только публичные поля: ни телефона, ни почты.
const { who, forWhom, mainAction, sections, items, proofs, tone } = brief;
const input = JSON.stringify({ who, forWhom, mainAction, sections, items, proofs, tone });
// Этап 2. Структура: JSON, который мы проверяем программой.
const structure = JSON.parse(await ask('Ответь только JSON вида {"sections":[{"title":""}]}, без пояснений.', `Бриф: ${input}`));
const titles = structure.sections.map((s) => s.title);
if (JSON.stringify(titles) !== JSON.stringify(sections)) throw new Error('Структура не совпала с брифом');
// Этап 3. Тексты по одному разделу, только из фактов брифа.
const copy = [];
for (const title of titles) {
const text = await ask('Пиши по-русски, коротко, только из фактов брифа. Цифр и достижений не выдумывай.', `Бриф: ${input}\nНапиши текст раздела «${title}».`);
for (const n of text.match(/d+/g) ?? []) if (!input.includes(n)) throw new Error(`Число ${n} в разделе «${title}» не из брифа`);
copy.push({ title, text });
}
// Этап 4. Код, и снова проверка программой.
const html = await ask('Верни один HTML-файл: смысловая разметка, один h1, lang="ru", alt у картинок, без внешних скриптов. Только код.', JSON.stringify({ copy, action: mainAction }));
if (/<script[^>]+src=/i.test(html)) throw new Error('В коде внешний скрипт');
if (/<img(?![^>]*alt=)/i.test(html)) throw new Error('Картинка без alt');
await writeFile('index.html', html);
console.log('Готово: index.html. Проверьте его глазами и по списку из прошлого урока.'); Запуск: ANTHROPIC_API_KEY=… MODEL=… node pipeline.mjs brief.json, где brief.json это ваш бриф без контактов. Это пример, а не готовый продукт: настоящему конвейеру понадобятся повторы при ошибках 429 и 5xx, учёт токенов и более терпимый разбор ответа (модель может обернуть JSON в пояснения). Но по этому образцу устроены и конструкторы из первого урока.
Практика
Постройте проект своего мини-конструктора: таблицу из четырёх этапов, JSON структуры для ваших разделов и решения о данных. Для каждого этапа назовите вход (из выхода предыдущего), что делает модель, выход с форматом и проверку. Потом решите три вопроса: какие факты разрешены в текстах, какие поля брифа вы отправите модели и какие не отправите, где хранится ключ и когда вы возьмёте российскую модель.
Это проект, а не запуск: учебник не вызывает модель из вашей практики, чтобы не отправлять ваши данные без вашего решения. Проверка читает вашу таблицу и убеждается, что этапы связаны, проверки на месте, а ключа и контактов в плане нет. Настоящий запуск вы можете сделать по примеру выше.
Что было не так с 2025 годом
В 2025 году конструктор был чёрным ящиком: вы писали запрос и получали сайт, не видя промежуточных шагов. Сегодня ценится обратное: видимые этапы, проверяемые выходы и данные, которые вы сами решили отправить. Тот, кто понимает конвейер, не зависит от конкретного продукта: он может собрать такой же из любых частей, и это настоящая мера понимания.
Практика
Готовлю вашу страницу…
Тест
Вопрос 1 из 5
Карточки
Эти карточки попадут в повторение, когда вы завершите урок.
Зачем конвейер вместо одного запроса?
Ответ
Этапы короче и точнее, выход каждого проверяется программой, ошибку видно там, где она возникла, а повтор стоит дешевле. Это приём «цепочка запросов» с проверками между шагами.
Из чего состоит вызов модели по API?
Ответ
HTTPS-запрос с JSON на адрес провайдера: название модели, сообщения (инструкция и задание), лимит ответа и ключ в заголовке. Ответ тоже JSON с текстом. Платят за токены на входе и выходе, они считаются отдельно.
Где можно хранить ключ API?
Ответ
У себя в защищённых настройках и на сервере в переменных окружения. Не в коде страницы, не в репозитории, не в архиве сайта. Попал в публичное место: отзовите и выпустите новый.
Что отправлять модели?
Ответ
Только то, что и так станет публичным: кто вы, для кого, разделы, предложения, подтверждения, тон. Контакты и чужие персональные данные не отправляют; для персональных данных россиян взвесьте российскую модель.
Источники
- Anthropic: Building effective agents только ссылка, по-английски
- Claude docs: Prompt engineering overview только ссылка, по-английски
- Yandex AI Studio: документация только ссылка, по-русски
- GigaChat API: руководства для разработчиков только ссылка, по-русски
- Федеральный закон № 152-ФЗ «О персональных данных» (КонсультантПлюс) только ссылка, по-русски
- OWASP: Top 10 for Large Language Model Applications CC BY-SA, по-английски
Дальше
Теперь вы знаете: работа с API модели и собственным ключом, конвейер «бриф → структура → тексты → код», российские модели и данные: GigaChat, YandexGPT.