مرحبًا برسائل الترحيب لأربعين عميلًا جديدًا، وشهادة لكل مشارك، وفاتورة لكل طلب: نفس المستند، سجل مختلف في كل مرة. مع تشغيل GroupDocs.Assembly.Mcp محليًا (dnx GroupDocs.Assembly.Mcp --yes)، يقوم Claude Desktop أو Cursor أو Copilot بذلك باستدعاء أداة واحد، assemble_per_record، الذي يملأ قالب Word الخاص بك مرة واحدة لكل عنصر في مصفوفة JSON، ويحفظ كل نتيجة كملف PDF خاص به يُسمّى بحقل تختاره، ويُبلغ عن السجلات التي فشلت بدلاً من التوقف عند الأولى:
أنشئ ملف PDF لرسالة ترحيب لكل عميل في customers.json باستخدام welcome-letter.docx، وسمِّ كل ملف باسم العميل.
الإصدار خطوة بخطوة مع الإعدادات واستكشاف الأخطاء موجود في الوثائق: How to generate one document per record (mail merge) with an AI agent.
لماذا لا نترك الوكيل يدوّر؟
يمكنه ذلك، ولخمسة سجلات يكون ذلك مناسبًا. لكن حلقة من أربعين استدعاء أداة تعني أربعين فرصة للوكيل أن يخطئ في العد، أو يتخطى سجلًا عندما يصبح السياق طويلاً، أو “يُعيد الصياغة” لرسالة ما. أداة per‑record تنقل الحلقة إلى الخادم: استدعاء واحد، قالب واحد، مرور واحد على المصفوفة، وتقرير يوضح بالضبط عدد الملفات التي كُتبت وأي السجلات لم تُنجز. مهمة الوكيل هي اختيار القالب، ملف البيانات، وحقل التسمية، ثم قراءة التقرير لك.
ما الذي يتحقق منه الوكيل أولًا؟
شيئان: ما شكل البيانات، وما يقرأه القالب. في اختبارنا، كان هناك خمسة عملاء في customers.json ورسالة ترحيب من صفحة واحدة:
-> get_document_info {"file":{"filePath":"customers.json"}}
<- { "dataKind": "json",
"data": { "root": "array", "length": 5, "keys": null } }
-> get_template_fields {"template":{"filePath":"welcome-letter.docx"}}
<- { "dataSourceNames": [ "customer" ],
"fields": [ "customer.Contact", "customer.Plan", "customer.Name",
"customer.Manager", "customer.FirstInvoice" ] }
القالب يُشير إلى سجل واحد باسم customer؛ الخادم يكتشف ذلك بنفسه، لذا لا يحتاج الوكيل إلى تمرير dataSourceName.
استدعاء واحد، خمسة سجلات، فشل واحد
-> assemble_per_record {"template":{"filePath":"welcome-letter.docx"},
"data":{"filePath":"customers.json"},"fileNameField":"Name",
"format":"pdf"}
<- Assembled 4 of 5 document(s) from 'welcome-letter.docx' with
'customers.json', one per record (each record as 'customer'), as PDF.
Saved to:
.../Contoso Pharma.pdf
.../Fabrikam Logistics.pdf
.../Tailspin Toys.pdf
.../Litware Labs.pdf
1 record(s) failed:
record 4: InvalidOperationException: ... Can not get the value of
member 'FirstInvoice' on type 'System.Data.DataRow'. The template
reads 'FirstInvoice', which the data does not have. ...
السجل الرابع، Wingtip Travel، لم يكن لديه تاريخ الفاتورة الأولى في البيانات. الأربعة رسائل الأخرى كُتبت، كل واحدة مسماة باسم العميل، وعاد الفشل مع رقم السجل والحقل المفقود. يُبلغ الوكيل ذلك كـ “تم إنشاء أربع رسائل؛ لا يوجد تاريخ فاتورة أولى لـ Wingtip Travel، هل تريد ترك السطر فارغًا أم الانتظار للحصول على التاريخ؟”. هذا هو الحوار الذي تريده، بدلاً من أربعين ملفًا ولا فكرة عن أيها خاطئ.
كيف يعمل التفريع (fan‑out)
customers.json [ {Name:"Contoso Pharma",...}, {Name:"Fabrikam ..."},
... 5 records ]
|
assemble_per_record {"template":{"filePath":"welcome-letter.docx"},
"data":{"filePath":"customers.json"},
"fileNameField":"Name","format":"pdf"}
|
+--> Contoso Pharma.pdf
+--> Fabrikam Logistics.pdf ... 2 more
'--> "4 of 5 ... 1 record(s) failed: record 4 ..."
ثلاثة معلمات تقوم بالمهمة. fileNameField يحدد اسم كل مخرج بحقل من السجل، مثل customer.Name أو رقم الفاتورة؛ بدونها تُعطى الملفات أرقامًا متسلسلة. recordsPath يشير إلى المصفوفة عندما يكون JSON كائنًا يحتوي على واحدة، مثل "customers" أو "batch.items". وmaxDocuments هو القيد.
ما الذي يوقف دفعة غير محدودة؟
maxDocuments، الذي يساوي افتراضيًا 100 ويمكن أن يصل إلى 1000. قبل كتابة أي شيء، يحسب الخادم عدد السجلات؛ إذا كان العدد أكبر من الحد، يرفض المتابعة. ضبطناه على 3 مقابل عملائنا الخمسة:
-> assemble_per_record {..., "maxDocuments":3}
<- Per-record assembly failed for 'welcome-letter.docx': there are 5
records, more than maxDocuments=3. Raise 'maxDocuments' (up to 1000)
or pass fewer records.
لم يُكتب شيء. بالنسبة لحملة بريدية تُرسل إلى أشخاص حقيقيين، هذا هو الإعداد الافتراضي الصحيح: سؤال يُطرح عندما يُشير المستخدم بطريق الخطأ إلى تصدير CRM كامل، بدلاً من إنشاء عشرات الآلاف من ملفات PDF.
بياناتي جدول بيانات، ليست JSON
إنشاء per‑record يقرأ JSON فقط: مصفوفة من الكائنات، أو كائن يحتوي على واحدة. عندما تكون القائمة في CSV أو ورقة عمل، يقوم الوكيل بتحويل الصفوف إلى JSON أولًا، وهو ما يجيده الوكلاء، ثم يكتب الملف في مجلد التخزين. إذا كنت تريد مستندًا واحدًا يُدرج كل صف، مثل قائمة أسعار أو سجل، فذلك يتم عبر assemble_document مع <<foreach>> في القالب، وهو يقرأ CSV وجداول البيانات مباشرة.
حدود صريحة
- إنشاء per‑record يقرأ JSON فقط؛ بيانات CSV وجداول البيانات تحتاج إلى تحويل أولًا.
- وضع التقييم: كل ملف مُولد يبدأ بـ “Evaluation Only. Created with GroupDocs.Assembly 26.7…"، وقوالب البريد الإلكتروني تحتفظ بنصها العادي فقط. رُخص الخادم قبل حملة بريدية فعلية.
- حقل مفقود يؤدي إلى فشل ذلك السجل.
allowMissingMembers: trueيكتب السطر فارغًا بدلاً من ذلك؛ اختر ما يناسبك. - التواريخ: اكتبها كـ
2026-12-01T00:00:00وصغّها في القالب، كما فعلنا في رسالتنا باستخدام<<[customer.FirstInvoice]:"d MMMM yyyy">>. لاحظ أن سلسلة تاريخية بدون وقت تم إزاحتها يومًا واحدًا على جهاز UTC+2 في اختبارنا. - الخادم يكتب الملفات؛ لا يرسلها. الإرسال خطوة منفصلة.
الأسئلة المتكررة
هل يمكنني دمج البريد مع Claude دون رفع قائمة العملاء؟
نعم. الخادم يعمل محليًا ويقرأ customers.json من مجلد التخزين الخاص بك؛ ملفات PDF المُولدة تُكتب هناك أيضًا.
كيف يتم تسمية ملفات الإخراج؟
بحسب حقل السجل الذي تمرره كـ fileNameField، هنا اسم العميل، لذا Contoso Pharma.pdf. بدون ذلك تُعطى أرقامًا متسلسلة.
هل يمكن أن يكون كل مستند بريدًا إلكترونيًا بدلاً من PDF؟
نعم: استخدم قالب EML أو MSG، أو مرّر format: "eml". في وضع التقييم يُستبدل جسم HTML للبريد بسطر التقييم، لذا اختبر مخرجات البريد الإلكتروني مع رخصة.
تعمق أكثر
- الوثائق، الدليل الرسمي: How to generate one document per record (mail merge) with an AI agent
- مركز الوثائق: GroupDocs.Assembly MCP Server
- ابدأ هنا: Let the model fill in the data, not write the document
- ذو صلة: What does this template need? Ask it.
- ذو صلة: The chart comes from the template, the numbers come from the data
- ذو صلة: Your repo already has the data; let the agent make the PDF
- النموذج المحلي وأمانه: 3 architectures for AI document processing, and the one that keeps files inside your network
- أسئلة: GroupDocs Assembly forum
- المصدر: GroupDocs.Assembly.Mcp on GitHub