Skip to content
دروس تعليميةمدة القراءة 11 دقيقة

الوضع الفردي: كيف يمكن لمُوصِّف واحد توسيم 10,000 مثال

دليل خطوة بخطوة للوضع الفردي في Potato: وسّم مجموعة أولية بنفسك، ودع نموذج لغة يوسّم الباقي، واستخدم فحوص الدقة لتقرر متى تصبح النتيجة جيدة بما يكفي للتوقف.

Potato Team

لديك 10,000 مراجعة منتجات تريد توسيمها بحسب المشاعر (إيجابي، محايد، سلبي). توظيف ثلاثة مُوصِّفين لتوسيمها كلها يستغرق أسابيع ويكلف آلاف الدولارات. يتيح الوضع الفردي لخبير مجال واحد أن يصل إلى جودة مماثلة بتوسيم 500-1,000 عنصر فقط. يتولى نموذج اللغة الباقي، ويراجع الإنسان كل ما لا يكون النموذج متأكدًا منه.

يمر هذا الدرس بالعملية كاملة.


ما ستحتاجه

  • Potato 2.3.0 أو أحدث، مع إضافات الذكاء الاصطناعي الخاصة بمزوّدي نماذج اللغة: pip install potato-annotation[ai]
  • مفتاح API من OpenAI أو Anthropic (لمكوّن نموذج اللغة)
  • مجموعة بياناتك بتنسيق JSONL
  • مُوصِّف واحد ملمّ بالمجال (قد تكون أنت)

الخطوة 1: تحضير بياناتك

أنشئ data/reviews.jsonl بمراجعة واحدة في كل سطر:

json
{"id": "rev_001", "text": "Absolutely love this product! Best purchase I've made all year.", "source": "amazon"}
{"id": "rev_002", "text": "It works fine. Nothing special but gets the job done.", "source": "amazon"}
{"id": "rev_003", "text": "Broke after two weeks. Complete waste of money.", "source": "amazon"}
{"id": "rev_004", "text": "The quality is decent for the price point. I might buy again.", "source": "amazon"}
{"id": "rev_005", "text": "Arrived damaged and customer service was unhelpful.", "source": "amazon"}

لأغراض هذا الدرس، تخيّل أن هذا الملف يحتوي على 10,000 مراجعة.


الخطوة 2: إنشاء الإعدادات

أنشئ config.yaml:

yaml
annotation_task_name: "Product Review Sentiment (Solo Mode)"
task_dir: "."
 
data_files:
  - "data/reviews.jsonl"
 
item_properties:
  id_key: id
  text_key: text
 
# --- Solo Mode Configuration ---
solo_mode:
  enabled: true
 
  # The model that labels. A list, so you can give fallbacks.
  labeling_models:
    - endpoint_type: openai
      model: "gpt-4o"
      api_key: ${OPENAI_API_KEY}
      temperature: 0.1
      max_tokens: 1024
 
  embedding:
    model_name: "all-MiniLM-L6-v2"
 
  uncertainty:
    strategy: direct_confidence
 
  # When you are allowed to stop labeling
  thresholds:
    end_human_annotation_agreement: 0.93
    minimum_validation_sample: 50
    confidence_low: 0.5
    confidence_high: 0.85
    periodic_review_interval: 100
 
  # What decides which instance you see next
  instance_selection:
    low_confidence_weight: 0.30
    disagreement_weight: 0.25
    diversity_weight: 0.20
    llm_predicted_weight: 0.15
    random_weight: 0.10
 
  batches:
    llm_labeling_batch: 25
    max_parallel_labels: 200
 
  labeling_functions:
    enabled: true
    auto_extract: true
    max_functions: 15
    min_confidence: 0.92
    min_coverage: 3
 
  edge_case_rules:
    enabled: true
    auto_extract_on_labeling: true
 
  confusion_analysis:
    enabled: true
    min_instances_for_pattern: 3
    max_patterns: 20
 
  prompt_optimization:
    enabled: true
    target_accuracy: 0.93
 
  refinement_loop:
    enabled: true
    trigger_interval: 50
    min_improvement: 0.02
    max_cycles: 3
 
  state_dir: "solo_state_reviews"
 
