Semantic Caching برای LLM در ۲۰۲۶: کاهش هزینه و تاخیر با GPTCache، Redis و pgvector

Semantic Caching با Embedding پرامپت‌های نزدیک‌معنا را در ۳ تا ۸ میلی‌ثانیه پاسخ می‌دهد. راهنمای عملی مقایسه‌ی GPTCache، Redis Vector و pgvector، تنظیم آستانه‌ی شباهت، الگوهای چند مستأجری و متریک‌های تولیدی برای صرفه‌جویی ۷۰ درصدی در صورتحساب LLM.

به‌روزرسانی: ۲۵ اوت ۲۰۲۶

Semantic Caching یک لایه‌ی کش سمت درخواست برای LLM است که پرامپت ورودی را به یک بردار Embedding تبدیل می‌کند، آن را در برابر پرامپت‌های قبلی جست‌وجو می‌کند و در صورتی که شباهت کسینوسی از یک آستانه‌ی قابل‌تنظیم عبور کند، پاسخ ذخیره‌شده را در ۳ تا ۸ میلی‌ثانیه بازمی‌گرداند. این الگو با Prompt Caching فرق دارد: به‌جای تطابق دقیق پیشوند توکن‌ها، معنای کلی درخواست را مقایسه می‌کند. در سال ۲۰۲۶ ابزارهایی مثل GPTCache، Redis Vector و pgvector این الگو را تولیدی‌سازی کرده‌اند و در بارهای FAQ و عامل‌ها ۳۰ تا ۷۰ درصد Hit Rate و کاهش هزینه‌ی مشابه گزارش می‌شود.

  • Semantic Cache با Embedding کار می‌کند و پرامپت‌های نزدیک‌معنا (نه دقیق) را کش می‌کند؛ کاملاً مکمل Prompt Caching است، نه جایگزین.
  • محدوده‌ی تولیدی آستانه‌ی شباهت کسینوسی در ۲۰۲۶ بین ۰.۹۲ تا ۰.۹۷ است؛ زیر ۰.۹۰ نرخ False Positive سریع بالا می‌رود.
  • سه انتخاب رایج: GPTCache برای شروع سریع پایتونی، Redis Vector برای اشتراک بین چند پاد، pgvector برای معماری‌های Postgres محور.
  • مدل Embedding سبک مثل BGE-M3 یا text-embedding-3-small بهترین توازن تاخیر/دقت را برای مسیر بحرانی می‌دهد.
  • Namespace کردن کش بر اساس tenant_id، language و template_id برای جلوگیری از آلودگی بین‌دامنه‌ای الزامی است.
  • معیار درست موفقیت، هزینه‌ی صرفه‌جویی‌شده به ازای هر مستأجر است، نه صرفاً Hit Rate خام.

Semantic Caching چیست و با Prompt Caching چه فرقی دارد؟

در تجربه‌ی من روی جریان‌های کاری تولیدی، وقتی می‌گویم «کش LLM»، معمولاً دو الگوی کاملاً متفاوت را در ذهن یک تیم می‌بینم که به هم چسبیده‌اند. اول، Prompt Caching که Anthropic، OpenAI و Gemini آن را در سطح API عرضه می‌کنند: پیشوند توکن‌های پرامپت را با هش دقیق کش می‌کنند و روی Hit، توکن‌های کش‌شده را تا ۹۰٪ ارزان‌تر حساب می‌کنند. این یعنی «همان بایت‌ها را دیدم، پس دوباره پردازش‌شان نمی‌کنم». دوم، Semantic Caching که ایده‌ی متفاوتی دارد: پرامپت را Embedding می‌کنیم، در یک ایندکس برداری جست‌وجو می‌کنیم و اگر یک پرامپت قدیمی «معنایی نزدیک» پیدا شد (شباهت کسینوسی بالای آستانه)، پاسخ ذخیره‌شده را برمی‌گردانیم بدون این‌که اصلاً به مدل بزنیم.

