تصور کنید تمام کانتینرهای شما یکسان هستند. کدها یکی هستند، پیکربندیها مشابهاند و حتی تصاویر کانتینر (Container Images) دقیقاً یکی هستند. اما ناگهان یکی از آنها پس از یک راهاندازی سرد (Cold Start) — شبیه به روشن کردن کامپیوتری که مدتها خاموش بوده و باید همه چیز را از نو بارگذاری کند — رفتاری کاملاً متفاوت از بقیه نشان میدهد. این کابوس عیبیابی زمانی رخ میدهد که شما به جای یک نسخهٔ ثابت، از یک «هدف متحرک» در استقرار مدلهای خود استفاده میکنید. در این حالت، تفاوت در دایرکتوریای است که کانتینر هنگام شروع به کار دانلود کرده است. تمام غرایز عیبیابی شما را به سمت بررسی استقرار خودتان سوق میدهد، اما هیچکدام چیزی پیدا نمیکنند چون خطا در جای دیگری است.
به نقل از یک راهنمای فنی منتشر شده در ۱۳ اوت ۲۰۲۶، مدلهای خانواده Gemma 3 گوگل نمونهای از این ریسک هستند. نسخههای «شناور» (Floating) مدلها میتوانند باعث شوند بهروزرسانیهای توکنسازها یا وزنها بدون هیچ اعلانی رخ دهند. اگر شما شاخه main یک مخزن را دنبال کنید، هر بار راهاندازی مجدد یک گره در خوشه (Cluster) میتواند بدون هیچ اعلانی، رفتار مدل شما را تغییر دهد. همانطور که در بحثهای گذشتهی ما دربارهی امنیت مدلهای بازمتن اشاره کردیم، اعتماد مطلق به مخازن آنلاین بدون نسخهبندی دقیق، نقطهضعفی در زیرساختهای عملیاتی است.
بسیاری از توسعهدهندگان از دستور from_pretrained("google/gemma-3-4b-it") استفاده میکنند که مستقیماً به آخرین وضعیت شاخه main اشاره دارد. این یک هدف متحرک است. در مورد Gemma، گوگل چندین بار بهروزرسانیهایی را برای اصلاح قالبهای چت، رفع خطاهای توکنسازی (Tokenization) — که مثل خرد کردن متن به تکههای کوچک برای درک مدل است — و بارگذاری مجدد وزنها (Weights) برای اصلاح خطاهای تبدیل ارسال کرده است.
ریسکهای پنهان در نسخههای شناور
یک مخزن مدل در Hugging Face در واقع یک مخزن git است و شاخه main هم مانند هر شاخه دیگری است. وقتی گوگل یک کامیت (Commit) جدید ارسال میکند، هر استقراری که بدون تعیین نسخه (Revision) باشد، در اولین راهاندازی سرد آن را دریافت میکند. طبق مستندات فنی، تغییر در فایلهای زیر در یک مخزن Hugging Face میتواند خروجی مدل را بهطور کلی تغییر دهد:
- tokenizer_config.json: حاوی قالب چت است؛ هر اصلاحی در اینجا، متن دقیقی را که مدل دریافت میکند تغییر میدهد و این امر مستقیماً پاسخ مدل را تغییر میدهد.
- generation_config.json: توکنهای توقف را کنترل میکند. تغییرات در این فایل تعیین میکند که مدل چه زمانی تولید متن را متوقف کند (که موضوع صفحه توکنهای توقف تکراری است).
- config.json: مقادیر معماری از جمله پنجرهٔ زمینه (Context Window) — که مثل میز کاری است که مدل فقط مقدار محدودی متن را روی آن نگه میدارد — و محدودیت موقعیت (Position Limit) را ذخیره میکند.
- Safetensors shards: خودِ وزنهای مدل که گاهی پس از اصلاحات تبدیل، مجدداً بارگذاری میشوند. این اتفاق در خانواده Gemma و مدلهای دیگر رخ داده است.
این تغییرات هیچ اعلانی ندارند. نتایج ارزیابی شما تغییر میکند، خروجیهای مرجع (Golden Outputs) دیگر مطابقت ندارند و تفاوت (Diff) در مخزنی قرار دارد که متعلق به شخص دیگری است. تثبیت (Pinning) این نوسانات را به تصمیمی تبدیل میکند که خود شما میگیرید.
پیادهسازی تثبیت سختگیرانه
برای توقف این رانش (Drift)، باید ابتدا تعیین کنید که در حال حاضر کدام نسخه را اجرا میکنید. این کار تضمین میکند که تثبیت باعث حفظ رفتار مدل شود، نه تغییر آن. برای مدلهای دسترسیمحدود (Gated) مثل Gemma، ابتدا باید پس از پذیرش لایسنس در صفحه مدل، از طریق huggingface-cli login (یا hf auth login در نسخههای قدیمیتر CLI) احراز هویت کنید. این احراز هویت یک بار برای هر ماشین یا Runner در CI انجام میشود.
سپس میتوانید از تابع model_info در کتابخانه huggingface_hub برای یافتن هش SHA فعلی شاخه main و تاریخ آخرین تغییرات (lastModified) استفاده کنید.
اگر مدل از قبل در حافظهٔ محلی ذخیره شده است، باید دایرکتوری کش را با استفاده از scan_cache_dir() بررسی کنید تا هش کامیت دقیقی را که واقعاً در حال استفاده از آن هستید بیابید، نه آنچه در حال حاضر در سرور (Upstream) است. این دو دقیقاً در لحظاتی که بیشترین اهمیت را دارند، با هم تفاوت میکنند.
جزئیات فنی اجرا
بسیار حیاتی است که هر لودر (Loader) را تثبیت کنید. یک اشتباه رایج این است که وزنهای مدل تثبیت شوند اما توکنساز روی شاخه main رها شود. این کار بدترین ترکیب ممکن را ایجاد میکند: پارامترهای ثابت با یک قالب چت شناور. شما باید آرگومان revision را به تمام فراخوانیهای from_pretrained که با مخزن در ارتباط هستند، پاس دهید.
یک ثابت برای هش ۴۰ کاراکتری SHA در ابتدای ماژول خود تعریف کنید. هش را در هر نقطه از فراخوانی قرار ندهید، بلکه آن را در یک جای واحد قرار دهید:
MODEL_ID = "google/gemma-3-4b-it"
REVISION = "0f1e2d3c4b5a69788796a5b4c3d2e1f0a9b8c7d6"
از این ثابت برای تمام اجزا استفاده کنید:
AutoTokenizer.from_pretrained(MODEL_ID, revision=REVISION)AutoProcessor.from_pretrained(MODEL_ID, revision=REVISION)(این مورد برای اندازههای بینایی در چکپوینتهای چندوجهی ضروری است)AutoModelForCausalLM.from_pretrained(MODEL_ID, revision=REVISION)
برای استقرارهای ایزوله (Air-gapped) یا کانتینری، از snapshot_download(MODEL_ID, revision=REVISION) در زمان ساخت (Build time) استفاده کنید. این کار نسخهٔ خاص را به عنوان یک واحد در تصویر (Image) جاسازی میکند. این روش ورودی/خروجی شبکه در زمان شروع را حذف کرده، تضمین میکند که قطعی در Hub مانع از مقیاسدهی شما نشود و اطمینان میدهد که احراز هویت لایسنس یک بار در محیطی کنترلشده انجام شده است.
تثبیت کتابخانه و محیط
دو تثبیت مجاور به اندازه تثبیت مدل اهمیت دارند. اول، نسخهٔ کتابخانه است. Gemma 3 به نسخهٔ جدیدی از transformers نیاز دارد تا معماری آن را بشناسد. در حالی که یک استک قدیمی در زمان بارگذاری شکست میخورد (که حالت خوبی است)، یک کتابخانه جدیدتر ممکن است بهطور خاموش پیشفرضی را در پردازشگر یا پیادهسازی توجه (Attention) تغییر دهد و باعث شود وزنهای تثبیتشده، خروجی متفاوتی بدهند. بنابراین کتابخانه را در کنار نسخه مدل تثبیت کنید.
دوم، بارگذاریهای شناور را بهجای توصیه به عدم استفاده، غیرممکن کنید. در محیط CI، از یک دستور grep استفاده کنید تا اگر هر فراخوانی from_pretrained فاقد revision بود، بیلد شکست بخورد. این کار باعث میشود فراخوانیهایی که ممکن است کسی شش ماه دیگر اضافه کند، شناسایی شوند. این رویکرد سختگیرانه در مدیریت کدها یادآور سازوکارهای ممیزی رفتاری است که از ادغام کورکورانه تغییرات در محیطهای عملیاتی جلوگیری میکند. همیشه از هش کامل ۴۰ کاراکتری استفاده کنید و نه تگها؛ زیرا تگها مراجع متحرکی هستند و همان مشکلات شاخه main را به ارث میبرند.
تایید و نگهداری
برای اینکه محیطهای بدپیکربندیشده بهجای ارائه مدل اشتباه، بهصورت بلند (Loudly) شکست بخورند، در زمان شروع برنامه، تثبیت را تایید کنید. در هر اجرای ارزیابی، این سه مقدار را ثبت کنید:
۱. هش SHA256 از tok.chat_template.
۲. مقدار model.generation_config.eos_token_id.
۳. مقدار model.config.max_position_embeddings (پنجره).
وقتی امتیازی تغییر میکند، بررسی این هشها در لاگها در چند ثانیه پاسخ میدهد که آیا مدل تغییر کرده است یا خیر. همچنین، ثبت نسخه در کنار سوابق لایسنس ضروری است؛ زیرا شرایط لایسنس Gemma به مصنوع (Artifact) خاصی که شما عرضه کردهاید متصل است و دانستن نسخه دقیق برای پاسخ به سوالات حقوقی در آینده لازم است.
بهروزرسانی آگاهانه
ارتقای مدل باید یک اتفاق آگاهانه همراه با بررسی تفاوتها (Diff) باشد. چرخه ارتقا کوتاه است: هش تثبیتشده خود را با model_info(MODEL_ID).sha مقایسه کنید و تاریخچه کامیتها را در Hub بررسی کنید تا ببینید چه چیزی تغییر کرده است. تغییر در README ساده است، اما تغییر در قالب یا generation-config نیازمند ارزیابی کامل است. مجموعه ارزیابی خود را روی هر دو نسخه اجرا کنید و اگر توکنساز تغییر کرده است، تعداد توکنها را مجدداً اندازهگیری کنید.
ثابت را بهروز کنید، مجدداً مستقر کنید و هش قبلی را در پیام کامیت نگه دارید تا بازگشت (Rollback) به جای یک تحقیق طولانی، تنها با یک ویرایش ساده انجام شود. برای سازماندهی این تغییرات و تبدیل آنها به کامیتهای منطقی، استفاده از ابزارهای مدیریت نسخه پیشرفته توصیه میشود. یک روال منطقی، اجرای هفتگی یک تسک است که هش شما را با شاخه main مقایسه کرده و در صورت تفاوت، یک Issue باز کند. این کار یک ریسک نامرئی را به یک نگهداری روتین تبدیل میکند.
این انضباط را به مصنوعات مشتقشده نیز تعمیم دهید. تبدیلهای کوانتیده (Quantized) — که مثل فشردهسازی یک فایل حجیم برای اجرای سریعتر در سختافزارهای ضعیف است — خروجیهای ONNX و آداپتورهای تنظیم دقیق (Fine-tuning) همگی وابستگی ضمنی به نسخه پایه دارند که از آن تولید شدهاند. هش پایه را در متادیتای محصول یا نام فایل در زمان ساخت بنویسید. وقتی یک آداپتور سالها بعد روی یک نسخه پایه جدیدتر رفتار عجیبی نشان میدهد، همین یک رشته متنی تفاوت بین یک پاسخ ۵ دقیقهای و یک بعدازظهر کامل کار است.
این موضوع مختص Gemma نیست؛ هر خانوادهای از مدلهای وزنهای باز (Open Weights) — یعنی مدلهایی که دستور پختشان علناً منتشر شده — که از یک مخزن تغییرپذیر سرو میشوند، این ریسک را دارند. هزینه عدم تثبیت، تلف کردن روزها برای عیبیابی استقراری است که خطا در واقع در یک مخزن راه دور رخ داده است.
گام بعدی شما
- تمام فراخوانیهای
from_pretrainedدر کد خود را بررسی کرده و آرگومانrevisionرا با هش SHA کامل جایگزین کنید. - در خط لوله CI/CD خود یک تست
grepاضافه کنید تا از عدم استفاده از نسخههای شناور مطمئن شوید. - برای مدلهای حساس، هش
chat_templateرا در لاگهای شروع برنامه ثبت کنید تا هرگونه تغییر خاموش را ردیابی کنید.
اما داستان سختافزاری این تحول حتی شگفتانگیزتر است — به تحلیل ما دربارهی تراشههای Blackwell مراجعه کنید.




گفتگو