# --- Annotation Schema ---
annotation_schemes:
  - annotation_type: radio
    name: sentiment
    description: "What is the overall sentiment of this review?"
    labels:
      - "Positive"
      - "Neutral"
      - "Negative"
    label_requirement:
      required: true
    sequential_key_binding: true
 
output_annotation_dir: "output/"
export_annotation_format:
  - jsonl
  - parquet

الخطوة 3: تشغيل الخادم

bash
potato start config.yaml -p 8000

افتح http://localhost:8000 وسجّل الدخول. تظهر لوحة تحكم الوضع الفردي، وتعرض المشروع في مرحلة الإعداد، جاهزًا لتراجع الموجّه الذي صاغه.


الخطوة 4: التوصيف المتوازي، أول 50 عنصرًا

اختار Potato 50 مراجعة متنوعة باستخدام التجميع القائم على التضمينات. هذه المراجعات ليست عشوائية، بل اختيرت لتغطي توزيع بياناتك على أوسع نطاق ممكن.

وسّم كل واحدة منها. هذه هي المرحلة الأهم، لأن جودة تسمياتك الأولية تضع الحد الأعلى لما يستطيع نموذج اللغة تعلّمه. خذ وقتك والتزم بالاتساق.

تقدير الوقت: 15-25 دقيقة بمعدل 20-30 ثانية لكل عنصر.

عندما يكتمل عدد كافٍ من هذه العناصر، يبدأ نموذج اللغة التوسيم إلى جانبك دون أن تطلب منه ذلك.


الخطوة 5: نموذج اللغة يلحق بك

تعمل هذه المرحلة من تلقاء نفسها. يرسل Potato إلى نموذج اللغة دفعة من 200 عنصر مع تسمياتك الأولية الخمسين بوصفها أمثلة few-shot، ثم يقارن التنبؤات بعشر تسميات أولية محجوزة لتقدير الدقة الأساسية.

يظهر مؤشر تقدّم في لوحة التحكم. يستغرق ذلك عادةً 1-2 دقيقة بحسب مزوّد نموذج اللغة.

النتيجة المعتادة: يصل نموذج اللغة إلى دقة 75-85% في المعايرة الأولى. هذا متوقع، فهو لم يتعلم أسلوبك في التوصيف بعد.


الخطوة 6: تحليل الالتباس

يعرض Potato مصفوفة التباس تبيّن مواضع اختلاف نموذج اللغة مع تسمياتك. مخرج نموذجي:

text
Confusion Analysis (Round 1)
============================
Overall Accuracy: 0.82 (target: 0.93)

Top Confusion Pairs:
  Neutral -> Positive:  14 instances (7.0%)
  Negative -> Neutral:   9 instances (4.5%)
  Positive -> Neutral:   4 instances (2.0%)

يشير هذا إلى نقطة الضعف الرئيسية لنموذج اللغة هنا: فهو يرفع المراجعات المحايدة إلى إيجابية مرة بعد مرة. هذا خطأ شائع، لأن نماذج اللغة تميل إلى الإيجابية.

إجراؤك: راجع أزواج الالتباس. انقر على كل زوج لترى العناصر المحددة التي أخطأ فيها نموذج اللغة، فهذه أسرع طريقة لفهم كيف يخطئ.


الخطوة 7: العودة إلى مراجعة الموجّه

بناءً على تحليل الالتباس، يصوغ Potato إرشادات محسّنة لنموذج اللغة ويعرضها جنبًا إلى جنب: الموجّه الحالي في جانب، والتعديلات المحددة التي يقترحها انطلاقًا من أنماط الأخطاء في الجانب الآخر.

على سبيل المثال، قد يقترح Potato إضافة:

"المراجعات التي تصف المنتج بأنه 'جيد' أو 'مقبول' أو 'لا بأس به' دون عاطفة قوية يجب أن توسم Neutral، حتى لو ذكرت الشراء مرة أخرى."

راجع كل تعديل مقترح ووافق عليه أو عدّله أو ارفضه. يمكنك أيضًا كتابة توضيحاتك الخاصة.

تقدير الوقت: 5-10 دقائق.


الخطوة 8: دوال التوسيم

يولّد Potato دوال توسيم برمجية من الأنماط الموجودة في تسمياتك الأولية. هذه قواعد سريعة وحتمية تتعامل مع الحالات السهلة:

text
Generated Labeling Functions:
  LF1: Strong positive words (love, amazing, best, excellent)
       Precision: 0.97, Coverage: 0.06
  LF2: Strong negative words (terrible, awful, worst, waste)
       Precision: 0.95, Coverage: 0.04
  LF3: Exclamation + positive adjective
       Precision: 0.94, Coverage: 0.03
  LF4: Return/refund mention + negative context
       Precision: 0.92, Coverage: 0.02
  ...
  Total coverage: 0.18 (1,800 of 10,000 instances)

تغطي دوال التوسيم 18% من مجموعة بياناتك بدقة تتجاوز 92%. توسم هذه العناصر تلقائيًا، فيتفرغ نموذج اللغة والإنسان للحالات الأصعب.

إجراؤك: راجع الدوال المولّدة وعطّل أي دالة تبدو غير موثوقة. هذه الخطوة اختيارية، لأن Potato لا يحتفظ في كل الأحوال إلا بالدوال التي تتجاوز عتبة الدقة التي أعددتها.


الخطوة 9: التوصيف النشط (125-375 عنصرًا)

هنا تنجز معظم التوسيم. يختار Potato العناصر باستخدام المجموعات الموزونة المحددة في instance_selection أعلاه:

  • low_confidence_weight (0.30): مراجعات تكون ثقة نموذج اللغة فيها في أدنى مستوياتها
  • disagreement_weight (0.25): مراجعات يختلف فيها نموذج اللغة ودوال التوسيم
  • diversity_weight (0.20): مراجعات مختارة لتنتشر في فضاء التضمينات بدلًا من أن تتكتل
  • llm_predicted_weight (0.15): مراجعات وسمها نموذج اللغة تُعاد لمقارنتها بتوسيم بشري
  • random_weight (0.10): مراجعات عشوائية للمعايرة

يوجد وزنان آخران يبقيان هنا على قيمتهما الافتراضية صفر، فلا يسهمان بشيء: edge_case_rule_weight للعناصر التي تطابق قاعدة حالة حدّية مكتشفة، وcartography_weight للعناصر التي تتأرجح ثقتها بين الجولات. يتحقق Potato من أن مجموع الأوزان يساوي 1.0 ويسجّل تحذيرًا إذا لم يكن كذلك، لكنه يستخدم القيم كما كُتبت، فاحرص بنفسك على أن يكون المجموع صحيحًا.

توسم هذه العناصر في دفعات من 25. بعد كل دفعة، يحدّث Potato تقدير دقة نموذج اللغة ويقرر ما إذا كان سيستمر.

المسار المعتاد:

  • الدفعات 1-3 (75 عنصرًا): ترتفع الدقة من 82% إلى 87%
  • الدفعات 4-6 (150 عنصرًا): تصل الدقة إلى 90%
  • الدفعات 7-10 (250 عنصرًا): تستقر الدقة عند 91-92%

إذا بلغ الاتفاق قيمة end_human_annotation_agreement التي حددتها، ينتقل الوضع الفردي نحو التوسيم الذاتي. وإلا فإنه يواصل التنقل بين المراجعة والتحسين.

تقدير الوقت: 45-90 دقيقة إجمالًا، بحسب عدد الدفعات المطلوبة.


الخطوة 10: حلقة التحسين

إذا بقيت الدقة دون العتبة بعد التوسيم النشط، يشغّل Potato جولة أخرى من حلقة التحسين:

  1. يعيد نموذج اللغة توسيم مجموعة البيانات كاملة بالإرشادات المحدّثة ومزيد من أمثلة few-shot
  2. يعيد Potato حساب الدقة مقابل جميع التسميات البشرية
  3. يحدد أنماط الالتباس الجديدة
  4. يحسّن الإرشادات مرة أخرى

لا تتطلب هذه المرحلة منك تدخلًا يُذكر. عليك فقط الموافقة على تغييرات الإرشادات.

النتيجة المعتادة: تتحسن الدقة بنسبة 2-4% في كل جولة تحسين.


الخطوة 11: حل الخلافات

