Головна / Статті

Семантичне кешування з використанням Redis для пошуку векторів

Зменшіть витрати на API для ембеддингу за допомогою семантичного кешування в Redis: дворівневий кеш, який повторно використовує результати векторного пошуку, коли запити означають одне й те саме, у Node.js.

Видавець: REACTAPP.TOP4 хв читання1033 слів

Джерела: Semantic Caching with Redis: Slashing API Costs in Vector Search

Створення продукту на основі ШІ часто дивує команди не стільки якістю моделі, скільки вартістю рахунків. Чат-бот, який здається економним при кількох сотнях користувачів, може раптово споживати багато ресурсів щоразу, коли кожен пошук, рекомендація чи запит викликають ще один виклик моделі ембеддингу.

Багато з цих викликів є зайвими. Семантичне кешування дозволяє повторно використовувати попередні результати, коли новий запит означає майже те саме. За допомогою Redis такий підхід може зменшити затримки та витрати на інфраструктуру без необхідності переписування бізнес-логіки додатку.

Прихована вартість векторного пошуку

Типовий процес генерації з підтримкою пошуку (RAG) виглядає так:

User Query
     ↓
Embedding API
     ↓
Vector Database
     ↓
Retrieved Documents
     ↓
LLM

Кожен новий запит зазвичай означає:

  • виклик моделі ембеддингу
  • оплату затримок мережі
  • виконання векторного пошуку
  • повернення результатів

Виклики моделей ембеддингу коштують грошей. Переходи туди-назад коштують часу.

Розгляньмо два пошукові запити, зроблені з інтервалом у дві хвилини:

  • “найкращий бюджетний геймінг-ноутбук”
  • “дешеві геймінг-ноутбуки”

Формулювання відрізняються; намір майже не змінюється. Проте багато систем перераховують обидва запити з нуля. Серед тисяч користувачів платформа неодноразово оплачує майже однакову роботу.

Що таке семантичне кешування?

Класичні кеші зберігають ключі у вигляді точних рядків. Якщо кешується “червоні черевики”, то спрацює лише ідентичний фразовий пошук. Фраза “черевики, які є червоними” не буде знайдена.

Семантичне кешування порівнює значення. Кожен запит перетворюється на вектор. Коли два вектори достатньо близькі, збережену відповідь можна повторно використати.

Наприклад:

Query A
"best beginner Python book"
↓
Embedding A

Пізніше:

Query B
"good Python books for beginners"

Якщо косинусова схожість досягає встановленого порогу — скажімо, 0.95 — система повертає кешовану інформацію. Не потрібно нового створення вектора, не потрібний пошук у векторному просторі, немає додаткових витрат.

Створення дворівневої кеш-системи

У продакшн-рішеннях часто використовують два рівні кешу.

Рівень 1: кеш вбудованих даних

Найшвидший рівень. Якщо надходить ідентичний рядок запиту, повертається збережений ембеддинг замість повторного виклику моделі.

Query
   ↓
Redis
   ↓
Embedding

Це вже саме по собі усуває один із найпоширеніших платних викликів у додатках на основі ШІ.

Рівень 2: кеш семантичних результатів

На другому рівні зберігаються кінцеві відповіді на пошук. Порівняння здійснюється за допомогою сусідства ембеддингів, а не за чистим текстом.

Embedding
      ↓
Redis Vector Search
      ↓
Cached Search Results

Якщо ембеддинги є близькими сусідами, база даних векторів ігнорується, і користувач отримує майже миттєву відповідь з кешу.

Чому Redis?

Redis — це швидкий мімкодовий сховище. За допомогою Redis Stack та RediSearch він також може виконувати пошук за схожістю векторів.

