translate Доступно на: EN VI
info Переведено с помощью ИИ

QuotyAI: Инструкции и автоматизация

Инструкции и автоматизация

Инструкции — основа поведения вашего торгового ассистента. Они выходят далеко за рамки простых текстовых запросов: у каждой инструкции есть категория, которая определяет как и когда она выполняется. Одни инструкции добавляют контекст в «мозг» ИИ, другие регистрируют инструменты, которые ИИ может использовать, а третьи выполняются как детерминированный код, запускающий действия до или после каждого сообщения клиента.


Проблема простых инструкций

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

  • «Отправь меню, когда кто-то спросит о ценах» — ИИ может отправить, может забыть, а может отправить не то. Это ненадёжно.
  • «Пометь клиента как «оплатил» после получения счёта» — ИИ должен помнить об этом каждый раз. Легко забыть.
  • «Показывай правила ценообразования на выходные только по пятницам» — ИИ путается, когда инструкции противоречат друг другу.

QuotyAI решает эту проблему, присваивая каждой инструкции категорию, которая точно определяет её поведение — как запрос (prompt), как инструмент, как предварительное условие или как автоматизированный код. Вы просто пишете, что нужно, на обычном языке — система определяет категорию, генерирует детерминированный код и позволяет просмотреть его до публикации.


Шесть категорий

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

Категория Где выполняется Что делает
Consistent Prompt (Постоянный запрос) В системном запросе ИИ Всегда включён — даёт ИИ постоянный контекст
Conditional Prompt (Условный запрос) В системном запросе ИИ Включается только при выполнении условия
Consistent Prompt + Tool (Постоянный запрос + инструмент) Запрос + зарегистрированный LangChain-инструмент Постоянный контекст + вызываемая функция, которую ИИ может использовать
Conditional Prompt + Tool (Условный запрос + инструмент) Запрос + зарегистрированный LangChain-инструмент Контекст + инструмент, но только когда условие истинно
Deterministic Router (Детерминированный маршрутизатор) Перед обработкой сообщения ИИ Выполняет код, который может перехватить сообщение, отправить ответ или полностью обойти ИИ
Deterministic Callback (Детерминированный обратный вызов) После ответа ИИ Выполняет код, который обновляет состояние, помечает клиентов или уведомляет команду

Реальная история из бизнеса

Небольшой ресторан в Хошимине использует QuotyAI для обработки заказов из Facebook и Telegram. Вот как они применяют каждую категорию инструкций:

Consistent Prompt:

«Наш фо стоит 65 000 VND за обычную порцию, 85 000 VND за большую. Бань ми — 35 000 VND.»

Эта информация всегда в «мозгу» ИИ — клиент может спросить в любое время и получить правильный ответ.

Conditional Prompt:

«После 22:00 доступен только самовывоз. Посадка в зале закрывается в 21:30.»

Функция условия проверяет текущее время. До 21:30 эта инструкция невидима для ИИ. После 21:30 она появляется автоматически, и ИИ начинает сообщать клиентам только о самовывозе.

Deterministic Router:

«Если клиент говорит «меню» или «что у вас есть», отправьте ему PDF-меню и не заставляйте его ждать ответа ИИ.»

Никаких форм, конструкторов действий или выпадающих списков — просто напишите, что нужно. ИИ-кодировщик читает вашу инструкцию, определяет подходящие действия (отправить сообщение, отправить вложение, прервать обработку и т.д.) и генерирует TypeScript-функцию автоматически. Функция маршрутизатора проверяет каждое входящее сообщение. Когда она обнаруживает запрос меню, она немедленно отправляет вложение и прерывает работу ИИ — клиент получает меню менее чем за 100 мс вместо ожидания генерации ответа ИИ.

Deterministic Callback:

«Когда клиент подтверждает платный заказ, отметь его как «has_paid_order» в состоянии разговора.»

После того как ИИ успешно обработал заказ и отправил подтверждение, срабатывает обратный вызов. Он обновляет состояние разговора, чтобы в следующий раз, когда этот клиент напишет, ИИ знал, что он платящий клиент.

Consistent Prompt + Tool:

«Вы можете узнать сегодняшние специальные предложения с помощью инструмента getDailySpecial. Спецпредложения меняются ежедневно в зависимости от свежих ингредиентов.»

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


Как это работает

