Skip to content

📚 Практические примеры сценариев

📖 Сборник практических примеров — от быстрого старта до продвинутых сценариев с оплатами, RAG хранилищем и сложной логикой.

📑 Содержание


🚀 Быстрый старт

Добро пожаловать в Coreness! Этот раздел поможет вам быстро создать первого бота и настроить первый сценарий.

Основные понятия

Тенанты — ваши боты и их конфигурация. Каждый тенант имеет свой ID, токен бота, набор сценариев и хранилище атрибутов (storage).

Сценарии — логика работы бота: команды, меню, обработка сообщений. Состоят из триггеров (когда запускается) и шагов (что делать). Могут запускаться по событиям (команды, сообщения) или по расписанию (scheduled сценарии).

Организация сценариев — сценарии можно организовывать в папки и подпапки для удобства. Все YAML-файлы из папки scenarios/ (включая подпапки) автоматически загружаются. Названия сценариев должны быть уникальными в рамках всего тенанта.

Storage — хранилище атрибутов тенанта в формате key-value. Позволяет гибко хранить настройки, лимиты, функции и другие данные без изменения схемы БД.

Плейсхолдеры — динамическая подстановка данных из события или предыдущих действий. Например: {username}, {user_id}, {event_text}.

Системные и публичные тенанты: По умолчанию можно работать с платформой через системные тенанты (ID < 100): конфигурация хранится в папке проекта config/tenant/, GitHub не нужен. Публичные тенанты (ID ≥ 100) используют внешний репозиторий и требуют отдельной настройки — см. блок Публичные тенанты (опционально).

Создание первого сценария (системный тенант)

Используйте системный тенант, чтобы сразу запуститься без настройки репозитория. Структура папок и формат сценариев одинаковы для всех типов тенантов; различаются только диапазон ID и источник конфигурации.

1. Настройте тенанта

Создайте папку в config/tenant/ по формату tenant_<ID>, где ID < 100 (например: tenant_10/). В проекте по умолчанию уже есть системный тенант tenant_1/ (мастер-бот) — его тоже можно использовать или взять за образец.

2. Настройте бота

В папке тенанта создайте файл tg_bot.yaml:

yaml
bot_name: "Мой бот"
bot_token: "1234567890:ABCdefGHIjklMNOpqrsTUVwxyz"
is_active: true

3. Создайте сценарии

Создайте папку scenarios/ внутри папки тенанта и добавьте в неё файлы сценариев (можно использовать подпапки для организации).

4. Напишите сценарий

Например, в scenarios/start.yaml:

yaml
start:
  trigger:
    - event_type: "message"
      event_text: "/start"
  
  step:
    - action: "send_message"
      params:
        text: |
          👋 Привет, {first_name|fallback:друг}!
          
          Добро пожаловать в бота!
        inline:
          - [{"📋 Меню": "menu"}, {"📚 Справка": "help"}]
        
        # Прикрепляем файл (опционально)
        # Можно использовать file_id из события: {event_attachment[0].file_id}
        attachment:
          - file_id: "AgACAgIAAxkBAAIUJWjyLorr_d8Jwof3V_gVjVNdGHyXAAJ--zEb4vGQS-a9UiGzpkTNAQADAgADeQADNgW"
            type: "photo"

Что происходит в этом примере:

  • trigger — условие запуска (команда /start)
  • step — последовательность действий
  • {first_name|fallback:друг} — плейсхолдер с модификатором
  • inline — кнопки под сообщением
  • attachment — пересылка файлов (фото, документы, видео) из событий или по file_id

📖 Подробнее о действиях, параметрах и плейсхолдерах: SCENARIO_CONFIG_GUIDE.md, ACTION_GUIDE.md

Применение изменений (системный тенант)

Конфигурация системного тенанта читается из локальной папки config/tenant/. После правок в сценариях или в tg_bot.yaml:

  1. Откройте мастер-бота
  2. Отправьте команду /tenant
  3. Укажите ID вашего тенанта (если ещё не был выбран)
  4. Нажмите кнопку «Синхронизировать»

Система подхватит изменения из локальных файлов и обновит данные. Репозиторий GitHub для системных тенантов не используется.

Публичные тенанты (опционально)