تفاوت عملیاتی روشن است. Prompt Caching برای پیشوندهای طولانی و ثابت (System Prompt، Tool Definitions، متن Retrieved) عالی است اما تنها روی تطابق بایت‌به‌بایت کار می‌کند؛ اگر کاربر یک کلمه در انتهای پرامپت عوض کند، Hit شما تحت تاثیر قرار نمی‌گیرد چون پیشوند ثابت مانده، ولی پاسخ نهایی مدل تازه محاسبه می‌شود. Semantic Cache برعکس، کل درخواست را نگاه می‌کند و از پاسخ‌ کامل ذخیره‌شده استفاده می‌کند، پس Hit یعنی اصلاً هزینه‌ی مدل صفر می‌شود. اما این آزادی هزینه دارد: خطر بازگرداندن پاسخ اشتباه به یک پرسش متفاوت. برای مقایسه‌ی جامع Prompt Caching بین ارائه‌دهندگان، به راهنمای Prompt Caching در ۲۰۲۶ رجوع کنید؛ در این نوشته تمرکز ما روی لایه‌ای است که روی آن سوار می‌شود.

چه زمانی از کش معنایی استفاده کنیم و کجا نه؟

Semantic Cache یک بهینه‌سازی وابسته به الگوی ترافیک است، نه یک «رایگان» فراگیر. بارهایی که بیشترین سود را می‌برند این‌ها هستند: چت‌بات‌های FAQ و پشتیبانی که هزاران کاربر سوال یکسانی را با جمله‌بندی متفاوت می‌پرسند، عامل‌هایی که همان Tool Descriptions و همان الگوهای Sub-Query را در حلقه اجرا می‌کنند، خط‌لوله‌های Classification و Extraction روی داده‌ی نیمه‌ساخت‌یافته که ورودی‌های مشابه دارد، و لایه‌های Retrieved-Augmented Generation جایی که کاربران پرسش‌های مترادف از یک دانش‌نامه دارند. در این بارها Hit Rate بین ۳۰ تا ۷۰ درصد کاملاً واقع‌بینانه است؛ گزارش‌های علنی مثل ProjectDiscovery نرخ ۸۴٪ و کاهش ۵۹ تا ۷۰ درصدی صورتحساب LLM را نشان می‌دهند.

در مقابل، این جاها ازش دور بمانید: تولید متن خلاقانه (هر بار پاسخ متفاوتی مطلوب است)، چت‌های چند نوبتی طولانی که حافظه دارند (کش سیاق قبلی را نمی‌داند)، وظایف Reasoning عمیق که پاسخ باید تازه محاسبه شود، و هرچیزی که پارامترهای stochastic بالا (Temperature بالای ۰.۷) در آن حیاتی است. Bifrost و بعضی گیت‌وی‌های ۲۰۲۶ حتی گزینه‌ای دارند که گفتگوهای بالاتر از N نوبت را خودکار از کش خارج می‌کنند تا از False Positive جلوگیری کنند. قاعده‌ای که من به تیم‌ها می‌دهم: قبل از پیاده‌سازی، یک هفته لاگ درخواست‌های پروداکشن را بگیرید و روی نمونه‌ی ۱۰۰۰تایی شباهت کسینوسی جفتی را حساب کنید؛ اگر توزیع شباهت‌ها یک قله‌ی مشخص بالای ۰.۹ ندارد، Hit Rate واقعی شما هم نخواهد داشت.

مقایسه‌ی ابزارهای Semantic Cache در ۲۰۲۶

سه ابزار غالب برای پیاده‌سازی کش معنایی در محیط تولید در ۲۰۲۶ عبارت‌اند از GPTCache (کتابخانه‌ی متن‌باز Zilliz)، Redis Vector Cache (با کلاینت مستقیم یا از طریق RedisSemanticCache در LangChain) و pgvector روی PostgreSQL. علاوه بر این‌ها، سرویس‌های گیت‌وی مثل Portkey و Bifrost یک لایه‌ی مدیریت‌شده ارائه می‌دهند که Semantic Cache را با روتینگ و Rate Limiting یکجا در HTTP هدر می‌گیرد. من انتخاب را با معیار «تناسب با پشته» انجام می‌دهم، نه سر و صدای بازار.

