التخزين المؤقت الدقيق باستخدام Redis
خزّنوا استجابات LLM مؤقتًا عبر تجزئة المطالبة الكاملة وتخزين النتيجة في Redis مع مدة صلاحية TTL، وقدّموا الطلبات المطابقة فورًا دون أي استدعاء لواجهة API.
التخزين المؤقت الدقيق باستخدام Redis درس مجاني في AI Engineering Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في AI Engineering Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
لماذا نُخزّن استجابات LLM مؤقتًا؟
تُعد استدعاءات واجهة API الخاصة بـ LLM مكلفة؛ فقد يتكلف طلب واحد إلى GPT-4o مبلغًا يتراوح بين 0.005 و0.15 دولار، حسب عدد الرموز. وفي العديد من التطبيقات، تكون نسبة كبيرة من الاستعلامات الواردة مطابقة تمامًا أو شبه مطابقة لاستعلامات سابقة — مثل روبوتات الأسئلة الشائعة وأنظمة دعم العملاء وأدوات مراجعة الشيفرة، حيث يطرح المستخدمون الأسئلة نفسها مرارًا. ويمكن للتخزين المؤقت إلغاء 20 إلى 50 بالمئة من استدعاءات API في حالات الاستخدام هذه، ما يخفض التكاليف مباشرةً ويقلل زمن الاستجابة.
التخزين المؤقت الدقيق: تصميم مفتاح التخزين
يخزّن التخزين المؤقت الدقيق استجابات LLM باستخدام تجزئة حتمية للمدخلات كمفتاح. ويجب أن يلتقط مفتاح التخزين كل مدخل يؤثر في الناتج: مصفوفة الرسائل، واسم النموذج، ودرجة الحرارة، وأي معاملات أخرى تغيّر الاستجابة. ويؤدي إغفال أي من هذه العناصر من المفتاح إلى تصادمات في التخزين المؤقت، بحيث تُقدَّم استجابة مخزنة مؤقتًا لطلب فعلي مختلف.
import hashlib
import json
def make_cache_key(messages: list[dict], model: str, temperature: float) -> str:
# Create a canonical, order-stable representation
key_data = {
'model': model,
'temperature': temperature,
'messages': messages, # list order matters
}
# Serialize to JSON with sorted keys for determinism
serialized = json.dumps(key_data, sort_keys=True, ensure_ascii=False)
# Hash to a fixed-length key safe for Redis
return 'llm_cache:' + hashlib.sha256(serialized.encode()).hexdigest()الاتصال بـ Redis
يُعد Redis الخيار القياسي لتخزين استجابات LLM مؤقتًا بفضل زمن القراءة الأقل من ميلي ثانية ودعم TTL المدمج. استخدم مكتبة redis-py للوصول المتزامن، أو aioredis (المدمجة الآن في redis-py باسم redis.asyncio) للوصول غير المتزامن في تطبيقات FastAPI. خزّن اتصال Redis كمفرد لتجنب استنفاد مجموعة الاتصالات.
import redis
import redis.asyncio as aioredis
# Synchronous Redis client
r = redis.Redis(
host='localhost',
port=6379,
db=0,
decode_responses=True, # return str instead of bytes
)
# Async Redis client (for FastAPI)
async_r = aioredis.Redis(
host='localhost',
port=6379,
db=0,
decode_responses=True,
)
# Test connection
print(r.ping()) # True if Redis is runningتنفيذ نمط Cache-Aside
يُعد نمط cache-aside استراتيجية التخزين المؤقت القياسية لواجهات API الخاصة بـ LLM. في كل طلب: (1) احسب مفتاح التخزين، (2) تحقق من وجود استجابة مخزنة مؤقتًا في Redis، (3) إذا وُجدت (إصابة في التخزين المؤقت) فأعدها فورًا، (4) إذا لم توجد (فقد في التخزين المؤقت) فاستدعِ واجهة API الخاصة بـ LLM، (5) خزّن الاستجابة في Redis مع TTL، (6) أعد الاستجابة. ويُبقي هذا النمط منطق التخزين المؤقت منفصلًا عن استدعاء LLM نفسه.
import json
from openai import OpenAI
client = OpenAI()
def cached_completion(
messages: list[dict],
model: str = 'gpt-4o-mini',
temperature: float = 0.7,
ttl_seconds: int = 3600,
) -> str:
cache_key = make_cache_key(messages, model, temperature)
# Cache hit?
cached = r.get(cache_key)
if cached is not None:
print('[CACHE HIT]')
return json.loads(cached)
# Cache miss: call API
print('[CACHE MISS]')
response = client.chat.completions.create(
model=model,
messages=messages,
temperature=temperature,
)
result = response.choices[0].message.content
# Store in cache with TTL
r.setex(cache_key, ttl_seconds, json.dumps(result))
return resultCache-Aside غير المتزامن لـ FastAPI
في تطبيق FastAPI غير المتزامن، استخدم عميل Redis غير المتزامن حتى لا تؤدي عمليات البحث في التخزين المؤقت إلى حظر حلقة الأحداث. والنمط مماثل للإصدار المتزامن، لكنه يستخدم await مع جميع عمليات Redis. ويحافظ ذلك على طبقة تخزين مؤقت غير حاجبة بالكامل ومتوافقة مع عميل LLM غير المتزامن.
from openai import AsyncOpenAI
import redis.asyncio as aioredis
import json
async_client = AsyncOpenAI()
async_r = aioredis.Redis(host='localhost', port=6379, decode_responses=True)
async def async_cached_completion(
messages: list[dict],
model: str = 'gpt-4o-mini',
temperature: float = 0.0,
ttl: int = 86400,
) -> str:
key = make_cache_key(messages, model, temperature)
cached = await async_r.get(key)
if cached:
return json.loads(cached)
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
result = response.choices[0].message.content
await async_r.setex(key, ttl, json.dumps(result))
return resultاختيار TTL المناسب
يتحكم TTL (مدة البقاء) في المدة التي تظل خلالها الاستجابات المخزنة مؤقتًا صالحة. بالنسبة إلى الأسئلة والأجوبة الواقعية ذات قواعد المعرفة المستقرة، تزيد مدد TTL الطويلة (من 24 إلى 72 ساعة) من معدلات الإصابة في التخزين المؤقت إلى أقصى حد. أما الاستجابات التي ينبغي أن تعكس أحدث البيانات (مثل تلخيص الأخبار والأسعار المباشرة)، فتناسبها مدد TTL قصيرة (من 5 إلى 15 دقيقة)، أو عدم استخدام التخزين المؤقت إطلاقًا. وبالنسبة إلى المهام الإبداعية ذات درجة حرارة غير صفرية، قد تنتج عملية التخزين المؤقت استجابات قديمة — لذا يُستحسن قصر التخزين المؤقت على temperature=0.
# TTL strategy by use case
TTL_STRATEGY = {
'faq_answering': 86400 * 7, # 7 days — stable facts
'code_explanation': 86400, # 1 day — code rarely changes
'document_summarization': 3600 * 6, # 6 hours
'news_analysis': 300, # 5 minutes — stale quickly
'creative_writing': 0, # 0 = don't cache (non-deterministic)
}
def get_ttl_for_use_case(use_case: str) -> int:
return TTL_STRATEGY.get(use_case, 3600) # default 1 hourمقاييس التخزين المؤقت ومراقبته
تابع معدل الإصابة في التخزين المؤقت بوصفه مقياسًا أساسيًا لخفض التكاليف. ويعني معدل إصابة قدره 30 بالمئة تجنّب 30 بالمئة من استدعاءات API. خزّن عدادات الإصابات والإخفاقات في Redis نفسه باستخدام أوامر INCR على عدادات منفصلة. واعرض نقطة نهاية /metrics في تطبيق FastAPI تُبلغ عن معدل الإصابة الحالي وإجمالي الطلبات والتوفير التقديري في التكاليف لقياس العائد على الاستثمار في التخزين المؤقت.
CACHE_HITS_KEY = 'llm_cache_metrics:hits'
CACHE_MISSES_KEY = 'llm_cache_metrics:misses'
async def async_cached_completion_instrumented(messages, model, temperature=0.0):
key = make_cache_key(messages, model, temperature)
cached = await async_r.get(key)
if cached:
await async_r.incr(CACHE_HITS_KEY)
return json.loads(cached)
await async_r.incr(CACHE_MISSES_KEY)
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
result = response.choices[0].message.content
await async_r.setex(key, 3600, json.dumps(result))
return result
async def get_cache_stats():
hits = int(await async_r.get(CACHE_HITS_KEY) or 0)
misses = int(await async_r.get(CACHE_MISSES_KEY) or 0)
total = hits + misses
return {'hit_rate': hits / total if total > 0 else 0, 'total': total}استراتيجيات إبطال التخزين المؤقت
يكون إبطال التخزين المؤقت الدقيق مباشرًا لأن المفاتيح حتمية. ولـإبطال إدخال محدد، أعد حساب مفتاحه واستدعِ r.delete(key). ولإبطال جميع الإدخالات لنمط مطالبة محدد، استخدم بادئات مفاتيح Redis مع فحص باستخدام حرف بدل. ولإبطال التخزين المؤقت بالكامل بعد تحديث رئيسي لقاعدة المعرفة، استدعِ r.flushdb() (استخدمه بحذر — إذ يحذف جميع المفاتيح في قاعدة البيانات).
async def invalidate_cache_entry(messages, model, temperature):
key = make_cache_key(messages, model, temperature)
deleted = await async_r.delete(key)
print(f'Deleted {deleted} cache entries')
async def invalidate_all_llm_cache():
# Scan for all keys with prefix 'llm_cache:'
keys_to_delete = []
async for key in async_r.scan_iter(match='llm_cache:*'):
keys_to_delete.append(key)
if keys_to_delete:
await async_r.delete(*keys_to_delete)
print(f'Invalidated {len(keys_to_delete)} cache entries')تسلسل الاستجابات المعقدة
إذا كان تطبيقك يخزّن مؤقتًا كائنات استجابة API كاملة (وليس محتوى النص فقط)، فقم بتسلسلها بعناية. يتضمن كائن ChatCompletion الكامل استخدام الرموز وإصدار النموذج وسبب الإنهاء — وهي معلومات مفيدة للتسجيل وتتبع التكاليف. استخدم طريقة SDK .model_dump_json() لتسلسل كائنات استجابة Pydantic إلى سلاسل JSON، وأعد إنشاءها باستخدام ChatCompletion.model_validate_json() عند استردادها من التخزين المؤقت.
from openai.types.chat import ChatCompletion
async def cached_completion_full_response(
messages, model='gpt-4o-mini', temperature=0.0
):
key = make_cache_key(messages, model, temperature) + ':full'
cached = await async_r.get(key)
if cached:
return ChatCompletion.model_validate_json(cached) # reconstruct object
response = await async_client.chat.completions.create(
model=model, messages=messages, temperature=temperature
)
# Serialize Pydantic model to JSON
await async_r.setex(key, 3600, response.model_dump_json())
return responseالتخزين المؤقت وعدم الحتمية
لا يكون التخزين المؤقت الدقيق منطقيًا إلا للطلبات الحتمية أو شبه الحتمية. عند temperature=0 وtop_p=1.0، تنتج معظم نماذج LLM المخرج نفسه للمدخل نفسه (مع أن ذلك غير مضمون بسبب عدم الحتمية في حسابات الفاصلة العائمة). وعند درجات الحرارة الأعلى، تصبح الاستجابات المخزنة مؤقتًا قديمة، إذ كان النموذج سينتج مخرجات مختلفة. احرص دائمًا على التخزين المؤقت عند temperature=0، أو وضّح في مفتاح التخزين أن الاستجابات قد تختلف.
إعداد Redis Cluster وبيئة الإنتاج
بالنسبة إلى عمليات النشر الإنتاجية ذات أحجام التخزين المؤقت الكبيرة، استخدم Redis Cluster للتقسيم الأفقي عبر عدة عقد، أو خدمة Redis مُدارة مثل AWS ElastiCache أو Redis Cloud. عيّن سياسة maxmemory (عادةً allkeys-lru لإخلاء الإدخالات الأقل استخدامًا مؤخرًا عند امتلاء الذاكرة) لمنع نفاد ذاكرة Redis وإدارة حجم التخزين المؤقت تلقائيًا.
# Redis configuration for production LLM caching
# In redis.conf:
# maxmemory 2gb
# maxmemory-policy allkeys-lru
# Connection with retry and connection pool
import redis
from redis.retry import Retry
from redis.backoff import ExponentialBackoff
retry = Retry(ExponentialBackoff(base=0.1), 3)
production_redis = redis.Redis(
host='your-redis-host.cache.amazonaws.com',
port=6379,
ssl=True,
decode_responses=True,
max_connections=50,
retry=retry,
retry_on_error=[redis.ConnectionError, redis.TimeoutError],
)تحقق سريع
اختبر مدى فهمك للتخزين المؤقت الدقيق لاستجابات LLM باستخدام Redis من هذا الدرس.
مراجعة الدرس
تعلمت في هذا الدرس أن التخزين المؤقت الدقيق يجزّئ جميع مدخلات LLM لإنتاج مفتاح تخزين حتمي، وأن نمط cache-aside يتحقق من Redis قبل استدعاء API ويخزّن النتائج بعد حدوث فقد، وأن اختيار TTL ينبغي أن يعكس مدى تكرار تغيّر المحتوى — بحيث يكون أطول للمعرفة المستقرة وأقصر للبيانات المتغيرة. راقب معدل الإصابة في التخزين المؤقت بوصفه مقياسًا أساسيًا لخفض التكاليف. سننتقل بعد ذلك إلى بناء تخزين مؤقت دلالي للاستعلامات المتشابهة لكن غير المتطابقة.
تعلم Python مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 30
- الدروس
- 120
الأسئلة الشائعة
هل درس «التخزين المؤقت الدقيق باستخدام Redis» مجاني؟
نعم — نص درس «التخزين المؤقت الدقيق باستخدام Redis» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة AI Engineering Academy، انتقل إلى CoddyKit PRO. تتضمن دورة AI Engineering Academy 4 دروس في المجموع.
ماذا ستتعلم في «التخزين المؤقت الدقيق باستخدام Redis»؟
خزّنوا استجابات LLM مؤقتًا عبر تجزئة المطالبة الكاملة وتخزين النتيجة في Redis مع مدة صلاحية TTL، وقدّموا الطلبات المطابقة فورًا دون أي استدعاء لواجهة API. تتمرن على AI Engineering Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ AI Engineering Academy؟
لا تُشترط خبرة سابقة. AI Engineering Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «التخزين المؤقت الدقيق باستخدام Redis»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس AI Engineering Academy هذا؟
نعم. كل درس في AI Engineering Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- التخزين المؤقت الدقيق باستخدام Redis
- التخزين المؤقت الدلالي باستخدام التضمينات
- التخزين المؤقت لبادئة المطالبة في OpenAI
- التجميع وتوجيه النماذج ولوحات التكاليف