Если нужен публичный тенант (ID ≥ 100) — например, для клиентского бота с конфигурацией во внешнем репозитории — структура папок и формат сценариев те же: tenant_<ID>/, tg_bot.yaml, scenarios/ и т.д. Отличие только в настройке системы:

  • Конфигурация хранится во внешнем репозитории (Repository-Tenant), а не в папке проекта.
  • Синхронизация изменений: пуллинг (периодическая проверка репозитория) или вебхуки (расширение). После push в репозиторий тенанты подхватываются при следующей проверке или вручную через мастер-бота (команда /tenant → «Синхронизировать»).

📖 Типы тенантов и синхронизация: TENANT_CONFIG_GUIDE.md.


💳 Продвинутые примеры

Работа с оплатами (Invoices)

Система поддерживает работу с оплатами через Telegram Stars (инвойсы). Механизм требует обработки двух событий: pre_checkout_query (запрос на подтверждение) и payment_successful (успешная оплата).

Обзор механизма оплаты

Как работает оплата в Telegram:

  1. Создание инвойса — бот создает счет через create_invoice и отправляет его пользователю
  2. Пользователь нажимает "Оплатить" → Telegram отправляет событие pre_checkout_query
  3. Бот должен ответить в течение 10 секунд — подтвердить или отклонить платеж через confirm_payment или reject_payment
  4. После подтверждения → Telegram обрабатывает платеж и отправляет событие payment_successful
  5. Обработка успешной оплаты — бот обрабатывает событие payment_successful через mark_invoice_as_paid

⚠️ Критически важно:

  • На событие pre_checkout_query нужно ответить в течение 10 секунд, иначе платеж будет автоматически отклонен
  • invoice_payload в событиях — это строка с invoice_id, который был передан при создании инвойса
  • Нужно обрабатывать оба события: pre_checkout_query (подтверждение) и payment_successful (финальная обработка)

Создание инвойса

Действие: create_invoice

Что делает:

  • Создает инвойс в БД
  • Отправляет инвойс в чат (или создает ссылку, если as_link=true)
  • Возвращает invoice_id, который используется как payload в событиях

Пример:

yaml
create_payment:
  description: "Создание инвойса для оплаты"
  trigger:
    - event_type: "message"
      event_text: "/buy"
  
  step:
    - action: "create_invoice"
      params:
        title: "Премиум подписка"
        description: "Доступ к премиум функциям на 1 месяц"
        amount: 100  # 100 звезд
        currency: "XTR"  # По умолчанию XTR, можно не указывать
        # as_link: false  # По умолчанию false - отправка в чат
        # chat_id: "{chat_id}"  # Опционально, если нужно отправить в другой чат

Результат:

  • invoice_id — ID созданного инвойса (используется для дальнейшей работы с инвойсом)
  • invoice_message_id — ID отправленного сообщения с инвойсом (если отправка в чат, опционально)
  • invoice_link — Ссылка на инвойс (если as_link=true, опционально)

Важно: invoice_id автоматически передается в Telegram как payload (строка). Этот payload придет в событиях pre_checkout_query и payment_successful как invoice_payload.

Обработка pre_checkout_query

Событие: pre_checkout_query

Когда возникает: Пользователь нажимает "Оплатить" в инвойсе, но до обработки платежа.

⚠️ Критически важно: Нужно ответить в течение 10 секунд, иначе платеж будет автоматически отклонен.

Доступные поля события:

  • pre_checkout_query_id — ID запроса на подтверждение (обязателен для ответа)
  • invoice_payload — ID инвойса (строка)
  • currency — валюта платежа (обычно "XTR")
  • total_amount — сумма платежа в минимальных единицах валюты

Действия для ответа:

  • confirm_payment — подтвердить платеж
  • reject_payment — отклонить платеж

Пример обработки (рекомендуемый):

yaml
handle_pre_checkout:
  description: "Обработка запроса на подтверждение оплаты"
  trigger:
    - event_type: "pre_checkout_query"
  
  step:
    # СНАЧАЛА подтверждаем платеж (критично для Telegram - таймаут ~10 сек)
    # Передаем invoice_payload для автоматической проверки статуса инвойса
    # confirm_payment автоматически проверит, не отменен ли инвойс и не оплачен ли уже
    - action: "confirm_payment"
      params:
        pre_checkout_query_id: "{pre_checkout_query_id}"
        invoice_payload: "{invoice_payload}"  # Автоматическая проверка статуса
    
    # ПОТОМ отправляем информационное сообщение (не блокируем подтверждение)
    - action: "send_message"
      params:
        text: |
          ✅ Платеж подтвержден!
          
          ID запроса: {pre_checkout_query_id}
          ID инвойса: {invoice_payload}
          Сумма: {total_amount} {currency}

