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

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

۱۱ مرداد ۱۴۰۵ مبانی هوش مصنوعی

دو صحنه که احتمالاً هر دو را دیده‌ای. صحنهٔ اول: یک گفت‌وگوی طولانی با دستیارِ هوش مصنوعی که خوب پیش می‌رفت، تا اینکه مدل ناگهان چیزی را که همان اولِ کار گفته بودی از یاد بُرد — انگار هرگز نگفته بودی. صحنهٔ دوم: صورت‌حسابِ یک سرویسِ هوش مصنوعی که بیشتر از تخمینت درآمد، یا سهمیه‌ای که زودتر از انتظار ته کشید، بی‌آنکه کارِ عجیبی کرده باشی.

این دو صحنه یک ریشه دارند، و ریشه‌شان یک کلمه است: token. توکن واحدی است که مدل با آن متن را می‌بیند، می‌شمارد و می‌سازد؛ هزینه با آن حساب می‌شود، حافظهٔ گفت‌وگو با آن اندازه‌گیری می‌شود، و چند خطای مشهورِ مدل‌ها مستقیم از آن می‌آید. و یک نکتهٔ سوم هم هست که کمتر جایی نوشته می‌شود: متنِ فارسی توکنِ بیشتری می‌گیرد. یعنی هر دو صحنهٔ بالا برای ما فارسی‌زبان‌ها زودتر اتفاق می‌افتد. این نوشته می‌گوید چرا — با عددهای اندازه‌گیری‌شده — و بعد می‌گوید دقیقاً چه کارش می‌شود کرد.

توکن دقیقاً چیست

مدل متن را آن‌طور که ما می‌بینیم نمی‌بیند. اول متن را به تکه‌های کوچک می‌شکند و هر تکه یک token است. توکن نه حرف است و نه لزوماً کلمه — یک تکهٔ پرتکرارِ متن است. یک کلمهٔ ساده و پرکاربرد معمولاً کلِ خودش یک توکن می‌شود؛ یک کلمهٔ بلند یا کم‌یاب به چند تکه می‌شکند. حتی فاصلهٔ پیش از یک کلمه هم معمولاً بخشی از همان توکن است، نه چیزی جدا.

چرا اصلاً این‌طور؟ چون زبان بی‌شمار کلمه دارد و هیچ فهرستِ ثابتی همه را پوشش نمی‌دهد؛ ولی اگر متن را به تکه‌های پرتکرار بشکنی، با تعدادِ محدودی تکه می‌توانی تقریباً هر چیزی را بسازی — حتی کلمه‌ای که تا حالا ندیده‌ای. این خاصیت مهم است: مدل جلوی یک کلمهٔ ناآشنا بی‌دست نمی‌ماند، فقط ریزتر تکه‌اش می‌کند.

یک جملهٔ انگلیسی و همان جمله به فارسی، وقتی تکه می‌شوند:

A token is a chunk of text.
["A", " token", " is", " a", " chunk", " of", " text", "."]      -> 8

توکن یک تکه از متن است.
["ت", "و", "ک", "ن", " ", "ی", "ک", " ت", "ک", "ه", " ا",
 "ز", " م", "ت", "ن", " است", "."]                              -> 17

این یک نمونه است که با یک tokenizer مشخص اندازه گرفته شده، نه خروجیِ قطعیِ یک محصولِ خاص؛ هر مدل tokenizer خودش را دارد و عددها فرق می‌کنند. ولی جهتِ ماجرا همیشه همین است.

به بلوکِ انگلیسی نگاه کن: تقریباً هر کلمه یک توکن است. حالا بلوکِ فارسی: بیشترِ تکه‌ها یک حرفِ تنهاست. و نکتهٔ تکان‌دهنده این است که جملهٔ فارسی از جملهٔ انگلیسی کوتاه‌تر است — ۲۳ نویسه در برابرِ ۲۷ — ولی بیش از دو برابر توکن گرفته.

اینکه گفتیم توکن همیشه کلمه نیست، در خودِ انگلیسی هم دیدنی است: در همان tokenizer، کلمهٔ library یک توکنِ کامل است، ولی Artificial به دو تکهٔ Art و ificial می‌شکند — چون library در متنِ آموزشی به‌مراتب پرتکرارتر بوده. و همان library به فارسی، یعنی «کتابخانه»، شش توکن می‌شود.

