Knaph

مدیریتِ زمینه25 از 37

کوتاه کردن، بی‌آنکه بشکند

در درسِ «[فشرده‌سازی در کد](compaction-in-code)» راهِ ارزان‌ترِ کوتاه کردنِ تاریخچه‌ی یک عامل را دیدید: قدیمی‌ترین نوبت‌ها را دور بریزید و بقیه را کلمه به کلمه نگه دارید. این راه یک قاعده دارد که هرگز نباید بشکند. هر tool_use با tool_result که به آن جواب می‌دهد همراه است، وگرنه API درخواست را رد می‌کند. اینجا همین کوتاه کردن را می‌نویسید. ## ورودی خطِ اول بودجه است. بعد برای هر پیام یک خط، از قدیمی‌ترین: نقشش، چند توکن دارد، و چه نوع پیامی است (task، text، tool_use یا tool_result): ``text budget 10000 user 1200 task assistant 300 tool_use user 4000 tool_result assistant 200 tool_use user 2500 tool_result assistant 250 tool_use user 3000 tool_result assistant 150 tool_use user 900 tool_result ` پیامِ ۰ کار است. بعد از آن، تاریخچه از **نوبت‌ها** ساخته شده است: یک پیامِ assistant، و بعد پیامِ user که به آن جواب می‌دهد. پیام‌های ۱ و ۲ یک نوبت‌اند، ۳ و ۴ نوبتِ بعد، و همین‌طور تا آخر. فهرست همیشه با یک پیامِ user تمام می‌شود: جوابِ تازه‌ترین نوبت، که مدل می‌خواهد بخواندش. ## آنچه باید بنویسید trim(messages, budget) را کامل کنید. این تابع شماره‌ی پیام‌هایی را که باید بمانند برمی‌گرداند، یا None: 1. **پیامِ ۰، یعنی کار، را همیشه نگه دارید.** 2. **تازه‌ترین نوبت را همیشه نگه دارید**، یعنی دو پیامِ آخر را. 3. **نوبت‌ها را از قدیمی‌ترین دور بریزید**، هر بار یک نوبتِ کامل: اول پیام‌های ۱ و ۲، بعد ۳ و ۴، و همین‌طور. 4. **به محضِ اینکه پیام‌های مانده جا شدند، بایستید**: یعنی جمعِ توکن‌هایشان بودجه یا کمتر شد. بیشتر از لازم دور نریزید. 5. **اگر حتی پیامِ ۰ و تازه‌ترین نوبت از بودجه بیشترند**، None برگردانید. در نمونه‌ی بالا، کلِ تاریخچه ۱۲٬۵۰۰ توکن است. دور ریختنِ قدیمی‌ترین نوبت (پیام‌های ۱ و ۲) آن را به ۸٬۲۰۰ می‌رساند که جا می‌شود، پس خروجی این است: `text dropped: 1 2 kept: 0 3 4 5 6 7 8 (8,200 tokens) ` main این را از فهرستی که برمی‌گردانید چاپ می‌کند، و برای None عبارتِ cannot fit را چاپ می‌کند. <details> <summary>یک راهنمایی، اگر گیر کردید</summary> با kept = list(range(len(messages))) شروع کنید. تا وقتی پیام‌های مانده از بودجه بیشترند و هنوز نوبتِ قدیمی‌ای برای دور ریختن هست (بیشتر از سه پیام مانده)، دو شماره‌ی درست بعد از کار را حذف کنید: del kept[1:3]. </details> ببینید چرا دور ریختنِ نوبت‌های کامل برای معتبر ماندنِ تاریخچه کافی است. هر tool_result در همان پیامِ user است که درست بعد از پیامِ assistant دارنده‌ی tool_use آن می‌آید، پس حذفِ هر دو با هم هرگز یکی را بی‌دیگری نمی‌گذارد، و نقش‌ها هنوز نوبتی‌اند: user، assistant، user`.

ورود برای امتحان این تمرین.