ویژگیGPTCacheRedis Vectorpgvectorگیت‌وی (Portkey/Bifrost)
محل استقراردرون‌فرآیندی (Python)سرور مستقلPostgres موجودSaaS/self-hosted
تاخیر Lookup (p99)۵–۱۵ms۳–۸ms۱۰–۳۰ms۱۵–۴۰ms (شبکه)
اشتراک بین پادهاندارد (مگر backend خارجی)دارددارددارد
بک‌اند برداریFAISS، Milvus، Redis، QdrantRediSearch HNSWHNSW، IVFFlatمدیریت‌شده
Namespace چند مستأجریMetadata FilterKey Prefix + FilterWHERE + Indexهدر x-portkey-cache-namespace
آستانه‌ی تطبیقیدستی (0.7–0.95)دستیدستی + Viewسیاست هر مسیر
هزینه‌ی راه‌اندازییک pip installسرور Redis StackافزونهSubscription
بهترین برایMVP و پروژه‌ی پایتونیچند پاد، تاخیر بحرانیپشته‌ی Postgres محورارکستراسیون چند مدل

خلاصه‌ی توصیه‌ی من: اگر تازه شروع می‌کنید یا یک اسکریپت پایتونی است، با GPTCache شروع کنید تا در چند دقیقه اثبات کنید کش برای بار شما جواب می‌دهد. اگر سه پاد یا بیشتر پشت Load Balancer دارید و می‌خواهید Hit بین‌شان به اشتراک بگذارید، Redis Vector گزینه‌ی درست است. اگر Postgres قبلاً پایگاه اصلی شما است، pgvector را انتخاب کنید تا از بک‌آپ‌ها و Observability موجود بهره ببرید. برای مقایسه‌ی عمیق‌تر پایگاه‌های داده‌ی برداری زیرین این تصمیم، به راهنمای پایگاه‌های داده برداری ۲۰۲۶ نگاه کنید.

پیاده‌سازی با GPTCache در پایتون

GPTCache از Zilliz برای من نقطه‌ی شروع همیشگی است چون در دو خط کد کلاینت OpenAI را می‌پیچد و سه مؤلفه‌ی مستقل (Embedding، Vector Store، Similarity Evaluator) را قابل تعویض می‌کند. مطابق مستندات رسمی GPTCache، برای کاربرد جدی باید FAISS داخل‌فرآیندی را کنار بگذارید و به بک‌اند اشتراکی سوئیچ کنید.

from gptcache import cache
from gptcache.adapter import openai
from gptcache.embedding import Onnx
from gptcache.manager import CacheBase, VectorBase, get_data_manager
from gptcache.similarity_evaluation.distance import SearchDistanceEvaluation

# 1) Embedding سبک ONNX روی CPU: ~3ms در هر lookup
encoder = Onnx()  # مدل all-MiniLM-L6-v2، 384 بعد

# 2) SQLite برای پاسخ‌ها، Faiss برای بردار (برای تک‌پاد کافی است)
data_manager = get_data_manager(
    CacheBase("sqlite"),
    VectorBase("faiss", dimension=encoder.dimension),
    max_size=100_000,
    eviction="LRU",
)

# 3) آستانه به صورت "حداکثر فاصله" تعریف می‌شود؛ 0.08 معادل شباهت کسینوسی ~0.92
cache.init(
    embedding_func=encoder.to_embeddings,
    data_manager=data_manager,
    similarity_evaluation=SearchDistanceEvaluation(max_distance=0.08),
    pre_embedding_func=lambda data, **_: data["messages"][-1]["content"],
)
cache.set_openai_key()