چرا فارسی گران‌تر است

جوابِ کوتاه: چون فهرستِ توکن‌ها را کسی دستی ننوشته؛ از روی یک پیکرهٔ متنی آموزش دیده — و آن پیکره عمدتاً انگلیسی بوده.

مکانیزمش ساده و کاملاً آماری است. tokenizer را روی حجمِ عظیمی متن می‌گذارند و الگوریتم مدام پرتکرارترین جفتِ مجاور را با هم ادغام می‌کند: اول حرف‌ها، بعد دوحرفی‌های پرتکرار، بعد پسوندها و ریشه‌ها، تا فهرستی از چند ده‌هزار تکه به‌دست بیاید. هر تکه‌ای که در آن پیکره زیاد آمده، جای خودش را در فهرست می‌گیرد؛ هر تکه‌ای که کم آمده، جا نمی‌گیرد و بعداً باید از تکه‌های ریزتر ساخته شود.

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

حالا عدد. ما همین را روی دو جملهٔ هم‌معنا اندازه گرفتیم، با tokenizer شناخته‌شدهٔ cl100k_base:

فارسی  :  52 نویسه ->  40 توکن   (1.3 نویسه در هر توکن)
انگلیسی:  63 نویسه ->  14 توکن   (4.5 نویسه در هر توکن)

دو جمله که یک چیز می‌گویند. جملهٔ انگلیسی حتی بلندتر است. ولی فارسی ۴۰ توکن خورد و انگلیسی ۱۴ — نزدیک به سه برابر.

و حالا چیزی که تصویر را کامل می‌کند و تقریباً هیچ‌جا گفته نمی‌شود: همان جملهٔ فارسی را با یک tokenizer چندزبانه دوباره شمردیم — paraphrase-multilingual-MiniLM-L12-v2، که فارسی هم در پیکرهٔ آموزشش بوده — و ۱۴ توکن شد. یک‌سوم. جملهٔ انگلیسی هم با هر دو tokenizer دقیقاً ۱۴ توکن بود.

این یعنی چه؟ یعنی آن «مالیاتِ فارسی» خاصیتِ زبانِ فارسی نیست، خاصیتِ آن tokenizer خاص است. تفاوت جایی ساخته شد که کسی تصمیم گرفت فهرستِ توکن‌ها را روی چه متنی بسازد.

دو نتیجهٔ عملی، و هر دو مهم‌اند:

  • اگر داری چیزی می‌سازی، tokenizer یک انتخاب است، نه یک سرنوشت. پیش از انتخابِ مدل یا سرویس، متنِ نمونهٔ خودت را با چند tokenizer بشمار؛ این آزمایش چند خط بیشتر نیست و می‌تواند هزینهٔ یک پروژه را چند برابر کم کند.
  • اگر فقط داری از یک دستیارِ آماده استفاده می‌کنی، این انتخاب دستِ تو نیست. tokenizer بخشی از خودِ مدل است و عوض‌شدنی نیست، پس مالیاتش برای تو کاملاً واقعی است — و کارهایی که در بخشِ آخرِ این نوشته می‌آید دقیقاً برای همین حالت است.

یک هشدارِ صادقانه هم لازم است: عددهای بالا با tokenizerهای مشخصی گرفته شده‌اند، نه با همهٔ آن‌ها. حتی برای یک tokenizer واحد، متنِ فنیِ پر از کلمه‌های انگلیسی نسبتِ کاملاً متفاوتی از یک متنِ محاوره‌ای دارد. برای تخمین عالی‌اند، برای صورت‌حساب نه. مصرفِ دقیق را از پاسخِ خودِ سرویس بگیر — پاسخ‌های API معمولاً بخشی به‌نامِ usage دارند که مصرفِ واقعی را می‌گوید — و نرخ‌ها و ظرفیت‌ها را از صفحهٔ خودِ سرویس بخوان. این‌ها مدام عوض می‌شوند و هیچ مقاله‌ای، از جمله همین یکی، جای آن صفحه را نمی‌گیرد.

سه پیامدی که هر روز می‌بینی

۱. هزینه: همان حرف، چند برابر گران‌تر