يعرض Potato أكثر العناصر إثارة للخلاف: الحالات التي يعطي فيها نموذج اللغة ودوال التوسيم وتحليل أقرب الجيران إجابات مختلفة. لكل عنصر ترى:

  • نص المراجعة
  • تنبؤ نموذج اللغة ودرجة ثقته
  • أصوات دوال التوسيم
  • أقرب 3 أمثلة موسومة مع تسمياتها
  • استدلال نموذج اللغة بطريقة chain-of-thought

هذه هي الحالات الصعبة، وتسمياتك هنا تحمل وزنًا أكبر مما تحمله في أي موضع آخر من العملية.

تقدير الوقت: 20-30 دقيقة لـ 100-150 عنصرًا.


الخطوة 12: تركيب الحالات الحدّية

يولّد Potato مراجعات اصطناعية تستهدف أنماط الالتباس المتبقية. على سبيل المثال، إذا ظل نموذج اللغة يتعثر في "المراجعات المحايدة التي تذكر الشراء مرة أخرى"، فإنه يولّد أمثلة مثل:

"إنه منتج مقبول بالنسبة لسعره. قد أشتري واحدًا آخر إذا كان هناك تخفيض."

توسم هذه الأمثلة الاصطناعية، ويضيفها Potato إلى سياق few-shot الخاص بنموذج اللغة.

تقدير الوقت: 10-15 دقيقة لـ 30 مثالًا.


الخطوة 13: المراجعة الدورية

في هذه المرحلة يكون نموذج اللغة قد وسم معظم مجموعة البيانات. يرتّب Potato جميع تسمياته بحسب الثقة ويرسل إليك الأقل ثقة منها في دفعات من 25.

text
Confidence Escalation Progress:
  Batch 1: 25 instances, 23/25 correct (92%)
  Batch 2: 25 instances, 24/25 correct (96%)
  Batch 3: 25 instances, 25/25 correct (100%)
  -> Stopping: last 3 batches stable

بمجرد أن تتوقف الدقة عن التغير عبر ثلاث دفعات متتالية، يعامل الوضع الفردي التسميات المتبقية عالية الثقة على أنها موثوقة. لاحظ أن المعيار هنا هو الاستقرار وليس الكمال. التشغيل أعلاه يتوقف بعد 92% و96% و100% لأن الرقم استقر، وليس لأن الدفعة الأخيرة خلت من الأخطاء.

تقدير الوقت: 15-20 دقيقة.


الخطوة 14: تحسين الموجّه

تعمل هذه المرحلة من تلقاء نفسها. يجرّب Potato 8 صيغ للموجّه ويحتفظ بالصيغة التي تحقق أعلى درجة F1 على التسميات البشرية التي جمعتها:

text
Prompt Optimization Results:
  Variant 1 (direct, 5 examples):     F1=0.91
  Variant 2 (CoT, 5 examples):        F1=0.93
  Variant 3 (direct, 10 examples):    F1=0.92
  Variant 4 (CoT, 10 examples):       F1=0.94  <-- selected
  Variant 5 (direct, 15 examples):    F1=0.92
  Variant 6 (CoT, 15 examples):       F1=0.93
  Variant 7 (self-consistency, 5x):   F1=0.94
  Variant 8 (self-consistency, 10x):  F1=0.94

ثم يستخدم أفضل موجّه في جولة نهائية لإعادة التوسيم.


الخطوة 15: التحقق النهائي

يسحب Potato 100 عنصر عشوائي وسمها نموذج اللغة لتراجعها. توسمها أنت، ويقارن Potato تسمياتك بتسميات نموذج اللغة.

text
Final Validation:
  Reviewed: 100 instances
  LLM correct: 94/100 (94%)
  Threshold: 93%
  -> PASSED

إذا تجاوز نموذج اللغة عتبتك، يكتمل المشروع. وإلا فإنه يعود إلى التوصيف النشط لجولة أخرى. هذه العودة هي الانتقال الوحيد المسموح به من التحقق النهائي.

تقدير الوقت: 10-15 دقيقة.


ملخص النتائج

في النهاية، تعرض لوحة التحكم مصدر التسميات. ليس للوضع الفردي واجهة سطر أوامر (فهو يعمل داخل الخادم ويُدار من صفحاته الخاصة)، لذا تُقرأ هذه النتائج من النسخة العاملة وليس من طرفية:

text
Solo Mode Complete
==================
Dataset: 10,000 instances
Total human labels: 612
  Seed: 50
  Active labeling: 275
  Disagreement exploration: 137
  Edge case synthesis: 30
  Confidence escalation: 75
  Final validation: 45