Конвейер автоматизации

Каждое сообщение клиента проходит через детерминированный конвейер до и после обработки ИИ:

Клиент отправляет сообщение

┌───────────────────────────────────────┐
│  1. Извлечение деталей заказа          │
│     Ассистент извлекает                │
│     структурированные данные заказа    │
│     из сообщения                       │
└───────────────────────────────────────┘

┌───────────────────────────────────────┐
│  2. Детерминированный маршрутизатор    │  ← Автоматизация до ИИ
│     Запускается ДО того, как ИИ        │
│     увидит сообщение. Может            │
│     перехватывать, отправлять          │
│     вложения или прерывать обработку.  │
└───────────────────────────────────────┘
        ↓ (если не прервано)
┌───────────────────────────────────────┐
│  3. Обработка ИИ-агентом               │
│     • Consistent prompts              │  ← Всегда в мозгу
│     • Conditional prompts             │  ← Только если условие выполнено
│     • Зарегистрированные инструменты   │  ← ИИ может вызывать функции
└───────────────────────────────────────┘

┌───────────────────────────────────────┐
│  4. Детерминированный обратный вызов   │  ← Автоматизация после ИИ
│     Запускается ПОСЛЕ ответа ИИ.      │
│     Обновляет состояние, помечает      │
│     клиентов, уведомляет команду.     │
└───────────────────────────────────────┘

Детерминированность — это гарантия

В отличие от ИИ, который может забыть или неверно истолковать инструкцию, Deterministic Router и Deterministic Callback выполняются как настоящий TypeScript-код, сгенерированный нашими ИИ-кодировщиками. Вам не нужно настраивать действия вручную — просто напишите, что должно произойти. Когда вы пишете:

«Если сумма заказа превышает 1 000 000 VND, предложите бесплатную доставку»

ИИ-кодировщик анализирует вашу инструкцию, определяет подходящие действия маршрутизации и условия, и генерирует отдельную TypeScript-функцию во время сборки ассистента. Вы можете просмотреть сгенерированный код прямо в редакторе — разверните любую инструкцию маршрутизатора, чтобы увидеть TypeScript с подсветкой синтаксиса, скопировать его или перегенерировать. Каждая функция работает независимо — если одна даст сбой, остальные продолжат работу без прерывания.

function route(ctx: RouterContext): RouterAction[] {
  const actions: RouterAction[] = [];

  if (ctx.order.totalAmount && ctx.order.totalAmount > 1000000) {
    actions.push({
      type: 'send_message',
      message: 'Ваш заказ подходит для бесплатной доставки! 🚚',
    });
  }

  actions.push({ type: 'noop' });
  return actions;
}

RouterContext предоставляет каждой функции маршрутизатора всё необходимое для принятия решений:

Поле Тип Описание
ctx.order Record<string, unknown> Структурированные параметры заказа, извлечённые из разговора
ctx.message string Исходный текст сообщения клиента — используйте для поиска ключевых слов
ctx.state Record<string, unknown> Полное состояние разговора (флаги клиента, прошлые данные)
ctx.business object Информация о бизнесе: timezone, name, industries, customAttributes — общедоступные атрибуты, определённые пользователем, которые применяются ко всем контактам/разговорам
ctx.contact object (опционально) Контактные данные клиента: name, email, phone, customAttributes, channelIdentifiers — создавайте условия на основе информации о клиенте
ctx.conversation object (опционально) Метаданные разговора: channel, externalId, lastInboundMessage, lastOutboundMessage — создавайте логику для конкретных каналов
ctx.now Date Текущее время (детерминированное — одинаковое для всех функций в одном запуске)

Каждая сгенерированная функция выполняется в изолированной среде — она никогда не забывает, не предполагает и не галлюцинирует. Поскольку контекст включает контактную информацию, метаданные разговора и бизнес-атрибуты, функции могут строить богатые условия, такие как «если это VIP-клиент из Telegram», «если домен email клиента указывает на корпоративный аккаунт» или «если общедоступный флаг allow_discounts установлен в true».

Действия маршрутизатора

Функция маршрутизатора возвращает действия. Платформа интерпретирует их:

Действие Эффект
send_message Немедленно отправить статическое сообщение клиенту
send_linked_attachments Отправить все привязанные вложения для этой инструкции
update_state Изменить значение в состоянии разговора
handover Перевести на оператора с указанием причины
short_circuit Полностью пропустить ИИ — ответ ИИ не генерируется
noop Ничего не делать, продолжить обычную обработку