# 4) از این پس هر تماس openai.ChatCompletion از کش رد می‌شود
resp = openai.ChatCompletion.create(
    model="gpt-4.1-mini",
    messages=[{"role": "user", "content": "ساعات کاری فروشگاه چیست؟"}],
    cache_obj=cache,
)
print(resp["choices"][0]["message"]["content"], "cache_hit=", resp.get("gptcache", False))

نکته‌ی مهمی که در راه‌اندازی‌های اولیه‌ی مشتریانم می‌بینم: تابع pre_embedding_func پیش‌فرض تمام تاریخچه‌ی چت را در Embedding می‌ریزد، پس در گفتگوهای چندنوبتی هر پیام تازه تقریباً منحصر به فرد به نظر می‌رسد و Hit به صفر می‌رسد. بالا فقط آخرین پیام کاربر را استخراج کرده‌ام. این تک تغییر (که خودم اولش دست‌کم گرفتم) Hit Rate را در یک پروژه‌ی FAQ از ۴٪ به ۴۸٪ برد.

راه‌اندازی Semantic Cache با Redis Vector و LangChain

وقتی چند پاد پشت Load Balancer دارید، کش داخل‌فرآیندی معنی خودش را از دست می‌دهد چون پاد A کشی می‌کند که پاد B هیچ‌گاه نمی‌بیند. Redis Vector این را با یک ایندکس HNSW اشتراکی حل می‌کند. LangChain کلاس RedisSemanticCache را به‌عنوان بکربند LLMCache ارائه می‌دهد که ادغام کاملی با Embeddings و Redis Stack دارد.

from langchain.globals import set_llm_cache
from langchain_community.cache import RedisSemanticCache
from langchain_openai import OpenAIEmbeddings, ChatOpenAI

# مدل Embedding سبک 1536-بعد OpenAI، یا BGE-M3 اگر خواستید همه‌چیز محلی باشد
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")

# score_threshold در LangChain در واقع «حداکثر فاصله»ی مجاز است.
# 0.10 تقریباً معادل شباهت کسینوسی 0.95 است (سخت‌گیرانه، برای پشتیبانی مالی).
semantic_cache = RedisSemanticCache(
    redis_url="redis://redis-stack:6379",
    embedding=embeddings,
    score_threshold=0.10,
)
set_llm_cache(semantic_cache)

llm = ChatOpenAI(model="gpt-4.1-mini", temperature=0)

# فراخوانی اول: به مدل می‌زند، پاسخ را در Redis ذخیره می‌کند
r1 = llm.invoke("چطور می‌توانم رمز عبورم را ریست کنم؟")

# فراخوانی دوم: عبارت متفاوت، معنای مشابه → Cache Hit، بدون تماس با مدل
r2 = llm.invoke("فراموش کرده‌ام رمز عبور را چطور بازنشانی کنم")
assert r1.content == r2.content  # همان پاسخ برگشت

در Redis Stack توصیه‌ی من HNSW با M=32 و EF_CONSTRUCTION=200 برای بارهای ثابت است. اگر ترافیک نوسانی دارید، مستندات Redis Vector Search پارامترهای دقیق را نشان می‌دهد. برای چند مستأجری هرگز فقط به Metadata Filter اکتفا نکنید. به جایش، از پیشوند کلید مثل cache:{tenant_id}:{template_id}:... استفاده کنید تا با SCAN بتوانید کل namespace یک مستأجر را در یک عملیات پاک کنید.

Semantic Cache روی pgvector برای پشته‌های Postgres

برای تیم‌هایی که Postgres را قبلاً به عنوان پایگاه اصلی می‌شناسند، اضافه کردن pgvector راه سوم است که Backup، Point-in-time Recovery و مانیتورینگ موجود را بازاستفاده می‌کند. الگو ساده است: یک جدول با ستون بردار و ایندکس HNSW، به علاوه‌ی یک تابع Postgres که Lookup را انجام می‌دهد.

