حافظهٔ ایجنت لاراول هزینه رو سه برابر میکنه
خلاصهٔ کاملتر
نویسنده با یه عدد شروع میکنه. در نوبت دهم یه گفتگوی واقعی، کاربر فقط پنج بولت خواسته بود و هیچ ابزاری هم صدا نشده بود، ولی درخواست ۲۴۶٬۲۲۱ توکن ورودی داشت. تقریباً همهش یه صفحه بود که ایجنت در نوبت ششم اسکرپ کرده بود. تریت RemembersConversations دو کار میکنه: هر نوبت رو ذخیره میکنه، و تاریخچه رو برمیگردونه تو پرامپت. اون عدد صد که پیشفرضه تعداد ردیفه، نه بودجهٔ توکن، و اندازهٔ هر ردیف هیچ سقفی نداره.
یه نوبتی که ابزار صدا کرده هم یه خط متن نیست. استور، tool_calls و tool_results رو تو ستونهای خودشون مینویسه و موقع لود کردن ردیف، بدنهٔ کامل هر نتیجه رو عیناً بازسازی میکنه. پس صفحهای که در نوبت شش ۷۰۰ کیلوبایت بوده، تو هر درخواست بعدی هم همونقدر جا میگیره. در اندازهگیری نویسنده با Sonnet 4.6 و ده نوبت، مجموع تاریخچهٔ دوبارهفرستادهشده ۱٬۱۵۴٬۰۹۳ توکن شد، یعنی ۵.۶۳ دلار برای یک گفتگو. از نوبت دو به بعد ۸۸ تا ۹۲ درصدش نتیجهٔ ابزارها بود و حرفهای کاربر و مدل زیر ۵ درصد.
نویسنده میگه وسط یک ران نمیتونی تاریخچه رو کوتاه کنی: لوپ آرایهٔ پیامها رو تو یه متغیر محلی نگه میداره و به ایونت StartingStep یه کپی میده، پس لیسنر کپی رو میبره و استپ بعدی اصل رو میفرسته (ایشو #669 روی مخزن SDK از خرداد ۱۴۰۵ همین رو میخواد). ولی بین نوبتها هوک دست خودته. متد messages() کل درز بین نوبتهاست و جایگزین میشه، نه فیلتر؛ یعنی اگه اوورراید کنی و یادت بره از استور لود کنی، بیصدا هیچ تاریخچهای فرستاده نمیشه.
public function messages(): iterable
{
$loaded = resolve(ConversationStore::class)
->getLatestConversationMessages($this->conversationId, $this->maxConversationMessages())
->all();
return $this->history->apply($loaded, $this->conversationId);
}سیاست اول یه پنجرهٔ توکنیه: تاریخچه رو از آخر به اول میری، تخمین میزنی و روی بودجه وایمیستی. Tokens::estimate() فقط تعداد کاراکتر تقسیم بر چهاره چون SDK توکنشمار نداره، و Sonnet روی این محتوا ۹ تا ۲۰ درصد بیشتر از تخمین حساب کرد. یه نکتهٔ حیاتی هم هست: برش ممکنه بین پیامی که ابزار رو صدا کرده و ToolResultMessage جوابش بیفته و پروایدر ارور جفتنشدن tool_use_id میده، پس باید نتیجههای بیصاحب اول لیست رو دور بریزی. با بودجهٔ ۳۰ هزار، ده نوبت از ۱٬۱۵۴٬۰۹۳ به ۱۹۵٬۴۶۷ توکن رسید. ولی نوبت هفت فقط ۸۸۶ توکن فرستاد: صفحهٔ نوبت شش از کل بودجه بزرگتر بود و دقیقاً وقتی حذف شد که کاربر داشت دربارهش میپرسید.
سیاست دوم همهٔ پیامها رو نگه میداره ولی بدنهٔ نتیجههای قدیمیتر از N نوبت آخر رو با یک خط «از کانتکست پاک شد» عوض میکنه و id و name و آرگومانها رو دست نمیزنه، تا جفت شدن با بلاک tool_use پروایدر نشکنه و مدل بدونه اون ابزار اجرا شده. آنتروپیک هم پاک کردن نتیجهٔ ابزار رو امنترین نوع فشردهسازی کانتکست میدونه. زنده روی Sonnet ۲۰۸٬۱۲۷ توکن حساب شد، با همون ۳۵ پیام نوبت دهم و بدون حذف هیچ پیامی. جوابها هم سالم موندن: نوبت ده پنج لینک داد و عددهای یه مقالهٔ نوبت پنج رو نقل کرد، چون جواب خود مدل سر جاش مونده بود و URL هم آرگومان ابزار بود.
سیاست سوم وقتی تاریخچه سرریز میکنه بخش قدیمی رو با SummarizeAgent خلاصه میکنه، خلاصه رو روی گفتگو ذخیره میکنه و از اون به بعد همون خلاصه بهعلاوهٔ دنبالهٔ اخیر رو میفرسته؛ خلاصهسازی هر نوبت پول پیشوند رو دو بار میده، چکپوینت یه بار. ارزونترین گزینه هم همینه: ۸۲٬۵۶۰ توکن تاریخچه در ده نوبت بهاضافهٔ سه فراخوانی خلاصهساز. ولی بعد نویسنده خلاصه رو خوند: بعد از سومین فولد، فقط دربارهٔ آخرین چیز فولدشده بود، هیچ URL و هیچ اشارهای به مقالهٔ نوبت چهار و پنج نداشت، و نوبت ده که پنج بولت با لینک خواسته بود صفر لینک داد. دو تا دلیل: SummarizeAgent(5) روی ورودی ساختارمند سیزده جمله برگردوند، پس محدودیت جمله فقط توصیهست؛ و مدل ارزون بهجای ادامه دادن خلاصه، از نو نوشتش.
نکات کلیدی:
- پیشفرض RemembersConversations صد ردیف پیامه، نه بودجهٔ توکن، و اندازهٔ هر ردیف محدود نیست.
- در گفتگوی دهنوبتی اندازهگیریشده، تاریخچه ۱٬۱۵۴٬۰۹۳ توکن و ۵.۶۳ دلار هزینه داشت.
- پنجرهٔ توکن با بودجهٔ ۳۰ هزار: ۱۹۵٬۴۶۷ توکن؛ ولی اگه یه نتیجهٔ ابزار از کل بودجه بزرگتر باشه همون صفحه حذف میشه.
- استاب کردن نتیجههای کهنه: ۲۰۸٬۱۲۷ توکن، بدون حذف هیچ پیامی و بدون از دست دادن لینکها.
- خلاصهسازی در چکپوینت: ۸۲٬۵۶۰ توکن، ولی نوبت دهم هیچکدوم از پنج لینک خواستهشده رو نداد.
- کوتاه کردن تاریخچه وسط یک ران کار نمیکنه؛ ایشو #669 روی مخزن laravel/ai هنوز بازه.