Действия обратного вызова

Функция обратного вызова выполняется после ответа ИИ:

Действие Эффект
update_state Изменить значение в состоянии разговора (например, отметить как оплачено)
notify_agent Отправить приватное уведомление вашей команде
noop Ничего не делать

Справочник категорий

Consistent Prompt (Постоянный запрос)

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

Когда использовать:

  • Ваше меню, прайс-лист или каталог услуг
  • Стандартные часы работы
  • Часто задаваемые вопросы и ответы на них
  • Бизнес-политики (отмена, возврат и т.д.)

Пример:

«Наш спа-салон предлагает: 60-мин шведский массаж — 500 000 VND, 90-мин глубокотканевой — 750 000 VND, добавить горячие камни — 150 000 VND.»


Conditional Prompt (Условный запрос)

Назначение: Инструкции, которые должны появляться в контексте ИИ только при выполнении условия. Условие — это сгенерированная TypeScript-функция, которая вычисляется во время выполнения.

Когда использовать:

  • Правила на основе времени (после работы, в выходные, праздники)
  • Правила на основе статуса клиента (постоянный клиент, VIP, отмечен флагом)
  • Правила на основе состояния заказа (только после выбора товаров)
  • Сезонные акции и ограниченные по времени предложения

Под капотом генерируется функция shouldInclude с сигнатурой function shouldInclude(ctx: ConditionContext): boolean. ConditionContext предоставляет:

Поле Тип Описание
ctx.order Record<string, unknown> Структурированные входные параметры заказа из разговора
ctx.contact object (опционально) Контактные данные клиента: name, email, phone, customAttributes
ctx.conversation object (опционально) Метаданные разговора: channel, externalId, lastInboundMessage
ctx.state Record<string, unknown> (опционально) Снимок состояния разговора (флаги клиента, прошлые данные)
ctx.business object (опционально) Информация о бизнесе: timezone, name, industries, customAttributes
ctx.now Date Текущее время (детерминированное)

Если функция возвращает false, содержимое инструкции невидимо для ИИ.


Consistent Prompt + Tool (Постоянный запрос + инструмент)

Назначение: Даёт ИИ постоянный контекст И регистрирует детерминированную функцию-инструмент, которую он может вызывать. Используйте, когда ИИ нужно как знание о чём-то, так и возможность действовать на его основе.

Когда использовать:

  • Поиск динамических данных (складские остатки, ежедневные спецпредложения, наличие)
  • Выполнение проверок (проверить адрес, подтвердить код купона)
  • Расчёт производных значений (налоговые ставки, стоимость доставки)

Инструмент регистрируется как функция-инструмент LangChain со сгенерированной JSON-схемой. ИИ может вызвать его во время разговора.


Conditional Prompt + Tool (Условный запрос + инструмент)

Назначение: Аналогично предыдущему, но и содержимое запроса, и инструмент доступны только при выполнении условия.

Когда использовать:

  • Инструменты только для выходных (например, поиск меню бранча)
  • Возможности только для VIP-клиентов (например, применить скидку лояльности)
  • Инструменты после заказа (например, отслеживание статуса доставки — доступно только после оформления заказа)

Условие вычисляется один раз — если оно истинно, и содержимое запроса, И инструмент становятся доступны ИИ.


Deterministic Router (Детерминированный маршрутизатор)

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

Когда использовать:

  • Мгновенные ответы: «Если клиент спрашивает часы работы, немедленно отправить вложение с часами» — без задержки ИИ
  • Ограничения: «Если клиент упоминает названия конкурентов, заблокировать и перевести на оператора»
  • Предобработка: «Если клиент говорит «меню» на любом языке, отправить PDF»
  • Комплаенс: «Если клиент из заблокированного региона, отправить сообщение об ошибке и прервать обработку»
  • По времени: «После 22:00 отправить сообщение «закрыто» и прервать обработку»
  • По статусу клиента: «Если у клиента уже есть активный заказ, заблокировать повторный заказ»

