توصيف وكلاء تصفح الويب: من مسارات WebArena إلى التقييم البشري
كيفية استخدام عرض مسارات وكلاء الويب في Potato لتقييم وكلاء تصفح الويب المستقلة، مع لقطات شاشة خطوة بخطوة وتراكبات SVG ومخططات توصيف لكل خطوة.
حوّل مسار الوكيل إلى تنسيق وكيل الويب في Potato، واعرضه بالعارض web_agent_trace بحيث تحمل كل لقطة شاشة تراكباً يبيّن أين نقر الوكيل، ثم قيّم الخطوات بمخطط trajectory_eval.
يُحكم على وكيل تصفح الويب من خلال الإجراءات التي ينفذها على الصفحة، لذا يحتاج التقييم إلى نصفي كل خطوة معاً، أي حالة الصفحة التي رآها الوكيل والإجراء الذي نفذه عليها. سجل الإجراءات وحده لا يكفي لإصدار الحكم. عبارة "Clicked element product-101" لا تخبر المراجع ما إذا كان ذلك أرخص حاسوب محمول في الصفحة، ولقطة الشاشة التي لا تحمل علامة تتركه يخمّن أيّ رابط من بين عشرات الروابط كان الهدف.
يُعدّ هذا الدليل ذلك التقييم لمسارات WebArena. ويصلح المسار نفسه لـ VisualWebArena وMind2Web وسجلات Anthropic Computer Use وتسجيلات المتصفح الخام، لأن محولاً واحداً يغطيها جميعاً. للاطلاع على المرجع الكامل للإعدادات، راجع الوثائق المصدرية.
ما تحتاج إليه
pip install potato-annotationتحتاج أيضاً إلى المسارات نفسها، وهي في WebArena لقطات شاشة مع سجل إجراءات بصيغة JSON لكل حلقة. يسجّل VisualWebArena البنية نفسها مع معلومات إضافية عن الربط البصري، أما تسجيلات المتصفح الخام فتحمل بدلاً من ذلك بيانات منفذ العرض ومسار الفأرة.
ما يحتويه مسار WebArena الخام
تحمل حلقة WebArena وصف المهمة وتسلسل الإجراءات ومسار كل لقطة شاشة:
{
"trace_id": "wa_001",
"task": "Find the cheapest laptop on the electronics store and add it to the cart",
"website": "shopping",
"steps": [
{
"step": 0,
"url": "http://shop.example.com/",
"action_type": "click",
"action_target": "Electronics category link",
"element_id": "nav-electronics",
"coordinates": [245, 82],
"screenshot": "screenshots/wa_001_step_00.png"
},
{
"step": 1,
"url": "http://shop.example.com/electronics",
"action_type": "click",
"action_target": "Laptops subcategory",
"element_id": "cat-laptops",
"coordinates": [180, 310],
"screenshot": "screenshots/wa_001_step_01.png"
}
],
"success": true
}تحويل المسار
يقرأ عارض Potato تنسيقاً موحداً للخطوات بدلاً من التنسيق الخاص بكل إطار عمل، لذا تمر الحلقات الخام عبر المحول أولاً:
python -m potato.trace_converter -i traces.json -f web_agent -o data/web_traces.jsonlيكتب ذلك نسخة واحدة لكل حلقة، وتحمل كل خطوة step_index وscreenshot_url وaction_type وelement المستهدف مع مربعه المحيط وcoordinates وmouse_path اختيارياً، إضافة إلى thought وobservation الخاصين بالوكيل حيث سجّلهما السجل المصدر. واستبدال -f web_agent بـ --auto-detect يجعل المحول يتعرف على التنسيق بنفسه، وهو الخيار المناسب عندما يضم مجلد واحد مسارات من أكثر من إطار عمل.
إعدادات المشروع
العارض نوع عرض وليس نوع توصيف، لذا يوضع تحت instance_display.fields وتبقى مخططات التوصيف منفصلة عنه. حجم لقطة الشاشة هو الإعداد الذي يستحق أن تحسمه أولاً. فعرض 900 بكسل يُبقي صفحة سطح مكتب كاملة مقروءة دون أن يدفع عناصر التحكم في التوصيف إلى ما دون أسفل الشاشة.
annotation_task_name: "WebArena Agent Evaluation"
task_dir: "."
data_files:
- "data/web_traces.jsonl"
item_properties:
id_key: id
text_key: task_description
output_annotation_dir: "output/"
export_annotation_format: "jsonl"
instance_display:
layout:
direction: vertical
gap: 16px
fields:
- key: task_description
type: text
label: "Task"
- key: steps
type: web_agent_trace
label: "Agent Browsing Trace"
display_options:
show_overlays: true
show_filmstrip: true
show_thought: true
show_observation: true
show_element_info: true
screenshot_max_width: 900
screenshot_max_height: 600
filmstrip_size: 80
annotation_schemes:
- annotation_type: radio
name: task_success
description: "Did the agent complete the task?"
labels:
- "Success"
- "Partial success"
- "Failure"
label_requirement:
required: true
- annotation_type: radio
name: task_efficiency
description: "Was the agent's path to the goal efficient?"
labels:
- "Optimal path"
- "Reasonable but not optimal"
- "Inefficient, unnecessary steps"
- "Completely wrong direction"
label_requirement:
required: true
- annotation_type: trajectory_eval
name: step_evaluation
description: "Judge each action against the task"
steps_key: steps
step_text_key: action_type
correctness_options:
- correct
- acceptable
- incorrect
- unnecessary
error_types:
- name: wrong_element_clicked
- name: wrong_page_navigated_to
- name: missed_better_option
- name: incorrect_form_input
- name: premature_completion
- name: unnecessary_navigation
- name: failed_to_scroll
- name: wrong_page_section
- name: other
severities:
- name: minor
weight: -1
- name: major
weight: -5
- name: critical
weight: -10
show_score: true
max_score: 100
user_config:
allow_all_users: trueيغطي مخطط trajectory_eval واحد مرحلة التقييم لكل خطوة بأكملها. فهو يعرض كل خطوة في بطاقة ويجمع في كل منها الصحة ونوع الخطأ والشدة وتبريراً مكتوباً، ثم يحسب درجة جودة على مستوى المسار من أوزان الشدة. الأوزان أعلاه تكلّف المسار خمس نقاط عن الخطأ الكبير وعشراً عن الخطأ الحرج. اضبطها عن قصد، لأنها تحدد ترتيب مسار فيه إخفاق خطير واحد مقارنة بمسار فيه أربعة إخفاقات صغيرة.
ما يراه الموصِّف