Ця комбінація дозволяє Redis:

  • зберігати ембеддинги
  • порівнювати вектори
  • повертати найближчі сусіди
  • Видалення записів за таймером TTL
  • Надання відповідей протягом кількох мілісекунд
  • Кеш перестає бути простим контейнером з ключами та значеннями та стає семантичним шаром пошуку.

    Вибір правильного порогу схожості

    Вибір порога впливає на якість. При значенні 0.99 збігаються лише майже ідентичні дані — висока точність, менше результатів. При 0.85 кількість результатів зростає, але можуть зустрічатися несуміжні запити (кросівки проти баскетбольних кросівок).

    Толерантність залежить від сфери застосування. У електронній комерції часто допускаються більш великі пороги; у медичних пошуках це зазвичай неможливо. Деякі системи навіть встановлюють різні пороги для кожної колекції.

    Підтримання актуальності кешу

    Кешовані відповіді корисні лише доти, доки вони залишаються актуальними. Інформація про «актуальні ціни iPhone» може стати застарілою протягом ночі без плану оновлення. Два поширені підходи вирішують більшість ситуацій.

    Видалення за часом

    Встановіть TTL, щоб Redis автоматично видаляв записи — це корисно для каталогів, які часто змінюються.

    Анулювання на основі подій

    Коли додаток дізнається про зміну — оновлення запасів, зміна цін, додавання нових документів чи їх видалення — він негайно видаляє вплинуті ключі, замість того щоб чекати закінчення TTL.

    Як Redis шукає ембеддинги

    Сучасний Redis зберігає ембеддинги у вигляді числових векторів та індексує їх за допомогою таких структур, як:

    • FLAT
    • HNSW

    Новий запит не обробляє кожен вектор методом brute-force; індекси швидко знаходять сусідні вектори, тому пошук за семантикою часто завершується протягом кількох мілісекунд.

    Об’єднання всього разом

    Шлях обробки запиту від початку до кінця виглядає так:

    User Query
          ↓
    Embedding Cache
          ↓
    Hit?
          ↓
    Yes → Use Cached Embedding
    No
     ↓
    Embedding API
     ↓
    Redis Semantic Cache
     ↓
    Hit?
     ↓
    Yes → Return Cached Results
    No
     ↓
    Vector Database
     ↓
    Store Results in Redis
     ↓
    Return Results
    

    Багаточасовий процес обробки ембеддингів та пошуку виконується лише у разі невдачі пошуку. Усе інше залишається швидким.

    Яке покращення ви можете очікувати?

    Цифри варіюються залежно від продукту, але багато звітів про виробництво виглядають так:

    • загальний семантичний пошук зазвичай дає рівень успішності близько однієї п’ятої до одної третини
    • функція автодоповнення та повторні запити можуть становити близько половини всього трафіку
    • запити до кешу зазвичай відповідають протягом однозначних мілісекунд
    • невдалий запит, який використовує вбудовування та пошук від початку до кінця, може зайняти кілька сотень мілісекунд

    Кожен успішний запит усуває один виклик API для генерації ембеддингу. При тисячах запитів це призводить до реальної економії коштів та зменшення затримок.

    Поширені проблеми

    Отруєння кешу

    Погана відповідь, яка потрапляє до кешу, може «отруїти» подібні майбутні запити. Моніторинг та розумний термін дії допомагають зменшити масштаб проблеми.

    Зростання пам’яті

    Ембеддинги є великими: по сотні чи тисячі чисел з плаваючою комою кожен. Колекції швидко зростають. Встановіть межі пам’яті та правила видалення ще до запуску.

    Холодний старт

    Новий розгортання починається з порожнім кешем, тому ранні запити оплачуються повною ціною. Популярні запити з часом нагрівають кеш; деякі команди завантажують заздалегідь поширені запити під час розгортання, щоб скоротити цей період.

    Коли семантичний кешування — не найкращий вибір

    Цей підхід ефективний, коли багато користувачів ставлять схожі запитання. Він стає менш ефективним, коли відповіді є сильно особистими чи надзвичайно актуальними:

    • «Ресторани поблизу»
    • індивідуалізовані рекомендації
    • панелі керування, спеціальні для користувача
    • актуальний склад товарів
    • швидко змінювані ціни

    У таких випадках використання кешованих семантичних даних сусіда може бути просто неправильним.

    Заключні міркування

    У міру зростання обсягу трафіку від ШІ витрати на інфраструктуру часто конкурують за увагу з якістю моделей. Семантичне кешування є прагматичним рішенням: воно дозволяє розпізнавати спільну мету та уникати повторної обробки даних через ембеддинги та пошук. Redis робить це можливим, поєднуючи швидкість роботи в оперативній пам’яті з вбудованим векторним пошуком — це дає швидкішу відповідь, менше оплачуваних запитів до ембеддингів та більш ефективне масштабування. Іноді найкращою оптимізацією є не використання кращої моделі, а уникнення обробки даних, яка ніколи не була потрібна.