سرویس‌های هوش مصنوعی بر اساسِ توکن پول می‌گیرند — هم توکن‌های ورودی و هم توکن‌های خروجی. پس وقتی همان مفهوم به فارسی چند برابر توکن می‌گیرد، همان مفهوم چند برابر خرج برمی‌دارد. این یک جریمهٔ ثابت روی هر کاری است که با متنِ فارسی می‌کنی، و از هیچ‌جای صورت‌حساب هم پیدا نیست که چرا.

پیامدِ دومش را کمتر می‌بینند: هر تخمینِ هزینه‌ای که در یک منبعِ انگلیسی خوانده‌ای، برای تو کم‌برآورد است. آن جدولی که می‌گوید «فلان‌قدر متن یعنی تقریباً فلان‌قدر توکن» روی متنِ انگلیسی حساب شده.

و یک پیامدِ سوم که اصلاً ربطی به پول ندارد: تولیدِ هر توکنِ خروجی زمان می‌برد. جوابِ فارسی‌ای که از نظرِ خواننده هم‌اندازهٔ جوابِ انگلیسی است، از نظرِ مدل بلندتر است — پس کندتر هم می‌رسد.

۲. پنجرهٔ زمینه: «اولش را فراموش کرد» زودتر می‌رسد

مدل نمی‌تواند بی‌نهایت متن را یک‌جا ببیند. یک سقف دارد به‌نامِ context window: بیشترین تعدادِ توکنی که در یک لحظه جلوی چشمش است. کلِ گفت‌وگو — هم پرامپت‌های تو، هم جواب‌های خودِ مدل — داخلِ همین پنجره جا می‌گیرد.

حالا دقت کن: این سقف با توکن اندازه‌گیری می‌شود، نه با صفحه و نه با کلمه. و همین‌جاست که مالیاتِ فارسی ضربهٔ دومش را می‌زند. یک سندِ فارسی و یک سندِ انگلیسیِ هم‌محتوا را بردار؛ سندِ فارسی زودتر پنجره را پر می‌کند. یعنی همان تجربهٔ آشنای «مدل چیزی را که اولِ گفت‌وگو گفتم فراموش کرد» در فارسی زودتر به سراغت می‌آید.

و کدام بخش زودتر از دست می‌رود؟ قدیمی‌ترین‌ها. وقتی از سقف رد می‌شوی، اولِ گفت‌وگو از لبهٔ پنجره بیرون می‌افتد. پس اگر یک نکتهٔ مهم را همان ابتدا گفته‌ای و ده‌ها پیام بعد هنوز انتظار داری رعایتش کند، مکانیزم دارد به تو می‌گوید که انتظارِ نابه‌جایی است. نه بی‌ادبیِ مدل است، نه خرابی؛ آن توکن‌ها دیگر در پنجره نیستند.

۳. شمردنِ حروف: چرا در یک کارِ به‌ظاهر ساده می‌لغزد

بپرس در یک کلمه چند بار یک حرفِ خاص آمده و بخواه «فقط عدد را بگو»؛ ممکن است با اطمینانِ کامل عددِ غلط بگیری. این خطای مشهور مستقیم از توکن می‌آید: مدل حرف‌ها را نمی‌بیند، تکه‌ها را می‌بیند. «کتابخانه» برای تو نُه حرف است؛ به مدل به‌صورتِ شش تکه رسیده. داری از او می‌خواهی چیزی را بشمارد که اصلاً در ورودی‌اش وجود ندارد.

و راهِ حلی که واقعاً کار می‌کند از همین مکانیزم بیرون می‌آید: از مدل بخواه حرف‌ها را فهرست کند، بعد خودت فهرست را بشمار. نوشتنِ یک فهرست کاری است که مدل خوب انجام می‌دهد؛ شمردنِ یک فهرستِ کوتاه کاری است که تو بی‌خطا انجامش می‌دهی. کار را طوری بینِ دو طرف تقسیم کن که هرکدام کارِ خودش را بکند.

یک احتیاطِ مهم هم لازم است: این روزها ممکن است دستیارت عددِ درست بدهد. معمولاً دلیلش این نیست که مدل حالا حرف‌ها را می‌بیند — احتمالاً یک ابزار پشتِ صحنه واقعاً شمرده، یا مدل پیش از جواب‌دادن بیشتر روی سؤال کار کرده. از روی خودِ عدد نمی‌فهمی کدام؛ یک عددِ درست و یک عددِ غلط دقیقاً یک شکل‌اند. همین را در نوشتهٔ توهم در هوش مصنوعی بازتر کرده‌ایم: اطمینانِ لحنِ مدل هیچ ربطی به درستیِ حرفش ندارد.

