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

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

Як семантичне кешування зменшує витрати та затримки у роботі ШІ: ембеддинги, порогові значення, Redis та RedisVL, налаштування точності та кешування підзапитів у межах робочих процесів агента.

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

Джерела: Semantic Caching for AI Agents: How to Make Your LLM Apps Faster and Cheaper

Виклики потужних LLM коштують чимало грошей та є повільними. Кожен, хто бачив, як зростає рахунок за API після використання агента між справжніми користувачами, розуміє цю проблему: найкращі моделі для відповідей є водночас найдорожчими та найповільнішими. Моделі класу GPT-4 можуть коштувати кілька доларів за тисячу запитів, а агентські робочі процеси погіршують ситуацію, оскільки один запит користувача може спричинити від 8 до 20 викликів моделі.

Семантичне кешування безпосередньо бореться з цими витратами, проте більшість команд використовують його недостатньо. Його легко створити за допомогою Redis.

Чому звичайні кеші не підходять

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

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

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

Механізм у чотирьох кроках

  1. Вбудовуйте надійшов запит, перетворюючи його на вектор високої розмірності за допомогою моделі ембеддингу.
  2. Порівнюйте цей вектор із кожним збереженим записом, використовуючи косинусову відстань або подібний показник.
  3. Якщо найближчий запис знаходиться в межах налаштованого порогу відстані, вважайте це успішним пошуком та негайно повертайте збережену відповідь.
  4. Якщо нічого не є достатньо близьким, надішліть запит через вашу систему RAG або LLM, а потім збережіть запит та відповідь на майбутнє.

Запитання, сформульовані по-іншому, зрештою мають однакові відповіді. У міру наповнення кешу до моделі надходить все менша кількість трафіку.

Мінімальна версія з нуля

Перш ніж використовувати бібліотеку для продакшну, корисно побачити її складові. Почнімо з імпортів:

from sentence_transformers import SentenceTransformer
import numpy as np

Потім вбудуйте невеликий набір FAQ та напишіть алгоритм пошуку за принципом найближчого сусіда:

model = SentenceTransformer("all-mpnet-base-v2")# Embed your FAQ dataset
faq_questions = ["How do I get a refund?", "Where is my order?", ...]
faq_embeddings = model.encode(faq_questions)def cosine_distance(a, b):
    return 1 - np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))def check_cache(query: str, threshold: float = 0.3):
    query_embedding = model.encode(query)
    distances = [cosine_distance(query_embedding, e) for e in faq_embeddings]
    best_idx = np.argmin(distances)
    best_distance = distances[best_idx]

    if best_distance < threshold:
        return faq_answers[best_idx]  # Cache hit
    return None  # Cache miss

Спробуйте тестове запитання щодо того, скільки днів потрібно, щоб гроші були повернуті, і система знаходить найбільш схожим записом збережені FAQ про отримання повернення коштів із косинусовою відстанню близько 0,33. Жодних збігів не було виявлено лише за рахунок спільних слів; вектори просто знаходяться поруч один з одним.

Робота з Redis

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

from redisvl.extensions.cache.llm import SemanticCache
from redisvl.utils.vectorize import HFTextVectorizer

Виберіть модель ембеддингу, створена спеціально для цієї роботи, а потім створіть кеш:

# Load a cache-optimized embedding model
vectorizer = HFTextVectorizer("redis/langcache-embed-v1")# Create the cache
cache = SemanticCache(
    name="customer_support_cache",
    vectorizer=vectorizer,
    redis_client=redis_client,
    distance_threshold=0.3
)# Set TTL (time to live) — keeps cache fresh
cache.set_ttl(86400)  # 24 hours

Модель langcache-embed-v1 — це модель ембеддингів з відкритими вагами, налаштована для семантичного кешування, тому вона зазвичай перевершує універсальні ембеддери у цьому завданні.

Режим Redis містить три функції для продакшну:

  • TTL. Елементи автоматично закінчують термін дії, тож застарілі відповіді не залишаються після змін продукту.
  • Namespacing. Команди, користувачі чи орендарі можуть мати окремий кеш у межах однієї інстанції Redis.
  • Оптимізований пошук векторів. Індексування HNSW забезпечує пошук найближчих сусідів з низькою затримкою навіть у великих масштабах.

Чотири показники, на які варто звернути увагу

Створення кешу — це проста частина. Вам також потрібно переконатися, що він працює правильно.

Коефіцієнт відповідності — це частка запитів, які знаходять відповідність у встановлених межах, і саме він визначає розмір вашої економії. При коефіцієнті відповідності 30% у системі, яка здійснює 10 000 викликів LLM на день, 3 000 викликів залишаються без використання.

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

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

Покращення затримки порівнює два способи обробки запитів. За даними тестів, час відповіді кешу становить приблизно 2–5 мс, на відміну від 300–500 мс для звичайного виклику GPT-4, що на 160 разів швидше. Те, що ви насправді відчуваєте, залежить від того, наскільки часто відбуваються відповідності, як показує ця формула:

With-Cache Latency = (avg_llm_latency × (1 - hit_rate)) + (avg_cache_latency × hit_rate)

При 30% кількості успішних пошуків очікуйте, що загальна затримка знизиться приблизно на 25–30%. Як тільки рівень використання кешу досягне 60–75%, позитивний ефект стане значно помітнішим.

Використання кешу як класифікатора

Кожен пошук закінчується одним із чотирьох результатів:

