Архитектура интеграции чат-бота: API и вебхуки
Разговоры об интеграции обычно схлопываются в один вопрос — подключается ли это к нашей CRM? — тогда как направлений на самом деле три, и у каждого свои сценарии отказа и своя граница безопасности. Читать, делать и уведомлять — разные задачи, и система, считающая их одной, окажется либо бесполезно ограниченной, либо опасно разрешительной. Статья разбирает, что следует получать живьём, а не индексировать, как спроектировать чтение, которое хорошо падает, как ограничить действия бота, почему исходящие события ломаются беззвучно и какая граница безопасности нужна каждому направлению.
Три направления, а не одна интеграция
Разделите три вещи прежде, чем что-то выбирать. Чтение: бот получает живое значение во время разговора — статус заказа, остаток, свободный слот. Действие: бот что-то меняет в системе — записывает, создаёт, обновляет. Уведомление: произошедшее в разговоре уходит наружу — лид в CRM, оповещение в командный канал.
У них разные профили риска. Неудавшееся чтение — неудобство, в котором бот может признаться. Неудавшееся или задвоенное действие — инцидент. Неудавшееся уведомление беззвучно, и на практике это самое опасное из трёх, потому что ничего не выглядит сломанным, пока лиды тихо перестают приходить.
И владельцы у них разные. Чтениям обычно достаточно эндпоинта и узкого доступа. Действиям нужно решение политики о том, что можно менять. Уведомлениям нужен человек, который владеет назначением и заметит, когда оно замолчит.
Живые чтения: что получать, а не индексировать
Общее правило простое: если факт меняется быстрее вашего цикла обновления, не кладите его в базу знаний. Получайте его.
- Статус заказа и доставки — меняется ежечасно и является самым запрашиваемым живым значением в большинстве компаний.
- Остатки и наличие — проиндексированный ответ становится неверным за сутки, причём в самом раздражающем направлении.
- Доступность записи и календаря — предложить уже занятый слот хуже, чем не предложить ничего.
- Значения по аккаунту — баланс, тариф, потребление — их вообще нельзя индексировать, не открыв данные одного клиента другому.
- Цены, зависящие от клиента или договора, в отличие от опубликованного прайса, который индексируется безопасно.
Всё остальное лучше проиндексировать. Живой вызов добавляет задержку, сценарий отказа и зависимость, поэтому он должен покупать вам то, что устаревание стоило бы дороже.
Как спроектировать чтение, которое хорошо падает
- Задайте таймаут, который клиент вытерпитДве-три секунды. Разговор, зависший на пятнадцать секунд, пока API думает, уже потерял клиента, что бы он в итоге ни вернул.
- Явно задайте сообщение при таймауте«Сейчас не получилось проверить — могу попросить коллегу подтвердить» — правильно. Откат к правдоподобному общему ответу — худший исход, потому что клиент разницы не увидит.
- Не повторяйте чтение больше одного раза внутри разговораПовторы умножают задержку. Если первая попытка и один повтор не прошли, ответ в том, что проверить не удалось.
- Кэшируйте ненадолго там, где значение это допускаетОстаток может быть на несколько секунд старым. Баланс обычно нет. Решайте по значению, а не глобально.
- Ограничьте доступ только чтениемТокен, который умеет ещё и писать, — это токен, который однажды запишет.
Действия: что боту позволено менять
Действия — это место, где интеграция становится вопросом управления, а не техники. Техническая часть проста; инциденты порождает зона охвата.
- Перечисляйте действия поштучно. «Управлять записями» — не действие; «создать запись» и «перенести запись позже в рамках политики» — действия.
- Делайте каждое действие идемпотентным, с ключом, выведенным из разговора. Сети повторяют запросы, клиенты нажимают дважды, а созданная дважды запись — это заявка в поддержку, которую вы создали себе сами.
- Разрушительные действия держите за человеком. Отмену, возврат и удаление бот может подготовить, а человек выполнить почти без потери в удобстве.
- Ограничивайте каждый параметр — насколько вперёд, сколько раз, в какие часы, до какой суммы.
- Возвращайте подтверждение, на которое клиент может опереться, включая номер. Действие, которое клиент не может проверить, он попробует ещё раз.
- Логируйте действие вместе с разговором, чтобы спорное изменение можно было разобрать, а не обсуждать.
Исходящие события: направление, падающее беззвучно
Это направление с наибольшей вероятностью ломается незамеченным, потому что на стороне клиента при этом ничего не меняется. Лид, не дошедший до CRM, выглядит ровно как неделя с меньшим числом лидов.
- Сделайте доставку наблюдаемой. Кто-то должен уметь ответить «пришли ли лиды за последний час?», не открывая базу.
- Повторяйте с нарастающей паузой и ограничьте число повторов. Эндпоинт, лежавший час, не должен получить четыре тысячи дублей при возвращении.
- Включайте идентификатор события, чтобы получатель мог убирать дубли. Доставка «хотя бы один раз» — нормальная гарантия, и получателей надо строить под неё.
- Оповещайте об отсутствии, а не только об ошибке. Сценарий отказа, с которым вы реально столкнётесь, — это тишина, и порог вроде «нет лидов четыре часа в рабочее время» её ловит.
- Держите полезную нагрузку маленькой и стабильной. Вебхук, отправляющий весь текст разговора, связывает две системы так, что это ломается при первом же изменении схемы.
- Версионируйте нагрузку. Вы её измените, а получатель не станет разворачиваться по вашему графику.
Границы безопасности
Каждому направлению нужна своя граница, и ниже — не общий чек-лист, а те отказы, которые действительно случаются.
- Заведите список разрешённых исходящих адресов. Система, вызывающая адрес, переданный во время работы, может быть направлена в вашу внутреннюю сеть.
- Не позволяйте содержимому разговора без проверки определять адрес или параметр. Сообщение клиента — недоверенный ввод на каждой границе.
- Считайте ответы API данными, а не инструкцией. Карточка с текстом, читающимся как команда модели, — реальная, а не теоретическая атака.
- Ограничивайте каждый доступ одной целью и ротируйте по графику, у которого есть владелец.
- Ограничивайте частоту по разговору и по клиенту, чтобы один разговор не стал генератором нагрузки на ваши системы.
- Не возвращайте больше, чем нужно ответу. Эндпоинт, отдающий всю карточку клиента просто потому, что так было удобно, расширил радиус поражения всех прочих ошибок.
Как интеграция устроена в Vexvon
На стороне переписки компания регистрирует собственные API как инструменты, которые движок может вызывать во время разговора, — это описанное выше направление живого чтения, — с защитой от направления запросов на внутренние и иным образом небезопасные адреса. Это и есть механизм, позволяющий ответить «где заказ 1234?» из системы, которая действительно знает.
На голосовой стороне модель инструментов явная и делится на три вида: статические значения, встроенные действия вроде перевода звонка, завершения звонка и поиска по базе знаний, и вебхуки к вашим эндпоинтам. Сценарии задают, какие инструменты доступны конкретному звонку, вместе с его направлением, языком, голосом и полями для извлечения, — так что зона действий настраивается по сценарию, а не выдаётся глобально.
Исходящее направление работает через триггеры: лид можно доставить уведомлением в Telegram в группу продаж с кнопкой «Начать», передать в Bitrix24 или записать во встроенную CRM, а каждое действие фиксируется в журнале активности с десятью типами. Поскольку доставка — настроенное назначение, а не неявный побочный эффект, у вопроса «дошло ли» есть место, где на него отвечают.
Стоимость и поведение наблюдаемы во всём этом: использование ИИ логируется по семнадцати назначениям с моделью, каналом и задержкой, а по звонку фиксируются токены, доля успеха и стоимость в долларах — именно это делает проблему интеграции диагностируемой, а не анекдотической.
Частые вопросы
- Что чат-бот должен получать живьём, а не индексировать?Всё, что меняется быстрее вашего цикла обновления: статус заказа, остатки, доступность записи, значения по аккаунту и договорные цены. Опубликованный прайс и устойчивые политики лучше индексировать.
- Какой таймаут задать живому запросу?Две-три секунды с явным сообщением при истечении. Разговор, зависший на пятнадцать секунд, уже потерял клиента независимо от того, что вернётся.
- Можно ли позволять боту совершать действия?Да, для ограниченных, идемпотентных и обратимых: создать запись, создать лид, обновить предпочтение. Отмену, возврат и удаление бот должен готовить, а выполнять человек.
- Почему здесь важна идемпотентность?Сети повторяют запросы, а клиенты нажимают дважды. Без ключа, выведенного из разговора, один запрос превращается в две записи, и вы сами создали себе обращение в поддержку.
- Какой отказ интеграции самый частый?Беззвучный отказ исходящих событий. На стороне клиента ничего не выглядит сломанным, поэтому CRM, переставшая получать лиды, неотличима от тихой недели. Оповещайте об отсутствии, а не только об ошибке.
- Какие границы безопасности обязательны?Список разрешённых адресов, запрет на выбор адреса или параметра содержимым разговора без проверки, отношение к ответам API как к данным, узко ограниченные доступы и ограничение частоты по разговору.
Начните со списка трёх направлений
Прежде чем оценивать любые интеграционные возможности, напишите три коротких списка: что боту нужно читать живьём, что ему позволено менять и что должно уйти наружу по окончании разговора. Большинство команд обнаруживает, что о третьем списке никто не думал, — а именно его отказ беззвучен.