Получение данных
Основой работы получения данных из таблиц Савви является специальный динамический генератор запросов (Dynamic SQL Generator - DSG). Это механизм позволяющий конвертировать запросы клиентов в SQL-запросы к таблице, таким образом получая возможность работать с неограниченными по длине таблицами не перегружая контекст модели и получая максимально точные ответы.
Что позволяет?
Использование таблиц обычно необходимо для получения:
актуальных цен на товары или услуги
информации об остатках товаров
списка актуальных предложений
динамической информации (акции, промо-коды и т.д.)
и т.д.
Требования к таблице
Основные требования по формату таблицы для ее корректного подключения следующие:
Первая строка таблицы должна быть заполнена заголовками колонок таблицы
Таблица не должна содержать объединение строк (такие таблицы называют обычно простыми или нормализованными).
Почему важно, чтоб таблица была простой (без объединения) - чтобы корректно работали запросы к ее данным.
Приведем пример правильной и не правильной таблицы:
Пример неправильной таблицы

Пример правильной таблицы

Подключение таблицы
Для подключения таблицы необходимо перейти в раздел Таблицы в настройках бота и выбрать один из вариантов подключения:
загрузка таблицы из CSV-файла
загрузка из файла Excel
подключение Google-таблицы
При подключении таблицы из CSV-файла важно, чтобы файл был сохранен в кодировке UTF-8 с разделителями - запятые.
Фундаментально процесс подключения практически идентичен, за исключением прохождения подключения Google-авторизации при подключении Google-таблицы.
При подключении статичной таблицы (CSV / XLS) необходимо просто выбрать файл.
А если речь идет о Google-таблице - нужно авторизоваться и выбрать нужную таблицу:

После выбора, откроется форма создания таблицы:

Название таблиц
Название для отображения в списке
Лист
Возможность выбора листа Google-таблицы
Частота обновления таблицы (минуты)
Время за которое таблица обновляется для ответов Савви. По умолчанию - 1440 минут - или раз в 24 часа. Кнопка обновления позволяет обновить данные в любой момент.
Использовать
Параметр определяющий будет Савви видеть таблицу или нет. По умолчанию - выключено.
Имя функции
имя функции по которой Савви будет обращаться к таблице. Подробнее о функциях в разделе "Функции"
Описание таблицы
Основная информация описывающая значение таблицы и данных хранящихся в ней данные. По описанию Савви будет понимать, когда нужно вызывать таблицу, при каких запросах.
Описание очень важная составляющая, т.к. она определяет поведение и запрос, который будет формироваться к таблице.
Предварительный SQL-запрос
Заранее подготовленный запрос к таблице, выполняется перед запросом от нейросети. Может быть использован как предварительный фильтр. Например: Вы заранее знаете, что при любом запросе вам нужно получить из таблицы только строки, где колонка "Доступность" = "ДА". В таком случае, вы можете прописать это в предварительном запросе вместо того, чтобы говорить боту писать это.
Не рекомендуем ставить обновление чаще, чем раз в 30 минут, т.к. каждый раз происходит скачивание таблицы, если она слишком большая, это может вызывать нагрузку на учетную запись Google, что может привести к ограничению доступа к ней.
Параметры колонок

При заполнении колонок таблицы важно соблюдать несколько правило - наименование должно быть без пробелов и должно отражать суть значений в колонке.
В таблице отображается первые 5 строк таблицы - просто для понимания какие данные в ней хранятся.
Поиск по части строки - позволяет находить данные в таблицы даже если было часть текста из колонки.
Не учитывать регистр - позволяет не учитывать регистр слова (заглавная или строчная) и находить названия написанные заглавными буквами даже если отбор сделан по слову со строчной буквы.
Всегда строка - позволяет работать с числами как со строкой.
Работа с таблицей
Первое, что важно знать - Савви понимает в какой момент нужно взять данные из таблицы по описанию таблицы.
Кроме того, всегда есть возможность обращаться к таблице как к функции из основной инструкции:
Например, для того, чтобы обратиться к таблице мы можем использовать конструкцию:
"Если клиент.......вызови функцию <название фукнции таблицы>", где <название фукнции таблицы> - конкретное название функции из таблицы, которое было создано при создании таблицы.
#ИНФОРМАЦИЯ ПО СТРОЙМАТЕРИАЛАМ
Если клиент спрашивает стоимость стройматериалов выполни следующие действия:
1. Обязательно уточни у клиента наименование материала и цвет.
2. Далее вызови функцию list_of_materials, и передай туда материал и цвет.
Как видно из промпта, мы сначала запросили у клиента необходимые параметры, а далее передали в функцию конкретные пункты по которым нам требуется сделать отбор.
При вызове таблицы, если мы занимаемся отладкой (подробнее об отладке ниже), мы можем увидеть, что Савви создает специальный SQL-запрос к таблице для того, чтобы получить конкретные данные:

Савви сам создает SQL-запросы при помощи специального движка (DSG), но неплохо в целом понимать принципы языка SQL-запросов, поэтому, если язык вам еще не знаком, рекомендуем почитать блок ниже:
Отборы на запросы к таблице
Важно Поскольку таблицы могут содержать довольно большое количество данных и за одно обращение Савви может получать множество строк из таблицы, очень важно:
Предварительно накладывать максимально возможный отбор на запрос к таблице.
Использовать искусственное ограничение на количество выбираемых данных
Если мы говорим про пункт 1, то накладывать отбор на запросы можно путем указания того, что мы должны передать в таблицу, в рассматриваемом выше примере это был отбор по наименованию и цвету. Цвет в данном случае позволяет сужать поиск.
Пример числового отбора
Кроме того, мы можем накладывать отборы на поля с типом Дата и число.
К примеру, если мы хотим указать, чтобы Савви предоставил материалы только там, где количество больше 60, мы можем сделать это через промпт/инструкцию таким образом:
#ИНФОРМАЦИЯ ПО СТРОЙМАТЕРИАЛАМ
Если клиент спрашивает стоимость стройматериалов выполни следующие действия:
1. Обязательно уточни у клиента наименование материала и цвет.
2. Далее вызови функцию list_of_materials, и передай туда материал и цвет и
только те, где количество > 60.
В этом случае в SQL-запрос к таблице добавится дополнительное условие и мы получим выборку с учетом дополнительного отбора:

Пример отбора с использованием LIMIT
Бывает так же, что несмотря на отборы по колонкам все равно в выборка получается большой, тем самым перегружает контекст и увеличивает стоимость запроса.
В этом случае дополнительном мы можем применять искусственное ограничение по количеству выбираемых записей из таблицы используя оператор LIMIT.
Например формулируя промпт таким образом:
#ИНФОРМАЦИЯ ПО СТРОЙМАТЕРИАЛАМ
Если клиент спрашивает стоимость стройматериалов выполни следующие действия:
1. Обязательно уточни у клиента наименование материала и цвет.
2. Далее вызови функцию list_of_materials, и передай туда материал и цвет и
только те, где количество > 60, но не более 1 запись.
В этом случае фраза "не более N записей" позволяет наложить отбор на таблицу и получить первые N подходящие записи.

Вот что вернул отбор таблицы, здесь только одна запись:

В случае, если такой промт работает не стабильно, можно дополнительно указать в текст в скобочках подсказку для модели:
#ИНФОРМАЦИЯ ПО СТРОЙМАТЕРИАЛАМ
Если клиент спрашивает стоимость стройматериалов выполни следующие действия:
1. Обязательно уточни у клиента наименование материала и цвет.
2. Далее вызови функцию list_of_materials, и передай туда материал и цвет и
только те, где количество > 60, но не более 3 записей (оператор LIMIT).
Предварительный SQL-запрос
Бывают случаи, когда в значениях колонки мы хотим работать с конкретными значениями. Они нам заранее известны.
Например, колонка имеет такие значение городов:
Москва
Санкт-Петербург
Волгоград
Зеленогорск
Тюмень
Но мы знаем, что согласно условиям задачи нам требуется находить данные только по значениям
Санкт-Петербург
Волгоград
Зеленогорск
Исходя из того, что мы обсуждали ранее, мы можем описать эти отборы в промте, например:
При обращении к функции <функция таблицы> находи значения только по городам "
Санкт-Петербург, Волгоград, Зеленогорск.
И это будет работать, НО, наша задача всегда повышать качество ответов и снижать вероятность ошибок. Как мы ранее описывали в разделе "Лучшие практики" основой повышения качества является уменьшение инструкции и там где это возможно использование алгоритмических механизмов.
Лучшие практикиПоэтому здесь к нам на помощь приходит механизм предварительного отбора к таблице, который задается через поле Предварительный SQL-запрос. Прописав в нем предварительный запрос к таблице, мы сразу получаем готовую выборку только по этим городам без дополнительной необходимости накладывать его внутри инструкции и увеличивая тем самым контекст и нагрузку на модель:

Работа с кросс-таблицами
Существует такой тип таблиц, который называется кросс-таблицами или матрицами данных.
В этой таблице поиск данных происходит на пересечении значений первой колонки (обычно представляющей категории) и остальных колонок (представляющих другие измерения данных).
Кросс-таблицы очень удобны для представления информации, когда нужно визуализировать зависимость между двумя или более переменными, что часто используется в статистике и аналитике.
Для конкретного примера представьте, что у вас есть таблица с данными о продажах товаров, где первая колонка — это названия товаров, а остальные колонки — продажи в различных регионах. Тогда каждое значение внутри таблицы представляет собой количество продаж конкретного товара в конкретном регионе:

Может возникнуть вопрос, как в этом случае составлять отборы и может ли Савви сам получить данные по таким таблицам?
Да! Может!
Во-первых, даже если мы ничего не будем принудительно описывать - он с справится с задачей используя простой промпт:
1. Уточни у клиента материал и в каких городах интересует информация.
2. Обратись к таблице материалов вызвав функцию list_of_materials и
передай туда материал и список городов.
Результат мы получим такой:



Как видно, он понял в каких колонках что находится и вызвал верные отборы.
Однако, когда речь идет о больших инструкциях, и если мы говорим о качестве и стабильности ответов, можно использовать дополнительные приемы.
Мы можем добавить внутри описания таблицы следующий пример инструкции:
Используй этот шаблон для поиска данных по материалам и городам:
```sql
SELECT <города> FROM data WHERE наименование = <наименование материала>
Поменяй <города> and <наименование материала> с вашими критериями поиска.
```
Четко заданный шаблон при больших основных инструкциях будет давать лучшую точность.
Смысловой поиск
Платформа "Савви" позволяет реализовать поиск данных по таблице, не только с использованием типовых отборов SQL, но и через дополнительную функцию, в основе которой лежит технология векторного поиска, аналогичная поиску при работе с большими файлами.
Данный способ поиска подходит в тех случаях, когда нам надо наложить отбор на таблицу не по фиксированному значению или маске, а по смыслу, то есть найти все строки у которых содержание в колонке поиска соответствует смыслу поискового запроса. Например, на базе данной технологии реализован блок работы с Wildberries. В подсистеме WB пользователи подгружают таблицу, с типовыми вопросами клиентов и необходимыми ответами на них, а система, при получении реального вопроса клиента, уже по смыслу находит подходящие варианты и формирует ответ.
Как настроить?
Рассмотрим порядок настройки поиска по смыслам, на примере бота для автосервиса. Задачей бота является предоставление информации клиентам по стоимости услуг по ремонту автомобиля. У организации существует прайс-лист на услуги, в разрезе моделей и наименований ремонтных работ:

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

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

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

После того как мы заполнили аргументы, добавляем шаг - "вызов таблицы"

Далее необходимо указать таблицу к которой будут выполняться запросы и сами запросы. Платформа позволяет задать не один запрос, а несколько. Они будут выполняться последовательно. В нашем примере было использовано два запроса. Первый запрос находил все строки по указанной клиентом модели, а второй запрос искал уже услугу.

Примеры запросов указанные на картинке выше являются запросами со смысловым поиском. За смысловой поиск по таблице в платформе отвечает функция VECTOR_SEARCH. Она имеет следующий формат:
VECTOR_SEARCH(ИмяКолонки, ПоисковыйЗапрос) >= ТочностьПоиска
Имя колонки - колонка по которой будет осуществляться смысловой поиск. Имя колонки задается при подключении таблицы, в разделе "Таблицы";
Поисковый запрос - это запрос, полученный от клиента, то есть то, что мы будем искать в таблице. Поисковой запрос передается ботом в аргумент функции. В нашем случае это аргумент "model" или "question";
Точность поиска - это число, от 0 до 1, которое задает точность поиска. Чем выше значение тем более строгим будет поиск, то есть при 1 должно быть практически полное совпадение запроса клиента и значения в поисковой колонке. Мы рекомендуем использовать значения от 0.5 до 0.8, в зависимости от условий. На примере выше поиск по модели требуется максимально строгий, поэтому стоит значение 0.8, а поиск по услугам должен возвращать все близкие по смыслу варианты - поэтому точность стоит уже ниже - 0.6.
Ниже приведем пример запроса, его можно использовать один в один, заменяя только имя колонки и имя аргумента функции (если у Вас оно указано другое):
SELECT * FROM data WHERE VECTOR_SEARCH(вопрос_по_автоработе, 'question') >= 0.6
Оптимизация цепочек запросов
Как мы упомянули выше, платформа позволяет задать не один запрос, а сразу несколько, как и сделано в описанном выше примере. Также мы видим, что в цепочке запросов, оба запроса использовали функцию векторного поиска - поиска по смыслам. Необходим отметить, что данный поиск не является быстрым и если возможно его заменить типовым поиском SQL, это надо всегда делать. В нашем примере, если мы боту дадим инструкцию узнавать у клиента точное название модели и передавать его в запрос, мы можем выполнить поиск по моделям используя оператор like (поиск по маске), и не использовать функцию векторного поиска. Это будет работать гораздо быстрее и лучше:

Last updated
Was this helpful?