Кеш повертає результат з пошуком Кеш не знаходить результату
Мав би знайти Правильно позитивний результат Хибно негативний результат
Мав би не знайти Хибно позитивний результат Правильно негативний результат

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

Підвищення точності

Встановіть поріг. Поріг відстані є найвпливовішою налаштуванням. Нижче значення підвищує точність та знижує відтворюваність, тоді як вище значення робить навпаки. Спробуйте різні значення на репрезентативному наборі тестів та оберіть те, яке максимізує показник F1 — гармонічне середнє точності та відтворюваності. Цей підхід підвищив точність з 79% до 90%, зберігши при цьому рівень успішних відповідей на рівні 25%.

Переранжуйте за допомогою крос-енкодера. Стандартні моделі ембеддингів кодують кожне речення окремо. Крос-енкодер читає запит та кандидатські речення разом, що дозволяє виявити тонкощі, які проходять повз бі-енкодери. Візьмемо речення про те, що банк підвищує процентні ставки, та інше про повінь річки біля банку після сильних дощів: спільне слово „банк“ досить сильно наближає їхні ембеддинги, але крос-енкодер бачить, що вони не пов’язані. У експериментах переранжування підвищило точність до 94%. Крос-енкодери не можуть створювати вектори для пошуку, тому вони використовуються як другий етап над кандидатами типу top-K, яких знаходить модель ембеддингів.

Запросіть невеликий LLM здійснити оцінку. Для максимальної точності нехай дешева модель, така як GPT-4o-mini, перевірить сумнівні випадки за допомогою простого запиту: чи є ці два запитання семантично еквівалентними? Вона відповідає за кілька мілісекунд за частку від вартості повного запиту. Тести показали 100% точність, але меншу повноту виявлення, оскільки оцінювач іноді відхиляє правильні зіставлення. Чи є це прийнятним, залежить від ситуації використання. У службі підтримки клієнтів трохи неправильна відповідь з кешу може бути гіршою, ніж новий дзвінок.

Спочатку виконайте пошук за принципом „фаззі-меч“. Перш ніж обчислювати будь-які ембеддинги, проведіть порівняння за відстанню редагування запиту з збереженими записами. Якщо він відрізняється від одного з записів на два чи три змінені символи, це майже напевно орфографічна помилка того самого запиту, тож потрібно знайти його безпосередньо. Це повністю усуває крок з ембеддингами та зводить час обробки майже до нуля. При високих порогах схожості цей підхід досягав 100% точності та 94% відтворюваності на тестових наборах, наповнених орфографічними помилками.

Ще більша перевага: кешування всередині агентів

Кешування лише кінцевої відповіді на запит користувача — це неповна модель мислення. Агенти працюють інакше. Типовий алгоритм обробки складного запиту з підтримки виглядає так:

  1. Розділіть запит на 3–5 підзапитів.
  2. Отримайте відповідні документи з бази знань.
  3. Запросіть ШІ створити відповідь.
  4. Оцініть якість відповіді та, за потреби, внесіть корективи.

Кожне підпитання — це можливість скористатися кешем. Якщо агент вже відповів на запитання „Які обмеження швидкості API?“, йому не потрібно знову запитувати модель, коли це підпитання з’являється у складному запиті іншого користувача.

Агент для глибоких досліджень на основі LangGraph був протестований у трьох сценаріях:

Сценарій Частка успішних відповідей Кількість викликів LLM Затримка
Новий користувач, холодний кеш 25% 8 приблизно 20 с
Повернувшийся користувач, теплий кеш 75% 4 приблизно 13 с
Перевірка перед покупкою 75% 6 приблизно 18 с

У третьому сценарії три з кожних чотирьох підзапитань надходили з кешу. Кількість викликів моделі знизилась з 8 до 4–6, а затримка від початку до кінця обробки скоротилась приблизно на третину. Якість відповідей залишилась незмінною — у будь-якому випадку отримувалися персоналізовані та точні відповіді.

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

Пов’язані матеріали

  • Ваш перший агент LangGraph: асистент з футболу з інструментами та маршрутизацією — Покроковий посібник з LangGraph: спільний стан, інструменти, вузол планування, умовні ребра та резюме у форматі Markdown, створене на основі фіктивного асистента зі статистики футболу.
  • Як працює сучасний ШІ: пояснення LLM, технік формулювання запитів, RAG, агентів та MCP — Простими словами про архітектуру ШІ: як LLM прогнозують токени, чотири техніки формулювання запитів, RAG із ембеддингами, цикл агента ReAct та функції MCP.
  • Локальний агент для програмування на Python: інструмент Ollama, який пише та виконує код — Створіть невеликий цикл агента за допомогою Ollama та llama3.1:8b, який пише файли на Python, виконує їх та виправляє помилки, без необхідності використання API-ключів чи оплати послуг хмари.
  • Виправлення тихих помилок RAG: процедура дебаггінгу для команд, що працюють з Python — Відповіді, отримані за допомогою RAG, можуть здаватися правильними, але все одно бути неправильними. Посібник для розуміння процесів отримання інформації, її розділення на частини, фільтрації та оцінки для кращого дебаггінгу.
  • Семантичний пошук у PostgreSQL за допомогою pgvector та Node.js без потреби у LLM — Створіть пошук, заснований на значеннях, усередині PostgreSQL за допомогою pgvector, ембеддингів MiniLM та Node.js: токени, частини тексту, вектори, індекс IVFFlat, оператори відстані та способи читання оцінок.