Мы автоматизируем генерацию SEO-описаний для интернет-магазинов, где каталог насчитывает тысячи позиций. Ручное написание уникальных текстов под каждый товар займёт месяцы и миллионы — наша система справляется за часы. Но просто вызвать API нейросети недостаточно: нужна продуманная архитектура из подготовки данных, промпт-инжиниринга, пакетной обработки, валидации и интерфейса ревью. Имея опыт более 10 лет в разработке высоконагруженных систем, мы гарантируем стабильность и качество генерации.
Почему это работает?
Современные языковые модели — такие как ChatGPT (GPT-4o) и Claude — генерируют осмысленные тексты, если дать им структурированные данные: название, категорию, характеристики. Согласно документации OpenAI, контекстное обучение позволяет адаптировать вывод под задачу. Промпт-инжиниринг задаёт тон, длину, структуру и требования к ключевым словам, чтобы результат был релевантным и SEO-оптимизированным. Пример для кроссовок Nike Air Max 270:
{
"id": "SKU-4821",
"name": "Кроссовки Nike Air Max 270",
"category": "Мужская обувь / Кроссовки",
"brand": "Nike",
"attributes": { "material": "mesh + synthetic", "sole": "Air Max unit", "colors": ["black/white", "navy/grey"], "sizes": "40–46", "weight": "310g" },
"tags": ["беговые", "повседневные", "амортизация"],
"targetKeywords": ["nike air max 270 купить", "кроссовки найк аир макс 270"]
}
Как гарантируется уникальность текстов?
Модель с температурой >0 всегда выдаёт разный результат. Дополнительно мы проверяем каждую генерацию на дубли через Elasticsearch — если текст совпадает с уже существующим, запускаем повторную генерацию с новым seed. Это исключает появление копий в каталоге. Такой подход позволяет сохранять уникальность даже при массовой генерации.
Как мы проектируем промпты для товарных текстов?
Промпт — это не «напиши описание товара». Хороший промпт задаёт структуру, тон, длину, требования к ключевым словам и запреты. Пример на TypeScript:
function buildProductSeoPrompt(product: Product, keywords: string[]): string {
return `
Write a product description for an e-commerce catalog in Russian.
Product: ${product.name}
Category: ${product.category}
Brand: ${product.brand}
Key attributes: ${JSON.stringify(product.attributes)}
Tags: ${product.tags.join(", ")}
Requirements:
- Length: 200–400 words
- Include these keywords naturally: ${keywords.join(", ")}
- Structure: opening benefit statement → key features (3–5 points) → use cases → closing
- Tone: informative, no hype, no superlatives like "лучший" or "уникальный"
- Do NOT use: "данный товар", "представляем вашему вниманию", bullet points
- Do NOT start with the product name
- Write for a person who is comparing options
Output: plain text, no markdown, no headings.
`.trim();
}
Почему важна пакетная обработка с очередями?
Генерировать тексты синхронно нельзя — запрос к LLM занимает 3–10 секунд, а позиций могут быть тысячи. Мы используем очередь задач на BullMQ с параллелизмом и повторными попытками.
import { Queue, Worker } from "bullmq";
import { openai } from "../lib/openai";
import { db } from "../lib/db";
const seoQueue = new Queue("seo-generation", {
connection: { host: "localhost", port: 6379 },
});
export async function queueProductsForGeneration(productIds: string[]) {
const jobs = productIds.map((id) => ({
name: "generate",
data: { productId: id },
opts: { attempts: 3, backoff: { type: "exponential", delay: 5000 }, removeOnComplete: 100 },
}));
await seoQueue.addBulk(jobs);
}
const worker = new Worker("seo-generation", async (job) => {
const product = await db.products.findById(job.data.productId);
if (!product) return;
const keywords = await getTargetKeywords(product);
const prompt = buildProductSeoPrompt(product, keywords);
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
temperature: 0.7,
max_tokens: 600,
});
const text = completion.choices[0].message.content?.trim();
if (!text) throw new Error("Empty response");
await db.productSeoTexts.upsert({
productId: product.id,
text,
status: "draft",
model: "gpt-4o-mini",
generatedAt: new Date(),
});
}, { connection: { host: "localhost", port: 6379 }, concurrency: 5 });
Как обрабатываются ошибки при генерации?
При сбое запроса или пустом ответе задача автоматически переставляется в очередь с экспоненциальной задержкой (backoff). После трёх неудачных попыток товар помечается как failed и отправляется на ручную проверку. Это обеспечивает отказоустойчивость и минимизирует потери данных.
Контроль качества через валидацию
Сгенерированный текст автоматически проверяется: длина, наличие всех ключевых слов, отсутствие стоп-фраз, плотность вхождений. Если проверка не пройдена — товар помечается флагом needs_review и отправляется на повторную генерацию с уточнённым промптом.
interface ValidationResult { passed: boolean; issues: string[] }
function validateSeoText(text: string, product: Product): ValidationResult {
const issues: string[] = [];
if (text.length < 500) issues.push(`Too short: ${text.length} chars`);
const missingKeywords = product.targetKeywords.filter(kw => !text.toLowerCase().includes(kw.toLowerCase()));
if (missingKeywords.length > 0) issues.push(`Missing keywords: ${missingKeywords.join(", ")}`);
const stopPhrases = ["данный товар", "представляем вашему вниманию", "уникальный", "лучший в своём классе"];
for (const phrase of stopPhrases) {
if (text.toLowerCase().includes(phrase)) issues.push(`Contains stop phrase: "${phrase}"`);
}
const wordCount = text.split(/\s+/).length;
for (const kw of product.targetKeywords) {
const kwCount = (text.toLowerCase().match(new RegExp(kw.toLowerCase(), "g")) || []).length;
if (kwCount / wordCount > 0.03) issues.push(`Keyword density too high for "${kw}": ${(kwCount / wordCount * 100).toFixed(1)}%`);
}
return { passed: issues.length === 0, issues };
}
Интерфейс ревью
Редактор видит список черновиков с кнопками «Опубликовать», «Регенерировать», «Редактировать». Регенерация учитывает причину предыдущего отклонения — воркер добавляет её в промпт. Все черновики хранятся в статусе draft, публикация происходит только после подтверждения.
Сравнение: ручная генерация vs AI
| Параметр | Ручной копирайтинг | AI-генерация |
|---|---|---|
| Скорость на 1 текст | 15–30 минут | 5–15 секунд |
| Стоимость на 10 000 текстов | высокая (зависит от авторов) | значительно ниже |
| Масштабируемость | линейно растёт с числом авторов | параллельная очередь |
| Контроль качества | зависит от исполнителя | автоматическая валидация |
| Актуальность | обновлять вручную | триггер по изменению данных |
Пример: для крупного клиента из сегмента одежды мы сгенерировали 12 000 описаний за 4 часа. Промпты учитывали сезонность, пол, размерную сетку. После первичной генерации 8% текстов попали в needs_review из-за высокой плотности ключевых слов — после корректировки промпта процент снизился до 2%. Финальный запуск занял один день.
Этапы внедрения
| Этап | Описание | Срок |
|---|---|---|
| Анализ | Сбор структуры данных, тестирование промптов на выборке | 1 неделя |
| Разработка | Интеграция LLM, очередь, валидаторы, интерфейс ревью | 2–3 недели |
| Тестирование | Прогон на 500 товарах, итеративная правка промптов | 1 неделя |
| Запуск | Генерация всего каталога, обучение команды | 1 неделя |
Что входит в реализацию?
- Интеграция с LLM (OpenAI, Claude) через API
- Система очередей на BullMQ с повторными попытками и backoff
- Промпт-инжиниринг под вашу специфику (категории, тональность, ключи)
- Интерфейс для ревью и модерации (React + TypeScript)
- Валидаторы: длина, ключевые слова, стоп-слова, плотность
- Документация и обучение команды
- Поддержка в течение месяца после запуска
Сроки и стоимость
Срок реализации — от 2 до 6 недель в зависимости от объёма каталога и сложности интеграции. Стоимость рассчитывается индивидуально — чем больше товаров, тем дешевле каждый отдельный текст. Оценим ваш проект? Свяжитесь с нами — расскажем, как снизить бюджет на SEO-контент в разы.
Закажите консультацию — мы проанализируем ваш каталог и подберём оптимальную модель генерации. Получите прототип на ваших данных и оцените эффект.







