پرش به محتوا
17/30فصل 17 از 30

Temperature، Top-p و قطعیتی که ندارید

temperature پیش از softmax، logitها را تقسیم می‌کند؛ همین واقعیت ایدهٔ «پیچ خلاقیت» را از بین می‌برد.

در این صفحه

این همان درخواست است که پنج بار به همان مدل فرستاده شده. همان وزن‌ها، همان prompt، همان ماشین، همان seed تصادفی. تنها چیزی که عوض می‌شود یک عدد است.

TEXT
prompt: "Q: What is the capital of France?\nA:"

T = 0.0   " Paris\nWhat is the question and does the answer answer it? The
           question is: What is the capital of France?..."

T = 0.7   " Paris\nWhat is the question: Which city is the capital of
           France?..."

T = 1.0   " Paris\nWhat is a good geographical qualifier for describing
           Paris concerning its location?\nA: Near the Mediterranean Sea..."

T = 1.5   " Paris\nWhat clue from premise allows we to conclude that Godwin
           was &, He chose Healing Crimson Colour No:white flour Pure..."

T = 2.0   "安全感金华.ITEMT]]];\naims assume parental.st-importe.valtermination
           Screens قطر_Zeroหมายเลข-zA ('$ספטמבר..."

هیچ‌چیز خراب نشده. هر token در خط آخر به‌طور کاملاً معتبر از توزیع احتمال خود مدل روی واژگان 151,936تایی‌اش بیرون کشیده شده است. عددی که تغییر کرده temperature نام دارد، در بیشتر مستندات مثل یک پیچ تنظیم خلاقیت توصیف می‌شود، و این توصیف به شکلی غلط است که این فصل می‌تواند به‌جای ادعا کردن، نشانش بدهد.

این همان فصلی هم هست که سه وعدهٔ قبلی موعدشان می‌رسد. فصل 4 logit را تعریف کرد و واقعاً خرجش نکرد. جعبهٔ ممیز شناور فصل 2 با یک دستور تمام شد — این را به خاطر بسپارید وقتی فصل 17 می‌پرسد چرا همان prompt، مدل و seed می‌تواند tokenهای متفاوت تولید کند. و جعبهٔ mixture-of-experts فصل 9 وعدهٔ فهرستی از چهار علت نادترمینیستی بودن را داد. هر سه پایین‌تر می‌رسند.

یک خطی که کل فصل به آن آویزان است

لینک به بخش: یک خطی که کل فصل به آن آویزان است

فصل 4 logit را به‌عنوان یک امتیاز حقیقی نرمال‌نشده معرفی کرد، یکی برای هر کلاس. فصل 8 کاری کرد یک مدل زبانی برای هر ورودی واژگان یکی از آن‌ها تولید کند. softmax آن بردار z\mathbf{z} را به احتمال‌ها تبدیل می‌کند:

pi=ezijezjp_i = \frac{e^{z_i}}{\sum_j e^{z_j}}

temperature همین‌جا وارد می‌شود — نامش از فیزیک آماری قرض گرفته شده، جایی که همین پارامتر کنترل می‌کند یک توزیع بولتزمان با چه شدتی روی حالت‌های کم‌انرژی‌اش متمرکز شود1 — و logitها را پیش از نمایی‌سازی تقسیم می‌کند:

pi(T)=ezi/Tjezj/Tp_i(T) = \frac{e^{z_i/T}}{\sum_j e^{z_j/T}}

همین جای‌گذاری کل سازوکار است، و ارزش دارد با دو خط جبر ببینیم چرا نمی‌توانست جای دیگری باشد. فرض کنید تلاش کنید temperature را به‌جای logitها روی احتمال‌ها اعمال کنید — آن‌ها را در 1/T1/T مقیاس کنید و دوباره نرمال‌سازی کنید. به این می‌رسید:

pi/Tjpj/T=pijpj=pi\frac{p_i/T}{\sum_j p_j/T} = \frac{p_i}{\sum_j p_j} = p_i

ثابت حذف می‌شود. مقیاس‌کردن احتمال‌ها هیچ کاری نمی‌کند؛ توزیع بدون تغییر برمی‌گردد. temperature فقط به این دلیل اثر دارد که روی توان عمل می‌کند، جایی که تقسیم بر TT پیش از نمایی‌سازی همان است که هر احتمال را به توان 1/T1/T برسانیم — یک بازشکل‌دهی غیرخطی که به‌جای مقیاس مشترک ورودی‌ها، نسبت‌های بین آن‌ها را عوض می‌کند.

از همین جای‌گذاری، هر دو حد بدون هیچ کار اضافه‌ای نتیجه می‌شوند. وقتی T0T \to 0 بزرگ‌ترین logit از بقیه جدا می‌شود و pp روی تنها token با بالاترین امتیاز فرو می‌ریزد: greedy decoding. وقتی TT رشد می‌کند، هر zi/Tz_i/T به سمت صفر می‌رود، هر نمایی به سمت 1 می‌رود، و توزیع به سمت یکنواختی روی کل واژگان تخت می‌شود. دقیقاً در T=0T = 0 فرمول بر صفر تقسیم می‌کند، بنابراین هر پیاده‌سازی آن را به‌صورت مورد ویژه به بیشینهٔ حسابی تبدیل می‌کند — از جمله ویجت پایین، که در T0.001T \le 0.001 به argmax سوئیچ می‌کند.

یک هشدار، چون برخورد نام‌ها واقعاً گیج‌کننده است. در machine learning چیز دوم و بی‌ربطی هم به نام temperature وجود دارد: temperature scaling، روشی برای کالیبراسیون که یک مقدار را روی مجموعهٔ اعتبارسنجی fit می‌کند تا اطمینان یک classifier با دقتش جور شود.2 همان فرمول، بی‌ربط به generation. مقاله‌هایی که می‌گویند «temperature» اغلب منظورشان همان یکی است؛ این فصل هرگز منظورش آن نیست.

این همان توزیع است، با محاسبات جلوی چشم شما. logitها ثابت و باورپذیرند، پس عددهای متن پایین را می‌توانید با چیزی که می‌بینید بسنجید:

  • ␣Paris96.9%
  • ␣the1.3%
  • ␣located0.8%
  • ␣a0.5%
  • ␣Lyon0.2%
  • ␣called0.1%
  • ␣home0.1%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

10 از 10 توکن از برش عبور می‌کنند و احتمال را بین خود تقسیم می‌کنند.

مشاهده داده‌ها به‌صورت جدول
توکنlogitپس از دماپس از برش
␣Paris⁨9.4⁩96.90%96.90%
␣the⁨5.1⁩1.31%1.31%
␣located⁨4.6⁩0.80%0.80%
␣a⁨4.1⁩0.48%0.48%
␣Lyon⁨3.2⁩0.20%0.20%
␣called⁨2.9⁩0.15%0.15%
␣home⁨2.4⁩0.09%0.09%
␣Marseille⁨1.8⁩0.05%0.05%
␣not⁨1.1⁩0.02%0.02%
␣banana⁨-2.6⁩0.00%0.00%
نمونه‌گیری: دما، top-p و top-k

ده ادامهٔ نامزد برای The capital of France is، در temperature برابر 1 بدون هیچ برشی. ␣Paris 96.90 % جرم را نگه می‌دارد؛ ␣banana، در پایین با logit برابر 2.6-2.6، 0.00 % می‌گیرد. temperature را به 0 ببرید و یک token با 100 % زنده می‌ماند. آن را به 2 ببرید و ␣Paris به 69.81 % می‌افتد، درحالی‌که ␣banana به 0.17 % بالا می‌آید — token ردشدهٔ مدل، که با پیچی که خواننده چرخانده احتمال واقعی گرفته است.

عدد ␣banana کل استدلال را در اندازهٔ کوچک نشان می‌دهد: بالا بردن temperature نمی‌تواند به مدل ایده‌ای بدهد که نداشته است. logitها از قبل محاسبه شده‌اند، رتبه‌بندی از قبل ثابت شده، و temperature آن را دقیقاً حفظ می‌کند — هیچ مقدار گرما هرگز token با امتیاز پایین‌تر را بالاتر از token با امتیاز بالاتر نمی‌برد. تنها کاری که می‌کند بازتوزیع جرم به سمت پایین رتبه‌بندی‌ای است که خود مدل تولید کرده. temperature بالا مدل را مبتکرتر نمی‌کند؛ فقط احتمال اینکه tokenهایی را emit کند که خودش بد امتیاز داده بیشتر می‌کند.

روی یک واژگان واقعی، این دیگر کنجکاوی نیست و به دلیل غیرقابل‌استفاده بودن خروجی با temperature بالا تبدیل می‌شود. اندازه‌گیری‌شده روی Qwen/Qwen2.5-0.5B-Instruct، یک forward pass، prompt بالا، با شمارش اینکه چند token لازم است تا سهم مشخصی از جرم احتمال جمع شود:

temperatureاحتمال top-1entropytokenهای نگهدارندهٔ 80 %90 %95 %99 %
0.599.98 %0.00 nats1111
0.799.65 %0.03 nats1111
1.096.01 %0.30 nats11114
1.288.20 %0.88 nats1213252
1.562.83 %3.07 nats293532,67226,787
2.016.62 %8.19 nats13,51632,96655,231101,205

ردیف آخر را آهسته بخوانید. در T=2T = 2، روی پرسشی با دقیقاً یک پاسخ درست، 32,966 token مختلف 90 % بالایی جرم احتمال را شریک می‌شوند. این فضای خلاقانهٔ گسترده‌تر نیست. این مدلی است که حساب به آن گفته یک پسوند کره‌ای و یک شناسهٔ C++ را گزینه‌های زنده برای کلمهٔ بعد از A: بداند. آشغال موجود در بلوک آغازین پیامد مستقیم همین است، و bug مدل یا library نیست — همان چیزی است که درخواست خواسته بود.

بازهٔ مفید باریک است و به task بستگی دارد نه سلیقه. در یک پرسش factual پاسخ یک token است و هر گرمایی بالاتر از حدود 1.2 بی‌دلیل خطا تزریق می‌کند. در یک پرسش open-ended واقعاً بیش از یک ادامهٔ خوب وجود دارد، و کمی گرما تنوعی می‌خرد که هنوز روان می‌ماند:

TEXT
"Write a two-sentence story about a lighthouse."

T = 0.0  "The lighthouse stood tall and proud, its beacon illuminating the
          night sky above. A lone sailor, his eyes fixed on the distant
          horizon..."

T = 0.7  "In the quiet, stormy waters of the sea, a lighthouse stood
          sentinel over the horizon, its golden dome casting a warm glow
          on the fog-shrouded streets below..."

T = 1.0  "In the quiet night, a lone lighthouse stood sentinel over the
          sea, its shining beacon a beacon of hope and solace for sailors
          and fishermen across the vast and endless ocean..."

T = 1.3  "In the gentle sunlight, now reflecting upon the opening of Jack's
          lighthouse, Jim Trahan, a small-time individual difficult to
          define in paperwork, wondered about a career where simplicity
          reigns..."

در 1.3 مدل یک نام خاص و جمله‌ای ساخته که parse نمی‌شود. نوار بین «هر بار یکسان» و «نامنسجم» برای این مدل روی این task تقریباً 0.6 تا 1.1 است، و توصیهٔ صادقانه این است که آن را با اندازه‌گیری روی task خودتان پیدا کنید، نه با کپی کردن عددی از یک پست وبلاگ.

چرا محتمل‌ترین متن، متن بدی است

لینک به بخش: چرا محتمل‌ترین متن، متن بدی است

یک پرسش بدیهی زیر همهٔ این‌ها پنهان است: اگر مدل یک توزیع احتمال دارد و یک token محتمل‌تر است، چرا همیشه همان را نگیریم؟ greedy decoding رایگان، بازتولیدپذیر و بی‌نیاز از پارامتر است.

چون نتیجه این است:

TEXT
prompt: "In a shocking finding, scientists discovered a herd of unicorns
         living in a remote valley."

greedy: " The unicorns were so rare that they were not even recognized by
         the local people. The unicorns were so rare that they were not
         even recognized by the local people. The unicorns were so rare
         that they were not even recognized by the local people. ..."

         repeated 4-grams: 87.6 %

هشت جمله، یک جمله. تقریباً نه از هر ده پنجرهٔ چهارتوکنی قبلاً در همان خروجی ظاهر شده بود. این neural text degeneration است، که Holtzman و همکاران در مقاله‌ای که top-p را معرفی کرد نام‌گذاری و توضیحش دادند.3 مدل خراب نیست؛ بیشینه‌سازی احتمال دنباله صرفاً هدف غلطی برای متن open-ended است. نوشتار انسانی محتمل‌ترین دنبالهٔ کلمات نیست — غافلگیری دارد، احتمال per-token آن پرسه می‌زند، افت می‌کند و برمی‌گردد — درحالی‌که مسیر با بیشینهٔ احتمال یک نقطهٔ ثابت است که وقتی واردش شد، دلیلی برای خروج ندارد.

اصلاً sampling به همین دلیل وجود دارد. و همچنین، بخشی که معمولاً حذف می‌شود، یک قانون جهان‌شمول نیست. فصل 12 روی مسائل واژه‌ای دو مرحله‌ای با greedy decoding ساده 24 از 24 پاسخ درست اندازه گرفت، و sampling در temperature برابر 0.8 آن را به 81 % پایین آورد؛ سپس self-consistency شش برابر token خرج کرد تا دوباره به جایی برسد که greedy از اول آنجا بود. هر دو واقعیت همزمان درست‌اند:

open-ended generation. ادامهٔ واحدِ درست وجود ندارد، پس محتمل‌ترین ادامه یک دام است — loop می‌شود، و 87.6 % آن از خودش کپی شده. sample کنید.

taskهایی با یک پاسخ درست. یک ادامهٔ درستِ واحد وجود دارد، پس کشیدن هر چیز دیگر یعنی کشیدن خطا. 100 % فصل 12 دقیقاً به همین دلیل 81 % شد. sample نکنید.

بیشتر promptهای production از نوع دوم‌اند و مثل نوع اول پیکربندی می‌شوند، چون temperature همان مقداری رها شده که کد نمونه استفاده کرده بود.

دو راه برای بریدن، و فقط یکی از آن‌ها سازگار می‌شود

لینک به بخش: دو راه برای بریدن، و فقط یکی از آن‌ها سازگار می‌شود

sampling از توزیع کامل کاری نیست که کسی واقعاً انجام دهد، چون دُم عظیم و پر از بی‌معنایی است. باید چیزی بریده شود. دو پاسخ کلاسیک وجود دارد و آن‌ها در یک جهت تفاوت دارند که همه‌چیز را تعیین می‌کند.

Top-k تعداد ثابتی از نامزدها را نگه می‌دارد. بر اساس احتمال مرتب کنید، kk اول را نگه دارید، بقیه را دور بریزید، دوباره نرمال‌سازی کنید.4 Top-p، که nucleus sampling هم نامیده می‌شود، مقدار ثابتی از جرم را نگه می‌دارد: tokenها را به‌ترتیب نزولی بردارید تا احتمال تجمعی‌شان به pp برسد، و توقف کنید.3 به‌صورت رسمی، nucleus کوچک‌ترین مجموعهٔ VpV_p است با

iVppip\sum_{i \in V_p} p_i \ge p

تفاوت ظاهراً جزئی است اما نیست، چون دو promptی که در یک دقیقه می‌فرستید شکل‌های کاملاً متفاوتی از توزیع دارند. هر دو، همان مدل در temperature برابر 1 هستند:

Q: What is the capital of France?\nA:Once upon a time,
احتمال top-196.01 %25.39 %
tokenهای نگهدارندهٔ 90 % جرم1467
top-k = 40 نگه می‌دارد99.61 % جرم78.87 % جرم
جرم در رتبه‌های 2 تا 403.61 %53.48 %
token در رتبهٔ 40␣Av، 0.0093 %␣Dr، 0.128 %

یک kk ثابت، دو شکست در جهت مخالف. روی prompt factual، k=40k = 40 39 token را راه می‌دهد که مجموعاً 3.6 % می‌ارزند — آشغال را عبور می‌دهد، از جمله نامزدی در حد نه هزارم درصد، چون قانون slotها را می‌شمارد نه شواهد را. روی prompt داستانی، همان k=40k = 40، 21 % جرمی را که مدل واقعاً اختصاص داده دور می‌اندازد، چون nucleus واقعی آنجا 467 token پهنا دارد.

Top-p با دقیقاً یک عدد هر دو کار را انجام می‌دهد. p=0.9p = 0.9 را تنظیم کنید و روی prompt اول 1 token و روی prompt دوم 467 token نگه می‌دارد، چون دربارهٔ توزیع سؤال می‌پرسد نه اینکه شمارشی را به آن تحمیل کند. این سازگاری را مستقیم ببینید — همان برش، چهار temperature:

  • ␣Paris91.1%
  • ␣the5.2%
  • ␣located3.7%
  • ␣a0.0%
  • ␣Lyon0.0%
  • ␣called0.0%
  • ␣home0.0%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

3 از 10 توکن از برش عبور می‌کنند و احتمال را بین خود تقسیم می‌کنند.

مشاهده داده‌ها به‌صورت جدول
توکنlogitپس از دماپس از برش
␣Paris⁨9.4⁩85.03%91.10%
␣the⁨5.1⁩4.84%5.18%
␣located⁨4.6⁩3.47%3.71%
␣a⁨4.1⁩2.48%
␣Lyon⁨3.2⁩1.36%
␣called⁨2.9⁩1.12%
␣home⁨2.4⁩0.80%
␣Marseille⁨1.8⁩0.54%
␣not⁨1.1⁩0.34%
␣banana⁨-2.6⁩0.03%
نمونه‌گیری: دما، top-p و top-k

Top-p در 0.90 با temperature برابر 1.5: سه token از ده token زنده می‌مانند و جرم را شریک می‌شوند، ␣Paris دوباره به 91.10 % نرمال‌سازی می‌شود. حالا فقط temperature را جابه‌جا کنید. در 0.7 همان 0.90 یک بازمانده باقی می‌گذارد — nucleus به این باریکی همان greedy decoding با نامی دیگر است. در 2.0 پنج بازمانده می‌گذارد. برش هرگز جابه‌جا نشد؛ شکل زیر آن عوض شد.

آن ویجت همچنین یک برداشت غلط را روشن می‌کند که نام‌بردنش می‌ارزد، چون برای افراد پول واقعی هزینه دارد. روی یک توزیع مطمئن، top_p = 0.9 «کمی تنوع» نیست. greedy است. در temperature برابر 1، token پیشتاز اینجا 96.90 % دارد، که از 0.9 بیشتر است، پس nucleus پهنای یک token دارد و هیچ چیز دیگری هرگز نمی‌تواند کشیده شود. تیم‌ها top_p را روی 0.9 می‌گذارند با این باور که چیزی را آزادتر کرده‌اند و بعد تعجب می‌کنند چرا هر پاسخ یکسان است.

به‌جایش top-k را تنظیم کنید و شکست مخالف به همان اندازه پیداست:

  • ␣Paris97.2%
  • ␣the1.3%
  • ␣located0.8%
  • ␣a0.5%
  • ␣Lyon0.2%
  • ␣called0.0%
  • ␣home0.0%
  • ␣Marseille0.0%
  • ␣not0.0%
  • ␣banana0.0%

5 از 10 توکن از برش عبور می‌کنند و احتمال را بین خود تقسیم می‌کنند.

مشاهده داده‌ها به‌صورت جدول
توکنlogitپس از دماپس از برش
␣Paris⁨9.4⁩96.90%97.20%
␣the⁨5.1⁩1.31%1.32%
␣located⁨4.6⁩0.80%0.80%
␣a⁨4.1⁩0.48%0.49%
␣Lyon⁨3.2⁩0.20%0.20%
␣called⁨2.9⁩0.15%
␣home⁨2.4⁩0.09%
␣Marseille⁨1.8⁩0.05%
␣not⁨1.1⁩0.02%
␣banana⁨-2.6⁩0.00%
نمونه‌گیری: دما، top-p و top-k

Top-k در 5، بدون top-p. پنج token در هر temperature زنده می‌مانند، چون پنج همان چیزی است که خواسته شده. در temperature برابر 1، همان‌طور که نشان داده شده، چهار نامزد زیر ␣Paris مجموعاً 2.79 % می‌ارزند. به 0.7 پایین بیاورید و همان چهار token 0.38 % می‌ارزند — برش نمایش است، و مدل عملاً greedy است. آن را به 2.0 بالا ببرید و آن‌ها 22.54 % می‌ارزند. تنظیم یکسان، تعداد بازماندهٔ یکسان، سه رفتار کاملاً متفاوت، و هیچ چیز در درخواست به شما نمی‌گوید کدام را می‌گیرید.

جریمه‌ها، با فرمول‌ها، چون اشتباه گرفتنشان همه‌گیر است

لینک به بخش: جریمه‌ها، با فرمول‌ها، چون اشتباه گرفتنشان همه‌گیر است

سه سازوکار متفاوت با نام‌های مشابه جابه‌جا می‌شوند، کارهای متفاوتی می‌کنند، و تفاوتشان قابل‌اندازه‌گیری است. بگذارید cic_i تعداد دفعاتی باشد که token ii قبلاً ظاهر شده است.

ziziα1[ci>0]z_i \leftarrow z_i - \alpha \cdot \mathbb{1}[c_i > 0]

از هر tokenی که اصلاً ظاهر شده یک ثابت کم کنید. یک بار ظاهر شدن و چهل بار ظاهر شدن دقیقاً یکسان جریمه می‌شوند. این یک سوئیچ است، نه پیچ تنظیم.

ziziβciz_i \leftarrow z_i - \beta \, c_i

به تناسب تعداد کم کنید. tokenی که چهار بار استفاده شده چهار برابر سخت‌تر از tokenی که یک بار استفاده شده جریمه می‌شود، و فشار با رشد متن مرکب می‌شود.

zi{zi/ρif zi>0ziρif zi0z_i \leftarrow \begin{cases} z_i / \rho & \text{if } z_i > 0 \\ z_i \cdot \rho & \text{if } z_i \le 0 \end{cases}

نسخهٔ اصلی، از مقالهٔ CTRL.7 به‌جای تفریق، تقسیم می‌کند، با حالت علامت که لازم است چون تقسیم کردن یک logit منفی آن را بزرگ‌تر می‌کند. بنابراین قدرتش به بزرگی logit بستگی دارد، یعنی همان ρ\rho در نقاط مختلف همان جمله اثر متفاوتی می‌گذارد.

همان ادامهٔ degenerate قبلی، با اعمال هرکدام. «گام‌های تغییرکرده» می‌شمارد چند تا از 120 گام generation، token متفاوتی نسبت به مدلی که جریمه نشده بود انتخاب کرد. این run اینجا 120 گام است در برابر 140 گام در بلوک بالا، برای همین baseline بدون جریمه 85.5 % خوانده می‌شود نه 87.6 %:

تنظیم4-gramهای تکراریگام‌های تغییرکرده
هیچ‌چیز85.5 %0 / 120
presence 0.565.0 %3 / 120
presence 1.03.4 %11 / 120
frequency 0.56.0 %12 / 120
frequency 1.00.0 %20 / 120
repetition 1.2 (CTRL)0.0 %35 / 120

سه چیز بیرون می‌افتد. Presence در 0.5 سه تصمیم از 120 را عوض کرد و تکرار را یک‌چهارم کاهش داد — loop با مشتی token کنار هم نگه داشته شده بود. Frequency در 0.5 چهار برابر تصمیم‌های بیشتری را برای اثری بسیار بزرگ‌تر عوض کرد، چون ضریب شمارش همچنان رشد می‌کند ولی ثابت presence نه. و جریمهٔ CTRL با مقدار بسیار کپی‌شدهٔ 1.2، 35 تصمیم از 120 را بازنویسی کرد، که تلنگر نیست؛ یک مدل دیگر است.

آن عدد آخر مقدمهٔ شکستی است که کسی درباره‌اش هشدار نمی‌دهد.

جریمه‌ها با متنی که قرار است تکرار شود چه می‌کنند

لینک به بخش: جریمه‌ها با متنی که قرار است تکرار شود چه می‌کنند

کد تکرار می‌شود. جدول‌ها تکرار می‌شوند. فهرست‌ها تکرار می‌شوند. خروجی ساختاریافته طبق تعریف تکرار می‌شود — ساختار یعنی همین. جریمه نمی‌تواند تفاوت بین مدلی گیرکرده در loop و مدلی که ردیف چهارم یک جدول را درست emit می‌کند تشخیص دهد، چون هر دو مثل ظاهر شدن دوبارهٔ یک token دیده می‌شوند.

همان سه task، به سه روش generate شده:

taskهیچ‌چیزfrequency 0.5repetition 1.2
جدول markdown، 6 ردیف0 / 56 گام تغییرکرده0 / 562 / 62
تابع Python0 / 930 / 9310 / 110
فهرست bullet، 1 تا 120 / 500 / 500 / 50

frequency penalty در 0.5 روی هر سه بی‌ضرر از آب درآمد، که نتیجه‌ای مفید و کمی غافلگیرکننده است، و چیز دقیقی می‌گوید: چون هیچ تصمیمی عوض نشد، tokenهای ساختاری باید جایگاه‌هایشان را با فاصله‌ای بیش از مقدار کم‌شدهٔ جریمه برده باشند، حتی بعد از پنج و شش بار ظاهر شدن. جریمهٔ CTRL، که به‌جای تفریق تقسیم می‌کند، آن‌ها را جابه‌جا می‌کند، و این چیزی است که تولید کرد:

TEXT
repetition 1.2, markdown table:
  | n | 2^n |
  | --- | --- |
  | 0 | 1      |
  | 1 | 2       |
  | 2 | 4       |

تراز از هم می‌پاشد: مقدار padding داخل هر سلول از ردیفی به ردیف دیگر عوض می‌شود، چون رشتهٔ فاصله‌ها پیش از pipe پایانی دقیقاً از همان نوع تکراری است که جریمه برای شکستن آن وجود دارد. ظاهری است، و شش token اضافه هزینه داشت. مورد Python ظاهری نیست:

TEXT
nothing / frequency 0.5:
      total = 0
      for i in range(1, n + 1):
          total += i ** 2
      return total

repetition 1.2:
      # Initialize total_sum with 0
      total_sum = 0
      # Loop through numbers from 1 to n, incrementing by 2 each time
      for i in range(1, n + 1,

جریمه مدل را از total — که قبلاً در docstring استفاده شده بود — به total_sum هل داد، خروجی را با commentهای ساختگی پُر کرد تا بودجه‌اش را روی tokenهای استفاده‌نشده خرج کند، و بعد وارد یک range سه‌آرگومانی با stride شد. comment می‌گوید هر بار 2 تا اضافه می‌کند، که برای جمع مربع‌ها از 1 تا nn غلط است. یک repetition penalty از promptی که بدون آن درست پاسخ داده شده بود کد نادرست تولید کرد.

قاعدهٔ نتیجه کوتاه است: جریمه‌ها برای نثر open-ended هستند، و برای کد، خروجی ساختاریافته، دادهٔ جدولی و هر چیزی با schema باید خاموش باشند. فصل 18 دقیقاً دربارهٔ همان دستهٔ دوم است.

ترتیب اعمال، و اینکه چرا پاسخ را عوض می‌کند

لینک به بخش: ترتیب اعمال، و اینکه چرا پاسخ را عوض می‌کند

هر پیاده‌سازی واقعی این‌ها را با یک ترتیب مشخص اعمال می‌کند:

penalties → temperature → top-k → top-p → sample

این bookkeeping دل‌بخواهی نیست، و جابه‌جا کردن دو مرحله توزیع‌هایی واقعاً متفاوت تولید می‌کند. دو اندازه‌گیری، هر دو روی prompt factual.

برش قبل یا بعد از temperature. nucleus روی هر توزیعی که به آن داده شود محاسبه می‌شود، و temperature آن توزیع را به‌شدت عوض می‌کند:

top-p 0.9 بعد از temperaturetop-p 0.9 قبل از temperature
T=1.0T = 1.01 token1 token
T=1.5T = 1.5353 token1 token
T=2.0T = 2.032,966 token1 token

در T=2T = 2 همان تنظیم اسمی، صرفاً بسته به اینکه کدام مرحله اول اجرا شود، یک مجموعهٔ نامزد 32,966تایی یا 1تایی می‌دهد. اگر تا حالا تعجب کرده‌اید چرا بالا بردن temperature روی یک provider «هیچ کاری نمی‌کند» و روی provider دیگر با همان دو عدد خروجی را نابود می‌کند، این جدول پاسخ محتملی است.

جریمه کردن قبل یا بعد از temperature. کم کردن جریمهٔ α\alpha و بعد تقسیم بر TT، جریمهٔ مؤثر α/T\alpha/T می‌دهد؛ اول تقسیم کردن و بعد کم کردن، α\alpha می‌دهد. با presence penalty برابر 1.0 که روی token پیشتاز اعمال شده:

temperatureاول جریمه، بعد temperاول temper، بعد جریمه
0.599.858 %99.948 %
1.089.839 %89.839 %
2.010.783 %6.830 %

در T=1T = 1 یکسان‌اند، همان‌طور که باید باشند. در T=2T = 2 با ضریب 1.58 فاصله دارند. «Presence penalty 1.0» مقدار خوش‌تعریفی از جریمه نیست مگر اینکه بدانید temperature کجا اعمال می‌شود، و هیچ API این را مستند نمی‌کند.

نمایش جزئیات

اختیاری: کل pipeline، با ترتیب بالا.

شانزده خط، و همه‌چیز این فصل در آن‌هاست. همان محاسبه‌ای است که ویجت انجام می‌دهد، روی یک بردار logit واقعی به‌جای ده عدد ثابت.

sample.pyPYTHON
def sample(logits, counts, presence=0.0, frequency=0.0,
           temperature=1.0, top_k=0, top_p=1.0, generator=None):
    z = logits.clone()

    idx = torch.tensor(list(counts))                       # 1. penalties
    if len(idx):
        z[idx] -= presence
        z[idx] -= frequency * torch.tensor([float(c) for c in counts.values()])

    if temperature <= 0:                                   # 2. temperature
        return int(z.argmax())                             #    T=0 is argmax
    p = torch.softmax(z / temperature, -1)

    p, order = p.sort(descending=True)
    if top_k:                                              # 3. top-k
        p[top_k:] = 0
    p = p * ((p.cumsum(0) - p) < top_p)                     # 4. top-p

    p = p / p.sum()                                        # 5. renormalise
    return int(order[torch.multinomial(p, 1, generator=generator)])

cumsum(0) - p در خط top-p جرم تجمعی به‌جز token فعلی است، و همین باعث می‌شود nucleus شامل tokenی شود که از آستانه عبور می‌کند، نه اینکه درست قبل از آن متوقف شود. اگر این را یک واحد اشتباه بگیرید، top_p = 0.9 بی‌سروصدا به برشی کمی سفت‌تر از هر پیاده‌سازی دیگر تبدیل می‌شود.

این یکی از معدود جاهای نیمهٔ دوم دوره است که Python زبان درست است، و دلیلش ساختاری است نه سبکی: هر خط بالا لازم دارد کل بردار logitها در دست شما باشد، و روی یک HTTP API چنین برداری وجود ندارد. می‌توانید temperature و top_p را به provider بفرستید؛ نمی‌توانید آن‌ها را پیاده‌سازی کنید، و نمی‌توانید ببینید چه کردند.

API جهان‌شمولی برای sampling وجود ندارد

لینک به بخش: API جهان‌شمولی برای sampling وجود ندارد

هر provider زیرمجموعهٔ متفاوتی از این کنترل‌ها را می‌گیرد، با بازه‌های متفاوت، و بقیه را بی‌صدا نادیده می‌گیرد. این شکایت انتزاعی نیست. هر برنامه‌ای که انتخاب مدل ارائه می‌کند باید تفاوت‌ها را جایی بنویسد، و فایلی که این کار را می‌کند نقشهٔ ناسازگاری است. این چیزی است که یکی از همین کاتالوگ‌ها برای یک پارامتر در نُه منبع متنی که پشتیبانی می‌کند اعلام می‌کند:

بازهٔ اعلام‌شدهٔ temperatureمنابع
0 تا 1Anthropic، Google، Meta، Cerebras، PaLM
0 تا 1.5Mistral
0 تا 2OpenAI، DeepSeek، xAI

کلمه یکی است؛ مقیاس یکی نیست. «temperature برابر 1» روی یکی توزیع دست‌نخورده است و روی دیگری بیشینهٔ گرمای مجاز، و نصف کاتالوگ نمی‌تواند مقداری را بیان کند که نصف دیگر آن را خنثی-به‌علاوه-کمی می‌داند. بقیهٔ پیچ‌ها به همین اندازه ناهموارند: ورودی‌های OpenAI، DeepSeek و xAI، presence و frequency penalties می‌گیرند و topK ندارند؛ ورودی‌های Google، Meta، Cerebras و PaLM، topK می‌گیرند و penalties ندارند؛ Anthropic، topK، topP و stop sequences می‌گیرد و penalties ندارد؛ و دقیقاً یکی از نُه‌تا — Mistral — seed می‌گیرد. فرستادن پارامتری که provider پیاده‌سازی نکرده معمولاً اصلاً خطا تولید نمی‌کند: درخواست موفق می‌شود، پیچ هیچ کاری نمی‌کند، و شما نتیجه می‌گیرید تنظیم اثر ندارد.

و توجه کنید چنین فایلی چیست: یک ادعا دربارهٔ API شخص دیگری، نوشته‌شده در یک روز خاص، که بعداً هیچ‌چیز آن را راستی‌آزمایی نمی‌کند. کاتالوگی که برای providerی که حالا 0 تا 2 می‌پذیرد می‌گوید 0 تا 1، بی‌صدا هر درخواست را سقف‌گذاری می‌کند.

دو کنترل دیگر هم به همین خانواده تعلق دارند. logprobs، هرجا ارائه شود، log-probabilityهای token انتخاب‌شده و اغلب چند جایگزین برتر را برمی‌گرداند — تنها پنجره‌ای که به توزیعی دارید که این فصل درباره‌اش است، و پایهٔ هر heuristic اطمینان ساخته‌شده روی یک مدل بسته. و maximum tokens به‌علاوهٔ stop sequences بدون هیچ ارجاعی به احتمال generation را تمام می‌کنند: یک سقف سخت و یک تطابق رشته‌ای. هر دو به‌صورت همان finish_reason از فصل 14 ظاهر می‌شوند، جایی که length یعنی پاسخ شما به‌خاطر بودجه وسط جمله بریده شده، نه اینکه مدل آن را تمام کرده باشد.

seed را تنظیم کنید و sampling بازتولیدپذیر می‌شود. این بخش واقعی است، و تأییدش آسان است:

TEXT
seed = 1234  " Paris\nWhat is a good geographical qualifier for describing
               Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 1234  " Paris\nWhat is a good geographical qualifier for describing
               Paris concerning its location?\nA: Near the Mediterranean Sea"
seed = 7     " Paris is the capital of France. The appellation of Paris is
               \"Île de Paris\"."
seed = 7     " Paris is the capital of France. The appellation of Paris is
               \"Île de Paris\"."

درون یک seed، byte-identical؛ بین seedها متفاوت؛ دقیقاً همان‌طور که تبلیغ شده. پس چیزی که seed ثابت می‌کند draw تصادفی در خط آخر آن تابع sample است — اینکه با داشتن یک توزیع، کدام token انتخاب شود.

چیزی که ثابت نمی‌کند خود توزیع است. و دردسر همین‌جاست، چون بردار logitهایی که مدل شما تولید می‌کند یک شیء ریاضی نیست؛ خروجی میلیاردها جمع ممیز شناور است، و آن جمع‌ها ترتیب دارند.

فصل 2 این آزمایش را آماده گذاشت. همان یک میلیون عدد float32، جمع‌شده در گروه‌بندی‌های متفاوت:

TEXT
sequential          998.564270020    error vs float64: 6.393e-03
pairwise (numpy)    998.570556641    error vs float64: 1.061e-04
in 4 chunks         998.570495605    error vs float64: 1.672e-04
in 8 chunks         998.570556641    error vs float64: 1.061e-04
in 16 chunks        998.570678711    error vs float64: 1.594e-05

sequential == pairwise?  False
4 chunks == 8 chunks?    False

به خط آخر نگاه کنید. تعداد chunkها پاسخ را عوض می‌کند. این کنجکاوی‌ای دربارهٔ numpy نیست؛ خود سازوکار است، چون وقتی یک inference server یک reduction را بین تعداد بیشتر یا کمتری واحد موازی تقسیم می‌کند، دقیقاً همین کار را می‌کند. و سرور بسته به تعداد درخواست‌هایی که سرویس می‌دهد تقسیم می‌کند.

این اثر روی خود مدل است. همان prompt، همان forward pass، تنها تفاوت اینکه چند درخواست دیگر اتفاقاً در batch بوده‌اند:

TEXT
20 identical forward passes, batch of 1:  20 / 20 bit-for-bit identical

the same prompt inside a batch of  2:  147,321 of 151,936 logits differ
the same prompt inside a batch of  4:  146,515 of 151,936 logits differ
the same prompt inside a batch of  8:  146,515 of 151,936 logits differ
the same prompt inside a batch of 16:  147,321 of 151,936 logits differ

largest change to any logit: 2.5e-05

تنها اجرا شود، مدل کاملاً deterministic است — بیست pass، bit-identical. همان prompt را در batchی با درخواست‌های نامرتبط بگذارید و 97 % از logitهایش تغییر می‌کنند. هیچ‌چیز دربارهٔ درخواست شما عوض نشده. درخواست شخص دیگری رسیده است.

حالا بخش صادقانه، چون معمولاً طوری روایت می‌شود انگار پایان داستان است. تغییر 2.5×1052.5 \times 10^{-5} فقط وقتی خروجی را عوض می‌کند که دو token نامزد در همان فاصله از هم بوده باشند. در 717 گام generation روی دوازده prompt، کوچک‌ترین فاصله بین دو logit برتر 2.5×1032.5 \times 10^{-3} بود — صد برابر بزرگ‌تر از perturbation — و هیچ گامی آن‌قدر نزدیک نبود که flip شود. پس روی این مدل، در float32، روی laptop، batching هر logit را جابه‌جا کرد و هیچ tokenی را عوض نکرد.

این توصیف شرایط مساعد است، نه اطمینان‌بخشی، و یک تغییر در آن شرایط کافی است:

TEXT
same weights, same prompts, greedy decoding, no seed involved
float32 vs bfloat16:   6 of 8 answers diverge
                       first divergence at step 23, on average

  float32: "...it is scattered and dispersed into different colors,
            including blue. The blue light is scattered more than other
            colors, so it appears to come from the sky."

  bfloat16: "...it is scattered and scattered, causing the colors of the
             sun to be scattered and scattered, creating the appearance
             of a blue color."

شش پاسخ از هشت پاسخ واگرا می‌شوند، و یکی از آن‌ها به‌شدت افت می‌کند. جدول فصل 2 می‌گوید چرا: bfloat16، 7 بیت mantissa نگه می‌دارد، پس نزدیک بزرگی logit برابر 16، مقدارهای قابل‌نمایش 0.125 تا 0.125 فاصله دارند — 16.0، بعد 16.125، بعد 16.25 — و rounding می‌تواند یک logit را تا 0.0625 جابه‌جا کند. در همین حال 4.7 % از گام‌های generation اندازه‌گیری‌شده در بالا فاصلهٔ top-two زیر 0.1 داشتند. کل تفاوت دو آزمایش همین است: در float32، perturbation صد برابر کوچک‌تر از نزدیک‌ترین تصمیم بود، و در bfloat16 هم‌اندازهٔ آن است. inference تولیدی در 16-bit اجرا می‌شود، روی سخت‌افزاری با kernelهای fused و ترتیب‌های reduction که هیچ‌کس وعده نمی‌دهد ثابت نگه دارد. اینکه «نویز عددی ناچیز است» پرسشی دربارهٔ precision و سخت‌افزار است، نه دربارهٔ مدل.

پس چهار علت، همان‌طور که فصل 9 وعده داده بود، فهرست‌شده‌اند:

جمع ممیز شناور associative نیست

لینک به بخش: جمع ممیز شناور associative نیست

جعبهٔ فصل 2. ترتیب یک جمع مقدارش را عوض می‌کند، پس هر تغییری در اینکه یک reduction چگونه تقسیم شود logitها را عوض می‌کند. این زیرلایه است؛ سه مورد دیگر راه‌هایی برای تغییر ترتیب‌اند.

Dynamic batching درخواست شما را با غریبه‌ها گروه‌بندی می‌کند

لینک به بخش: Dynamic batching درخواست شما را با غریبه‌ها گروه‌بندی می‌کند

Continuous batching، از فصل 13، دلیل مقرون‌به‌صرفه بودن inference است — و یعنی شکل ماتریس‌هایی که tokenهای شما از آن‌ها عبور می‌کنند به ترافیک بستگی دارد. اندازه‌گیری بالا: 147,321 logit به‌خاطر تغییر batch size جابه‌جا شد.

routing در Mixture-of-experts به batch بستگی دارد

لینک به بخش: routing در Mixture-of-experts به batch بستگی دارد

جعبهٔ فصل 9 قبلاً گفته بود. router برای هر token در هر layer یک انتخاب گسسته انجام می‌دهد، مشروط به محدودیت‌های ظرفیت هر expert که روی batch محاسبه می‌شوند. tokenی که تنها بود به expert 7 می‌رفت، در جمع به expert 12 می‌رود. این تفاوت rounding نیست؛ مجموعهٔ متفاوتی از وزن‌هاست.

version stringی مثل -latest یک pointer است، و pointerها دوباره نشانه‌گذاری می‌شوند. providerها همچنین serving stack را زیر یک شناسهٔ نسخهٔ ثابت به‌روزرسانی می‌کنند. هیچ‌کدام با ریزدانگی‌ای اعلام نمی‌شود که بتوانید آن را با تغییر خروجی خودتان correlate کنید.

پارامتر seed در OpenAI در تنها شکلی که می‌تواند صادق باشد دربارهٔ این صادق است: همراه با یک فیلد system_fingerprint می‌آید که backend configuration را شناسایی می‌کند، و مستندات می‌گوید determinism در حد best-effort است و fingerprint تغییرکرده یعنی نتایج ممکن است متفاوت شوند. این را همان‌طور بخوانید که هست — provider به شما می‌گوید هر چهار علت بالا را او کنترل می‌کند، شما هیچ‌کدام را کنترل نمی‌کنید، و تنها چیزی که می‌تواند ارائه کند این است که بعد از وقوع به شما بگوید چیزی جابه‌جا شده.

همهٔ این‌ها دربارهٔ یک پیچ و پیامدهایش بود. یک سطح عقب بروید و مسئلهٔ سخت‌تر ظاهر می‌شود: شیئی که تنظیم می‌کردیم یک توزیع احتمال است، و توزیع‌های احتمال interface ندارند.

یک function call دارد. یک ردیف database دارد. یک handler POST که انتظار یک JSON body با سه field اجباری دارد، interface دارد، و هر چیز دیگری را رد می‌کند. بین مدل و هر component دیگر در سیستم شما قراردادی نشسته که یک طرفش نمی‌تواند وعده بدهد: مدل چیزی تولید خواهد کرد، کشیده‌شده از توزیعی که شکل داده‌اید اما ثابت نکرده‌اید، و کد آن طرف به مقداری با نوع معلوم نیاز دارد وگرنه throw می‌کند.

پل بین این دو جهان از مصالح همین فصل ساخته می‌شود، نه از parsing و retry. اگر tokenی ساختار لازم را می‌شکند، آن را sample نمی‌کنید و امید ببندید — logit آن را پیش از اینکه softmax اصلاً ببیند روی -\infty می‌گذارید. Constrained decoding ماسکی روی همان برداری است که این فصل صرف بازشکل‌دهی‌اش کردیم، و «لطفاً در JSON پاسخ بده» را از درخواست به تضمین تبدیل می‌کند.

فصل 18 همان قرارداد است: tool calling، JSON Schema، structured outputs، و آنچه لازم است تا ساختن روی یک سیستم deterministic بر فراز سیستمی probabilistic امن شود.


همهٔ اندازه‌گیری‌های این فصل از Qwen/Qwen2.5-0.5B-Instruct روی CPU می‌آیند، float32 مگر اینکه گفته شده باشد، با samplingی که همان‌طور که در بخش اختیاری نوشته شد پیاده‌سازی شده نه delegate شده به library. آن‌ها یک مدل کوچک‌اند، و مقدارهای خاص متعلق به همان مدل‌اند؛ سازوکارها نه. مقالهٔ Von Platen با عنوان How to generate text with different decoding methods (Hugging Face, 2020) مقاله‌ای است که این یکی در برابرش اندازه‌گیری شده و هنوز بهترین مقدمهٔ کوتاه برای همین material است. برای بخش determinism: یادداشت‌های reproducibility در PyTorch توضیح می‌دهند seed روی یک ماشین چه چیزی را fix می‌کند و چه چیزی را نه، مستندات OpenAI دربارهٔ seed و system_fingerprint توضیح می‌دهد یک provider چه چیزی را می‌تواند و نمی‌تواند وعده بدهد، و بحث Thinking Machines در 2025 دربارهٔ batch-invariant kernels روشن‌ترین روایت عمومی از این است که fix کردن این در سطح inference-server ممکن است اما رایگان نیست.

  1. Ackley, D. H., Hinton, G. E. و Sejnowski, T. J. A Learning Algorithm for Boltzmann Machines. Cognitive Science 9(1), pp. 147–169 (1985)، جایی که temperature در softmax از فیزیک آماری می‌آید. Hinton, G., Vinyals, O. و Dean, J.، Distilling the Knowledge in a Neural Network، arXiv:1503.02531 (2015)، بخش 2، جایی است که همان پارامتر دوباره در deep learning مدرن ظاهر می‌شود — به‌عنوان راهی برای آشکار کردن توزیع کامل teacher، که soft labels فصل 13 است نه sampling این فصل.

  2. Guo, C., Pleiss, G., Sun, Y. و Weinberger, K. Q. On Calibration of Modern Neural Networks. arXiv:1706.04599 (2017). این را با temperature این فصل اشتباه نگیرید. Temperature scaling یک مقدار واحد را روی مجموعهٔ اعتبارسنجی fit می‌کند تا اطمینان مدل با دقتش match شود؛ یک روش کالیبراسیون post-hoc است که روی خروجی‌های یک classifier اعمال می‌شود. Temperature sampling یک کنترل runtime روی این است که generator چگونه tokenها را draw کند. همان فرمول، هدف متفاوت، و بدون مقدار مشترک.

  3. Holtzman, A., Buys, J., Du, L., Forbes, M. و Choi, Y. The Curious Case of Neural Text Degeneration. arXiv:1904.09751 (2019). nucleus sampling و اندازه‌گیری‌ای را معرفی می‌کند که نشان می‌دهد decoding مبتنی بر maximisation متنی تولید می‌کند که profile احتمالش هیچ شباهتی به متن انسانی ندارد. 2

  4. Fan, A., Lewis, M. و Dauphin, Y. Hierarchical Neural Story Generation. arXiv:1805.04833 (2018). مقاله‌ای که top-k sampling را محبوب کرد.

  5. Nguyen, M. et al. Turning Up the Heat: Min-p Sampling for Creative and Coherent LLM Outputs. arXiv:2407.01082 (2024).

  6. Meister, C., Pimentel, T., Wiher, G. و Cotterell, R. Locally Typical Sampling. arXiv:2202.00666 (2022).

  7. Keskar, N. S., McCann, B., Varshney, L. R., Xiong, C. و Socher, R. CTRL: A Conditional Transformer Language Model for Controllable Generation. arXiv:1909.05858 (2019). بخش 4.1 همان repetition penalty اصلی است — همان که تقسیم می‌کند.


تهیه‌شده توسط

David Vicente Campos

بنیان‌گذار NeuraLIA Labs و هم‌بنیان‌گذار MyRealFood

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

بیشتر درباره نویسنده

منتشرشده توسط NeuraLIA Labs.

پست‌های جدید را در ایمیل خود دریافت کنید

اخبار AI، راهنماها و به‌روزرسانی‌های محصول — هر وقت چیزی ارزشمند منتشر کنیم، یک ایمیل کوتاه می‌فرستیم.

فهرست دوره

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev12 دقیقه مطالعه

مدل هوش مصنوعی Jev برای تصمیم ساخته شده، نه نثر

Jev از TypeSafe AI توجه‌ها را جلب کرده چون هوشمندی نرم‌افزار را مسئله‌ای احتمالاتی می‌بیند: شاخه درست را انتخاب کنید، میزان اطمینان را کنار آن بگذارید، و وقتی کد به یک تصمیم نیاز دارد برای نوشتن متن به یک LLM پول ندهید.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering13 دقیقه مطالعه

مهندسی کانتکست برای عامل‌های AI بلندافق

عامل‌های طولانی‌اجرا فقط به‌خاطر کوچک بودن پنجره شکست نمی‌خورند. وقتی فایل‌ها، خروجی ابزارها و تاریخچهٔ کهنه وظیفه‌ای را که عامل قرار بود تمام کند کنار می‌زنند، شکست رخ می‌دهد.

آماده‌اید انتخاب مدل را به LIA بسپارید؟

با همه مدل‌های هوش مصنوعی در یک جا بسازید — همین امروز رایگان شروع کنید.