-- افزونه (Postgres 15+ همراه با pgvector 0.7+)
CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE llm_cache (
    id           BIGSERIAL PRIMARY KEY,
    tenant_id    TEXT      NOT NULL,
    template_id  TEXT      NOT NULL,
    prompt_text  TEXT      NOT NULL,
    prompt_vec   VECTOR(384) NOT NULL,       -- BGE-M3 در حالت 384-بعدی Matryoshka
    response     JSONB     NOT NULL,
    model        TEXT      NOT NULL,
    created_at   TIMESTAMPTZ DEFAULT NOW(),
    hit_count    INT       DEFAULT 0
);

-- ایندکس HNSW با فاصله‌ی کسینوسی
CREATE INDEX llm_cache_vec_idx
  ON llm_cache USING hnsw (prompt_vec vector_cosine_ops)
  WITH (m = 16, ef_construction = 128);

-- ایندکس ثانویه برای namespace چند مستأجری
CREATE INDEX llm_cache_tenant_tpl_idx
  ON llm_cache (tenant_id, template_id);
# کلاینت پایتونی سبک با psycopg و مدل Embedding محلی
import psycopg, json
from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=True)
COS_SIM_THRESHOLD = 0.94  # پشتیبانی: بین دقت و پوشش

def cache_lookup(conn, tenant, template, prompt):
    vec = model.encode([prompt], max_length=256)["dense_vecs"][0].tolist()
    with conn.cursor() as cur:
        cur.execute(
            """
            SELECT id, response, 1 - (prompt_vec <=> %s::vector) AS sim
            FROM llm_cache
            WHERE tenant_id = %s AND template_id = %s
            ORDER BY prompt_vec <=> %s::vector
            LIMIT 1
            """,
            (vec, tenant, template, vec),
        )
        row = cur.fetchone()
        if row and row[2] >= COS_SIM_THRESHOLD:
            cur.execute("UPDATE llm_cache SET hit_count = hit_count + 1 WHERE id = %s", (row[0],))
            return row[1]           # cache hit
    return None                     # cache miss

عملگر <=> در pgvector فاصله‌ی کسینوسی برمی‌گرداند، پس 1 - distance شباهت است. با ایندکس HNSW تاخیر Lookup روی ۱۰۰ هزار ردیف زیر ۱۵ میلی‌ثانیه می‌ماند. برای مطالعه‌ی جدید مخزن رسمی pgvector پارامترهای ef_search در زمان کوئری را توضیح می‌دهد—بالا بردنش دقت را بیشتر می‌کند به قیمت تاخیر.

تنظیم آستانه‌ی شباهت و ارزیابی نرخ Hit

تنظیم آستانه مهم‌ترین تصمیم پیاده‌سازی است و نمی‌شود آن را با شهود انجام داد. توصیه‌ی من روال چهار مرحله‌ای زیر است: ۱) یک هفته لاگ درخواست‌ها را ذخیره کنید. ۲) ۳۰۰ تا ۵۰۰ جفت پرامپت-پاسخ را دستی برچسب بزنید (equivalent / not-equivalent). ۳) شباهت کسینوسی همه‌ی جفت‌ها را با مدل Embedding منتخب حساب کنید. ۴) منحنی Precision-Recall را رسم کنید و آستانه‌ای انتخاب کنید که Precision ≥ ۹۵٪ باشد. طبق پژوهش ۲۰۲۶ محدوده‌ی تولیدی برای انواع بار متفاوت است: FAQ حول ۰.۹۴، جست‌وجوی محصول ۰.۸۸، پشتیبانی متوازن ۰.۹۲ و کوئری‌های تراکنشی ۰.۹۷.

# اسکریپت ارزیابی: precision و recall را برای دامنه‌ای از آستانه‌ها گزارش می‌دهد
import numpy as np
from sklearn.metrics import precision_recall_curve

# pairs: [(sim_score, is_equivalent), ...]  → is_equivalent ∈ {0, 1}
sims, labels = zip(*pairs)
prec, rec, thr = precision_recall_curve(labels, sims)

