Итоговая работа: мини-конструктор «бриф, структура, тексты, код»

Зачем:Один большой запрос ломается там, где его не видно. После урока вы собираете конвейер из четырёх этапов с проверками между ними, понимаете, как устроен вызов модели по API (запрос, ключ, токены, ошибки), решаете, какие поля брифа уходят модели и когда нужна российская модель, и записываете проект своего мини-конструктора.

35 минут

Озвучено синтезом речи (Qwen3-TTS), голос не принадлежит человеку.

Конвейер «бриф, структура, тексты, код» — цепочка запросов к модели, где выход каждого этапа проверяет обычный код, прежде чем он станет входом следующего.

Один запрос или конвейер

На прошлых уроках вы поставили задачу модели и проверили результат. Теперь соберите это в конвейер: цепочку маленьких запросов, где результат каждого проверяется, прежде чем стать входом следующего. Это и есть мини-конструктор, то, что внутри любого ИИ-конструктора из первого урока, только вы видите все детали.

Зачем дробить. Один большой запрос «сделай сайт» ломается там, где его не видно: непонятно, на каком шаге появился выдуманный факт и что именно переделывать. В конвейере этапы короче и точнее, выход каждого можно проверить программой, ошибка видна там, где возникла, а повтор одного этапа стоит дешевле повтора всего. Авторы руководств по созданию агентов называют это приёмом «цепочки запросов» (prompt chaining) и советуют ставить программные проверки между шагами.

Четыре этапа

  1. Бриф. Вы выбираете, какие поля уйдут модели. Только публичное: кто вы, для кого, главное действие, разделы, предложения, подтверждения, тон. Телефон, почта и чужие личные данные остаются у вас. Выход: JSON из выбранных полей. Проверка: нет ли в нём контактов.
  2. Структура. Модель получает JSON и возвращает JSON со структурой: список разделов и подпись главной кнопки. Формат строгий, потому что его читает программа. Проверка: схема (разобрался ли JSON) и сверка с брифом (названия разделов точно такие же, лишних нет, подпись кнопки совпадает).
  3. Тексты. По одному разделу за запрос, только из фактов брифа и в вашем тоне (на примерах). Проверка фактов: каждое число и имя в тексте найдено в брифе, нет пустых формул («индивидуальный подход»).
  4. Код. Модель получает структуру и тексты и пишет HTML и CSS. Проверка кода: один h1, lang, alt у картинок, подписи у полей, нет внешних скриптов и «кнопок» из div. Это те же проверки, что вы делали руками на прошлом уроке, теперь программой.

Проверки между этапами это обычный код, а не ещё одна модель: он применяет точное правило, не устаёт и не «одобряет» ошибку уверенно. Модель-рецензент годится как дополнение, но не как единственные ворота.

Поиграйте на схеме. Это учебный режим: модель не запускается, а каждый этап собирает выход по правилу из вашего брифа, чтобы схема работала без сети и бесплатно. Но устройство то же: что входит, что выходит и как проверка отказывает. Включайте у каждого этапа «ошибку модели» и смотрите, что скажет проверка.

Конвейер «бриф, структура, тексты, код» с проверками

Модель здесь не запускается. Каждый этап собирает выход по написанному правилу из вашего брифа: так страница работает без сети и бесплатно. Настоящее здесь устройство конвейера: что входит в этап, что выходит и в каком формате, и как проверка (обычный код, а не ещё одна модель) отказывает, когда выход нарушил договор.

1. Бриф: что уходит модели
{
 "who": "Что делает проект",
 "forWhom": "Для кого",
 "mainAction": "Оставить заявку",
 "sections": [
  "О проекте",
  "Услуги",
  "Контакты"
 ],
 "items": [
  "Услуга"
 ],
 "proofs": []
}

Проверка пройдена. В запросе только то, что станет публичным: личных контактов нет. Примерно 76 токенов на входе.

2. Структура (JSON)
{
 "sections": [
  {
   "title": "О проекте"
  },
  {
   "title": "Услуги"
  },
  {
   "title": "Контакты"
  }
 ],
 "cta": "Оставить заявку"
}

Проверка пройдена. JSON разобран, разделы и подпись кнопки точно совпадают с брифом.

3. Тексты по разделам
  • О проекте. Что делает проект. Для кого: Для кого.
  • Услуги. Услуга: Что это.
  • Контакты. Чтобы «Оставить заявку», воспользуйтесь формой ниже.

Проверка пройдена. Каждое число есть в брифе, пустых формул нет.

4. Код
<!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?

    Ответ

    У себя в защищённых настройках и на сервере в переменных окружения. Не в коде страницы, не в репозитории, не в архиве сайта. Попал в публичное место: отзовите и выпустите новый.

  • Что отправлять модели?

    Ответ

    Только то, что и так станет публичным: кто вы, для кого, разделы, предложения, подтверждения, тон. Контакты и чужие персональные данные не отправляют; для персональных данных россиян взвесьте российскую модель.

Источники

Дальше

Теперь вы знаете: работа с API модели и собственным ключом, конвейер «бриф → структура → тексты → код», российские модели и данные: GigaChat, YandexGPT.