تاريخ النشر: 30 يناير 2026
عند إنشاء ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" في "الأداء"، كان التحدي الهندسي الأساسي هو جعل Gemini يعمل بسلاسة مع عمليات تتبُّع الأداء المسجّلة في DevTools.
تعمل النماذج اللغوية الكبيرة (LLM) ضمن "قدرة استيعاب" تشير إلى حدّ صارم لكمية المعلومات التي يمكنها معالجتها في المرة الواحدة. يتم قياس هذه السعة بالرموز المميزة. بالنسبة إلى نماذج Gemini، يتألف الرمز المميز الواحد من أربعة أحرف تقريبًا.
عمليات تتبُّع الأداء هي ملفات JSON ضخمة، وغالبًا ما تتألف من عدة ميغابايت. سيؤدي إرسال تتبُّع أولي إلى استنفاد قدرة استيعاب النموذج على الفور ولن يترك مساحة لأسئلتك.
لإتاحة المساعدة المستندة إلى الذكاء الاصطناعي في "الأداء"، كان علينا تصميم نظام يزيد من كمية البيانات المفيدة لنموذج لغوي كبير مع الحد الأدنى من استخدام الرموز المميزة. في هذه المدونة، يمكنك التعرّف على الأساليب التي استخدمناها لتحقيق ذلك وتطبيقها في مشاريعك.
تخصيص السياق الأوّلي
إنّ تصحيح الأخطاء في أداء موقع إلكتروني مهمة معقّدة. يمكن للمطوّر إما الاطّلاع على التتبُّع الكامل للحصول على السياق، أو التركيز على "مؤشرات Core Web Vitals" والفترات الزمنية ذات الصلة من التتبُّع، أو حتى الانتقال إلى التفاصيل والتركيز على الأحداث الفردية، مثل النقرات أو عمليات التمرير، ومكدّسات طلبات التنفيذ ذات الصلة.
للمساعدة في عملية تصحيح الأخطاء، يجب أن تتطابق المساعدة المستندة إلى الذكاء الاصطناعي في DevTools مع مسارات المطوّرين هذه، وأن تعمل فقط مع البيانات ذات الصلة لتقديم نصائح خاصة بمجال تركيز المطوّر. لذلك، بدلاً من إرسال التتبُّع الكامل دائمًا، أنشأنا ميزة تستند إلى الذكاء الاصطناعي لتقسيم البيانات استنادًا إلى مهمة تصحيح الأخطاء التي تنفّذها:
| مهمة تصحيح الأخطاء | البيانات التي تم إرسالها في البداية إلى ميزة المساعدة المستندة إلى الذكاء الاصطناعي |
|---|---|
| الدردشة حول بيانات تتبُّع الأداء | ملخّص التتبُّع: تقرير مستند إلى نص يتضمّن معلومات عالية المستوى من عملية التتبُّع وجلسة تصحيح الأخطاء. يتضمّن عنوان URL للصفحة وشروط تقييد السرعة ومقاييس الأداء الرئيسية (سرعة عرض أكبر محتوى مرئي (LCP) ومدى استجابة الصفحة لتفاعلات المستخدم (INP) ومتغيّرات التصميم التراكمية (CLS)) وقائمة بالإحصاءات المتاحة، وملخّصًا عن CrUX إذا كان متاحًا. |
| الدردشة حول إحصاءات الأداء | ملخّص التتبُّع واسم "إحصاءات الأداء" المحدّدة |
| إجراء محادثة عن مهمة من تتبع | ملخّص التتبُّع وشجرة الاتصال المتسلسلة التي توجد فيها المهمة المحدّدة |
| الدردشة بشأن طلب شبكة | ملخّص التتبُّع ومفتاح الطلب والطابع الزمني المحدّدان |
| إنشاء تعليقات توضيحية للتتبُّع | شجرة المكالمات المتسلسلة التي تقع فيها المهمة المحدّدة تحدّد الشجرة المتسلسلة المهمة المحدّدة. |
يتم إرسال ملخّص التتبُّع دائمًا تقريبًا لتوفير السياق الأوّلي لـ Gemini، وهو النموذج الأساسي للمساعدة المستنِدة إلى الذكاء الاصطناعي. بالنسبة إلى التعليقات التوضيحية من إنشاء الذكاء الاصطناعي، يتم حذفها.
منح الأدوات للذكاء الاصطناعي
يعمل الدعم الذكي في "أدوات مطوّري البرامج" كوكيل. وهذا يعني أنّه يمكنه البحث بشكل مستقل عن المزيد من البيانات استنادًا إلى الطلب الأولي الذي يقدّمه المطوّر والسياق الأولي الذي تتم مشاركته معه. للاستعلام عن المزيد من البيانات، زوّدنا ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" بمجموعة من الدوال المحدّدة مسبقًا التي يمكنها طلبها. نمط يُعرف باسم استدعاء الدوال أو استخدام الأدوات
استنادًا إلى رحلات تصحيح الأخطاء الموضّحة سابقًا، حدّدنا مجموعة من الوظائف الدقيقة للوكيل. تتعمّق هذه الدوال في التفاصيل التي تُعتبر مهمة استنادًا إلى السياق الأولي، على غرار الطريقة التي يتّبعها مطوّر بشري لتصحيح أخطاء الأداء. مجموعة الدوال هي كما يلي:
| الوظيفة | الوصف |
|---|---|
getInsightDetails(name) |
تعرض هذه الطريقة معلومات تفصيلية حول "إحصاءات الأداء" معيّنة (على سبيل المثال، تفاصيل حول سبب وضع علامة على مقياس LCP). |
getEventByKey(key) |
تعرض هذه الطريقة خصائص تفصيلية لحدث واحد محدّد. |
getMainThreadTrackSummary(start, end) |
تعرض هذه الدالة ملخّصًا لنشاط سلسلة التعليمات البرمجية الرئيسية ضمن الحدود المحدّدة، بما في ذلك الملخّصات من أعلى إلى أسفل ومن أسفل إلى أعلى والملخّصات الخاصة بالجهات الخارجية. |
getNetworkTrackSummary(start, end) |
تعرض هذه السمة ملخّصًا لنشاط الشبكة ضمن الحدود الزمنية المحدّدة. |
getDetailedCallTree(event_key) |
تعرِض هذه السمة شجرة الاتصال الكاملة لحدث محدّد في سلسلة التعليمات البرمجية الرئيسية ضمن "تتبُّع الأداء". |
getFunctionCode(url, line, col) |
تعرض هذه الدالة الرمز المصدري لدالة محدّدة في موقع معيّن في أحد الموارد، مع إضافة تعليقات توضيحية تتضمّن بيانات أداء وقت التشغيل من تتبُّع الأداء. |
getResourceContent(url) |
تعرض هذه السمة محتوى مصدر نصي تستخدمه الصفحة (مثل HTML أو CSS). |
من خلال حصر عملية استرجاع البيانات في طلبات الدوال هذه، نضمن عدم إدخال سوى المعلومات ذات الصلة إلى نافذة السياق بتنسيق محدّد جيدًا، ما يؤدي إلى تحسين استخدام الرموز المميزة.
مثال على عملية وكيل
لنلقِ نظرة على مثال عملي حول كيفية استخدام ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" لميزة "استدعاء الدوال" من أجل استرداد المزيد من المعلومات. بعد ظهور الطلب الأوّلي "لماذا هذا الطلب بطيء؟"، يمكن أن تستدعي المساعدة المستندة إلى الذكاء الاصطناعي الدوال التالية بشكل تدريجي:
getEventByKey: لجلب تفاصيل تقسيم التوقيت (الوقت حتى بايت الأول، ووقت التنزيل) للطلب المحدّد الذي اختاره المستخدم.getMainThreadTrackSummary: تحقَّق مما إذا كانت سلسلة التعليمات الرئيسية مشغولة (محظورة) عندما كان من المفترض أن يبدأ الطلب.getNetworkTrackSummary: حلِّل ما إذا كانت موارد أخرى تتنافس على النطاق الترددي في الوقت نفسه.getInsightDetails: تحقَّق مما إذا كان "ملخّص التتبُّع" يشير إلى إحصاءات ذات صلة بهذا الطلب باعتباره مؤثّرًا سلبيًا.
من خلال الجمع بين نتائج هذه الطلبات، يمكن أن تقدّم المساعدة المستندة إلى الذكاء الاصطناعي تشخيصًا وتقترح خطوات قابلة للتنفيذ، مثل اقتراح تحسينات على الرموز البرمجية باستخدام getFunctionCode أو تحسين تحميل الموارد استنادًا إلى getResourceContent.
ومع ذلك، فإنّ استرداد البيانات ذات الصلة هو نصف التحدي فقط. حتى مع توفير الدوال بيانات دقيقة، يمكن أن يكون حجم البيانات التي تعرضها هذه الدوال كبيرًا. ولنأخذ مثالاً آخر، يمكن أن تعرض الدالة getDetailedCallTree شجرة تحتوي على مئات العُقد. في ملف JSON العادي، سيتضمّن ذلك العديد من { و}
للتضمين فقط.
لذلك، هناك حاجة إلى تنسيق مضغوط بما يكفي ليكون فعالاً من حيث الرموز المميزة، ولكنّه يظل منظَّمًا بما يكفي لكي يفهمه نموذج لغوي كبير (LLM) ويستند إليه.
تسلسل البيانات
لنتعمّق أكثر في كيفية التعامل مع هذا التحدي، وسنواصل استخدام مثال شجرة الاستدعاء، لأنّ أشجار الاستدعاء تشكّل معظم البيانات في عملية تتبُّع الأداء. للعلم، تعرض الأمثلة التالية مهمة واحدة في حزمة استدعاء بتنسيق JSON:
{
"id": 2,
"name": "animate",
"selected": true,
"duration": 150,
"selfTime": 20,
"children": [3, 5, 6, 7, 10, 11, 12]
}
يمكن أن يتضمّن تتبُّع الأداء الواحد آلافًا من هذه البيانات، كما هو موضّح في لقطة الشاشة التالية. يتم تمثيل كل مربّع صغير ملوّن باستخدام بنية الكائن هذه.