⚠️ Важно: Если инвойс отменен или уже оплачен, confirm_payment автоматически отклонит платеж и вернет result: "failed" с кодом ошибки:

  • INVOICE_CANCELLED — инвойс отменен
  • INVOICE_ALREADY_PAID — инвойс уже оплачен

Эти коды можно использовать для обработки в сценариях через validate и transitions.

Обработка payment_successful

Событие: payment_successful

Когда возникает: После успешной обработки платежа через инвойс.

Доступные поля события:

  • invoice_payload — ID инвойса (строка)
  • telegram_payment_charge_id — ID платежа в Telegram (обязателен для mark_invoice_as_paid)
  • currency — валюта платежа
  • total_amount — сумма платежа

Действие: mark_invoice_as_paid

Что делает:

  • Отмечает инвойс как оплаченный в БД
  • Сохраняет telegram_payment_charge_id и дату оплаты

Пример обработки:

yaml
handle_payment_successful:
  description: "Обработка успешной оплаты"
  trigger:
    - event_type: "payment_successful"
  
  step:
    # Шаг 1: Отмечаем инвойс как оплаченный
    - action: "mark_invoice_as_paid"
      params:
        invoice_payload: "{invoice_payload}"
        telegram_payment_charge_id: "{telegram_payment_charge_id}"
        paid_at: "{event_date}"  # Опционально, по умолчанию текущая дата
    
    # Шаг 2: Отправляем подтверждение пользователю
    - action: "send_message"
      params:
        text: |
          ✅ Платеж успешно обработан!
          
          ID инвойса: {invoice_payload}
          ID платежа: {telegram_payment_charge_id}
          Сумма: {total_amount} {currency}
    
    # Шаг 3: Можно выполнить дополнительные действия
    # Например, активировать подписку, выдать доступ и т.д.
    - action: "set_user_storage"
      params:
        key: "premium_active"
        value: true

Полный пример: Flow оплаты

Полный flow от создания инвойса до обработки оплаты:

yaml
# 1. Создание инвойса
create_payment:
  description: "Создание инвойса для оплаты"
  trigger:
    - event_type: "message"
      event_text: "/buy"
  
  step:
    - action: "create_invoice"
      params:
        title: "Премиум подписка"
        description: "Доступ к премиум функциям на 1 месяц"
        amount: 100
        currency: "XTR"

# 2. Обработка pre_checkout_query (подтверждение платежа)
handle_pre_checkout:
  description: "Обработка запроса на подтверждение оплаты"
  trigger:
    - event_type: "pre_checkout_query"
  
  step:
    # Подтверждаем платеж (с автоматической проверкой статуса)
    - action: "confirm_payment"
      params:
        pre_checkout_query_id: "{pre_checkout_query_id}"
        invoice_payload: "{invoice_payload}"  # Автоматическая проверка статуса

# 3. Обработка payment_successful (финальная обработка)
handle_payment_successful:
  description: "Обработка успешной оплаты"
  trigger:
    - event_type: "payment_successful"
  
  step:
    # Отмечаем инвойс как оплаченный
    - action: "mark_invoice_as_paid"
      params:
        invoice_payload: "{invoice_payload}"
        telegram_payment_charge_id: "{telegram_payment_charge_id}"
    
    # Отправляем подтверждение
    - action: "send_message"
      params:
        text: |
          ✅ Платеж успешно обработан!
          
          Спасибо за покупку!
    
    # Активируем подписку (пример)
    - action: "set_user_storage"
      params:
        key: "premium_active"
        value: true

Что происходит в этом flow:

  1. Пользователь отправляет /buy → запускается create_payment
  2. Создается инвойс → отправляется пользователю в чат
  3. Пользователь нажимает "Оплатить" → Telegram отправляет pre_checkout_query
  4. Бот подтверждает платежhandle_pre_checkout отвечает через confirm_payment (в течение 10 секунд)
  5. Telegram обрабатывает платеж → отправляет payment_successful
  6. Бот обрабатывает успешную оплатуhandle_payment_successful отмечает инвойс как оплаченный и выполняет бизнес-логику