Все инструкции маршрутизатора генерируют отдельные TypeScript-функции во время сборки — по одной на инструкцию. Каждая функция получает полный объект RouterContext с исходным сообщением клиента, структурированными данными заказа, состоянием разговора, информацией о бизнесе, контактными данными клиента, метаданными разговора и текущим временем. Это означает, что каждое правило может независимо оценивать все доступные контекстные данные.

Изоляция инструкций: Если одна функция маршрутизатора выдаёт ошибку, остальные продолжают работу. Ни одна ошибочная инструкция не может сломать все ваши правила маршрутизации.

Как это работает в конвейере:

  1. Извлечение структурированных данных заказа из сообщения клиента
  2. Построение RouterContext с исходным сообщением, данными заказа, состоянием разговора, информацией о бизнесе, контактными данными клиента, метаданными разговора и текущим временем
  3. Последовательный запуск каждой функции route(ctx) — если возвращается short_circuit, остальные функции всё равно выполняются, но ИИ пропускается
  4. Обработка накопленных действий: отправка сообщений, отправка вложений, обновление состояния, перевод на оператора или прерывание

Deterministic Callback (Детерминированный обратный вызов)

Назначение: Выполняется как настоящий TypeScript-код после того, как ИИ ответил. Для побочных эффектов, которые не должны прерывать взаимодействие с клиентом.

Когда использовать:

  • Отслеживание состояния: «После подтверждения заказа установить флаг hasActiveOrder»
  • Уведомления: «После неудачной попытки оплаты уведомить команду»
  • Аудит: «После предоставления коммерческого предложения записать его в состояние разговора»
  • Сегментация клиентов: «После 5-го заказа клиента пометить его как VIP»

Каждая инструкция обратного вызова генерирует собственную функцию с сигнатурой function callback(ctx: CallbackContext): CallbackAction[]. CallbackContext предоставляет:

Поле Тип Описание
ctx.order Record<string, unknown> Структурированные входные параметры заказа из разговора
ctx.aiResponse string Ответ, сгенерированный ИИ и только что отправленный клиенту
ctx.contact object (опционально) Контактные данные клиента: name, email, phone, customAttributes — условия на основе личности клиента
ctx.conversation object (опционально) Метаданные разговора: channel, externalId — условия на основе канала, из которого пришёл разговор
ctx.state Record<string, unknown> (опционально) Снимок состояния разговора для чтения или обновления флагов клиента
ctx.business object (опционально) Информация о бизнесе: timezone, name, industries, customAttributes

В дополнение к стандартным действиям, обратные вызовы могут записывать данные в контакты и разговоры:

Действие Эффект
set_contact_attribute Установить пользовательский атрибут в документе контакта (сохраняется между разговорами)
set_conversation_attribute Установить пользовательский атрибут в документе разговора

Это позволяет сгенерированному ИИ обратному вызову сохранять такие данные, как «отметить этого клиента как VIP» или «пометить этот разговор как обработанный», записывая в ctx.contact.customAttributes или ctx.conversation.customAttributes.

Обратные вызовы неблокирующие — клиент получает ответ, пока обратные вызовы обрабатываются в фоновом режиме.


Детали технической реализации

Интеграция с конвейером сборки

Во время сборки ассистента инструкции проходят через генерацию кода:

Инструкции из БД

Сборщик получает активные инструкции

┌────────────────────────────────────────────┐
│  Проверка категории                         │
│                                            │
│  CONSISTENT_* → Генерация кода не требуется│
│                 (только запрос)             │
│                                            │
│  CONDITIONAL_* → Генерация                 │
│  shouldInclude() для каждой инструкции      │
│                                            │
│  DETERMINISTIC_ROUTER → Генерация           │
│  route() для КАЖДОЙ инструкции —           │
│  каждая функция работает независимо         │
│  с полным RouterContext                     │
│                                            │
│  DETERMINISTIC_CALLBACK → Генерация         │
│  callback() для каждой инструкции           │
│                                            │
│  *_PROMPT_AND_TOOL → Генерация              │
│  функции инструмента + JSON-схемы           │
│  для каждой инструкции                      │
└────────────────────────────────────────────┘

Код записывается обратно в документ инструкции (для предпросмотра)

Код сохраняется в aiExecutableSource (источник истины)

Снимок фиксируется в неизменяемом ассистенте

Хранение сгенерированного кода

