النص هو الجزء السهل: خط الأنابيب الذي يوضّح المقالات المكتوبة بالذكاء الاصطناعي
توليد النص أصبح مسألة محلولة. توضيحه بصريًا لا يزال معضلة. خط الأنابيب الكامل من البداية للنهاية — موجّه التوجيه، بحث الصور، مخططات Mermaid، الرسوم البيانية المُتحقَّق منها، ونص alt والائتمان وترميز ImageObject الذي يحوّل كل ذلك إلى SEO حقيقي.
أنت مطوّر لديك هدف محتوى: عشرات المقالات شهريًا، ربما مئات. نموذج الكتابة يتولى المسودة، والمخطط، ووصف الميتا، والروابط الداخلية. ثم يصطدم خط الأنابيب بالخطوة الوحيدة التي لا يوجد لها نموذجها الخاص — الصور — ويتوقف. ليس لأن الحصول على الصور صعب، بل لأن لا شيء في المكدّس يعرف أي صورة، من أين، بأي ترخيص، ووُصفت كيف.
هذا المقال هو تلك الخطوة المفقودة، موصولة من طرف إلى طرف: أي نوع من الصور يُنتَج لأي نوع من الأقسام، والمُوجِّه الذي يحوّل مسودة جاهزة إلى ملخّصات بحث، واستدعاء واجهة برمجة التطبيقات الذي يُعيد الصور، والنموذج الثاني الذي يرسم ما لا تستطيع الصورة الفوتوغرافية قوله، والمُجمِّع الذي يُصدر ترميزًا يمكن لـ Google قراءته فعليًا. سير عملين كاملين في النهاية، جاهزان للاقتباس.
النص محلول. الرسم التوضيحي هو حيث يتعطّل الأمر.
أجرِ التدقيق الصادق لخط أنابيب مقالات آلي. المخطط: محلول. المسودة: محلولة. العنوان، وصف الميتا، السكيما، الروابط الداخلية، الترجمة: محلولة، كلها بواسطة النموذج نفسه، كلها نصية. ثم:
| خطوة خط الأنابيب | الحالة | ما الذي يعطّل فعليًا |
|---|---|---|
| المخطط والمسودة | محلول | استدعاء نموذج واحد، مُوجِّه واحد |
| العناوين، الميتا، السكيما، الروابط | محلول | نص يدخل، نص يخرج |
| الصورة الرئيسية | معطّل | تحتاج إلى ملف حقيقي، وترخيص، وأبعاد، ونص alt — لا شيء من ذلك يستطيع نموذج نصي إنتاجه |
| صور الأقسام | معطّل | من ثلاث إلى خمس لكل مقال، كل واحدة مختلفة، لا تتكرر عبر الموقع |
| الرسوم البيانية والمخططات | معطّل | يجب أن تكون دقيقة — الصورة الوحيدة التي لا يمكن للبحث إعادتها ويجب ألا يخترعها المولّد |
الإخفاق ليس جماليًا، بل بنيويًا: يُنشَر المقال ببديل مؤقّت (placeholder) من مخزون الصور، أو بالصورة نفسها المستخدمة في الاثني عشر مقالًا الأخيرة، أو بصورة مولَّدة تكون يدها ذات الأصابع الستة أول ما يراه القارئ. والصورة ليست مجرد زخرفة — توثيق Google نفسه للصور يقول بوضوح: نص alt "هو أهم سمة (attribute) عندما يتعلق الأمر بتوفير بيانات وصفية (metadata) للصورة"، والإرشاد هو استخدام عناصر <img> حقيقية مع alt وصفي بدلًا من خلفيات CSS، حتى يمكن العثور على الصورة وفهمها أصلًا.1
أربعة أنواع من العناصر البصرية، أربعة أنواع من النماذج
أكبر خطأ تصميمي هو التعامل مع "الصورة" كمشكلة واحدة بمزوّد واحد. هي في الواقع أربع مشكلات، والموجِّه بينها سطر واحد في المُوجِّه (prompt)، وليس خدمة:
| القسم يحتاج إلى… | أنتِجه باستخدام | لماذا لا الأدوات الأخرى |
|---|---|---|
| مشهد من العالم الحقيقيصورة رئيسية، مواقف بشرية، أماكن، أشياء، إيماءات | بحث فوتوغرافي دلالي (Pexafy) | المولّد يخترع التفاصيل؛ والرسم البياني لا شيء لديه ليرسمه |
| أرقام لديك فعليًاقياسات أداء، تسعير، نتائج استطلاع، زمن استجابة | نموذج يكتب كود رسم بياني، يُنفَّذ في بيئة معزولة (sandbox) | لا يمكن الوثوق بنموذج صور بقيمة؛ والصورة لا يمكنها حمل بيانات |
| بنية أو تدفّقمعمارية، تسلسل، آلة حالات | نموذج يكتب Mermaid / Graphviz، يُعرَض بشكل حتمي (deterministic) | مكتبات الصور المجانية لا تملك مخططًا لنظامك أنت |
| منتجك على الشاشةالوثائق، سجل التغييرات، الدروس التعليمية | لقطة شاشة مبرمَجة (Playwright) | لا شيء آخر يستطيع إظهار واجهة مستخدم موجودة فقط في نسختك الفعلية |
وماذا عن الرسوم التوضيحية المولّدة؟ تحتفظ بمكان واحد نزيه: المشهد الذي لا يمكن تصويره وليس بيانات — آلية مجردة، منتج لم يوجد بعد، أسلوب رسم توضيحي خاص بك. (الحجة الكاملة للتصوير الحقيقي مقابل التوليد — السرعة عند الحجم الكبير، الدقة، مشكلة التشابه — مطروحة هنا.) والسعر يتّجه في اتجاه واحد: منذ 2 أغسطس 2026، تُلزم المادة 50 من قانون الذكاء الاصطناعي الأوروبي مزوّدي الأنظمة التوليدية بوسم المخرجات الاصطناعية بصيغة قابلة للقراءة الآلية.2 هذا التزام يقع على مزوّدي ونشري الذكاء الاصطناعي، وليس قاعدة تحكم ما يجوز أن تنشره مدونة — لكنه السبب في أن مصدر الصورة في أعلى مقالك أصبح، على نحو متزايد، أمرًا يستطيع القارئ التحقق منه بدل أن يأخذه على الثقة.
خط الأنابيب، من طرف إلى طرف
خمس مراحل. المرحلة 3 فقط تلامس واجهة برمجة تطبيقات صور، والمرحلة 4 فقط اختيارية:
┌─ 1. WRITE ────────────────────────────────────────────────────┐
topic ──▶ LLM ──▶ draft.md (h2 sections, front-matter)
└───────────────────────────────┬───────────────────────────────┘
┌─ 2. BRIEF ────────────────────┴───────────────────────────────┐
draft.md ──▶ LLM ──▶ { hero: {...}, sections: [ {...} ] }
one JSON object: per slot, a kind +
either a camera brief or a data/diagram spec
└──────────┬──────────────────────────────────┬─────────────────┘
│ kind = "photo" │ kind = "chart" | "diagram"
▼ ▼
┌─ 3. SEARCH ───────────────┐ ┌─ 4. DRAW (optional) ─────────┐
GET /search/photos LLM ──▶ mermaid | plotting code
← credited photo + ──▶ sandbox ──▶ .svg / .png
w/h, blur_hash, alt, (deterministic render, no
licence, source URL invented numbers)
└──────────┬────────────────┘ └──────────────┬───────────────┘
└───────────────┬──────────────────┘
┌─ 5. ASSEMBLE ─────────────┴───────────────────────────────────┐
<img> with width/height + fetchpriority | loading
alt written for a human · visible credit · ImageObject JSON-LD
photo_id stored so no two pages share a hero
└───────────────────────────────────────────────────────────────┘
خاصيتان مهمتان أكثر من المخطط ذاته. المرحلة 2 هي موجِّه: تقرّر لكل خانة (slot) أي منتِج يعمل، لذا لن تطلب أبدًا من مكتبة صور رسمًا بيانيًا شريطيًا. والمرحلة 5 هي حيث يعيش تحسين محركات البحث — كل ما تُوثّقه Google بخصوص الصور (نص alt وصفي، بيانات ترخيص وصفية، صورة رئيسية آمنة من ناحية LCP) يُصدَر هنا، من حقول كانت استجابة البحث تحملها بالفعل.
المرحلة 2: تحويل المسودة إلى ملخّصات بصرية
استدعاء واحد للنموذج على المسودة النهائية، وما يعيده هو خطة وليس استعلامًا. كيفية كتابة موجز صورة واحد — لماذا عنوان المقال هو أسوأ مُدخَل ممكن، وكيف يبدو موجز كاميرا من 12 إلى 25 كلمة، وطرق فشله — مشروحة بالكامل في دليل توضيح مقال واحد، ولا نكررها هنا. ما تضيفه خط أنابيب هو التوجيه: على الاستدعاء نفسه أن يقرر، خانة تلو أخرى، أي مولّد يعمل — وإدخال مخطط بياني يحمل بيانات بينما إدخال صورة يحمل مشهدًا.
# system prompt — run once per finished draft
You are the art director of a technical publication. Read the article and
return the visual plan: one entry for the hero, one per H2 section.
For each entry choose exactly one kind:
"photo" a real scene: someone doing something somewhere, a place,
an object, a gesture. The default for heroes.
"chart" the section states numbers that are IN the article. Never
invent values: copy them into data, verbatim.
"diagram" the section describes a structure, a flow or a sequence.
"none" the section is short, or already carries a code block.
Rules for "photo" entries — the field is query:
اكتب موجزاً للكاميرا: مشهداً يمكن لكاميرا أن تلتقطه، من 12 إلى 25 كلمة،
باللغة الإنجليزية، بما يتوافق مع أجواء القسم. اذكر ما يظهر في الإطار،
وليس الموضوع أبداً. بلا نص أو شعارات أو علامات تجارية أو أشخاص مشهورين؛
وبلا استعارات غير مرئية. (القواعد الكاملة، مع أمثلة وحالات الفشل:
pexafy.com/blog/illustrate-blog-articles-at-scale/)
Do NOT write the alt text of a photo entry: the picture you get back is the
closest match to the brief, not the scene you described, so its alt has to be
written from the chosen photo. Chart and diagram entries DO carry an alt —
there you control exactly what is rendered.
Return JSON only:
{
"hero": { "kind": "photo", "query": "…", "orientation": "landscape" },
"sections": [
{ "h2": "…", "kind": "photo", "query": "…" },
{ "h2": "…", "kind": "chart", "title": "…", "unit": "ms",
"data": [ {"label": "…", "value": 0} ], "alt": "…" },
{ "h2": "…", "kind": "diagram", "spec": "flowchart LR; …", "alt": "…" }
]
}
سطر kind يؤدي معظم العمل، وتعليمة data تكمل الباقي: لا يجوز لإدخال
المخطط البياني أن يحمل سوى أرقام موجودة أصلًا في المسودة، بحيث ينسخ النموذج بدل أن يخترع.
إليك الموجِّه على ثلاثة أقسام حقيقية من مقال تقني:
| القسم | kind | ما أعاده الموجِّه |
|---|---|---|
| الصورة الرئيسية — "لماذا يستغرق بناؤنا الليلي 40 دقيقة" | photo |
"مطوّر يعمل حتى وقت متأخر على مكتب مع شاشتين ولوحة مفاتيح ميكانيكية في غرفة مظلمة تضيئها الشاشات" |
| "أين يذهب الوقت فعليًا" | chart |
data منسوخة من الفقرة: التثبيت 480 ثانية، الترجمة 1080 ثانية، الاختبار 720 ثانية، الرفع 120 ثانية |
| "كيف نقسّم الرسم البياني (graph)" | diagram |
flowchart LR لرسم بياني لتبعيات المهام |
| "ما الذي غيّرناه، وما الذي سنكرّره" | photo |
"مهندسان يقفان أمام سبورة بيضاء مغطّاة بمخططات وهما يعملان معًا على حل مشكلة" |
المرحلة 3: الصور تعود موثَّقة المصدر
كل خانة من نوع kind: "photo" هي طلب واحد. ملخّص الصورة الرئيسية أعلاه، عند تشغيله على واجهة برمجة التطبيقات العامة، يعيد هذا في 147 ملّي ثانية:
ملخّص القسم الأخير، مشهد مختلف تمامًا، في 144 ملّي ثانية:
ما يعود لكل صورة هو الجزء الذي يجعل المرحلة 5 ممكنة — وليس مجرّد ملف:
{
"photo_id": "019e1c7f-0063-759e-b498-33ce1714e6c9", // store it: no repeats
"urls": { "small": "…?w=400", "regular": "…?w=1080",
"large": "…?w=1920" },
"width": 3000, "height": 1688, // → no layout shift
"blur_hash": "LJ8gjv9rVq-6OFxanNNFI7xco$Na", // → real placeholder
"alt_description": "Person types on keyboard in front of dual monitors…",
"photographer_full_name": "Jakub Żerdzicki", // → ImageObject.creator
"source": "Unsplash", "license_type": "free",
"source_image_url": "https://unsplash.com/photos/…",
"attribution": { "html": "<span…>Photo by …</span>",
"plain": "Photo by Jakub Żerdzicki on Unsplash (…)" }
}
المرحلة 4: ما لا تستطيع الصورة الفوتوغرافية قوله
خانتان في الخطة غير قابلتين للبحث، وهنا بالضبط يثبت نموذج ثانٍ جدارته — ليس لرسم صورة، بل لكتابة كود يرسمها. الفرق مهم: الكود قابل للمراجعة، وحتمي (deterministic)، ولا يمكن أن يهلوس بارتفاع عمود.
المخططات: نص يدخل، SVG يخرج
يعرض Mermaid المخططات من تعريف نصي بسيط،3 ما يجعله الهدف الأكثر أمانًا لنموذج: المخرج قابل للفحص، وقابل للمقارنة (diff) في git، ويُعرَض بالطريقة نفسها في كل مرة. الموجِّه أعاد المواصفة (spec) بالفعل.
# the "spec" field of a diagram entry, written to build/graph.mmd
cat build/graph.mmd
flowchart LR
install["install deps · 480s"] --> compile["compile · 1080s"]
compile --> test["test suite · 720s"]
compile --> upload["upload artifacts · 120s"]
npx -y @mermaid-js/mermaid-cli -i build/graph.mmd -o static/img/graph.svg
# → an SVG you can review in the PR, not a picture you have to trust
الرسوم البيانية: فقط الأرقام التي يحتويها المقال بالفعل
المبدأ نفسه، مع ضمانة إضافية واحدة. الموجِّه نسخ القيم من المسودة؛ والنموذج يكتب كود الرسم؛ والكود يعمل في بيئة معزولة؛ والمُجمِّع يعيد التحقق من القيم المعروضة مقابل الأرقام المصدرية قبل السماح للرسم البياني بالاقتراب من الصفحة.
import re, matplotlib
matplotlib.use("Agg") # headless: no display in CI
import matplotlib.pyplot as plt
def assert_in_draft(value, draft: str) -> None:
"""A plotted number must appear in the article AS A NUMBER."""
# Substring matching is the trap here: "120" is inside "1200", and
# inside "?w=1200" — a naive `str(v) in draft` passes on anything.
# Match on word boundaries, and accept 1 234 / 1,234 / 1234.
body = re.sub(r"(?<=\d)[ ,](?=\d{3}\b)", "", draft) # strip separators
if not re.search(rf"(?<![\d.]){re.escape(str(value))}(?![\d.])", body):
raise ValueError(f"{value} is not stated in the article — refusing to plot")
def render_chart(entry: dict, draft: str, out: str) -> str:
labels = [d["label"] for d in entry["data"]]
values = [d["value"] for d in entry["data"]]
for v in values:
assert_in_draft(v, draft) # hallucinated value → no chart
fig, ax = plt.subplots(figsize=(8, 4.5), dpi=160)
ax.barh(labels, values)
ax.set_xlabel(entry["unit"])
ax.set_title(entry["title"])
fig.tight_layout()
fig.savefig(out) # deterministic, reviewable artefact
return out
الضمانة قصيرة، لكن اكتبها بعناية: فحص السلسلة الفرعية (substring) لا يعمل.
"120" in draft صحيح لمقال يحتوي على 1200 أو
?w=1200، لذا النسخة الساذجة تنجح على كل شيء ولا تحمي شيئًا. اربط بحدود الأرقام، وطبّع فواصل الآلاف، وفئة الخطأ التي تجعل مقالًا تقنيًا يُفكَّك في التعليقات — رسم بياني يناقض فقرته الخاصة — لن تصل إلى الإنتاج. لقطات الشاشة تتبع المبدأ نفسه: page.screenshot() مبرمجة تعمل على نسختك الفعلية هي المصدر الوحيد للحقيقة بشأن واجهة مستخدمك، وتبقى صحيحة مع تغيّر الواجهة.
المرحلة 5: التجميع هو حيث يعيش تحسين محركات البحث
كل ما سبق أنتج ملفات وحقولًا. هذه المرحلة تحوّلها إلى ترميز — ويستحق الأمر الدقة هنا، لأن ثلاثة سلوكيات موثَّقة تُقرَّر في هذه الأسطر القليلة.
<!-- The bytes come from another origin: pay the handshake early -->
<link rel="preconnect" href="https://images.unsplash.com" crossorigin>
<!-- LCP element: never lazy, always high priority -->
<figure>
<img src="{urls.regular}"
width="{width}" height="{height}" <!-- kills layout shift -->
alt="{alt}" <!-- written AFTER the pick -->
fetchpriority="high" decoding="async"
style="background:{color_hex}"> <!-- dominant colour, 1 field -->
<figcaption>{attribution.html}</figcaption>
</figure>
<!-- Section images, below the fold: the opposite settings -->
<img src="{urls.regular}" width="{width}" height="{height}"
alt="{alt}" loading="lazy" decoding="async">
ربط مباشر (hotlink) أم إعادة استضافة؟ المقتطف أعلاه يستخدم ربطًا مباشرًا، وهو الأسرع في النشر وسبب استخدام preconnect: الصورة الرئيسية عن بُعد تكلّف بحث DNS ومصافحة TLS في المسار الحرج، وهذا قد يلتهم المكسب الذي اشتريته للتو بـfetchpriority. إعادة الاستضافة تزيل المصدر الخارجي كليًا، وتتيح لك تقديم AVIF/WebP عند نقاط الفصل (breakpoints) الخاصة بك، وتصمد أمام تغيّر رابط المصدر — على حساب التخزين، وخطوة جلب إضافية في خط الأنابيب، وفاتورة CDN الخاصة بك. أيًا كان اختيارك، color_hex يمنحك بديلًا مؤقتًا لحقل واحد (بصمة التمويه أجمل، لكن يجب فك تشفيرها إلى data URI أولًا — إنها ليست لون CSS). نسخ صورة رئيسية خام مباشرة إلى background: هو حيث تنشر معظم خطوط الأنابيب بصمت مربعًا رماديًا فارغًا.
-
لا تُحمِّل الصورة الرئيسية بشكل كسول (lazy) أبدًا. web.dev واضح بلا لبس: "لا تُحمِّل صورة LCP الخاصة بك بشكل كسول أبدًا، فذلك سيؤدي دومًا إلى تأخير غير ضروري في تحميل المورد، وسيكون له أثر سلبي على LCP"، ويوصي باستخدام
fetchpriority="high"على العنصر المرجَّح أن يكون LCP — يُستخدم بحذر، على صورة واحدة.4 خط أنابيب يضعloading="lazy"على كل صورة، بما فيها الصورة الرئيسية، هو الجرح الأكثر شيوعًا الذي تُلحقه بنفسها Core Web Vitals في النشر الآلي. -
أصدِر دائمًا
widthوheight— تعودان في الاستجابة، فلا عذر لغيابهما؛ زوج السمات هذا هو ما يتيح للمتصفح حجز المساحة ويمنع قفز التخطيط. استخدمblur_hashكبديل مؤقت أثناء تحميل الملف. -
اكتب نص alt بعد الاختيار، وليس قبله أبدًا. هذه النقطة الدقيقة. حقل
altفي الخطة يصف المشهد الذي طلبته؛ والصورة التي حصلت عليها هي أقرب تطابق، وليست ذلك المشهد. نشر نص الملخّص كما هو كـ alt هو بالضبط إخفاق إمكانية الوصول الذي يُفترض بخط الأنابيب هذا تجنّبه — وصف صورة غير موجودة في الصفحة. ابنِ نص alt منalt_descriptionللصورة المختارة، مُنقَّحًا بما يتناسب مع الفقرة التي يقع فيها. إرشاد Google هو "التركيز على إنشاء محتوى مفيد وغني بالمعلومات يستخدم الكلمات المفتاحية بشكل مناسب وفي سياق محتوى الصفحة"، ويحذّر من أن حشو سمات alt بالكلمات المفتاحية "يؤدي إلى تجربة مستخدم سلبية وقد يجعل موقعك يُعتبر بريدًا مزعجًا (spam)".1
الجزء الذي لا يكاد أحد يؤتمته: بيانات الترخيص الوصفية
تدعم Google بيانات ImageObject المهيكلة لترخيص الصور. تتطلب contentUrl بالإضافة إلى واحد على الأقل من creator أو creditText أو copyrightNotice أو license، وتوصي بـacquireLicensePage، وتصبح الصور التي تحمل معلومات ترخيص مؤهَّلة لشارة Licensable في Google Images.5 كل حقل من هذه الحقول موجود بالفعل في استجابة البحث — لذا إصداره قالب، وليس مشروعًا:
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "ImageObject",
"contentUrl": "{urls.large}", // required
"creator": { "@type": "Person",
"name": "{photographer_full_name}" },
"creditText": "{photographer_full_name} on {source}",
"license": "{LICENSE_URL[source]}", // the library's own page
"acquireLicensePage": "{source_image_url}" // the photo's page
}
</script>
# LICENSE_URL maps the `source` field to the licence that actually governs
# the photo — unsplash.com/license, pexels.com/license, pixabay.com/…
تفصيل يستحق أن تحرص على صحته: يجب أن يشير license إلى الترخيص الذي يحكم تلك الصورة تحديدًا — صفحة الترخيص الخاصة بالمكتبة المصدر — وليس إلى صفحة ملخّص على نطاقك الخاص. تقرأها Google لتحديد أهلية الشارة، والرابط ذاتي المرجعية أضعف كإشارة ويصعب الدفاع عنه كأي شيء آخر غير رابط يعود إليك نفسك. أبقِ ملخّص الترخيص الخاص بك كصفحة داخلية للقراء؛ وضع الرابط الرسمي (canonical) في الترميز.
وبما أنك في المُجمِّع: امنح الملف اسمًا وصفيًا قصيرًا بدلًا من
IMG_0042.jpg، وأضف الصورة إلى خريطة موقع (sitemap) — تنسيق خريطة موقع الصور من Google يقبل حتى 1,000 صورة لكل رابط صفحة.6 كلاهما سطر واحد فقط في خط أنابيب، ولا يُنجَز أبدًا يدويًا.
خطّا أنابيب يستحقان الاقتباس
المراحل الخمس نفسها، لكن بشكلين مختلفين تمامًا — واحد للمقالات التي تكتبها، وآخر للوثائق التي يجب أن تطابق منتجًا قيد التشغيل. اختر الشكل الذي تتعرّف على نمط إخفاقه.
1 · مدونة المطورين في CI — Markdown في المستودع
المقالات تعيش كملفات Markdown، والصور تُرفَع (committed) بجوارها، ويعمل كل شيء عند الدفع (push). حتمي، قابل للمراجعة في طلب السحب (PR)، بلا اعتماد وقت تشغيل على أي واجهة برمجة تطبيقات:
on: { pull_request: { paths: ["content/**.md"] } }
jobs:
illustrate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: python plan_to_pr.py $(git diff --name-only origin/main -- 'content/*.md')
env:
PEXAFY_API_KEY: ${{ secrets.PEXAFY_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- uses: peter-evans/create-pull-request@v6 # images land in the PR
with: { commit-message: "chore(content): illustrate" }
إنسان لا يزال يوافق على طلب السحب، وهذا هو المغزى: خط الأنابيب يقترح، والمراجِع يبتّ، والبيانات الأمامية (front-matter) التي كتبها قابلة للمقارنة (diffable).
نصف البحث هو طلب GET واحد — الطلب وscore_threshold الخاص به
والحقول التي يعيدها مكتوبة سطرًا سطرًا في
دليل المقال
الواحد، لذا نستوردها هنا بدل إعادة طباعتها. ما يضيفه هذا الملف هو كل ما تحتاجه خطة
ولا تحتاجه صورة واحدة: إعادة المحاولة عند موجز لا يعيد شيئًا، وحجز photo_id بحيث لا
تشترك صفحتان في الصورة نفسها، والنص البديل المكتوب من الصورة التي عادت.
import frontmatter
from photo_search import search # طلب GET /search/photos واحد؛ يتخطى المعرّفات في `used`
def find_photo(entry: dict, used: set) -> dict | None:
"""Search; if the brief was too specific, widen it once, then give up."""
orientation = entry.get("orientation", "landscape")
for query in (entry["query"], widen(entry["query"])):
photo = search(query, orientation, used)
if photo:
used.add(photo["photo_id"]) # claim it: no repeats site-wide
return photo
return None # caller decides: skip the slot, or fail
def widen(query: str) -> str:
"""Drop the last clause — usually the over-specific one."""
return query.rsplit(" in ", 1)[0] if " in " in query else query
def illustrate(path: str, plan: dict, used: set) -> None:
post = frontmatter.load(path)
hero = find_photo(plan["hero"], used)
if hero is None: # no hero is better than a bad one
raise SystemExit(f"{path}: no photo above threshold — rewrite the brief")
post["hero"] = { # everything the template needs
"src": hero["urls"]["regular"], "w": hero["width"], "h": hero["height"],
# The alt describes the photo we GOT, never the scene we asked for.
"alt": alt_for(hero, section=post.get("title", "")),
"bg": hero["color_hex"], "credit": hero["attribution"]["html"],
"creator": hero["photographer_full_name"], "id": hero["photo_id"],
"source": hero["source"],
"source_url": hero["source_image_url"], # → acquireLicensePage
}
open(path, "w").write(frontmatter.dumps(post))
def alt_for(photo: dict, section: str) -> str:
"""alt_description as the base, trimmed to ~125 chars for screen readers.
Send it back through the model with the paragraph if you want better."""
base = photo.get("alt_description") or photo.get("description", "")
return base[:125].rstrip(" ,;")
2 · الوثائق وسجل التغييرات — لقطات الشاشة أولًا، الصور الفوتوغرافية أخيرًا
اعكس الإعدادات الافتراضية للموجِّه. في وثائق المنتج، العنصر البصري الصادق هو غالبًا واجهة مستخدمك أنت: نص Playwright برمجي يفتح النسخة الفعلية، ويضبط عرض عرض ثابتًا (viewport)، ويلتقط الحالة الدقيقة التي تصفها الفقرة. المخططات تغطي صفحات المعمارية، وتظهر الصور الفوتوغرافية فقط في الصفحات المفاهيمية وصفحات الهبوط — حيث لن تقول لقطة الشاشة شيئًا.
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page(viewport={"width": 1440, "height": 900},
device_scale_factor=2) # retina-crisp
page.goto("http://localhost:3000/dashboard")
page.get_by_role("button", name="New API key").click()
page.screenshot(path="static/img/docs/new-api-key.png")
browser.close()
# Runs in the same CI job as the docs build → the screenshot can never
# describe a version of the UI that no longer exists.
متغيّران يستحقان الذكر ولكن ليس وصفة مستقلة لكل منهما. تحسين محركات البحث البرمجي (Programmatic SEO) يعكس الحلقة: مع مئات الصفحات المولَّدة من قاعدة بيانات، لا تبحث لكل صفحة على حدة — يعيد طلب واحد حتى 100 صورة، لذا تبحث لكل مجموعة مواضيع وتخصّص من مجموعة (pool)، مع قيد تفرّد (uniqueness) يتولى إزالة التكرار
(تلك المعمارية بالتفصيل).
والنشرات البريدية وبطاقات التواصل الاجتماعي تحتاج إلى الصورة نفسها بأربع قصّات (crops): احتفظ بـ
photo_id، واطلب الحجم الذي تحتاجه من urls، ولا تبحث مجددًا إلا حين تفشل قصّة ما فعليًا.
خط الأنابيب نفسه، بوصفه وكيلًا واحدًا
إذا كان النموذج يكتب المسودة بالفعل، فإن أقصر طريق هو إعطاؤه أداة البحث مباشرة
بدلاً من نقل JSON بين العمليات. تُشغّل Pexafy خادم Model Context
Protocol مستضافًا على mcp.pexafy.com/mcp. تم تناول إعداد الموصل والأدوات التي
يوفّرها في مواضع أخرى — إعداد سطح المكتب والمحرر في
دليل المقالة الواحدة،
والنسخة غير المرئية لمشغّل CI في
مقالة المحتوى على نطاق واسع،
وشكل سوق الموصلات الأوسع — من يوفّر خادم صور MCP، وبأي شروط —
في دراسة
بنية البحث عن الصور لوكلاء الذكاء الاصطناعي.
ما يستحق العرض هنا هو ما يحدث لهذا الأنبوب بالذات حالما تمتلك الوكيل الأدوات:
فهو لم يعد خمس مراحل بل يصبح تعليمة واحدة.
You Here is the draft. Build the visual plan, illustrate it, and open a PR.
Charts only from numbers already in the text.
Agent → plan: hero=photo · §2=chart · §3=diagram · §4=photo
→ search_photos(q="a developer working late at a desk with two
monitors and a mechanical keyboard in a dark room…")
← 16 photos · 147 ms · picked #1, 3000×1688, credited
→ mermaid-cli build/graph.mmd → static/img/graph.svg
→ chart.py §2 → 4 values checked against the draft ✓
→ search_photos(q="two engineers standing at a whiteboard…")
← 16 photos · 144 ms · picked #1
✓ 4 slots filled · 2 API calls · alt + credit + ImageObject written
⚠ §5 returned nothing above 0.5 — brief too abstract, rewritten as
"a person at a kitchen table checking figures on a laptop"
هذا السطر الأخير هو سبب استحقاق وكيل أن يكون في هذه الحلقة بدلًا من نص برمجي بحت: نمط إخفاق الرسم التوضيحي الآلي هو ملخّص سيئ، وإعادة كتابة ملخّص سيئ هو بالضبط ما يصلح له نموذج لغوي. أبقِ الأجزاء الحتمية — التخصيص، إزالة التكرار، الضمانة الرقمية — في الكود.
تكلفة مقال واحد مُصوَّر
ثلاث خانات صور لكل مقال تعني ثلاثة طلبات بحث، لذا الخطة المجانية (5,000 طلبًا شهريًا) تغطّي 1,666 مقالًا شهريًا قبل أن تطرح مسألة الدفع أصلًا — وإذا جمعت (pool) عمليات البحث لكل مجموعة مواضيع بدلًا من كل مقال، تتحرّك هذه السقف بمقدار رتبة أخرى من الحجم. التفصيل خطة تلو الأخرى، ومعمارية التجميع التي تجعل الأمر بلا أهمية، موجودان في المقال المرافق عن رسم المحتوى واسع النطاق.
استدعاءا النموذج لكل مقال — واحد للمسودة، وآخر للخطة البصرية — هما بضعة آلاف من الرموز (tokens) وسيكونان أرخص سطر في خط الأنابيب؛ ولا تكلّف عمليات عرض Mermaid وmatplotlib شيئًا سوى ثوانٍ من CI. الرقم الذي يفاجئ الناس هو أي سطر ليس رخيصًا: توليد أربع صور لكل مقال، أربعمئة صورة شهريًا، بالإضافة إلى المحاولات التي لم تنجح — والمُخرَج لا يزال بلا مصوّر، وبلا تاريخ، وبلا رابط مصدر.
ما لا يصلحه خط الأنابيب هذا
قسم صادق، لأن الإخفاق الذي يمنعه مكلف. مقال مُصوَّر جيدًا يبقى مقالًا. التصوير الفوتوغرافي الحقيقي، والرسوم البيانية الدقيقة، والترميز الصحيح تُحسّن صفحة تستحق الوجود أصلًا. لكنها لا تجعل محتوى رقيقًا ومنتَجًا بكميات ضخمة يُصنَّف. تُسمّي سياسات البريد المزعج من Google إساءة استخدام المحتوى واسع النطاق (scaled content abuse) — توليد صفحات كثيرة أساسًا للتلاعب بالترتيب مع تقديم قيمة ضئيلة للمستخدمين، سواء كانت الأتمتة متورطة أم لا — وجودة الرسوم التوضيحية ليست عاملًا في ذلك الحكم.7
إذن التأطير الذي يصمد: خط الأنابيب هذا هو أرضية جودة تتحكم بها، تُطبَّق على صفحات لها سبب للنشر أصلًا. حيث يُثبت جدواه بوضوح:
- مصدر يمكن للقارئ التحقق منه. سطر توثيق (credit line) بمصوّر حقيقي ورابط مصدر هو ادّعاء يمكن التحقق منه — والحقول نفسها تغذّي ترميز
ImageObjectالذي تقرأه Google. - إمكانية الوصول وCore Web Vitals. نص alt حقيقي، أبعاد على كل صورة، صورة رئيسية لا تُحمَّل أبدًا بكسل. اضرب ذلك في كل مقال تنشره وهذه هي قصة جودة الصور في الموقع.
- الدقة حيث يمكن التحقق منها. رسم بياني تُتحقَّق أرقامه مقابل المقال، ولقطة شاشة مولَّدة من النسخة قيد التشغيل فعليًا، ومخطط قابل للمراجعة كنص في طلب السحب — ثلاثة عناصر بصرية لا يمكن أن تنحرف عن الحقيقة دون فشل اختبار.
بخصوص الإسناد، النقطة الخاصة بخط الأنابيب ضيقة:
الحجة الداعية لعرض
الاعتماد دائمًا مطروحة في مكان آخر، وما يضيفه المجمِّع الآلي هو أن السلسلة نفسها
attribution التي يطبعها هي creditText التي تحتاجها البيانات
المهيكلة. حقل واحد، مكانان، يُصدَران في تمريرة القالب نفسها — وهو السبب في أن خط الأنابيب لديه
عذر أقل حتى من الإنسان لإسقاطه.
من أين تبدأ
- أضف مُوجِّه التوجيه (router) إلى أيًا كان ما يكتب مسوداتك أصلًا، واطبع JSON دون التصرّف بناءً عليه. اقرأ عشر خطط. إذا كانت الملخّصات تُسمّي مواضيع بدلًا من مشاهد، أصلِح المُوجِّه قبل كتابة أي تكامل.
- وصِّل خانات الصور فقط. استدعاء
GET /search/photosواحد لكل ملخّص، وخزّنphoto_idمنذ اليوم الأول — إزالة التكرار المُعالَجة بأثر رجعي عبر 3,000 صفحة حية هجرة (migration)، وليست عمودًا. - أصدِر العرض والارتفاع ونص alt في نفس عملية الرفع (commit). إنه أرخص عمل لـCore Web Vitals ستنجزه على الإطلاق.
- ثم أضف المرحلة 4، المخططات قبل الرسوم البيانية — Mermaid نص، لذا هو الوحيد الخالي من أي نمط إخفاق يتجاوز خطأ نحوي.
- أضف الضمانة الرقمية قبل وصول أول رسم بياني إلى القارئ، وليس بعده.
المراجع والحواشي
1 Google Search Central، أفضل ممارسات تحسين محركات البحث للصور: نص alt
هو "أهم سمة عندما يتعلق الأمر بتوفير بيانات وصفية للصورة"؛ الإرشاد هو إنشاء "محتوى مفيد وغني بالمعلومات يستخدم الكلمات المفتاحية بشكل مناسب وفي سياق محتوى الصفحة"، وتجنّب سمات alt المحشوّة بالكلمات المفتاحية، واستخدام عناصر HTML
<img> بدلًا من صور CSS، ومنح الملفات أسماء قصيرة لكن وصفية.
2 قانون الذكاء الاصطناعي للاتحاد الأوروبي، المادة 50 — التزامات الشفافية السارية اعتبارًا من 2 أغسطس 2026: يجب على مزوّدي الأنظمة التي تولّد صورًا أو صوتًا أو فيديو أو نصوصًا اصطناعية وسم المخرجات بتنسيق قابل للقراءة الآلية وجعلها قابلة للاكتشاف كمُولَّدة اصطناعيًا. يُلزم مزوّدي ومُشغّلي الذكاء الاصطناعي؛ وليس قاعدة بشأن أي الصور يجوز لموقع نشرها.
3 يعرض Mermaid المخططات والرسوم البيانية من تعريفات نصية مستوحاة من Markdown، وهذا ما يجعل المُخرَج قابلًا للمراجعة وحتميًا.
4 web.dev، تحسين Largest Contentful Paint: "من الجيد ضبط fetchpriority="high" على عنصر <img> إذا كنت تعتقد أنه من المرجح أن يكون عنصر LCP لصفحتك"، يُستخدم بحذر؛ و"لا تُحمِّل صورة LCP الخاصة بك بشكل كسول أبدًا، فذلك سيؤدي دومًا إلى تأخير غير ضروري في تحميل المورد، وسيكون له أثر سلبي على LCP."
5 Google Search Central، بيانات وصفية للصور (بيانات مهيكلة):
يتطلب ImageObject contentUrl بالإضافة إلى واحد على الأقل من
creator أو creditText أو copyrightNotice أو
license؛ يُوصى بـacquireLicensePage، ويمكن للصور الحاملة لمعلومات ترخيص أن تصبح مؤهَّلة لشارة Licensable في Google Images.
6 Google Search Central، خرائط مواقع الصور: خرائط مواقع الصور تُعلِم Google بالصور الموجودة على موقع، بما فيها تلك المكتشَفة عبر JavaScript، وتقبل حتى 1,000 صورة لكل رابط صفحة.
7 سياسات البريد المزعج في بحث Google — إساءة استخدام المحتوى واسع النطاق: توليد صفحات كثيرة أساسًا للتلاعب بالترتيب مع تقديم قيمة ضئيلة للمستخدمين، سواء أُنشئت عبر الأتمتة أو الجهد البشري أو مزيج منهما.
تم التحقق من المصادر في 17 أغسطس 2026: أفضل ممارسات تحسين محركات البحث للصور · بيانات وصفية للصور · خرائط مواقع الصور · تحسين LCP · سياسات البريد المزعج في البحث · المادة 50 من قانون الذكاء الاصطناعي · Mermaid · وثائق Pexafy API وMCP. توقيتات البحث (147 ملّي ثانية، 144 ملّي ثانية) وكل صورة مُعروضة هي استجابات واجهة برمجة تطبيقات حقيقية التُقطت في اليوم نفسه.
الأسئلة الشائعة
كيف أوضّح تلقائيًا المقالات المكتوبة بواسطة نموذج لغوي كبير؟
GET /api/v1/search/photos، بزمن استجابة حوالي 150 مللي ثانية). إدخالات الرسوم البيانية والمخططات تُرسَل إلى نموذج يكتب كود الرسم أو Mermaid، ويُعرض بشكل حتمي. لا تُدخل عنوان المقالة أبدًا في بحث الصور: العناوين مجرّدة ولا توجد صورة فوتوغرافية تصوّرها.هل يجب أن يستخدم موقع التوثيق لقطات شاشة أم صورًا جاهزة؟
كيف أمنع خط أنابيب الذكاء الاصطناعي من وضع أرقام خاطئة في رسم بياني؟
data في إدخال الرسم البياني. ثم تحقّق من ذلك في الكود قبل العرض — لكل قيمة، تأكّد من أن نصّها موجود في المقالة، وإلا أطلق خطأ. تسعة أسطر فقط، ورسم بياني يناقض فقرته الخاصة لا يمكنه أبدًا الوصول إلى القارئ.ما ترميز الصور الذي يجب أن يصدره خط أنابيب مؤتمت لتحسين محركات البحث؟
alt وصفي يُكتب في سياق الفقرة — تصف Google نص alt بأنه أهم بيانات وصفية للصورة، وتحذّر من حشو الكلمات المفتاحية. width و height على كل صورة، مع fetchpriority="high" على الصورة الرئيسية وعدم استخدام loading="lazy" عليها أبدًا، لأن صورة LCP يجب ألا تُحمَّل ببطء. وبيانات ImageObject المنظّمة التي تضم contentUrl و creator و creditText و license، وهي ما يجعل الصورة مؤهلة لشارة Licensable في Google Images.هل توضيح المقالات المكتوبة بالذكاء الاصطناعي يساعدها على التصدّر في نتائج البحث؟
كيف أشغّل خطوة التوضيح في CI دون أن أفقد السيطرة التحريرية؟
photo_id، والتأكد من أن كل رقم مرسوم في الرسم البياني يظهر في المقالة، والفشل الصارم عندما لا تتجاوز أي صورة عتبة النقاط. لا صورة رئيسية أفضل من صورة خاطئة.