نیم‌فاصله: هزینه‌ای که کسی نمی‌بیند

«نیم‌فاصله» یک نویسهٔ نامرئی است به‌نامِ ZWNJ که در فارسی معنا دارد: «می‌روم» را از «میروم» و «دانشگاه‌ها» را از «دانشگاه ها» جدا می‌کند. تو آن را نمی‌بینی، ولی tokenizer می‌بیند — و برای یک tokenizer که پیکرهٔ آموزشش عمدتاً انگلیسی بوده، این فقط یک نویسهٔ عجیبِ دیگر است که معمولاً یک توکنِ کاملِ جدا می‌شود.

سه املای مختلف از یک کلمه، با همان cl100k_base:

"برنامه‌نویسی"   (با نیم‌فاصله)   -> 10 توکن
"برنامه نویسی"   (با فاصله)       ->  9 توکن
"برنامهنویسی"    (چسبیده)         ->  9 توکن

همین الگو در بقیهٔ کلمه‌ها هم تکرار می‌شود: «دانشگاه‌ها» ۹ توکن در برابرِ «دانشگاه ها» ۸ توکن؛ «می‌روم» ۵ در برابرِ «میروم» ۴. هر نیم‌فاصله دقیقاً یک توکنِ اضافه است، و یک متنِ چندهزارکلمه‌ایِ پر از نیم‌فاصله هزینه‌ای می‌دهد که هیچ‌جای متن دیده نمی‌شود.

ولی هزینه نکتهٔ مهم‌ترِ ماجرا نیست. به آن سه سطر دوباره نگاه کن: این‌ها سه دنبالهٔ توکنِ متفاوت برای یک کلمه‌اند. یعنی مدل «برنامه‌نویسی» و «برنامه نویسی» را به‌طور خودکار یک چیز نمی‌بیند؛ باید از داده‌اش یاد گرفته باشد که این دو یکی‌اند — و از پیکره‌ای یاد گرفته که فارسی در آن اقلیت بوده. بدترین حالت این است که در یک سندِ واحد هر دو املا را داشته باشی، چون آن‌وقت خودت داری به مدل می‌گویی این‌ها دو چیزِ متفاوت‌اند.

همین ماجرا برای «ی» و «ک» هم هست و آنجا حتی موذیانه‌تر است. «ی» و «ک»ِ فارسی با «ي» و «ك»ِ عربی روی صفحه تقریباً یک‌شکل‌اند ولی نویسه‌های متفاوتی‌اند، پس توکن‌های متفاوتی هم می‌شوند. اینجا تعدادِ توکن لزوماً فرق نمی‌کند؛ چیزی که فرق می‌کند این است که «کتاب» با کافِ فارسی و «كتاب» با کافِ عربی برای مدل دو کلمهٔ متفاوت‌اند. متنی که از چند منبعِ مختلف کپی شده، تقریباً همیشه هر دو را قاطی دارد.

و نتیجه‌ای که از این بخش نباید بگیری: «پس نیم‌فاصله را بردار.» فارسیِ درست به نیم‌فاصله نیاز دارد و «میروم» غلط است. نتیجهٔ درست این است: یکدست بنویس — و اگر داری حجمِ زیادی متن به یک مدل می‌دهی، اول متن را یکدست کن.

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

۱. کوتاه‌تر بنویس، ولی نه مبهم‌تر. در فارسی هر کلمهٔ اضافه گران‌تر از انگلیسی تمام می‌شود، پس تعارف و مقدمه‌چینی («سلام، امیدوارم حالت خوب باشد، می‌خواستم اگر ممکن است لطف کنید و…») دقیقاً همان چیزی است که باید برود. ولی حواست باشد: کوتاه‌کردن یعنی حذفِ تشریفات، نه حذفِ مشخصات. یک پرامپتِ کوتاهِ مبهم جوابِ مبهم می‌گیرد و مجبورت می‌کند دوباره بپرسی — که در مجموع گران‌تر است. هدف این است که هر توکن بارِ معناییِ بیشتری حمل کند. اینکه چه چیزی تشریفات است و چه چیزی مشخصات، موضوعِ پرامپت‌نویسی است.

