Генерация SEO-контента через API: как не получить воду

Модель по умолчанию тяготеет к общим фразам и спискам ни о чём. Как настроить запрос, чтобы получить текст с фактами, а не заполнитель места.

4 мин · · Обновлено · контент · seo

Почему модель тянет к воде

Если в запросе нет ни фактов, ни ограничений, модель заполняет пробелы обобщениями — это её обычный способ закрыть требование "напиши 1000 слов" без источника конкретики. Лечится это не сменой модели, а тем, что вы даёте в промпте: конкретные цифры, факты о продукте, примеры, и явный запрет на определённые конструкции.

Промпт с запретами работает лучше промпта с пожеланиями

Просить "пиши живо и по делу" почти бесполезно — модель не знает, что именно вы считаете водой. Работает список конкретных фраз, которые нельзя использовать, и требование подкреплять каждый тезис числом или примером:

bash
{
  "model": "claude-sonnet-5",
  "messages": [
    {
      "role": "system",
      "content": "Пиши без фраз 'в этом разделе мы рассмотрим', 'важно отметить', 'таким образом', без списков вида 'первое / второе / третье' без конкретики внутри пунктов. Каждый абзац должен содержать число, название инструмента или пример команды."
    },
    {"role": "user", "content": "Напиши раздел статьи про настройку кэша ответов API, 300 слов."}
  ]
}

Привязка к фактам через веб-поиск

Модели, у которых нет встроенного поиска в реальном времени, можно подключить к POST /v1/web-search — это отдельный эндпоинт шлюза для тех случаев, когда нужно опереться на актуальные данные, а не на то, что модель помнит из обучения:

bash
curl https://api.zukko.pro/v1/web-search \
  -H "Authorization: Bearer fetch_ваш_ключ" \
  -H "Content-Type: application/json" \
  -d '{"query": "SEO title length recommendations 2026"}'

Результат можно подмешать в контекст следующего запроса на генерацию — тогда текст ссылается на конкретные цифры, а не на усреднённое "рекомендуется делать заголовок не слишком длинным".

Технические ограничения SEO-полей

Title и description имеют жёсткие рамки по символам, и это единственное место, где стоит требовать точное соответствие, а не "примерно". Например description в 120–160 символов — попросите модель сгенерировать пять вариантов, чтобы выбрать тот, что укладывается в диапазон, вместо того чтобы обрезать вручную и терять смысл на полуслове:

bash
resp = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[
        {"role": "system", "content": "Верни ровно 5 вариантов meta description, каждый 120-160 символов, без кавычек."},
        {"role": "user", "content": "Тема: миграция с OpenAI API на совместимый шлюз."},
    ],
)

Локализация чисел и валют

При генерации RU и EN версий одной статьи стоит явно указывать модели формат чисел и валюты — 1 000 000 против 1,000,000, знак доллара до суммы или после. Без этого уточнения модель расставляет форматы непоследовательно от абзаца к абзацу внутри одного текста, и это сразу заметно при вычитке готовой статьи.

Extended thinking для структуры длинных материалов

На длинных статьях (от 1500 слов) полезно сначала попросить модель составить план с распределением по подзаголовкам и весом каждого раздела в словах, и только вторым запросом писать текст по этому плану — раздельно на секцию. Модели Claude и GPT в каталоге держат extended thinking и контекст 1M токенов (у GLM — 128K, чего для статьи тоже обычно хватает), так что план и черновик можно держать в одном диалоге без потери связности между разделами.

Кэш для шаблонных частей

Если генератор контента регулярно создаёт однотипные блоки — например, стандартный дисклеймер или блок "как связаться с поддержкой" — включайте кэш заголовком X-Zukko-Cache: true (temperature: 0 тоже включает кэш, но только у моделей, которые принимают этот параметр; Claude-модели — claude-sonnet-5, claude-opus-5-5 — могут отклонить temperature, отличную от 1, с ошибкой 400, поэтому им его не передавайте). Повтор полностью одинакового запроса (тело должно совпадать целиком — «почти такой же» промпт в кэш не попадёт) вернётся мгновенно и бесплатно, с пометкой X-Zukko-Cache: hit в ответе — нет смысла платить за генерацию одного и того же абзаца в сотый раз.

Проверка на повторяющиеся формулировки между статьями

Если контент генерируется пачками по похожим темам, велик риск, что модель будет открывать разные статьи одной и той же фразой — она статистически самая вероятная для этого типа запроса. Простое решение — держать список уже использованных вступительных предложений и передавать его в промпт как список "не повторять":

bash
{
  "role": "system",
  "content": "Не начинай статью так же, как эти уже опубликованные вступления: ['Подключение к совместимому API обычно занимает пару минут...', 'Модель по умолчанию тяготеет к общим фразам...']. Начни иначе."
}

На практике десяти-пятнадцати последних вступлений в списке достаточно, чтобы заметно снизить повторы без раздувания промпта.

Генерация excerpt и тегов отдельным вызовом

Excerpt и теги для карточки статьи в блоге разумно генерировать отдельным, более дешёвым вызовом после основного текста, а не одним большим промптом сразу на всё — так проще ограничить длину excerpt (одно-два предложения) и переиспользовать этот же вызов для разных языковых версий статьи, передав уже готовый текст как контекст вместо того, чтобы заново объяснять тему.

Контроль качества по чужому эталону

Хороший способ проверить, что промпт действительно убрал воду — прогнать готовый текст второй раз тем же запросом с задачей "найди в тексте предложения без конкретных фактов и удали их". Это отдельный вызов к той же или другой модели (например, claude-opus-5-5 — проверьте на своих текстах, внимательнее ли он разбирает), и на практике он вылавливает остаточные общие фразы, которые проскочили в первом проходе.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.