Рекомендации и best practices

1. Всегда обрабатывайте оба события:

  • pre_checkout_query — для подтверждения/отклонения платежа
  • payment_successful — для финальной обработки и бизнес-логики

2. Используйте invoice_payload в confirm_payment:

  • Если передать invoice_payload в confirm_payment, система автоматически проверит статус инвойса
  • Если инвойс отменен или уже оплачен, платеж будет автоматически отклонен

3. Таймаут 10 секунд для pre_checkout_query:

  • Обработка должна быть быстрой
  • Если нужна долгая проверка (например, запрос к внешнему API), используйте async действия, но ответьте быстро
  • Можно подтвердить платеж сразу, а проверку сделать в payment_successful

4. Обработка ошибок:

  • Всегда обрабатывайте result: "failed" в confirm_payment (инвойс отменен/уже оплачен)
  • Используйте коды ошибок для различения ситуаций:
    • INVOICE_CANCELLED — инвойс отменен
    • INVOICE_ALREADY_PAID — инвойс уже оплачен
  • Обрабатывайте result: "error" в mark_invoice_as_paid (технические ошибки)
  • Пример обработки через validate и transitions:
yaml
- action: "confirm_payment"
  params:
    pre_checkout_query_id: "{pre_checkout_query_id}"
    invoice_payload: "{invoice_payload}"
  transition:
    - action_result: "failed"
      transition_action: "jump_to_step"
      transition_value: 2  # Переход к обработке ошибки

- action: "validate"
  params:
    condition: "{last_error.code} == 'INVOICE_CANCELLED'"
  transition:
    - action_result: "success"
      transition_action: "jump_to_scenario"
      transition_value: "handle_cancelled_invoice"

5. Использование as_link=true:

  • Если нужно создать ссылку на инвойс вместо отправки в чат, используйте as_link: true
  • Ссылка сохранится в _cache.invoice_link и можно отправить её пользователю вручную

6. Отмена инвойсов:

  • Используйте cancel_invoice для отмены неоплаченных инвойсов
  • Важно: Отмена инвойса работает только на уровне платформы — Telegram продолжает хранить инвойс и может прислать запрос на подтверждение по отмененному инвойсу
  • Если передан invoice_payload в confirm_payment, система автоматически проверит статус инвойса и отклонит платеж, если инвойс отменен (вернет result: "failed")

7. Получение информации об инвойсе:

  • Используйте get_invoice для проверки статуса инвойса
  • Используйте get_user_invoices для получения всех инвойсов пользователя

Работа с RAG хранилищем

RAG (Retrieval-Augmented Generation) — система для хранения и поиска текстовых данных с использованием векторных embeddings. Позволяет находить релевантные фрагменты текста по смыслу и использовать их как контекст для AI.

Обзор RAG системы

Как работает RAG:

  1. Сохранение — текст разбивается на чанки, для каждого генерируется векторное представление (embedding) и сохраняется в БД
  2. Поиск — по запросу находится похожий текст через векторный поиск (cosine similarity)
  3. Использование — найденные чанки передаются в AI completion как контекст для более точных ответов

Типы документов:

  • knowledge — база знаний (документация, справочная информация)
  • chat_history — история диалога (сообщения пользователя и бота)
  • other — прочее (добавляется в блок ДОП. КОНТЕКСТ вместе с кастомным context)

Роли для OpenAI messages:

  • system — системные инструкции
  • user — сообщения пользователя
  • assistant — ответы ассистента

Метаданные (chunk_metadata) — JSON объект для фильтрации (например, chat_id, username). Используются для фильтрации при поиске и удалении. Могут быть использованы в chunk_format для отображения в контексте AI.

Сохранение данных в векторное хранилище

Действие: save_embedding

Что делает:

  • Очищает текст от HTML, markdown и лишних символов
  • Разбивает на чанки с перекрытием (overlap) для сохранения контекста
  • Генерирует embeddings для каждого чанка
  • Сохраняет в таблицу vector_storage

Пример: Сохранение базы знаний

yaml
save_knowledge:
  description: "Сохранение документации в базу знаний"
  trigger:
    - event_type: "message"
      event_text: "/save_knowledge"
  
  step:
    - action: "save_embedding"
      params:
        text: |
          Coreness — это платформа для создания Telegram ботов.
          
          Основные возможности:
          - Сценарии на YAML
          - Хранилище данных (storage)
          - Работа с оплатами
          - RAG для контекстных ответов
        document_type: "knowledge"
        role: "user"
        # Опционально: метаданные для фильтрации
        metadata:
          category: "documentation"
          version: "0.21.0"

