Семантычнае кэшаванне для LLM-агентаў з Redis: менш выдаткаў і затрымкі
Як семантычнае кэшаванне скарачае выдаткі і затрымку LLM: эмбедынгі, парогі, Redis і RedisVL, налада дакладнасці і кэшаванне падпытанняў унутры працэсаў агента.
Крыніцы: Semantic Caching for AI Agents: How to Make Your LLM Apps Faster and Cheaper
Выклікі супэрсільных LLM коштаюць рэальных грошаў, і яны працуюць повольна. Кожны, хто бачыў, як падрахунак за API вырастае пасля таго, як праміж рэальных корыстувачаў і сістэмы стаў агент, знае гэты напэўненне: мадэлі, якія даюць найлепшыя адпаведзі, ёсць тыя, якія коштаюць найбольш і працуюць найповольней. Мадэлі класу GPT-4 можу коштаць кальколькі долераў за тыячу запытанняў, а агентныя праграмы ўскладнююць сітуацыю, таму што адна запытанне корыстувача можа спрычыніць ад 8 да 20 выклікаў мадэлі.
Семантычны кэшыранне бярэся за гэтыя вітыкі безпасэродна, а большасць команд яго недастаткова вікорыстоўвае. Йго лёгка стварыць за дапамогою Redis.
Чаму звычныя кэшы не падходзяць
Звычны кэш счытае два запытання аднаковымі толькі тады, калі ў яных адпаведныя байты. Гэта працюе для запытанняў да базы дадзенаў і HTTP-запытанняў, але не працуе для мовы працоўніка. Уявіце сабе агента падтрымкі, які прымае такія запытанняя ад трох разных корыстувачаў:
- Кліент запытаеся, як можна запрашаць вярненне грошаў
- Іншыя выкарыстоўваюць свае грошы, каб іх адзыскаць.
- Трэція група хочаць з’ясавіць, што працюе правіла вярнення грошаў.
Кэш на рэвэльнай лэвэлі бачыць тры незв’язаныя запыткі і плаціць за тры вызовы LLM. Чалавек мог бы сказаць, што всі трое хочаць аднаковай адпаведзі. Семантычны кэш працюе на адпаведнасці значэнняў, а не на сімволах.
Механізм у чатыро кракі
- Укладзіце прыйшоўшы запыт у вектар высокай выразнасці за дапамогою модэлю укладкі.
- Пораўняйце гэты вектар з кожным зберажаным элементам, выкарыстоўваючы косінусавы абэкт або падобны показнік.
- Калі найбліжэйшы элемент знаходзіцца ў заданым вам порогу абэкта, зарахаваце гэта як успех і негайна аддаце зберажаную адпаведзь.
- Калі нічога няма достатнь як блізка, перадаце запыт праз вашу схему RAG або LLM, а потым зберажыце запыт і адпаведзь на будучы раз.
Запытанні, перафразаваныя, ў падсумку маюць аднаковыя адпаведзі. Калі кэш запоўняецца, да модэлю прабівае ўсё менша частка трафіку.
Мінімальная версія з нуля
Перш чым вжываць бібліятэку для практычнага выкарыстоўвання, корыстна пазнакоміцца з елементамі, якія ў ёй працуюць. Пачніце з імпорта:
from sentence_transformers import SentenceTransformer
import numpy as np
Потым уключыце невялікі набор частаўых запытанняў і напісце алгорытм пошуку па найбліжэйшам суседзе:
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
Прабуйце тэставальныя запытанне пра тое, сколькі дзён трэба, каб грошы былі вярнуты, і апаратна пацьверджэнне вяртае зберажаныя часта запытанняя пра вярненне грошаў як самыя блізкія рэзультаты, з косай адстаню прыблізна 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 мс, тым час як для звычайнага вызоў GPT-4 час станавіць 300 да 500 мс, тое ў 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% вярнага адліквідавання на тэстовых наборах, наполненых упамылкамі.
Большая перадача: кэшаванне ўнутрь агентаў
Кэшаванне толькі фінальнай адпаведзі на запыт корыстніка — гэта непашырэны ментальны модэль. Агенты працуюць інакш. Тыповы прайсупутак для складнага запыту падтрымкі выглядае так:
- Разбейце запыт на 3-5 падзапытаў.
- Знайдзіце стосунакі дакументы з базы знаёмых.
- Запытайце LLM пра сінтэз адпаведзі.
- Оценіце якасць адпаведзі і, як трэба, прабуйце знову.
Кожны падзеякі ўпыт яўляецца можлівасцю для выкарыстоўвання кэша. Калі агент ужэ адпаведзе на запыт „Каліяяць ліміты швайнаў API?“, яму не трэба зноў запытаць мадэль, калі гэты падзеякі ўпыт з’явіцца ў складным запыце іншага корыстніка.
Агент для глыбокых даследжэнняў, адаснованы на LangGraph, быў працаваны ў трох сцэнарыях:
| Сцэнарый | Рэшта ў 95% случаў | Колькасць вызоў LLM | Затрымка |
|---|---|---|---|
| Новы корыстнік, холадны кэш | 25% | 8 | прыблізна 20 секунд |
| Корыстнік, які вяртаецца, тэплы кэш | 75% | 4 | прыблізна 13 секунд |
| Перагляд пры пярэднім абавесці | 75% | 6 | прыблізна 18 секунд |
У трэцьям сцэнарыі тры з кожных чатырох падзядачных запытанняў выйшлі з кэша. Колькасць вызваў модэляў зменілася з 8 на 4–6, а час адпаведзення зменіўся прыбліжна на трохці. Якосць адпаведзення засталася той самай — у будзь-якім случае адпаведзенні былі персоналізаваныя і точныя.
Этот эфект нарастае. Кожны успешны запуск дадае матэрыялу ў кэш, і пазнейшыя корыстувальнікі з падобнымі запытаннямі можаць корыстацца всім, што ўжо ў кэшы, таму заўсёды ёсць эконамія, калі сістэма обрабоцвае сотні чы роўныя тысячы запытанняў.