huggingface_hub هو عميل Python الموجود في قاعدة النظام البيئي Hugging Face. transformers, datasets, diffusers, sentence-transformers وتعتمد عليها العشرات من المكتبات الأخرى للتواصل مع Hub. كل أسبوع لا نشحن فيه إصدارًا جديدًا هو أسبوع من الإصلاحات والميزات العالقة main.
لفترة طويلة كنا نصدر كل 4 إلى 6 أسابيع. نحن نصدر الآن كل أسبوع من سير عمل GitHub Actions واحد. لقد قمنا ببنائها باستخدام أدوات مفتوحة المصدر ونماذج ذات أوزان مفتوحة وأبقينا الإنسان على اطلاع بالمكان الوحيد الذي يهم فيه الحكم. لا شيء في هذا المنشور يتطلب عقد بائع، أو نموذجًا مغلقًا، أو بنية تحتية لا يمكنك تشغيلها بنفسك. لقد كان هذا هدف التصميم منذ البداية لأننا أردنا سير عمل يمكن للمشرفين الآخرين التقاطه وتكييفه.
بحلول نهاية هذه التدوينة، سيكون لديك كل ما تحتاجه لبناء موقعك الخاص.
حيث بدأنا
كانت العملية القديمة آلية جزئيًا، وفي الغالب يدوية.
بالفعل في CI:
- النشر إلى PyPI بمجرد دفع العلامة.
- فتح فروع الاختبار في المكتبات النهائية مع تثبيت مرشح الإصدار.
لا يزال يدويًا، في كل مرة:
- إنشاء فرع الإصدار، وإدخال الإصدار فيه
__init__.py، الالتزام، وضع العلامات، الدفع. - مشاهدة تشغيل CI في اتجاه المصب وفشل الفرز.
- قراءة كل العلاقات العامة التي تم دمجها منذ الإصدار الأخير وكتابة ملاحظات الإصدار يدويًا: مجمعة حسب الموضوع، مع السياق، بصوت لا يُقرأ مثل
git logأحمق. - قطع الإصدار المستقر بعد فترة RC.
- صياغة إعلان Slack داخلي ومنشورات اجتماعية.
- فتح العلاقات العامة بعد الإصدار لعثرة
mainإلى التاليdev0.
كانت كتابة ملاحظات جيدة للإصدار الجديد هي الجزء الأكبر، حيث تم تجميع العشرات من العلاقات العامة حول مواضيع مختلفة. لا يوجد شيء صعب من الناحية الفنية سوى بضع ساعات من الاهتمام المركّز. أضف الإعلانات في الأعلى وكان الإصدار البسيط عبارة عن نصف يوم عمل ممتد على عدة أيام.
نوعان من العمل
لذلك قررنا تبسيط الأمر برمته. وبالنظر إلى تلك القائمة، ينقسم العمل إلى قسمين.
بعض الخطوات ميكانيكية بحتة ويمكن تشغيلها تلقائيًا: رفع الإصدار، والالتزام، ووضع العلامات، والدفع، وفتح فروع الاختبار النهائية، وفتح العلاقات العامة بعد الإصدار. لا أحد يحتاج إلى التفكير في هؤلاء. كل ما عليهم فعله هو أن يحدثوا بالترتيب الصحيح، في كل مرة، وهو ما يجيده سير عمل CI.
والباقي مختلف. كتابة ملاحظات الإصدار، وتحديد ما يجب تسليط الضوء عليه، وصياغة إعلان لجمهور بشري: هذا هو العمل العقلي. إنه نوع الحكم الذي احتفظ بدليل الإصدار لسنوات. وهنا يأتي دور الذكاء الاصطناعي، الذي يحول الصفحة الفارغة إلى مسودة أولى قوية في ثوانٍ. إنه أيضًا المكان الذي يجب أن نكون فيه حذرين لأن المسودة التي تبدو واثقة وخاطئة تمامًا هي أسوأ من عدم وجود مسودة على الإطلاق.
مبدأ التصميم: أجزاء مفتوحة، قابلة لإعادة الاستخدام من قبل أي شخص
عندما قررنا إصلاح هذه المشكلة، وضعنا قيدًا واحدًا في المقدمة: كل جزء متحرك يجب أن يكون شيئًا يمكن لأي مشرف تشغيله بنفسه. لا يوجد نموذج مغلق خلف واجهة برمجة التطبيقات (API) التي لا يمكننا تبديلها، ولا توجد منصة إصدار خاصة، ولا توجد صلصة سرية.
وهنا المكدس بأكمله:
المبدأ الثاني: النموذج يرسم والإنسان هو الذي يقرر. نماذج اللغة جيدة في تحويل ثلاثين عنوانًا مقتضبًا للعلاقات العامة إلى ملاحظات إصدار قابلة للقراءة. إنهم لا يجيدون الثقة العمياء. لذا فإن سير العمل يخضع لإشراف الإنسان: يقوم النموذج بالمرور الأول، ويتحقق البرنامج النصي الحتمي من عمله، ويقوم الإنسان بالمراجعة والتحرير قبل إرسال أي شيء (المزيد حول ذلك أدناه).
جولة في خط الأنابيب
سير العمل الكامل هو ملف واحد، .github/workflows/release.yml، يتم تشغيله يدويًا من واجهة مستخدم الإجراءات. يستغرق الأمر إدخالاً واحدًا بالضبط:
on:
workflow_dispatch:
inputs:
release_type:
type: choice
options:
- minor-prerelease
- minor-release
- patch-release
ومن هناك، يتم تشغيل الوظائف تقريبًا بهذا الترتيب:
- يحضر. حساب الإصدار التالي، أو إنشاء فرع الإصدار أو إعادة استخدامه، أو Bump
__version__، ارتكاب، علامة، دفع. - انشر على PyPI. بناء وتحميل
huggingface_hub. بالتوازي، قم ببناء وتحميل ملفhfCLI كحزمة PyPI الخاصة بها. - ملاحظات الإصدار. قم بتفريق نطاق الالتزام منذ العلامة الأخيرة، واسحب البيانات التعريفية للعلاقات العامة من واجهة برمجة تطبيقات GitHub، واطلب من النموذج صياغة سجل تغيير منظم (إليك أحدث سجل). تم الحفظ باسم أ مسودة إصدار جيثب.
- فروع الاختبار المصب. بالنسبة للمنسقين المقيمين، افتح فرعًا في
transformers,datasets,diffusers,sentence-transformersمع تثبيت RC، لذلك يخبرنا CI الخاص بهم بسرعة إذا كسرنا شيئًا ما. - إعلان ركود. اقرأ الملاحظات وأصدر إعلانًا داخليًا بصوت فريقنا.
- أرشفة الملاحظات. قم بتحميل كل من مسودة الذكاء الاصطناعي الأولية والنسخة المحررة بواسطة الإنسان إلى Hugging Face Bucket، جنبًا إلى جنب.
- عثرة ما بعد الإصدار. بعد إصدار مستقر، افتح PR
mainالاصطدام إلى التاليdev0. - التعليق على العلاقات العامة المشحونة. اترك تعليقًا “تم شحن هذا في vX.YZ” على كل العلاقات العامة في الإصدار.
- مزامنة مستندات CLI. افتح العلاقات العامة لمستودع مهاراتنا مع المجددين
hfمستندات مهارات CLI. - تقرير إلى سلاك. تنشر كل خطوة حالتها كرد على موضوع؛ مهمة نهائية تقوم بتحديث رسالة الجذر بـ ✅ أو ❌.
تتمثل الخطوات اليدوية المتبقية في مراجعة مسودة ملاحظات الإصدار ونشرها، ومراجعة رسالة Slack الداخلية ونشرها. هاتان الخطوتان هما المكان الذي نريد أن يكون فيه الإنسان في الحلقة.
ثق ولكن تحقق: جوهر الإنسان في الحلقة
هذا هو وضع الفشل الذي يقلق الجميع بشأن ملاحظات الإصدار التي تم إنشاؤها بواسطة الذكاء الاصطناعي: يقوم النموذج بإسقاط العلاقات العامة بهدوء أو يخترع واحدة غير موجودة في هذا الإصدار. إن سجل التغيير الذي يكاد يكون صحيحًا هو أسوأ من عدم وجود سجل تغيير لأنه لا أحد يعيد التحقق منه.
نحن لا نثق في أن ملاحظات الإصدار التي تم إنشاؤها ستكون كاملة من المحاولة الأولى، بل نتحقق منها بشكل حتمي. قبل تشغيل النموذج، يسترد برنامج Python النصي جميع العلاقات العامة التي تنتمي إلى الإصدار ويخزنها كحقيقة أساسية.
PR_NUMBER_PATTERN = re.compile(r"\(#(\d+)\)$")
pr_numbers = [
int(m.group(1))
for commit in commits_since_last_tag
if (m := PR_NUMBER_PATTERN.search(commit.title))
]
save_manifest(pr_numbers)
ثم يقوم النموذج بصياغة الملاحظات منهم. بمجرد الانتهاء من ذلك، نتحقق من مخرجاته مقابل القائمة الأولية للمستفيدين الرئيسيين:
expected = set(load_manifest())
found = extract_pr_refs(notes_md)
missing = expected - found
extra = found - expected
إذا كان هناك أي شيء مفقود أو إضافي، فإننا لا نفشل ولا نشحن ملفًا خاطئًا. نعيد هذا التناقض إلى الوكيل ونطلب منه إصلاح هذه العلاقات العامة بالضبط:
for _ in range(MAX_ITERATIONS):
missing, extra = validate(notes)
if not missing and not extra:
break
run_agent_fix(missing_prs=missing, extra_prs=extra)
هذا هو النمط الذي يجعل الأمر برمته جديرًا بالثقة: نموذج غير حتمي مغلف بحواجز حتمية. النموذج رائع في كتابة النثر ولا يمكن الاعتماد عليه في كونه شاملاً. لذلك نتركها تكتب ونترك الكود يفرض الاتساق.
تأريض النموذج بحيث لا يختلق الأشياء
الاكتمال هو النصف. الدقة هي الأخرى. النموذج الذي يلخص العلاقات العامة من عنوانه وحده سوف يخترع بكل سرور مثالًا برمجيًا لا يتطابق مع واجهة برمجة التطبيقات الحقيقية.
ولمنع ذلك، عندما نجلب البيانات الوصفية للعلاقات العامة، فإننا نسحب أيضًا اختلافات التوثيق الفعلية من كل PR: الفرق الموحد لأي .md الملف تحت docs/ التي لمست العلاقات العامة.
def fetch_doc_diffs(pr):
return [
"filename": f.filename, "status": f.status, "patch": f.patch
for f in pr.get_files()
if f.filename.startswith("docs/") and f.filename.endswith(".md") and f.patch
]
يذهب هذا الاختلاف إلى سياق النموذج، لذلك عندما يكتب “هذا هو أمر CLI الجديد،” فهو يقتبس المثال الذي كتبه مؤلف العلاقات العامة بالفعل في المستندات. هذا هو نفس المنطق كما كان من قبل: إعطاء النموذج مادة مصدر حقيقية ومهمة محدودة.
المطالبات نفسها تعيش كمهارات: ملفات تخفيض السعر الصغيرة (SKILL.md بالإضافة إلى القوالب المرجعية) تم التحقق منها في الريبو. توضح مهارة ملاحظات الإصدار كيفية اختيار النقاط البارزة، وكيفية تنظيم الأقسام، ومتى يتم إضافة رابط مستند، وما إلى ذلك. إنها تشبه تعليمات الإعداد، وهو بالضبط النموذج العقلي الصحيح.
نقطة التفتيش البشرية
بعد نشر RC، توجد مسودة إصدار GitHub هناك مع التمريرة الأولى للذكاء الاصطناعي. وهنا يأتي دور الإنسان:
- يقرأ المراجع المسودة، ويعدل النغمة والتأكيد، ويصلح أي شيء في النموذج زائد أو ناقص الوزن.
- عندها فقط يقومون بتشغيل
minor-releaseتشغيل، مما يؤدي إلى ترقية RC إلى النهائي.
يذهب وقت المراجع إلى الصقل، مما يحول نصف يوم من الكتابة إلى جلسة تحرير مدتها خمسة عشر دقيقة.
نحتفظ أيضًا بسجل ورقي للتحسين بمرور الوقت. نقوم بأرشفة ملفين جنبًا إلى جنب في Hugging Face Bucket: مسودة الذكاء الاصطناعي الأولية، التي تم تحميلها في وقت RC قبل أن يلمسها أي شخص، والنسخة التي تم تحريرها بواسطة الإنسان، والتي تم تحميلها عند انتهاء الإصدار النهائي.
hf cp release_notes_raw.txt "hf://buckets/huggingface/releases/huggingface_hub/$V/release_notes_raw.txt"
hf cp release_notes_edited.txt "hf://buckets/huggingface/releases/huggingface_hub/$V/release_notes_edited.txt"
إن جمع كليهما كل أسبوع يمنحنا مجموعة بيانات متزايدة حول “ما كتبه النموذج” مقابل “ما كنا نتمنى أن يكتبه”. مجموعة البيانات التي يمكننا بعد ذلك إعادة استخدامها لتحديث مهارة العميل.
سباكة مفتوحة وآمنة
وكان تجديد عملية الإصدار فرصة جيدة لتشديد الإجراءات الأمنية، وخاصة ضد هجمات سلسلة التوريد.
لا يوجد رمز PyPI. يستخدم النشر النشر الموثوق: يتحقق PyPI من رمز OIDC قصير العمر الذي تم سكه بواسطة GitHub لسير العمل الدقيق هذا، ويصدر شهادات PEP 740 / مصدر Sigstore لكل قطعة أثرية. ليس هناك سر طويل الأمد للتسرب أو التدوير.
permissions:
id-token: write
attestations: write
- uses: pypa/gh-action-pypi-publish@v1.14.0
with:
attestations: true
يتم تثبيت وقت تشغيل الوكيل والتحقق منه. نحن لا نفعل ذلك curl | bash أحدث OpenCode والأمل. نقوم بتثبيت الإصدار والتحقق من SHA256 قبل تشغيله:
curl -fsSL https://opencode.ai/install | bash -s -- --version "$OPENCODE_VERSION"
echo "$OPENCODE_SHA256 $(which opencode)" | sha256sum -c -
الأدوات المفتوحة لا تعني الأدوات الإهمال.
إذًا، ما هي التكلفة؟
لا شيء تقريبا. الإصدار الكامل (الملاحظات بالإضافة إلى إعلان Slack، عبر 20-40 من العلاقات العامة وبضع جولات من المطالبة) يكلف حوالي 0.25 دولار على مقدمي الاستدلال. مع الأوزان المفتوحة التي تتم محاسبتها على أساس الدفع أولاً بأول، فإن السؤال الحقيقي الوحيد كل أسبوع هو “هل هناك شيء يستحق الشحن؟”، وهناك دائمًا.
ما تغير في الممارسة العملية
انتقل الإيقاع من إصدار واحد كل 4 إلى 6 أسابيع إلى مرة واحدة في الأسبوع. وكانت التأثيرات الثانوية هي تلك المثيرة للاهتمام:
- أصبحت الملاحظات أفضل، وليس أسوأ. المسودة الأولى موجودة دائمًا، لذلك يذهب وقت المراجعة إلى الصقل. التجميع أكثر اتساقًا ونحذف عددًا أقل من الأشياء.
- تظهر الكسور في وقت سابق. تكتشف فروع الاختبار النهائية في كل RC مشكلات التكامل أثناء نافذة المرشح.
- تم تقصير حلقات المساهم. تبين أن التعليق التلقائي “تم الشحن في vX.YZ” كان مهمًا أكثر مما توقعنا. عندما يقوم شخص ما بالإبلاغ عن مشكلة في العلاقات العامة المغلقة، يمكن للجميع على الفور معرفة الإصدار الذي تم إصلاحه. كان ذلك عبارة عن عملية بحث يدوية عن العلامات.
اجعلها لك
هذا هو الجزء الذي نهتم به أكثر. يتشكل سير العمل حول huggingface_hub لكن الهيكل عام.
قابلة لإعادة الاستخدام تقريبًا كما هي:
- منطق التشغيل والإصدار (
minor-prereleaseثمminor-releaseثمpatch-release). - حلقة الثقة ولكن التحقق: البيان الحتمي، مسودة النموذج، التحقق من الصحة، إعادة المطالبة. هذه هي الفكرة القابلة للتحويل، بغض النظر عما تقوم بإنشائه.
- النشر الموثوق لـ OIDC، وقت التشغيل المثبت والتحقق من المجموع الاختباري، وترابط Slack.
- المطالبات القائمة على المهارات: قم بتبديل القوالب، واحتفظ بالهيكل.
خاص بنا:
- قائمة الريبو النهائية وتنسيقات دبوس التبعية الخاصة بها.
- التصنيف الدقيق للقسم ونبرة المهارات.
- وجهات الركود والدلو.
لتكييفه: افصل ملف سير العمل والبرامج النصية، ووجهه إلى الحزمة الخاصة بك، وأعد كتابة مهارة Markdown لصوت مشروعك، وقم بتعيين متغيرين من الريبو (معرف النموذج وإصدار OpenCode الخاص بك)، وقم بإعداد النشر الموثوق على PyPI، واحذف مهمة الاختبار النهائي إذا لم يكن لديك تدفقات أسفل. حلقة Trust-but-Verify هي الجزء الذي يستحق إعادة استخدامه كما هو. هذا ما يجعل قطعة أثرية تم إنشاؤها آمنة للشحن.
ما هي الخطوة التالية
- الفرز التلقائي لفشل المصب. اليوم يفتح سير العمل فروع الاختبار ويقرأ الإنسان CI. الخطوة التالية الواضحة هي التحقق من السجلات الفاشلة للإبلاغ عنها في رسالة Slack الداخلية.
- تمديد النمط. معظم هذا عام. نتوقع إعادة استخدام أجزاء كبيرة عبر مكتبات Python الأخرى في نظامنا البيئي.
الوجبات الجاهزة
إن أجزاء الإصدار التي كانت تحتاج إلى نصف يوم من العمل البشري المركز (كتابة الملاحظات، وصياغة الإعلانات، وتنسيق عمليات التحقق النهائية) هي الأجزاء التي يجيد النموذج صياغتها. كل شيء آخر ميكانيكي ويناسب ملف YAML. لم تكن الحيلة أبدًا مجرد “السماح للذكاء الاصطناعي بالقيام بذلك”. إنها السماح للنموذج بالصياغة، والسماح للكود الحتمي بالتحقق، والسماح للإنسان باتخاذ القرار. لقد تم تصميمه بالكامل من الأدوات المفتوحة والأوزان المفتوحة بحيث تقريب التكلفة إلى الصفر ويمكن لأي شخص تشغيله.
ملف سير العمل الكامل عام. إذا كنت تحتفظ بمكتبة بايثون، فقم بتقسيمها، وتعديلها، وأخبرنا كيف تسير الأمور!