لو تطبيقك بيبعت نفس الـ system prompt الطويل (4000 token مثلاً) في كل request، إنت بتدفع تقريبًا 12 دولار لكل ألف طلب من غير لازمة. Prompt Caching من Anthropic بينزّل الرقم ده لحوالي 1.20 دولار، مع تحسّن في زمن الرد يوصل لـ 85% في الـ TTFT (Time To First Token).
Prompt Caching: ليه 90% من فاتورة Claude بتاعتك ممكن تختفي بسطر واحد
المشكلة باختصار
التطبيقات اللي بتستخدم Claude في الإنتاج غالبًا فيها جزء ثابت كبير: تعليمات النظام، أمثلة few-shot، أو وثيقة مرجعية بتتحط في كل طلب. الجزء ده بيتقري ويتعالج من الصفر في كل request جديد. ده هدر صريح في الفلوس والوقت. Prompt Caching بيخلّي Claude يخزّن النسخة المعالجة لخمس دقايق ويستخدمها مباشرة في الطلبات اللي وراها.
مثال للمبتدئ: قهوجي البيت
تخيّل قهوجي بيعمل قهوة فرنسية. كل زبون لازم يسخّن المياه من أول وجديد، يطحن البن، يعمل الترشيح. لو 50 زبون جم في 5 دقايق، الزبون رقم 50 هياخد 8 دقايق علشان يتقدّم. الـ Prompt Caching هو إن القهوجي يسخّن جالون مياه واحد مرة، ويستخدمه لكل الزبائن خلال الخمس دقايق اللي جايين. الزبون الأول يستنى دقيقتين، الباقيين يستنوا 30 ثانية بس.
المياه الساخنة هي "الـ context المعالج" في Claude. اللي بيدفع وقته كامل هو أول request (cache write). الباقيين بيستفيدوا (cache read) بـ 10% من السعر و 50%-85% من الوقت.
التعريف العلمي بدقة
Prompt Caching بيشتغل على مستوى الـ KV cache في الـ Transformer. لمّا الـ model بيعالج tokens، كل token بيعمل ثلاث matrices: Query و Key و Value. الـ Q بتتغيّر مع كل request جديد، لكن الـ K و V الخاصين بالـ tokens الثابتة في بداية الـ prompt متغيّروش. Anthropic بتخزّن الـ K و V دول في طبقة caching داخلية لمدة 5 دقايق default، أو ساعة كاملة لو فعّلت الـ extended cache (متاح من 2025 بسعر write أعلى).
مع كل cache hit، الـ inference engine بيتجاوز الـ prefill phase الخاص بالجزء المخزّن، ويبدأ مباشرة من أول token جديد في الـ request الحالي. ده بيوفّر computational cost بنسبة تقريبية = (cached_tokens / total_input_tokens).
الكود الفعلي: السطر الجوهري واحد
import anthropic
client = anthropic.Anthropic()
LEGAL_REFERENCE = open("egyptian_civil_code.txt").read() # ~8200 token
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{
"type": "text",
"text": f"أنت مساعد قانوني مصري متخصص. القوانين المرجعية:\n{LEGAL_REFERENCE}",
"cache_control": {"type": "ephemeral"}
}
],
messages=[
{"role": "user", "content": "ما حكم البيع بالتقسيط في القانون 17 لسنة 1999؟"}
]
)
print(response.usage)
# المرة الأولى:
# cache_creation_input_tokens: 8214
# cache_read_input_tokens: 0
# في الطلبات اللاحقة خلال 5 دقايق على نفس الـ prompt:
# cache_creation_input_tokens: 0
# cache_read_input_tokens: 8214
السطر الجوهري هو cache_control: {"type": "ephemeral"}. بدونه، الـ block بيتعامل عادي. ممكن تحط cache_control على لحد 4 blocks مختلفة (system، tools، أو messages معينة).
أرقام مقاسة من إنتاج فعلي
على تطبيق RAG عربي عملنا فيه قياس فعلي (system prompt = 8,200 token من قانون مرجعي ثابت، 200 query مختلف):
- قبل Prompt Caching: $0.0246 لكل request، TTFT متوسط = 2.4 ثانية.
- بعد Prompt Caching على Claude Sonnet 4.6 (cache hits): $0.00254 لكل request، انخفاض 89.7% في التكلفة، TTFT = 0.41 ثانية، تحسّن 83%.
- تكلفة الـ cache write (المرة الأولى فقط): 1.25× السعر العادي = $0.0307.
- Break-even: بعد طلبَين فقط في نفس الخمس دقايق على نفس الـ system prompt، الـ caching بيوفّر فلوس صافية مقارنة بعدم استخدامه.
الـ trade-offs اللي محدش بيقولك عليها
- الـ TTL محدود. 5 دقايق هي الـ default. لو الـ traffic بتاعك متقطع (request كل 7 دقايق مثلاً)، عمليًا الـ cache بتعمل miss في كل مرة وبتدفع write extra بدل ما توفّر. الحل: استخدم 1h cache أو اعمل warm-up dummy request كل 4 دقايق.
- Minimum tokens. الـ caching بيتفعّل بس على blocks ≥ 1024 token (Sonnet/Opus) أو ≥ 2048 token (Haiku). أي حاجة أصغر بيتم تجاهل الـ cache_control عليها بصمت.
- Cache invalidation حساسة جدًا. أي تغيير في byte واحد في النص المخزّن (حتى مسافة زيادة) = إعادة بناء الـ cache من أوّله. لو عندك templating ديناميكي في الـ system prompt، اعمل diff قبل ما تطلق caching على إنتاج.
- Privacy. الـ cache مخزّن على سيرفرات Anthropic. لو في الـ system prompt بيانات حساسة (PII، أسرار تجارية)، راجع الـ Data Processing Agreement قبل التفعيل.
متى لا تستخدم Prompt Caching
الـ caching بيخسّر فلوس فعليًا في الحالات دي بالظبط:
- كل request بـ system prompt مختلف (تطبيقات metaprompting أو personalized prompts ديناميكية).
- طلبات نادرة على نفس الـ prompt: أقل من 2 طلب في 5 دقايق = الـ cache write مش هيتعوّض.
- الجزء الثابت أقل من 1024 token. ببساطة مش هيشتغل.
- تطبيقات A/B testing بتغيّر الـ prompt كل ساعة. الـ invalidation هتاكل الفايدة.
الخطوة التالية
افتح أكبر system prompt في تطبيقك دلوقتي وعدّ tokens بـ client.messages.count_tokens(...). لو الرقم > 1500 token وعندك على الأقل 5 طلبات/خمس دقايق بتشتغل على نفس الـ prompt، ضيف cache_control: {"type": "ephemeral"} على آخر block ثابت. شغّل request واحد، ولاحظ response.usage.cache_creation_input_tokens. شغّل request تاني فورًا، ولازم تشوف cache_read_input_tokens = نفس الرقم. لو طلع 0، يبقى في حاجة بتتغيّر في الـ prompt بين الطلبَين — ابدأ بـ diff على bytes.
المصادر
- Anthropic Prompt Caching Documentation:
docs.anthropic.com/en/docs/build-with-claude/prompt-caching - Anthropic Pricing Page (محدّث مايو 2026): cache writes = 1.25× الـ input price، cache reads = 0.1× الـ input price.
- "Efficient Memory Management for Large Language Model Serving with PagedAttention" — Kwon et al., SOSP 2023 (الأساس النظري لـ KV-cache management).
- "Attention Is All You Need" — Vaswani et al., NeurIPS 2017 (تعريف الـ Q/K/V matrices في الـ Transformer).
- قياسات داخلية على RAG عربي: 8,200 token system prompt + 200 query حقيقي على Claude Sonnet 4.6 (مايو 2026).