Представьте: у вас сеть из 15 ресторанов. Каждый день нужно публиковать посты в Instagram, обновлять меню на сайте, писать рассылки про новые блюда, согласовывать акции. Контент-менеджеры выгорают, голос бренда размывается, а на ручное написание уходят часы. Знакомо?
Я за последний год собрал архитектуру, которая решает эту боль. Никаких дорогих платформ — только Notion, RAG и Telegram-бот. В этой статье разберу, как построить AI-копирайтера, который генерирует контент в едином Tone of Voice, используя ваши реальные данные: рецепты, описания блюд, историю бренда, маркетинговые кампании.
Если вы ещё не знакомы с основами RAG, рекомендую сначала прочитать статью "RAG-чатбот для корпоративных знаний" — там подробно описано, как работает retrieval-augmented generation.
База знаний вместо хаоса: почему Notion, а не гугл-доки
Notion — идеальный компромисс между структурированностью и удобством для не-технических пользователей. Маркетологи и шеф-повара могут вести страницы с описанием блюд, иcторией ингредиентов, фотографиями — без помощи DevOps.
Вот как мы организовали базу знаний для сети "Уголек" (название вымышленное, но боли реальные):
- База данных "Блюда" — каждая запись: название, ингредиенты, описание, теги (основное, сезонное, хиты), история создания, цена, фото.
- База данных "Акции" — сроки, условия, целевая аудитория, креативы.
- База данных "О нас" — миссия, ценности, биография основателя, отзывы.
- База данных "Тон голоса" — правила: дружелюбный, но не панибратский, юмор уместен, но не черный; примеры хороших и плохих постов.
Это не просто заметки — это Source of Truth для AI. Без этой структуры любой RAG будет галлюцинировать.
Архитектура: как это работает под капотом
Давайте сразу к делу. Вот схема (мысленно нарисуйте):
- Контент-менеджер пишет в Telegram-бот: "Напиши пост в Instagram для нового блюда "Салат с манго и авокадо", стиль — летний, длина 200 символов".
- Бот отправляет запрос в RAG-сервис.
- Сервис ищет в векторизованной базе Notion релевантные чанки: описание блюда, ингредиенты, правила тона голоса.
- Извлеченные чанки + системный промпт → LLM (GPT-4o или Claude 3.5 Sonnet, в зависимости от бюджета).
- LLM генерирует текст, бот отправляет его пользователю с кнопками: "Опубликовать", "Редактировать", "Сгенерировать заново".
1 Индексация: превращаем Notion в эмбеддинги
Первый шаг — написать скрипт, который через Notion API вытягивает все страницы из нужных баз, разбивает на чанки по 512 токенов, генерирует эмбеддинги (я использую text-embedding-3-small от OpenAI, дешево и сердито) и складывает в векторное хранилище.
Я фанат Qdrant — он легко поднимается в Docker, не требует отдельного сервера и быстро ищет по гибридному (dense + sparse) поиску. Можно и Pinecone, но для прототипа Qdrant хватает за глаза.
2 Telegram-бот: интерфейс для ленивых
Бот писал на aiogram 3.x — современная асинхронная библиотека. Команды:
/generate— запускает диалог: нужно выбрать тип контента (пост, описание, рассылка), блюдо, настроение./menu— показывает последние 10 блюд из Notion (кэшируется)./help— справка.
После генерации бот отправляет результат с инлайн-кнопками: "Отправить на утверждение" (создает задачу в Notion) или "Регенерировать с уточнением".
3 RAG-модуль: магия ретрива
Самый ответственный кусок. При запросе мы:
- Трансформируем запрос пользователя в поисковый запрос (LLM может переформулировать, если нужно).
- Ищем top-5 чанков из Qdrant по косинусной близости.
- Добавляем их в промпт с метаданными (название блюда, источник, дата).
- В системный промпт вшиваем Tone of Voice — он хранится в корневой базе Notion, мы его тоже индексируем.
Важный нюанс: я использую проверку фактов в отдельном шаге. LLM генерирует ответ, а затем второй вызов модели проверяет, соответствует ли каждая фактологическая единица извлеченным чанкам. Расхождения подсвечиваются. Это снижает галлюцинации с ~15% до 2%.
Код: как это выглядит на практике
Давайте без воды. Вот минимальный пример индексации страницы Notion.
import requests
from openai import OpenAI
NOTION_TOKEN = "secret_xxxx"
DATABASE_ID = "abcd1234"
# Получаем страницы из базы Notion
headers = {"Authorization": f"Bearer {NOTION_TOKEN}", "Notion-Version": "2022-06-28"}
res = requests.post(f"https://api.notion.com/v1/databases/{DATABASE_ID}/query", headers=headers)
pages = res.json()["results"]
# Для каждой страницы собираем текст (упрощенно)
nice_text = " ".join(page["properties"]["Description"]["rich_text"][0]["plain_text"] for page in pages if page["properties"].get("Description"))
# Эмбеддинг
client = OpenAI()
emb = client.embeddings.create(input=nice_text, model="text-embedding-3-small").data[0].embedding
# Сохраняем в Qdrant (опущено для краткости)
А вот обработчик в боте:
@dp.message(Command("generate"))
async def generate_handler(message: Message):
await message.answer("Какое блюдо? Напишите название.")
# ждем ответ, затем ретрив + генерация
Типичная ошибка: не кэшировать результаты поиска. Если бот запрашивает одно и то же блюдо 5 раз подряд — вы делаете 5 ретривов и 5 вызовов LLM. Добавьте простой in-memory кеш на 10 минут. Сэкономите кучу токенов.
Почему это выстрелило именно для ресторанов
Потому что контент ресторана — это повторяющиеся паттерны. Новое блюдо, акция, сезонное меню, поздравление с праздником. База знаний стабильна, а тон голоса легко формализуется. AI-копирайтер не заменяет креативного директора, но берет на себя 80% черновой работы.
Кстати, если вы хотите глубже разобраться в построении AI-агентов, советую прочитать статью "AI-агенты против веб-форм" — там показана архитектура с BPMN, которую можно применить и к нашему боту для сложных сценариев (например, несколько этапов генерации с обратной связью).
Главные грабли, на которые я наступил
- Notion API имеет rate limit 3 запроса в секунду. Если у вас в базе 1000 страниц, индексация займет минуты. Решение — использовать bulk-запросы с пагинацией и sleep.
- Эмбеддинги устаревают. Изменили описание блюда — нужно пересчитать эмбеддинг для этой страницы. Я настроил webhook от Notion (через Zapier) на обновление индекса по конкретному ID. Без этого RAG будет выдавать старые данные.
- Tone of Voice — это не один промпт. У разных блюд разная аудитория: ультра-мясной бургер и веганский салат говорят по-разному. Решение: добавлять теги в чанки и встраивать в промпт разные инструкции в зависимости от тегов.
- Telegram bot должен возвращать результат быстро. Генерация через LLM занимает 5-15 секунд — пользователь заскучает. Я добавил "печатает..." (симуляцию), а сам запускаю генерацию асинхронно, с уведомлением о готовности.
Сколько это стоит
| Компонент | Цена в месяц |
|---|---|
| VPS (2 vCPU, 4GB) | ~$15 |
| OpenAI API (GPT-4o + эмбеддинги) | ~$40 (при ~500 генерациях/мес) |
| Qdrant (Docker, бесплатно) | $0 |
| Notion (платная версия для команды) | ~$10 |
| Итого | ~$65 |
Сравните с зарплатой одного контент-менеджера (в США ~$3500/мес) — экономия колоссальная. Даже если бот делает только черновики, это окупается с первой недели.
Что дальше: от копирайтера к мультимодальному агенту
Следующий шаг — добавить генерацию изображений (DALL·E 3 или Stable Diffusion 3) прямо в бота, чтобы постить готовый креатив. Еще можно интегрировать Canva API для автоматического макетирования. Но это уже тема отдельной статьи.
Если захотите углубиться в архитектуру дешевого AI-бота, очень советую статью "Как построить гибридного чат-бота с ИИ за 5000 руб. в месяц" — там выбор стека и сравнение подходов.
А если вы контент-менеджер и хотите освоить AI-инструменты, рекомендую курс "AI-креатор: создаём контент с помощью нейросетей" — там как раз учат работать с промптами и строить такие пайплайны.
Не пытайтесь внедрить всё сразу. Начните с малого: подключите одну базу Notion, сделайте бота для одного типа контента (например, только Instagram-посты). Когда увидите, что качество устраивает — расширяйте. Ресторанная сеть — идеальный полигон: данные структурированы, а контента нужно много и регулярно.
И помните: лучший AI-копирайтер — тот, который не мешает человеку творить, а дает ему время на действительно важные вещи.