Сгенерированный код записывается в два места для разных целей:

  • Документ инструкции (поле generatedCode) — для мгновенного предпросмотра в редакторе с подсветкой синтаксиса
  • aiExecutableSource ассистента — источник истины, который фиксируется в неизменяемых снимках и используется во время выполнения

Структура хранения в aiExecutableSource с ключом по ID инструкции:

Категория Хранение Пример ключа
Маршрутизатор (на инструкцию) deterministicRouterInstructions[instructionId].code Одна запись на инструкцию маршрутизатора — изолирована и независима
Обратный вызов (на инструкцию) deterministicCallbacks[instructionId].code Одна запись на инструкцию обратного вызова
Условие (на инструкцию) conditionFunctions[instructionId].code Одна запись на условную инструкцию
Инструмент (на инструкцию) instructionTools[instructionId] Одна запись на инструкцию-инструмент

Изолированное выполнение

Все сгенерированные TypeScript-функции выполняются в той же изолированной среде, что и формулы ценообразования:

  • Встроенный конструктор Function Bun
  • Нет доступа к файловой системе, сети или переменным окружения
  • Переопределённые методы console для аудита
  • Возвращают типизированные объекты действий, которые интерпретирует конвейер

Пользовательские атрибуты на трёх уровнях

Все три типа контекста (RouterContext, CallbackContext, ConditionContext) предоставляют доступ к пользовательским атрибутам на трёх уровнях, позволяя создавать условия на основе общедоступных настроек бизнеса, данных клиента или контекста разговора:

Уровень Путь доступа Область Пример
Бизнес ctx.business.customAttributes Наследуется всеми контактами и разговорами allow_discounts: true, max_order_limit: 5000000
Контакт ctx.contact.customAttributes Конкретный клиент во всех его разговорах vip_tier: 'gold', preferred_language: 'vi'
Разговор ctx.conversation.customAttributes Только конкретный разговор no_ai: true, priority: 'urgent'

Атрибуты полностью определяются пользователем — вы сами задаёте ключи и значения. Сгенерированный ИИ код читает их напрямую:

// Маршрутизатор — предложить скидку только если и бизнес, и контакт разрешают
if (ctx.business.customAttributes?.allow_discounts && ctx.contact.customAttributes?.vip_tier === 'gold') {
  actions.push({ type: 'send_message', message: 'Вы получаете скидку 10%!' });
}
// Обратный вызов — сохранить флаг после успешного заказа
if (ctx.order.totalAmount > 1000000) {
  actions.push({ type: 'set_contact_attribute', key: 'high_value', value: true });
}
// Условие — скрыть инструкции для отмеченных разговоров
if (ctx.conversation.customAttributes?.no_ai) {
  return false;
}

Лучшие практики

Для Consistent Prompts

  • Делайте их точными и фактическими: точные цены, точные часы, точные политики
  • Одна концепция на инструкцию (не смешивайте несвязанные правила)
  • Используйте тот же язык, что и ваши клиенты

Для Conditional Prompts

  • Условие должно быть очевидным из содержания инструкции: «После 22:00…» работает лучше, чем «Ночные правила»
  • Не злоупотребляйте условиями — ИИ работает лучше со стабильным контекстом
  • Тестируйте условия, моделируя разные сценарии

Для Deterministic Routers

  • Используйте для всего чувствительного ко времени — маршрутизатор выполняется за миллисекунды, ИИ — за секунды
  • Просматривайте сгенерированный код в редакторе, чтобы убедиться, что ИИ правильно определил действия
  • Если сгенерированный код не соответствует вашему замыслу, перепишите инструкцию более понятным языком
  • short_circuit — мощный инструмент: используйте его, когда ИИ не может добавить ничего полезного
  • Маршрутизаторы не имеют доступа к знаниям ИИ — они работают только со структурированными данными заказа

Для Deterministic Callbacks

  • Используйте для изменений состояния, которые должны всегда происходить после определённых событий
  • Не используйте обратные вызовы для действий, обращённых к клиенту — клиент уже получил ответ
  • Обратные вызовы идеально подходят для комплаенса и аудита

Общие рекомендации

  • Порядок инструкций не имеет значения для маршрутизаторов (они объединяются в одну функцию)
  • Для запросов порядок важен — более ранние инструкции располагаются выше в контексте ИИ
  • Если инструкция не подходит ни под одну категорию, она пропускается — каждой инструкции нужна действительная категория