Knaph

مدیریتِ زمینه23 از 375 دقیقه مطالعه

شمردنِ آنچه می‌فرستید

لیلا برای اولین بار mini را روی یک پروژه‌ی واقعی اجرا می‌کند: چهل فایل، مجموعه‌ای از آزمون‌ها، و کاری که بیست دقیقه طول می‌کشد. کار انجام می‌شود. اما هزینه‌ی همین یک کار از همه‌ی اجراهای تمرینی‌اش روی هم بیشتر است، و نزدیکِ آخر انگار mini یادش رفته بود لیلا چه خواسته بود. لیلا پیش از اینکه چیزی را تغییر دهد، می‌خواهد ببیند: هر درخواستی که mini می‌فرستد چقدر بزرگ است، و از چه ساخته شده؟


لیلا می‌توانم خودم بشمارم. نویسه‌های همه‌ی چیزهای messages را جمع کنم و تقسیم بر چهار کنم.

امید می‌توانی. چه چیزی را از قلم می‌اندازد؟

لیلا پرامپت سیستمی و توضیحِ ابزارها را، مگر یادم بماند. تازه آن چهار فقط یک قاعده‌ی سرانگشتی برای انگلیسی است. گزارش‌های من جدول و عدد دارند.

امید پیام‌ها هم فقط متن نیستند: فراخوانیِ ابزار، نتیجه‌ها، فکر کردنِ مدل. چه کسی دقیقاً می‌داند همه‌ی این‌ها چند توکن شد؟

لیلا خودِ API. باید تک‌تکشان را می‌خواند.

امید پس از خودش بپرس. هر پاسخ دقیقاً می‌گوید درخواست چند توکن داشت، و راهی هم هست که پیش از فرستادن بپرسی.


اندازه‌ی هر درخواست

هر پاسخ یک شیءِ usage (مصرف) دارد: شمارشِ خودِ API از آنچه فرستادید و آنچه نوشت. آن را در درسِ «خواندنِ پاسخ» دیدید. برای مدیریتِ زمینه، سؤال این است: درخواستی که همین الان فرستادم چقدر بزرگ بود؟ جوابش جمعِ سه بخش است:

u = response.usage
size = u.input_tokens + u.cache_read_input_tokens + u.cache_creation_input_tokens
print(f"turn {turn + 1}: request {size:,} tokens, reply {u.output_tokens:,}")
Python

چرا سه بخش؟ به خاطرِ کش، که در پایانِ همین بخش به آن می‌رسیم. وقتی بخشی از درخواست از کش خوانده می‌شود، آن توکن‌ها در cache_read_input_tokens شمرده می‌شوند، نه در input_tokens؛ توکن‌هایی که تازه در کش نوشته می‌شوند در cache_creation_input_tokens می‌روند. فقط باقیِ آن input_tokens است. هر سه را جمع کنید تا کلِ درخواست را داشته باشید، چه از کش آمده باشد چه نه. (اشتباهی رایج این است که فقط input_tokens را نگاه کنیم، ببینیم پس از راه افتادنِ کش کوچک مانده، و خیال کنیم زمینه بزرگ نمی‌شود.)

یک درخواست به شکلِ یک نوار، در سه بخش: آغازِ آن که از کش خوانده شد (cache_read_input_tokens)، بخشی که تازه در کش ذخیره شد (cache_creation_input_tokens) و باقیِ آن (input_tokens). جمعِ هر سه اندازه‌ی درخواست است.

آن print را در حلقه‌ی mini، درست بعد از رسیدنِ پاسخ بگذارید و یک کارِ واقعی را اجرا کنید. شکلی را که در پنجره‌ی زمینه دیدید، در عددهای خودتان خواهید دید: هر نوبت کمی بزرگ‌تر از قبلی، با جهش‌هایی ناگهانی جایی که ابزاری چیزِ بزرگی برگردانده است.

اندازه‌ی درخواست، نوبت به نوبت، در یک جلسه‌ی ۲۰ نوبتیِ mini. ستون‌ها با هر نوبت کمی بلندتر می‌شوند و در نوبتِ ۶، جایی که mini یک فایلِ بزرگ خواند، یک‌باره بالا می‌روند. یک خطِ‌چین بودجه‌ی ۱۵۰٬۰۰۰ توکنیِ mini را نشان می‌دهد، خیلی پایین‌تر از پنجره‌ی ۱٬۰۰۰٬۰۰۰ توکنی.

شمردن پیش از فرستادن

گاهی عدد را پیش از خرج کردنِ هر چیزی می‌خواهید: این فایل جا می‌شود؟ این متنِ بلندی که می‌چسبانم چقدر اضافه می‌کند؟ API برای این کار یک endpoint جدا دارد: count_tokens. همان آرگومان‌های یک درخواست را می‌گیرد و بی‌آنکه مدل را اجرا کند، شمارش را برمی‌گرداند:

def tokens_in(text):
    """How many tokens `text` would add, as a user message."""
    count = client.messages.count_tokens(
        model=MODEL, messages=[{"role": "user", "content": text}])
    return count.input_tokens
 
 
print(tokens_in(Path("big_report.csv").read_text()))
Python