Пример: Сохранение истории диалога

yaml
save_user_message:
  description: "Сохранение сообщения пользователя в историю"
  trigger:
    - event_type: "message"
  
  step:
    # Сохраняем сообщение пользователя
    - action: "save_embedding"
      params:
        text: "{event_text}"
        document_type: "chat_history"
        role: "user"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"
          message_id: "{message_id}"

Пример: Сохранение истории с AI ответом

yaml
ai_chat_with_history:
  description: "Чат с AI с сохранением истории"
  trigger:
    - event_type: "message"
  
  step:
    # Шаг 1: Сохраняем сообщение пользователя
    - action: "save_embedding"
      params:
        text: "{event_text}"
        document_type: "chat_history"
        role: "user"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"
    
    # Шаг 2: Получаем историю для контекста
    - action: "get_recent_chunks"
      params:
        limit_chunks: 10
        document_type: "chat_history"
        metadata_filter:
          chat_id: "{chat_id}"
    
    # Шаг 3: Запрос к AI с историей
    - action: "completion"
      params:
        prompt: "{event_text}"
        rag_chunks: "{_cache.chunks}"
    
    # Шаг 4: Сохраняем ответ AI модели
    - action: "save_embedding"
      params:
        text: "{_cache.response}"
        document_type: "chat_history"
        role: "assistant"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"
    
    # Шаг 5: Отправляем ответ пользователю
    - action: "send_message"
      params:
        text: "{_cache.response}"

Параметры:

  • text — текст для сохранения (обязательно)
  • document_type — тип документа: knowledge, chat_history, other (обязательно)
  • role — роль для OpenAI: system, user, assistant (по умолчанию user)
  • metadata — метаданные для фильтрации (JSON объект, опционально)
  • document_id — ID документа (опционально, генерируется автоматически)
  • chunk_size — размер чанка в символах (по умолчанию 1000)
  • chunk_overlap — перекрытие между чанками (по умолчанию 200)

Семантический поиск

Действие: search_embedding

Что делает:

  • Преобразует запрос в вектор (если передан query_text)
  • Ищет похожие чанки по cosine similarity
  • Возвращает отсортированные результаты с оценкой схожести

Пример: Поиск по тексту

yaml
search_knowledge:
  description: "Поиск в базе знаний"
  trigger:
    - event_type: "message"
      event_text: "/search"
  
  step:
    # Шаг 1: Поиск релевантных чанков
    - action: "search_embedding"
      params:
        query_text: "{event_text}"
        document_type: "knowledge"
        limit_chunks: 5
        min_similarity: 0.7
        limit_chars: 2000  # Лимит по символам поверх limit_chunks
    
    # Шаг 2: Отправка результатов пользователю
    - action: "send_message"
      params:
        text: |
          Найдено {_cache.chunks_count} релевантных фрагментов:
          
          [1] (similarity: {_cache.chunks[0].similarity})
          {_cache.chunks[0].content}
          
          [2] (similarity: {_cache.chunks[1].similarity})
          {_cache.chunks[1].content}
          
          [3] (similarity: {_cache.chunks[2].similarity})
          {_cache.chunks[2].content}

Пример: Поиск с фильтрацией по метаданным

yaml
search_user_history:
  description: "Поиск в истории конкретного пользователя"
  trigger:
    - event_type: "message"
      event_text: "/my_history"
  
  step:
    - action: "search_embedding"
      params:
        query_text: "{event_text}"
        document_type: "chat_history"
        metadata_filter:
          chat_id: "{chat_id}"
          username: "{username}"
        limit_chunks: 10

Параметры:

  • query_text или query_vector — запрос для поиска (обязательно один из них)
  • document_type — фильтр по типу документа (строка или массив)
  • document_id — фильтр по ID документа (строка или массив)
  • limit_chunks — количество результатов (по умолчанию 10)
  • limit_chars — лимит по символам поверх limit_chunks (опционально)
  • min_similarity — минимальный порог схожести (по умолчанию 0.7)
  • until_date / since_date — фильтр по дате (формат: YYYY-MM-DD или YYYY-MM-DD HH:MM:SS)
  • metadata_filter — фильтр по метаданным (JSON объект)

