توسعه‌دهندگان دریافتند که قابلیت prompt-caching در Claude می‌تواند به صورت بی‌صدا با شکست مواجه شود، به طوری که نرخ‌های بالاتر (premium) را شارژ می‌کند در حالی که صفر توکن از کش بازگردانده شده است. یک اجرای لاگ یک‌هفته‌ای روی یک هندلر WhatsApp نشان داد که هیچ خوانشی از کش انجام نشده است، با این حال API هزینه قابلیت کش کردن را دریافت کرد؛ این موضوع هزینه‌ها را از ۱۸۹۰ دلار به ۴۰۶ دلار در ماه کاهش داد.

چرا این موضوع اهمیت دارد

کش کردن پرامپت (Prompt caching) با هدف کاهش هزینه‌ها و افزایش سرعت پاسخ‌دهی از طریق استفاده مجدد از یک بخش ثابت از پرامپت (یعنی «پیشوند» یا prefix) طراحی شده است. وقتی این قابلیت درست کار می‌کند، اپلیکیشن‌های با ترافیک بالا می‌توانند صدها دلار از صورت‌حساب‌های ماهانه خود بکاهند. اما وقتی کار نمی‌کند، توسعه‌دهندگان هزینه قابلیتی را می‌پردازند که هرگز واقعاً از آن استفاده نمی‌کنند، و این شکست بی‌صدا هیچ خطا یا هشداری برای نشان دادن مشکل ارائه نمی‌دهد.

این باگ چگونه خود را نشان می‌دهد

این API یک پرچم cache-control و یک پیشوند را می‌پذیرد و سپس گزارش می‌دهد که چه تعداد توکن از کش خوانده شده است. در مورد مشاهده شده، هر درخواست تعداد خوانش از کش را صفر گزارش کرد. فراخوانی با موفقیت انجام شد، هیچ استثنایی (exception) رخ نداد و صورت‌حساب نیز منعکس‌کننده هزینه ویژه کش بود. این شکست نامرئی است مگر اینکه شما صراحتاً تعداد خوانش‌ها را لاگ کنید.

روش‌های رایج از کار افتادن کش

  • پیشوند خیلی کوتاه است – هر مدل Claude یک حداقل طول توکن برای یک پیشوند قابل کش کردن تعریف می‌کند. مدل Haiku 4.5 حداقل به ۴۰۹۶ توکن نیاز دارد؛ Sonnet 4.6 تنها به ۱۰۲۴ توکن نیاز دارد. ارسال پیشوند کوتاه‌تر، فرمت درخواست را برآورده می‌کند اما سرویس دستور کش کردن را نادیده می‌گیرد.
  • جابجایی یک بایت متغیر – کش کردن مستلزم تطابق دقیق بایت‌به‌بایت است. اضافه کردن یک عنصر پویا مانند برچسب زمانی (timestamp)، new Date() یا ایمیل کاربر به ابتدای سیستم پرامپت، توالی بایت‌ها را تغییر می‌دهد و باعث می‌شود هر درخواست به عنوان یک نوشته جدید و بدون کش در نظر گرفته شود.
  • تغییر در ترتیب لیست ابزارها (Tools) – ابزارها به ابتدای پرامپت اضافه می‌شوند. اگر آرایه ابزارها از کلیدهای اشیاء (object keys) ساخته شود، ترتیب تکرار می‌تواند بین فراخوانی‌ها متفاوت باشد، که باعث تغییر چیدمان بایت‌ها و از کار افتادن کش می‌شود.

راهکارهایی که همین امروز می‌توانید اجرا کنید

  • اعتبارسنجی طول پیشوند – قبل از ارسال درخواست، تعداد توکن‌های پیشوند را نسبت به حداقل مورد نیاز مدل تخمین بزنید. اگر پیشوند کوتاه‌تر بود، آن را رد کنید یا با اضافه کردن محتوا (pad) طول آن را بیشتر کنید.
  • ثبت (Log) خوانش‌های کش در هر فراخوانی – فیلد "cache read tokens" را ثبت کنید. تکرار مداوم عدد صفر، نشانه واضحی است که کش در حال استفاده نیست.
  • ثابت نگه داشتن بایت‌های ابتدایی پرامپت – داده‌های پویا را از بخش کش‌شده دور نگه دارید. اگر مجبور به گنجاندن اطلاعات مربوط به کاربر هستید، آن را بعد از پیشوند کش‌شده قرار دهید.
  • همگام‌سازی شناسه‌های مدل – اطمینان حاصل کنید که مدل ID استفاده شده در مسیریابی (routing) با مدل ذخیره شده در جدول کش شما مطابقت دارد؛ عدم تطابق شناسه‌ها مانع از جستجوی کش می‌شود.

جنبه هزینه‌ای

برای اپلیکیشنی که روزانه هزاران فراخوانی دارد، گذار از حالت بدون کش به حالت کش‌شده می‌تواند هزینه‌های ماهانه را به شدت کاهش دهد؛ مانند مورد گزارش شده که از حدود ۱۸۹۰ دلار به ۴۰۶ دلار رسید. حتی ترافیک متوسط نیز صرفه‌جویی قابل توجهی را نشان می‌دهد و افزایش عملکرد ناشی از استفاده مجدد از یک پرامپت استاتیک بزرگ، می‌تواند تأخیر (latency) را کاهش دهد.

نکته متقابل

با این حال، ماهیت بی‌صدای این شکست به این معناست که تنها راه اطمینان از اینکه هزینه اضافی پرداخت نمی‌کنید، بررسی تعداد خوانش‌هاست؛ چیزی که بسیاری از آن غافل می‌شوند.

موارد بعدی که باید زیر نظر بگیرید

  • داشبوردهای متریک – یک نمودار برای توکن‌های خوانده شده از کش در کنار حجم درخواست‌ها اضافه کنید.
  • پایداری در ترتیب ابزارها – اگر به لیست‌های ابزار که به صورت پویا تولید می‌شوند متکی هستید، قبل از قرار دادن آن‌ها در پرامپت، آن‌ها را به صورت قطعی (deterministic) مرتب کنید.

خلاصه کلام: قابلیت prompt caching در Claude زمانی که درخواست شما را نادیده می‌گیرد، خطایی صادر نمی‌کند. اثربخشی کش را با لاگ کردن توکن‌های خوانده شده تأیید کنید، طول پیشوند مناسب را اعمال کنید و بایت‌های ابتدایی پرامپت را تغییرناپذیر نگه دارید. تنها در این صورت است که از مزایای وعده داده شده در زمینه هزینه و سرعت بهره‌مند خواهید شد.