هذا التنسيق مناسب للتعامل معه آليًا في "أدوات مطوّلي البرامج"، لكنه غير فعّال بالنسبة إلى نماذج اللغات الكبيرة للأسباب التالية:
- المفاتيح المكرّرة: يتم تكرار السلاسل، مثل
"duration"و"selfTime"و"children"، لكل عقدة في شجرة طلبات البيانات. لذا، فإنّ شجرة تحتوي على 500 عقدة يتم إرسالها إلى نموذج ستستهلك رموزًا مميزة لكل مفتاح من هذه المفاتيح 500 مرة. - القوائم التفصيلية: يؤدي إدراج كل معرّف عنصر فرعي بشكل فردي من خلال
childrenإلى استهلاك عدد كبير من الرموز المميزة، خاصةً بالنسبة إلى المهام التي تؤدي إلى العديد من الأحداث اللاحقة.
كان تنفيذ تنسيق فعّال من حيث عدد الرموز المميزة لجميع البيانات المستخدَمة مع ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" في "الأداء" عملية تدريجية.
التكرار الأول
عندما بدأنا العمل على ميزة "المساعدة المستندة إلى الذكاء الاصطناعي" في Performance، حرصنا على تحسين سرعة الشحن. كانت طريقتنا في تحسين الرموز المميزة بسيطة، إذ أزلنا الأقواس الفاصلة والفواصل من ملف JSON الأصلي، ما أدّى إلى ظهور تنسيق مشابه لما يلي:
allUrls = [...]
Node: 1 - update
Selected: false
Duration: 200
Self Time: 50
Children:
2 - animate
Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children:
3 - calculatePosition
5 - applyStyles
6 - applyStyles
7 - calculateLayout
10 - applyStyles
11 - applyStyles
12 - applyStyles
Node: 3 - calculatePosition
Selected: false
Duration: 15
Self Time: 2
URL: 0
Children:
4 - getBoundingClientRect
...
لكنّ هذه النسخة الأولى كانت تحسينًا طفيفًا مقارنةً بتنسيق JSON الأوّلي. كانت هذه الطريقة لا تزال تعرض بشكل واضح عناصر فرعية للعقدة مع أرقام تعريف وأسماء، وتضيف مفاتيح وصفية مكرّرة (Node: وSelected: وDuration: وما إلى ذلك) في بداية كل سطر.
تحسين قوائم العُقد الفرعية
كخطوة تالية لتحسين الأداء بشكل أكبر، أزلنا أسماء العناصر الفرعية للعقدة
(calculatePosition وapplyStyles وما إلى ذلك في المثال السابق). بما أنّ المساعد المستند إلى الذكاء الاصطناعي يمكنه الوصول إلى جميع العُقد من خلال استدعاء الدوال، وبما أنّ هذه المعلومات متوفّرة في رأس العقدة (Node: 3 - calculatePosition)، ليس من الضروري تكرار هذه المعلومات. وقد أتاح لنا ذلك اختصار Children إلى قائمة بسيطة من الأعداد الصحيحة:
Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3, 5, 6, 7, 10, 11, 12
..
وعلى الرغم من أنّ هذا كان تحسّنًا ملحوظًا مقارنةً بما كان عليه الوضع في السابق، كان لا يزال هناك مجال أكبر للتحسين. عند النظر إلى المثال السابق، قد تلاحظ أنّ Children تسلسلي تقريبًا، مع فقدان 4 و8 و9 فقط.
والسبب هو أنّنا استخدمنا في محاولتنا الأولى خوارزمية بحث في العمق أولاً (DFS) لتسلسل بيانات الشجرة من "تتبُّع الأداء". وقد أدّى ذلك إلى ظهور معرّفات غير متسلسلة للعُقد الشقيقة، ما استدعى إدراج كل معرّف على حدة.
أدركنا أنّه إذا أعدنا فهرسة الشجرة باستخدام بحث العرض أولاً (BFS)، سنحصل على أرقام تعريف تسلسلية بدلاً من ذلك، ما يتيح إجراء تحسين آخر. بدلاً من إدراج أرقام تعريف فردية، يمكننا الآن تمثيل مئات الأطفال بنطاق مضغوط واحد، مثل 3-9 في المثال الأصلي.
يبدو تدوين العقدة النهائي، مع قائمة Children المحسّنة، على النحو التالي:
allUrls = [...]
Node: 2 - animate
Selected: true
Duration: 150
Self Time: 20
URL: 0
Children: 3-9
تقليل عدد المفاتيح
بعد تحسين قوائم العُقد، انتقلنا إلى المفاتيح المكرّرة. بدأنا بإزالة جميع المفاتيح من التنسيق السابق، ما أدّى إلى ما يلي:
allUrls = [...]
2;animate;150;20;0;3-10
مع أنّ هذه الطريقة فعّالة من حيث عدد الرموز المميزة، كان علينا تزويد Gemini بتعليمات حول كيفية فهم هذه البيانات. نتيجةً لذلك، عند إرسال شجرة مكالمات إلى Gemini للمرة الأولى، تضمّن الطلب ما يلي:
...
Each call frame is presented in the following format:
'id;name;duration;selfTime;urlIndex;childRange;[S]'
Key definitions:
* id: A unique numerical identifier for the call frame.
* name: A concise string describing the call frame (e.g., 'Evaluate Script', 'render', 'fetchData').
* duration: The total execution time of the call frame, including its children.
* selfTime: The time spent directly within the call frame, excluding its children's execution.
* urlIndex: Index referencing the "All URLs" list. Empty if no specific script URL is associated.
* childRange: Specifies the direct children of this node using their IDs. If empty ('' or 'S' at the end), the node has no children. If a single number (e.g., '4'), the node has one child with that ID. If in the format 'firstId-lastId' (e.g., '4-5'), it indicates a consecutive range of child IDs from 'firstId' to 'lastId', inclusive.
* S: **Optional marker.** The letter 'S' appears at the end of the line **only** for the single call frame selected by the user.
....
على الرغم من أنّ وصف التنسيق هذا يتكبّد تكلفة رمز مميّز، إلا أنّها تكلفة ثابتة تُدفع مرة واحدة للمحادثة بأكملها. تتفوق الوفورات التي تحققت من خلال عمليات التحسين السابقة على التكلفة.
الخاتمة
يُعدّ تحسين استخدام الرموز المميزة من الاعتبارات المهمة عند إنشاء التطبيقات باستخدام الذكاء الاصطناعي. من خلال الانتقال من تنسيق JSON الأولي إلى تنسيق مخصّص متخصص، وإعادة فهرسة الأشجار باستخدام البحث الأول في العرض، واستخدام عمليات استدعاء الأدوات لجلب البيانات عند الطلب، تمكّنا من تقليل عدد الرموز المميزة التي تستهلكها المساعدة المستندة إلى الذكاء الاصطناعي في "أدوات مطوّري البرامج في Chrome" بشكل كبير.
كانت عمليات التحسين هذه شرطًا أساسيًا لإتاحة المساعدة المستندة إلى الذكاء الاصطناعي لتتبُّع الأداء. وبسبب نافذة السياق المحدودة، ما كان بإمكانها التعامل مع هذا الحجم الهائل من البيانات. في المقابل، يتيح التنسيق المحسّن لبرنامج الأداء الاحتفاظ بسجلّ أطول للمحادثات وتقديم إجابات أكثر دقة ومراعية للسياق بدون أن يتأثر بالضوضاء.
نأمل أن تلهمك هذه الأساليب لإلقاء نظرة ثانية على بنى البيانات الخاصة بك عند تصميمها بما يتوافق مع الذكاء الاصطناعي. لبدء استخدام الذكاء الاصطناعي في تطبيقات الويب، يمكنك الاطّلاع على تعرَّف على الذكاء الاصطناعي على web.dev.