۲. متن را یکدست کن. یک املا برای هر کلمه، نیم‌فاصلهٔ یکسان، و «ی» و «ک»ِ فارسی به‌جای عربی. برای یک پیامِ کوتاه فرقِ محسوسی نمی‌کند؛ برای یک سندِ بلند یا سامانه‌ای که هر روز متن می‌فرستد، هم توکن کم می‌کند و هم — مهم‌تر — کلمه‌های یکسان را برای مدل واقعاً یکسان می‌کند. اگر متن را از چند منبع جمع کرده‌ای، این کار را پیش از فرستادن انجام بده.

۳. دستور را آخر بگذار. وقتی یک متنِ بلند می‌فرستی و بعد می‌خواهی کاری رویش انجام شود، دستور را بعد از متن بنویس، نه قبلش. دو دلیلِ مکانیزمی دارد: در یک زمینهٔ طولانی، انتهای پنجره تازه‌ترین چیزی است که مدل دیده؛ و اگر گفت‌وگو از سقف رد شود، چیزی که اول بیرون می‌افتد قدیمی‌ترین بخش است. دستوری که تهِ متن نشسته از هر دو خطر جان به‌در می‌برد. در فارسی که پنجره زودتر پر می‌شود، این بیشتر به‌کارت می‌آید.

۴. گفت‌وگوی طولانی را ببُر و خلاصه کن. هر بار که در یک گفت‌وگوی طولانی پیامِ تازه‌ای می‌فرستی، معمولاً کلِ تاریخچه دوباره فرستاده و شمرده می‌شود — یعنی داری بارها برای همان متنِ قدیمی هزینه می‌دهی. وقتی یک گفت‌وگو دراز و پراکنده شد، به‌جای ادامه‌دادن، نتیجه‌های مهم را در یک پیامِ تازه و کوتاه بنویس و از آنجا ادامه بده. هم ارزان‌تر می‌شود، هم آنچه واقعاً لازم داری داخلِ پنجره می‌ماند.

۵. متنِ خودت را بشمار، نه متنِ من را. این عملی‌ترین کارِ کلِ فهرست است. یک نمونهٔ واقعی از متنی که هر روز می‌فرستی بردار، با tokenizer همان سرویسی که استفاده می‌کنی بشمار، و نسبتِ نویسه به توکن را حساب کن. نسبت‌های این نوشته نقطهٔ شروع‌اند، نه جوابِ تو: متنِ فنیِ پر از اصطلاحِ انگلیسی و متنِ محاوره‌ایِ فارسی دو دنیای متفاوت‌اند. و برای مصرفِ واقعی، بخشِ usage در پاسخِ API را نگاه کن — آن عدد، عددِ واقعی است.

و در آخر

token یک ریزه‌کاریِ فنی نیست؛ واحدی است که هم صورت‌حساب را تعیین می‌کند، هم حافظهٔ گفت‌وگو را، و هم چند تا از عجیب‌ترین خطاهای مدل را. وقتی همین یک واحد را بشناسی، خیلی چیزها از «مدل خراب است» به «مکانیزمش همین است» تبدیل می‌شود — و برای مکانیزم، برخلافِ خرابی، می‌شود کاری کرد.

برای ما فارسی‌زبان‌ها یک لایهٔ اضافه هم دارد: همان معنا با توکنِ بیشتری بیان می‌شود، پس گران‌تر تمام می‌شود و پنجره را زودتر پر می‌کند. ولی همان‌طور که دیدیم، این خاصیتِ زبانِ فارسی نیست — خاصیتِ فهرستی از توکن‌هاست که عمدتاً از متنِ انگلیسی ساخته شده: یک انتخابِ مهندسی، نه یک حکمِ طبیعت. و با هر انتخابِ مهندسی همان کاری را باید کرد که با این یکی — اول اندازه‌اش بگیر.

اگر می‌خواهی بدانی این توکن‌ها اصلاً چطور به یک جوابِ روان تبدیل می‌شوند، مدل‌های زبانی چطور کار می‌کنند؟ نقطهٔ شروع است؛ برای اینکه بفهمی چرا مدل گاهی با اطمینانِ کامل اشتباه می‌گوید، توهم در هوش مصنوعی را ببین؛ و برای اینکه از همان اول جوابِ دقیق‌تری بگیری — و توکنِ کمتری خرج کنی — سراغِ پرامپت‌نویسی برو.