for target in (0.95, 0.98, 0.99):
    ok = np.where(prec[:-1] >= target)[0]
    if len(ok) == 0:
        print(f"precision {target}: در دسترس نیست")
        continue
    idx = ok[0]
    print(f"precision≥{target} → threshold={thr[idx]:.3f}  recall={rec[idx]:.2%}")

یک تله‌ی رایج: خیلی‌ها فقط Hit Rate را دنبال می‌کنند، اما متریک واقعی «هزینه‌ی صرفه‌جویی‌شده به ازای هر مستأجر و هر Template» است. یک داشبورد که Hit Rate ۴۱٪ نشان می‌دهد ولی صورتحساب فقط ۸٪ کمتر شده، یعنی کش دارد روی درخواست‌های ارزان Hit می‌زند و درخواست‌های گران را از دست می‌دهد. برای انتخاب مدل Embedding خود کش نیز حواس‌تان باشد مدل بزرگ‌تر همیشه بهتر نیست؛ راهنمای مقایسه‌ی مدل‌های Embedding در ۲۰۲۶ نشان می‌دهد BGE-M3 در حالت ۳۸۴-بعدی Matryoshka برای مسیر بحرانی چقدر مقرون به صرفه است.

استراتژی‌های Invalidate و چند مستأجری امن

Semantic Cache بدون سیاست تازه‌سازی، یک بمب ساعتی است. اگر قیمت محصول عوض شود یا سیاست بازگشت کالا به‌روز شود، کش قدیمی به کاربر پاسخ نادرست می‌دهد و شما فکر می‌کنید سیستم درست کار می‌کند. سه استراتژی که در تولید جواب داده‌اند: TTL دسته‌بندی‌شده (FAQ عمومی ۷ روزه، سیاست‌های حساس ۲۴ ساعته، قیمت‌ها ۱ ساعته)، Event-driven Invalidation که وقتی سند منبع در CMS تغییر می‌کند، تمام رکوردهای کش با source_doc_id مربوطه پاک می‌شوند، و Versioning که هر بار مدل یا System Prompt عوض می‌شود cache_generation بالا می‌رود و کش قدیمی نامرئی می‌شود.

برای چند مستأجری، الگویی که در معماری‌های اخیر پیاده کرده‌ام: cache:{env}:{tenant_id}:{template_id}:{lang} به عنوان پیشوند کلید Redis یا ستون‌های ایندکس‌شده در Postgres. این ساختار سه مزیت دارد: (۱) پاک کردن کل کش یک مستأجر با یک SCAN + UNLINK امن است، (۲) اندازه‌گیری هزینه بر اساس مستأجر ساده می‌شود، و (۳) اگر یک زبان جدید اضافه کنید، آلودگی بین‌زبانی پیش نمی‌آید. Gateway هایی مثل Portkey این namespace را با هدر x-portkey-cache-namespace می‌گیرند و سیاست هر مسیر را جداگانه قابل تنظیم می‌کنند.

شیوه‌های تولیدی و متریک‌هایی که واقعاً مهم‌اند

وقتی Semantic Cache به تولید می‌رود، پنج متریک را حتماً به داشبورد اضافه کنید و روی هرکدام Alert بگذارید: (۱) Hit Rate بر تفکیک Template—افت ناگهانی نشانه‌ی تغییر توزیع ترافیک یا خرابی مدل Embedding است، (۲) هزینه‌ی صرفه‌جویی‌شده به دلار که با ضرب Hitها در قیمت مدل پشتیبان محاسبه می‌شود، (۳) p50/p99 لاتنسی Lookup که اگر از p95 مدل بگذرد کش ضرر می‌دهد، (۴) نرخ False Positive نمونه‌گیری‌شده که هر روز روی ۱٪ Hitها با یک قاضی LLM ارزیابی می‌کنید، و (۵) Coverage (نسبت درخواست‌های واجد شرایط برای کش نسبت به کل ترافیک).

