Обучение на обратной связи
Сервис умеет учиться на ваших действиях. Не ML, а просто и понятно: вы отправляете обратную связь, сервис анализирует ее и предлагает улучшения.
/admin/learn, /feedback и управление синонимами через API работают только в PRO-сборке. В Free-редакции /admin/learn вернет 404.
accept и zero_result. Записи с reject сохраняются, но пока не используются для построения синонимов. При accept сервис учит, что искали одно, а выбрали другое, и предлагает синонимы; при zero_result — частые запросы, по которым ничего не нашлось.
Как это работает — по шагам
В 1С после поиска сервис показал товары. Оператор либо выбирает подходящий и подтверждает (
accept), либо сообщает, что ничего не нашлось (zero_result).1С формирует запрос: что искали, какой товар выбрали, и действие оператора.
Каждая запись выглядит так:
{"timestamp":"2024-01-15T10:30:00Z","query_name":"болт м16 цинк","matched_1c_id_out":"1C-GUID-0001","product_name":"Болт М16х60 оцинкованный ГОСТ 7798-70","action":"accept"}
Раз в неделю (или чаще) администратор выполняет команду:
# Через CLI:
sku-cli learn
# Или через API:
curl http://localhost:8080/admin/learn
Доступно только в PRO.
Сервис ищет закономерности: если оператор искал слово "цинк", а в выбранном товаре встречается "оцинкованный", значит, это хорошая пара для синонима. Анализ строится по полю
product_name, поэтому без него предложения не генерируются.Сервис возвращает JSON с рекомендациями:
{
"recommendations": [
{
"recommendation_type": "synonym",
"title": "Синоним: цинк → оцинкованный",
"description": "В 82% accept-запросов со словом 'цинк' выбран товар, содержащий 'оцинкованный'",
"confidence": 0.82,
"data": {
"query_token": "цинк",
"product_token": "оцинкованный"
}
},
{
"recommendation_type": "missing_product",
"title": "Возможно отсутствующий товар: болт м16 din933",
"description": "15 zero_result запросов за период",
"confidence": 0.95,
"data": {
"query": "болт м16 din933",
"count": 15
}
},
{
"recommendation_type": "check_product",
"title": "Проверьте товар 1C-GUID-0001",
"description": "Высокий reject rate (45%)",
"confidence": 0.45,
"data": {
"id": "1C-GUID-0001",
"reason": "Высокий reject rate (45%)"
}
},
{
"recommendation_type": "typo",
"title": "Опечатка: перфоротар → перфоратор",
"description": "Похоже на опечатку, найден канонический вариант",
"confidence": 0.78,
"data": {
"query": "перфоротар",
"canonical": "перфоратор"
}
}
],
"processed_entries": 42
}
Если предложение хорошее — добавляем его вручную через API:
# Через CLI:
sku-cli synonyms add --word "цинк" --expansions "оцинкованный,zn,zinc"
# Или через API:
curl -X POST http://localhost:8080/synonyms \
-H "Content-Type: application/json" \
-d '{"items":[{"word":"цинк","expansions":["оцинкованный","zn","zinc"]}]}'
С этого момента все новые поиски "цинк" будут находить "оцинкованный". Перезапуск сервиса не нужен.
Как настроить 1С для отправки feedback
В 1С, после того как сервис вернул результаты поиска, добавьте кнопки "Выбрать этот товар" (accept) и "Ничего не нашлось" (zero_result). При нажатии вызывайте:
// Псевдокод 1С
Процедура ВыбранТовар(НайденныйТовар, ПоисковыйЗапрос)
Данные = Новый Структура;
Данные.Вставить("query_name", ПоисковыйЗапрос.Наименование);
Данные.Вставить("matched_id_out", НайденныйТовар.Идентификатор);
Данные.Вставить("product_name", НайденныйТовар.Наименование);
Данные.Вставить("action", "accept"); // "accept" — выбрали этот товар
// Отправка POST /feedback
Ответ = ОтправитьHTTPЗапрос("/feedback", Данные);
КонецПроцедуры
Процедура НичегоНеНашлось(ПоисковыйЗапрос)
Данные = Новый Структура;
Данные.Вставить("query_name", ПоисковыйЗапрос.Наименование);
Данные.Вставить("action", "zero_result"); // ничего не нашлось
Ответ = ОтправитьHTTPЗапрос("/feedback", Данные);
КонецПроцедуры
Автоматизация обучения
Можно настроить cron для регулярного анализа:
# Запускать каждую неделю в понедельник в 9 утра
0 9 * * 1 cd /opt/sku-search && ./sku-cli learn >> /var/log/learn.log 2>&1
Полный цикл обучения на примере
- Оператор ищет "болт м16 цинк", сервис предлагает "Болт М16 черный"
- Оператор выбирает "Болт М16х60 оцинкованный ГОСТ 7798-70" и нажимает "Это тот товар", 1С отправляет feedback с
action: "accept" - В лог попадает запись: искали "цинк", выбрали товар с "оцинкованный"
- Администратор через неделю запускает
sku-cli learn - Сервис анализирует: в нескольких accept-запросах со словом "цинк" выбран товар, содержащий "оцинкованный"
- Сервис предлагает синоним: "цинк" → "оцинкованный"
- Администратор добавляет синоним через API
- Теперь "болт м16 цинк" находит "Болт М16х60 оцинкованный" с высоким score
Что происходит в feedback.log
Файл data/feedback.log накапливает все действия операторов. Пример содержимого:
{"timestamp":"2024-01-15T10:30:00.123Z","query_name":"болт м16 цинк","matched_1c_id_out":"1C-GUID-0001","product_name":"Болт М16х60 оцинкованный ГОСТ 7798-70","action":"accept"}
{"timestamp":"2024-01-15T10:32:15.456Z","query_name":"гайка нерж м16","matched_1c_id_out":"1C-GUID-0002","product_name":"Гайка М16 нержавеющая","action":"accept"}
{"timestamp":"2024-01-15T10:35:22.789Z","query_name":"шайба м8","matched_1c_id_out":"1C-GUID-0003","action":"zero_result"}
Вы можете анализировать его вручную:
# Сколько раз отклонили
grep '"action":"reject"' data/feedback.log | wc -l
# Сколько подтверждений
grep '"action":"accept"' data/feedback.log | wc -l
# Какие запросы чаще всего отклоняют
grep '"action":"reject"' data/feedback.log | jq -r '.query_name' | sort | uniq -c | sort -rn | head -10
Частые вопросы про обучение на фидбеке
1. Как часто нужно запускать sku-cli learn?
Зависит от объема данных. Если у вас 1000 новых feedback-записей в день — запускайте раз в неделю. Если 100 — раз в месяц. Сервис анализирует все записи с момента последнего запуска (он не хранит состояние, просто читает весь файл каждый раз).
2. Почему сервис предлагает синоним, который уже есть?
Алгоритм ищет пересечения токенов в query_name и названии выбранного товара (product_name). Если синоним уже есть в synonyms.json, он все равно может предложить его снова. Просто игнорируйте такие предложения.
3. Как удалить синоним, который добавили по ошибке?
Через API:
curl -X DELETE http://localhost:8080/synonyms/цинк
# или через CLI:
sku-cli synonyms remove --word цинк
Также можно отредактировать data/synonyms.json вручную и перезапустить сервис, но это не требуется.
4. Что означает confidence в предложениях?
Число от 0 до 1, которое показывает долю accept-запросов, содержащих query-токен, в которых выбран товар с product-токеном. 0.7 = в 70% таких accept-запросов выбран товар с предложенным токеном. Можете использовать как фильтр: добавлять только те, у кого confidence > 0.5. Внутренний порог генерации синонимов — 0.3.
5. А сервис сам добавит синоним, если я не проверю?
Нет. Сервис только предлагает. Решение всегда за администратором. Это сделано специально — чтобы вы случайно не испортили поиск автоматическими правками.
6. Почему после добавления синонима поиск не изменился?
Проверьте:
- Синоним добавился (проверьте
GET /health— там естьsynonyms_count) - Ваш запрос содержит слово, которое совпадает с ключом синонима (регистр не важен, все приводится к нижнему)
- Синоним не конфликтует со стоп-словом (стоп-слова фильтруются ДО применения синонимов)
7. Можно ли автоматизировать добавление синонимов?
Можно, но осторожно. Напишите скрипт, который раз в неделю:
- Вызывает
GET /admin/learn - Фильтрует предложения с
confidence > 0.8 - Отправляет их через
POST /synonyms
Рекомендуем сначала хотя бы месяц смотреть вручную, чтобы понять, какие предложения действительно полезны.
8. Что делать, если feedback.log слишком большой?
Сервис сам не ротирует этот файл. Добавьте в crontab:
# Каждую неделю архивировать и очищать
0 2 * * 0 mv /path/to/data/feedback.log /path/to/data/feedback.log.$(date +\%Y\%m\%d) && touch /path/to/data/feedback.log
9. Почему GET /admin/learn возвращает пустые предложения?
Причины:
- Нет accept-записей с
product_nameвfeedback.log(для синонимов) - Нет zero_result-записей (для missing_product)
- Нет повторяющихся accept/reject по одному товару (для check_product)
- Включен параметр
enabled = falseв конфиге (фидбек не пишется) - В запросах все токены короче
learn_min_token_len(по умолчанию 3 символа). "М6", "шт", "уп" — игнорируются
10. Можно ли обучить сервис на "хороших" совпадениях (action: "accept")?
Да. Алгоритм синонимов как раз работает на accept-записях с заполненным product_name. Хорошие совпадения показывают, что искали одно, а выбрали другое — и это самый надежный источник для предложений синонимов.
11. Как проверить, что обучение реально помогло?
Возьмите 100 запросов, на которых раньше были ошибки. Запустите поиск до добавления синонимов и после. Сравните результаты. Эффект зависит от качества и полноты feedback.
12. Что делать, если операторы нажимают "неверно" случайно?
Алгоритм ищет повторяющиеся паттерны. Для синонима нужно минимум 2 accept-записи с одним query-токеном и confidence ≥ 0.3. Случайные нажатия не наберут статистику.
Продвинутая настройка обучения
В config.toml есть параметры:
[feedback]
enabled = true # Включить сбор фидбека
log_path = "./data/feedback.log" # Путь к логу
learn_min_token_len = 3 # Игнорировать слова короче 3 букв
learn_max_suggestions = 20 # Максимум предложений за раз
Что изменить, если...
| Ситуация | Решение |
|---|---|
| Слишком много мусорных предложений | Увеличьте learn_min_token_len до 4-5 |
| Сервис не видит короткие важные слова ("М6", "din") | Уменьшите learn_min_token_len до 2 |
| Приходит 100+ предложений, трудно читать | Уменьшите learn_max_suggestions до 10 |
| Нет предложений, хотя ошибки есть | Проверьте, что длина токенов >= learn_min_token_len, и что в accept-записях передано product_name |