LLM labels: 8,200 (accuracy: 94.1%)
LF labels: 1,800 (precision: 95.3%)
Unlabeled: 0

Final label distribution:
  Positive: 4,823 (48.2%)
  Neutral:  3,011 (30.1%)
  Negative: 2,166 (21.7%)

Total human time: ~3.5 hours
Estimated multi-annotator cost (3x): ~$4,500
Solo Mode cost: ~$450 (API fees) + ~$175 (annotator time)
Savings: ~88%

وسم الإنسان 612 عنصرًا من أصل 10,000، أي نحو 6%. تولى نموذج اللغة ودوال التوسيم الباقي بدقة تتجاوز 94%.


تصدير النتائج

يكتب الوضع الفردي في وحدة التخزين نفسها التي يكتب فيها أي مشروع آخر، لذا تُستخرج التسميات عبر أداة التصدير المعتادة:

bash
python -m potato.export -c config.yaml -f jsonl -o ./export/

يتضمن كل سطر التسمية ومصدرها:

json
{"id": "rev_001", "sentiment": "Positive", "source": "human", "confidence": 1.0}
{"id": "rev_002", "sentiment": "Neutral", "source": "llm", "confidence": 0.91}
{"id": "rev_003", "sentiment": "Negative", "source": "labeling_function", "confidence": 0.97}

لتصدير Parquet:

python
import pandas as pd
df = pd.read_parquet("output/exports/parquet/annotations.parquet")
print(df["sentiment"].value_counts())

يحتوي annotations.parquet على صف واحد لكل عنصر ومُوصِّف، ويُسطَّح كل مخطط توصيف في عمود خاص به، لذا تختار المخطط باسمه وليس عبر عمود عام باسم value.


ضمان الجودة: التحقق الهجين

لمجموعات البيانات التي تحتاج إلى جودة صالحة للنشر، أضف مُوصِّفًا ثانيًا يراجع عيّنة. يصف التوثيق المصدري للوضع الفردي خيارات التحقق بمزيد من التفصيل.

ليس للوضع الفردي كتلة تحقق خاصة به، لذا فهذه جولة ثانية عادية: صدّر التسميات، ثم مرّرها مرة أخرى عبر Potato كمشروع عادي يراجع فيه مراجع واحد عيّنة بنسبة 10%، واحسب الاتفاق بين المراجع وتسميات الوضع الفردي كما تفعل مع أي مُوصِّفَين. (لـ icl_labeling كتلة verification بالفعل، لكنها تخص التوسيم داخل السياق وليس الوضع الفردي.)


استكشاف الأخطاء وإصلاحها

دقة نموذج اللغة تستقر دون العتبة

  • زِد عدد العناصر الأولية: جرّب 75-100 عنصر أولي بدلًا من 50
  • غيّر نموذج اللغة: جرّب claude-sonnet-4-20250514 بدلًا من GPT-4o (أو العكس)
  • اخفض العتبة: إذا تعذّر الوصول إلى 93%، ففكّر في ما إذا كانت 90% مقبولة لحالة استخدامك
  • افحص بياناتك: بعض مجموعات البيانات غامضة بطبيعتها. إذا كان الاتفاق بين البشر أنفسهم لن يتجاوز 90%، فلا تتوقع أن يؤدي نموذج اللغة أفضل من ذلك

التوصيف النشط يستغرق دفعات كثيرة جدًا

  • زِد حجم الدفعة: غيّر batch_size من 25 إلى 50
  • اضبط أوزان المجموعات: إذا جاءت معظم العناصر المُصعَّدة من مجموعة الثقة المنخفضة، فقلّل low_confidence_weight وارفع disagreement_weight أو diversity_weight

تغطية دوال التوسيم منخفضة

  • هذا طبيعي في المهام التي تفتقر إلى إشارات معجمية قوية (مثل كشف السخرية والمشاعر الضمنية)
  • تعمل دوال التوسيم بأفضل شكل مع الأنماط الصريحة القائمة على الكلمات المفتاحية
  • يظل الوضع الفردي يعمل دون دوال توسيم، وفي هذه الحالة يغطي نموذج اللغة تلك العناصر

قراءة إضافية