Результат:

  • chunks — массив найденных чанков с полями: content, document_id, chunk_index, document_type, role, similarity, created_at, chunk_metadata
  • chunks_count — количество найденных чанков

Получение последних чанков

Действие: get_recent_chunks

Что делает:

  • Получает последние N чанков по дате created_at (не векторный поиск)
  • Полезно для получения истории диалога или последних сообщений

Пример: Получение последних сообщений из чата

yaml
get_recent_messages:
  description: "Получение последних сообщений из чата"
  trigger:
    - event_type: "message"
      event_text: "/recent"
  
  step:
    - action: "get_recent_chunks"
      params:
        limit_chunks: 20
        limit_chars: 3000  # Лимит по символам поверх limit_chunks
        document_type: "chat_history"
        metadata_filter:
          chat_id: "{chat_id}"
    
    - action: "send_message"
      params:
        text: |
          Последние {_cache.chunks_count} сообщений:
          
          [{_cache.chunks[0].created_at}] {_cache.chunks[0].role}: {_cache.chunks[0].content}
          
          [{_cache.chunks[1].created_at}] {_cache.chunks[1].role}: {_cache.chunks[1].content}
          
          [{_cache.chunks[2].created_at}] {_cache.chunks[2].role}: {_cache.chunks[2].content}

Параметры:

  • limit_chunks — количество чанков (по умолчанию 10). Работает вместе с limit_chars - сначала выбирается limit_chunks чанков, затем фильтруются по limit_chars
  • limit_chars — лимит по символам поверх limit_chunks (опционально). После получения limit_chunks чанков они отбираются по порядку (от новых к старым), пока сумма символов не превысит limit_chars
  • document_type — фильтр по типу документа
  • document_id — фильтр по ID документа
  • until_date / since_date — фильтр по дате
  • metadata_filter — фильтр по метаданным

Использование RAG в AI completion

Параметр: rag_chunks в действии completion

Что делает:

  • Автоматически формирует правильную структуру messages для AI
  • Группирует чанки по типам: chat_history → диалог, knowledge → контекст, other → дополнительный контекст
  • Добавляет среднюю similarity для оценки качества контекста

Пример: AI ответ с контекстом из базы знаний

yaml
ai_answer_with_context:
  description: "Ответ AI с использованием RAG контекста"
  trigger:
    - event_type: "message"
  
  step:
    # Шаг 1: Поиск релевантного контекста
    - action: "search_embedding"
      params:
        query_text: "{event_text}"
        document_type: "knowledge"
        limit_chunks: 5
        limit_chars: 2000
    
    # Шаг 2: Получение последних сообщений для контекста диалога
    - action: "get_recent_chunks"
      params:
        limit_chunks: 10
        document_type: "chat_history"
        metadata_filter:
          chat_id: "{chat_id}"
    
    # Шаг 3: Объединение результатов и запрос к AI
    - action: "completion"
      params:
        prompt: "{event_text}"
        system_prompt: |
          Ты — помощник, который отвечает на вопросы пользователя.
          Используй предоставленный контекст для точных ответов.
        rag_chunks: "{_cache.chunks}"  # Чанки из search_embedding и get_recent_chunks
        model: "gpt-4o-mini"
    
    # Шаг 4: Отправка ответа
    - action: "send_message"
      params:
        text: "{_cache.response}"
    
    # Шаг 5: Сохранение диалога в историю
    - action: "save_embedding"
      params:
        text: "{event_text}"
        document_type: "chat_history"
        role: "user"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"
    
    - action: "save_embedding"
      params:
        text: "{_cache.response}"
        document_type: "chat_history"
        role: "assistant"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"

Формат messages, который формируется автоматически:

1. System сообщение (из system_prompt)
2. Диалог из chat_history (отсортированный по created_at)
3. Финальный user с:
   - KNOWLEDGE (3, avg: 0.85):
     [1] 0.90 ...
     [2] 0.82 ...
   - ДОП. КОНТЕКСТ:
     [1] [other чанки из rag_chunks]
     [кастомный context]
   - ВОПРОС: [prompt]

Полный пример: RAG flow

Полный flow от сохранения до использования RAG:

yaml
# 1. Сохранение базы знаний (один раз)
save_documentation:
  description: "Сохранение документации в базу знаний"
  trigger:
    - event_type: "message"
      event_text: "/admin_save_docs"
  
  step:
    - action: "save_embedding"
      params:
        text: |
          [Ваша документация здесь]
        document_type: "knowledge"
        metadata:
          category: "docs"
          updated_at: "{event_date}"

# 2. Обработка вопроса пользователя с RAG
handle_question:
  description: "Ответ на вопрос с использованием RAG"
  trigger:
    - event_type: "message"
  
  step:
    # Поиск релевантного контекста
    - action: "search_embedding"
      params:
        query_text: "{event_text}"
        document_type: "knowledge"
        limit_chunks: 5
        limit_chars: 2000
    
    # Получение истории диалога
    - action: "get_recent_chunks"
      params:
        limit_chunks: 10
        document_type: "chat_history"
        metadata_filter:
          chat_id: "{chat_id}"
    
    # AI ответ с контекстом
    - action: "completion"
      params:
        prompt: "{event_text}"
        system_prompt: "Ты — помощник. Используй контекст для точных ответов."
        rag_chunks: "{_cache.chunks}"
    
    # Отправка ответа
    - action: "send_message"
      params:
        text: "{_cache.response}"
    
    # Сохранение в историю
    - action: "save_embedding"
      params:
        text: "{event_text}"
        document_type: "chat_history"
        role: "user"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"
    
    - action: "save_embedding"
      params:
        text: "{_cache.response}"
        document_type: "chat_history"
        role: "assistant"
        chunk_metadata:
          chat_id: "{chat_id}"
          username: "{username}"

# 3. Удаление старых данных (опционально)
cleanup_old_data:
  description: "Удаление старых данных из истории"
  trigger:
    - event_type: "scheduled"
      schedule: "0 0 * * *"  # Каждый день в полночь
  
  step:
    - action: "delete_embedding"
      params:
        document_type: "chat_history"
        until_date: "{date_sub_days(event_date, 30)}"  # Старше 30 дней
        metadata_filter:
          chat_id: "{chat_id}"

Рекомендации и best practices

1. Типы документов:

  • Используйте knowledge для статичной информации (документация, справочники)
  • Используйте chat_history для диалогов (сообщения пользователя и бота)
  • Используйте other для прочего (добавляется в блок ДОП. КОНТЕКСТ вместе с кастомным context)

2. Метаданные для фильтрации:

  • Всегда сохраняйте chat_id и username в метаданных для истории диалога
  • Используйте метаданные для фильтрации по чатам, пользователям, категориям
  • Метаданные не передаются в контекст AI, используются только для поиска

3. Размер чанков:

  • Оптимальный размер: 500-1500 символов
  • Перекрытие (overlap): 10-20% от размера чанка
  • Слишком маленькие чанки теряют контекст, слишком большие — точность поиска

4. Поиск и лимиты:

  • Используйте limit_chunks для ограничения количества результатов
  • Используйте limit_chars для более гибкого контроля размера контекста
  • Рекомендуемый min_similarity: 0.7-0.8 (зависит от качества embeddings)

5. Использование в AI completion:

  • Всегда передавайте rag_chunks в completion для автоматического формирования messages
  • Система автоматически группирует чанки по типам и ролям
  • chat_history сортируется по created_at для сохранения порядка диалога
  • Чанки типа other объединяются с кастомным context в блок ДОП. КОНТЕКСТ

6. Формат чанков (chunk_format):

  • Параметр chunk_format позволяет настроить отображение чанков в контексте AI
  • Шаблоны используют маркеры $ для подстановки значений: $content (обязательно) + любые поля из chunk_metadata
  • Поддерживается fallback: $field|fallback:значение
  • Пример для группового чата: chunk_format: {chat_history: "[$username|fallback:Пользователь]: $content"}
  • Пример для базы знаний: chunk_format: {knowledge: "[$category|fallback:База знаний] $content"}

7. Производительность:

  • Сохраняйте данные асинхронно (не блокируйте ответ пользователю)
  • Используйте фильтры по метаданным для ускорения поиска
  • Очищайте старые данные периодически через delete_embedding

8. Обработка ошибок:

  • Всегда проверяйте result: "success" перед использованием результатов
  • Обрабатывайте случаи, когда поиск не нашел результатов (chunks_count: 0)
  • Используйте fallback логику, если контекст не найден

Coreness — Create. Automate. Scale.