در نهایت، Semantic Cache را به‌عنوان یک قطعه‌ی مستقل نبینید. باید آن را با روتینگ مدل، Prompt Caching و Rate Limiting در یک لایه‌ی LLM Ops ادغام کنید. الگویی که در طراحی زیرساخت‌های LLM توصیه می‌کنم این است: در دروازه، اول Exact Cache را چک کنید (میلی‌ثانیه)، اگر Miss شد Semantic Cache را بزنید (تک‌رقمی میلی‌ثانیه)، و اگر باز هم Miss شد از روتینگ LLM با LiteLLM و RouteLLM استفاده کنید تا درخواست را به ارزان‌ترین مدل مناسب بفرستید. این پشته‌ی سه لایه‌ای در پروژه‌های خودم ۷۰ تا ۸۵ درصد صرفه‌جویی روی صورتحساب اصلی داده، بدون اینکه کیفیت پاسخ به کاربر افت کند.

پرسش‌های متداول

Semantic Caching با Prompt Caching Anthropic و OpenAI چه فرقی دارد؟

Prompt Caching در سطح API فقط پیشوند بایت‌به‌بایت پرامپت را کش می‌کند و توکن‌های کش‌شده را تا ۹۰٪ ارزان‌تر می‌کند، اما مدل باز هم اجرا می‌شود. Semantic Caching در لایه‌ی خود شما اجرا می‌شود، پرامپت‌های نزدیک‌معنا را تشخیص می‌دهد و در Hit اصلاً به مدل نمی‌زند، پس هزینه صفر است و تاخیر تک‌رقمی میلی‌ثانیه.

آستانه‌ی مناسب شباهت کسینوسی برای Semantic Cache چیست؟

محدوده‌ی تولیدی در ۲۰۲۶ بین ۰.۹۲ تا ۰.۹۷ است. برای FAQ حول ۰.۹۴، برای جست‌وجوی محصول ۰.۸۸، برای پشتیبانی ۰.۹۲ و برای بارهای تراکنشی حساس ۰.۹۷ توصیه می‌شود. زیر ۰.۹۰ False Positive سریع بالا می‌رود؛ به‌جای حدس زدن، منحنی Precision-Recall را روی ۳۰۰ جفت برچسب‌خورده رسم کنید.

آیا Semantic Cache برای گفتگوهای چند نوبتی جواب می‌دهد؟

معمولاً نه. کش تاریخچه‌ی سیاق را نمی‌شناسد و اگر کل تاریخچه را Embedding کند، هر پیام تازه تقریباً منحصر به فرد می‌شود و Hit Rate به صفر می‌رسد. الگوی پیشنهادی این است که تنها آخرین پیام کاربر را برای کلید استفاده کنید، یا گفتگوهای بالاتر از سه یا چهار نوبت را کاملاً از کش خارج کنید.

کدام مدل Embedding برای Semantic Cache بهترین گزینه است؟

برای مسیر بحرانی BGE-M3 در حالت ۳۸۴ یا ۵۱۲-بعدی (Matryoshka) بهترین توازن تاخیر و دقت را می‌دهد. text-embedding-3-small OpenAI هم گزینه‌ی خوبی است اگر تاخیر شبکه مشکل نباشد. از مدل‌های ۱۵۳۶-بعدی روی مسیر بحرانی پرهیز کنید چون Lookup را کند می‌کنند.

چطور رکوردهای Semantic Cache را وقتی داده‌ی منبع تغییر می‌کند Invalidate کنم؟

سه استراتژی رایج: TTL دسته‌بندی‌شده (FAQ ۷ روزه، قیمت‌ها ۱ ساعته)، Event-driven Invalidation که با تغییر سند منبع در CMS تمام رکوردهای کش مرتبط را پاک می‌کند، و Versioning که هر بار System Prompt یا مدل عوض می‌شود cache_generation را بالا می‌برد و کش قدیمی نامرئی می‌شود.

Emma Bergstrom
درباره نویسنده Emma Bergstrom

Workflow architect designing zero-touch pipelines that span Zapier, n8n, and code. Calls herself a recovering ops engineer.