تملأ لقطة شاشة الخطوة الحالية اللوحة الرئيسية، وتُرسم فوقها تراكبات SVG. يحدد كل تراكب جزءاً مختلفاً من الخطوة، وألوانها ثابتة:
| التراكب | ما يحدده |
|---|---|
| دائرة حمراء مع علامة تصويب | إحداثيات النقر |
| تظليل أصفر | الحقل الذي كتب فيه الوكيل |
| سهم أخضر | اتجاه التمرير ومقداره |
| مستطيل أزرق متقطع | المربع المحيط بالعنصر المستهدف |
| خط منحنٍ برتقالي | مسار الفأرة حتى الهدف |
يمتد شريط من الصور المصغرة على طول الأسفل، والنقر على إحداها ينقلك إلى تلك الخطوة. في المسارات التي تتجاوز نحو عشر خطوات، يصنع شريط الصور المصغرة الفرق بين مراجع يرى شكل التشغيل كله ومراجع يمرّر دون أن يرى شيئاً. تعرض لوحة تفاصيل الخطوة معلومات العنصر وتفكير الوكيل نفسه والملاحظة التي سجّلها، ويمكن إيقاف كل منها في display_options عندما لا يحتوي السجل المصدر على شيء مفيد فيها.
صف من مربعات الاختيار أسفل العارض يشغّل التراكبات ويوقفها:
| عنصر التحكم | التراكب |
|---|---|
| Clicks | علامة التصويب الحمراء للنقر |
| Bounding Boxes | المستطيل الأزرق المتقطع |
| Mouse Path | الخط المنحني البرتقالي |
| Scroll | السهم الأخضر للتمرير |
لإيقاف التراكبات أهمية في الصفحات المزدحمة، حيث قد تقع علامة النقر فوق النص الذي يخبرك بالضبط ما إذا كان النقر صحيحاً. لاحظ أن التظليل الأصفر للكتابة ليس له عنصر تحكم خاص به. أربعة من التراكبات الخمسة يمكن تبديلها كل على حدة، أما تظليل الحقل المكتوب فيُرسم دائماً. لا توجد اختصارات لوحة مفاتيح في هذا العارض، لذا يجري التنقل بين الخطوات عبر شريط الصور المصغرة وعناصر التحكم في الخطوات.
مرحلة التوصيف
يعالج المراجع المسار الواحد في خمس خطوات:
- اقرأ وصف المهمة. كل ما يلي ذلك حكم يُقاس عليه.
- تصفّح شريط الصور المصغرة. كوّن صورة عن شكل التشغيل قبل تقييم أي شيء، حتى لا تُعلَّم خطوة مبكرة بأنها صحيحة استناداً إلى أدلة لا تظهر إلا لاحقاً.
- امشِ عبر الخطوات. في كل خطوة، اقرأ حالة الصفحة، وافحص التراكب لترى على أي شيء تصرّف الوكيل، ثم قيّم الإجراء. إذا كان خاطئاً، فاختر نوع الخطأ وشدته، واذكر في التبرير ما كان ينبغي للوكيل أن يفعله بدلاً من ذلك.
- قيّم المسار. احكم على النجاح العام والكفاءة بعد أن ترى كل الخطوات.
- أرسل وانتقل إلى التالي.
تقسم خيارات الصحة الأربعة الخطوات على امتداد الخط الذي يهم بيانات التدريب. الإجراءات الصحيحة تتقدم نحو الهدف بالطريقة المتوقعة. الإجراءات المقبولة تحرز تقدماً عبر طريق أبطأ، مثل التصفح إلى صفحة فئة بدلاً من استخدام مربع البحث. الإجراءات غير الصحيحة أخطاء، مثل عنصر خاطئ أو صفحة غير ذات صلة أو نص خاطئ في نموذج. الإجراءات غير الضرورية لا تنفع ولا تضر، مثل نقرة يتبعها فوراً رجوع إلى الصفحة السابقة، ويستحق فصلها عن الأخطاء لأن الوكيل الذي يتجول بلا هدف مشكلة مختلفة عن الوكيل الذي يخطئ.
تصنيف الأخطاء
أنواع الأخطاء هي ما يحوّل كومة من المسارات الفاشلة إلى شيء يستطيع مطور الوكيل أن يتصرف بناءً عليه، لذا ينبغي أن تقابل الفئات أسباباً يمكن التمييز بينها لا درجات من الخطأ:
| نوع الخطأ | معناه | مثال |
|---|---|---|
| نقر عنصر خاطئ | تصرّف الوكيل على عنصر الواجهة الخطأ | نقر "Tablets" بدلاً من "Laptops" |
| الانتقال إلى صفحة خاطئة | انتهى الوكيل إلى مكان غير ذي صلة | انتقل إلى "About Us" بدلاً من قائمة المنتجات |
| تفويت خيار أفضل | كان هناك إجراء أفضل متاح | تصفّح الفئات بينما كان مربع البحث أمامه |
| إدخال خاطئ في نموذج | أدخل الوكيل نصاً خاطئاً | بحث عن "labtop" بدلاً من "laptop" |
| إكمال مبكر | أعلن الوكيل النجاح قبل الأوان | أضاف المنتج الخطأ إلى السلة وتوقف |
| تنقل غير ضروري | الخطوة لا تسهم في الهدف | زار الصفحة الرئيسية بين صفحتي فئتين |
| الإخفاق في التمرير | كان الهدف أسفل منفذ العرض | لم يظهر العنصر قط ولم يمرّر الوكيل قط |
| قسم خاطئ من الصفحة | الصفحة صحيحة والمنطقة خاطئة | نقر الترويسة بدلاً من المحتوى الرئيسي |
التعامل مع المسارات الصعبة
في مسار يتجاوز خمس عشرة خطوة، يؤدي تقييم كل خطوة بالعمق نفسه إلى إنفاق معظم الجهد على خطوات كانت سليمة بوضوح. تصفّح شريط الصور المصغرة بحثاً عن الأنماط الثلاثة التي تدل على مشكلة، ثم ركّز الجهد هناك. هذه الأنماط هي عنوان URL يتغير على نحو غير متوقع، وخطوة يرجع فيها الوكيل إلى الوراء، وسلسلة من لقطات الشاشة شبه المتطابقة، وهي تعني عادةً أن الوكيل عالق في حلقة تكرار.
في المسار الفاشل، أول خطوة غير صحيحة هي التوصيف الذي يستحق أن تتقنه. فكل ما يليها يحدث في حالة ما كان ينبغي للوكيل أن يبلغها أصلاً، لذا تصف الأخطاء اللاحقة العواقب لا السبب.
بعض الإجراءات لا يمكن الحكم عليها من لقطة الشاشة وحدها، وذلك عادةً حين تتداخل عدة عناصر عند نقطة النقر. تعطي معلومات العنصر في لوحة الخطوة الوسمَ والنص والمربع المحيط الخاص بالهدف، وهذا يكفي في العادة لحسم ما جرى نقره فعلاً؛ وshow_element_info يُبقي تلك اللوحة ظاهرة.
VisualWebArena
تمر مسارات VisualWebArena عبر المحول نفسه، الذي يتعرف على التنسيقين من الحقلين action_type وelement في خطوات الإجراءات. وتظهر معلومات الربط التي تحملها تلك المسارات في صورة تراكب المربع المحيط، لذا فإن مرحلة تركّز على الربط مسألة تتعلق بما يُبقيه الموصِّفون على الشاشة لا بتعديل في الإعدادات. إبقاء Bounding Boxes محدداً وإلغاء تحديد Clicks يعطي العرض الذي يبيّن ما إذا كان الوكيل قد استهدف العنصر الصحيح وليس البكسل الصحيح فقط.
قراءة النتائج
تميل أخطاء وكلاء الويب إلى التجمع عند نقاط بعينها من المسار، ومعدل الخطأ بحسب موضع الخطوة هو أسرع طريقة لمعرفة أين. يخزّن كل توصيف trajectory_eval قائمة من السجلات لكل خطوة، لكل منها step_index وcorrectness:
import json
annotations = []
with open("output/exports/jsonl/annotations.jsonl") as f:
for line in f:
annotations.append(json.loads(line))
step_counts = {}
for ann in annotations:
evaluation = ann["labels"].get("step_evaluation", {})
for step in evaluation.get("steps", []):
pos = step["step_index"]
counts = step_counts.setdefault(pos, {})
label = step.get("correctness", "unrated")
counts[label] = counts.get(label, 0) + 1
print("Error rate by step position:")
for pos in sorted(step_counts):
counts = step_counts[pos]
total = sum(counts.values())
errors = counts.get("incorrect", 0) + counts.get("unnecessary", 0)
print(f" Step {pos}: {errors / total:.1%} error rate ({total} observations)")يجيب توزيع أنواع الأخطاء عن السؤال الآخر، وهو ما الذي يخطئ فيه الوكيل لا متى يخطئ:
error_counts = {}
for ann in annotations:
evaluation = ann["labels"].get("step_evaluation", {})
for step in evaluation.get("steps", []):
error = step.get("error_type")
if error:
error_counts[error] = error_counts.get(error, 0) + 1
for error, count in sorted(error_counts.items(), key=lambda x: -x[1]):
print(f" {error}: {count}")توسيع نطاق التقييم
لنتيجة تنوي نشرها، لا يكفي مراجع واحد لكل مسار، لأن الأحكام على مستوى الخطوة تحمل بالضبط نوع الغموض الذي وُجدت إحصاءات الاتفاق لقياسه. اضبط هدف التغطية وترتيب التوزيع في المستوى الأعلى من الإعدادات:
num_annotators_per_item: 3
assignment_strategy: randomثم قارن بين الموصِّفين في التسمية على مستوى المسار، فهي التسمية التي يكون فيها الخلاف غير ملتبس. صدّر إلى Parquet أولاً، حتى تجري المقارنة على أعمدة لا على JSON يحتاج إلى تحليل:
python -m potato.export -c config.yaml -f parquet -o ./parquet_export/from sklearn.metrics import cohen_kappa_score
import pandas as pd
df = pd.read_parquet("parquet_export/annotations.parquet")
success = df[df["schema_name"] == "task_success"]
pivot = success.pivot(index="instance_id", columns="annotator", values="value")
annotators = pivot.columns.tolist()
for i in range(len(annotators)):
for j in range(i + 1, len(annotators)):
pair = pivot[[annotators[i], annotators[j]]].dropna()
kappa = cohen_kappa_score(pair[annotators[i]], pair[annotators[j]])
print(f"Kappa ({annotators[i]} vs {annotators[j]}): {kappa:.3f}")في التقييمات التي تبلغ مئات المسارات، يضع Solo Mode نموذجاً على قائمة الانتظار نفسها التي يعمل عليها المراجع البشري، فيقترح النموذج التسميات ويصححها الإنسان إلى أن يتفقا بما يكفي من التكرار ليُكمل النموذج الباقي:
solo_mode:
enabled: true
labeling_models:
- endpoint_type: "anthropic"
model: "claude-sonnet-4-20250514"
api_key: "${ANTHROPIC_API_KEY}"
thresholds:
end_human_annotation_agreement: 0.90
minimum_validation_sample: 50الإعداد الذي يستحق التفكير هو عتبة الاتفاق، لا اختيار النموذج. عند 0.90 يواصل الإنسان التوصيف حتى تطابق تسع من كل عشر تسميات للنموذج تسمياته، مقيسةً على خمسين مقارنة على الأقل، وخفضها يقايض جودة التسميات بساعات المراجعة بطريقة يصعب اكتشافها لاحقاً.
قراءات إضافية
- التوصيف الوكيلي للمرجع الكامل للمحولات والعروض
- توصيف وكلاء الويب لخيارات العرض في العارض
- تقييم وكلاء الذكاء الاصطناعي لتقييم الوكلاء خارج المتصفح
- التصدير إلى Parquet للأعمدة التي يقرؤها التحليل أعلاه