شمردن رایگان است، اما باز هم یک درخواست به API است، پس کمی طول می‌کشد و مثل هر درخواستِ دیگری محدودیتِ تعداد دارد. اگر system= و tools= را هم بدهید، اندازه‌ی یک درخواستِ کامل را پیش از فرستادنش می‌گیرید. با همان مدلی بشمارید که واقعاً به آن می‌فرستید: توکن‌سازِ خانواده‌های مختلفِ مدل فرق می‌کند، پس یک متن ممکن است جورِ دیگری شمرده شود.

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

چند جلسه را اندازه بگیرید، معمولاً همین تصویر را می‌بینید:

  • آغازِ ثابت (پرامپت سیستمی و توضیحِ ابزارها) برای mini کوچک است: حدودِ هزار توکن. در بخشِ بعد که دستورها و مهارت‌ها را اضافه می‌کنید، بزرگ‌تر می‌شود.
  • پیام‌های خودِ مدل کوتاه‌اند: یک جمله، یک فراخوانیِ ابزار.
  • نتیجه‌های ابزار تقریباً همه‌چیزند. یک read_file از فایلی ۳٬۰۰۰ خطی می‌تواند ۳۰٬۰۰۰ توکن باشد، و از آن به بعد در همه‌ی درخواست‌ها می‌ماند.

برای همین هوکِ cut_long_output در mini از هر نتیجه حداکثر ۱۰٬۰۰۰ نویسه نگه می‌دارد (حدودِ ۲٬۵۰۰ توکنِ انگلیسی). برای همین هم یک read_file بهتر بازه‌ای از خط‌ها را می‌گیرد، و یک ابزارِ جست‌وجو از خواندنِ کاملِ فایل‌ها بهتر است. ارزان‌ترین توکن آن است که هرگز وارد زمینه نشود.

چرا بودجه‌ای خیلی پایین‌تر از پنجره

mini CONTEXT_BUDGET = 150_000 را تنظیم می‌کند، هرچند پنجره‌ی مدل یک میلیون توکن جا دارد. سه دلیل، که حالا می‌توانید در عددهای خودتان ببینید:

  • هر نوبت هزینه‌ی کلِ درخواست را می‌دهد. یک درخواستِ ۶۰۰٬۰۰۰ توکنی، با قیمتِ ۴ دلار برای هر میلیون و پیش از کش، در هر نوبت حدودِ ۲٫۴۰ دلار هزینه‌ی ورودی دارد.
  • زمینه‌ی شلوغ بدتر کار می‌کند. پاسخ‌ها معمولاً وقتی زمینه با نتیجه‌های قدیمی پر می‌شود مبهم‌تر می‌شوند، خیلی پیش از آنکه پنجره پر شود.
  • پاسخ هم جا لازم دارد، در همان پنجره.

وقتی درخواستی از بودجه بگذرد، mini فشرده‌سازی می‌کند. این موضوعِ درسِ بعد است.

امتحان کنید

خطِ print را به حلقه‌ی mini اضافه کنید و کاری در یک پروژه‌ی واقعی به آن بدهید: «find where the tests are and tell me how many there are». اندازه‌ها را نوبت به نوبت بخوانید و جهشی را پیدا کنید که در آن چیزِ بزرگی خوانده است. کلید ندارید؟ نمودارِ ستونیِ بالا را بردارید و تخمین بزنید جمعِ ۲۰ درخواست چقدر می‌شود: این همان تعدادِ توکن‌های ورودی است که جلسه فرستاد.

درست به کار بردن

  1. وقتی عامل می‌سازید، اندازه‌ی درخواست را در هر نوبت ثبت کنید. یک خط خروجی بیشتر از هر حدسی درباره‌ی زمینه‌ی عاملتان می‌گوید.
  2. هر سه بخشِ ورودی را جمع بزنید. به محضِ اینکه کش کار کند، input_tokens به‌تنهایی دیگر «اندازه‌ی درخواست» نیست.
  3. پیش از افزودنِ چیزی بزرگ بشمارید. count_tokens رایگان است؛ با آن تصمیم بگیرید فایلی کامل وارد شود، تکه‌ای از آن، یا اصلاً نه.
  4. نتیجه‌های ابزار را در همان سرچشمه کوچک کنید. یک سقف، یک بازه‌ی خط یا یک ابزارِ جست‌وجو، زمینه را برای همه‌ی نوبت‌های بعد کوچک نگه می‌دارد.

واژه‌های این درس

  • usage (مصرف) - بخشی از هر پاسخ که توکن‌های درخواست (input_tokens، cache_read_input_tokens، cache_creation_input_tokens) و پاسخ (output_tokens) را گزارش می‌کند
  • count_tokens - یک endpoint از API که توکن‌های یک درخواست را بی‌آنکه مدل را اجرا کند می‌شمارد؛ رایگان
  • بودجه‌ی زمینه (context budget) - سقفی که خودتان، خیلی پایین‌تر از پنجره، تعیین می‌کنید و عاملتان با رسیدن به آن زمینه‌اش را کوتاه می‌کند

ایده‌ی اصلی

لازم نیست زمینه‌ی عاملتان را حدس بزنید: API اندازه‌ی هر درخواست را گزارش می‌کند و می‌تواند یک درخواست را پیش از فرستادن بشمارد. در هر نوبت اندازه بگیرید تا ببینید نتیجه‌های ابزار پنجره را پر می‌کنند، پس همان‌جاست که باید برید.

دانش خود را بسنجید

ورود برای سنجش دانش خود از این درس و پیگیری پیشرفتتان.