Les lettres de bienvenue pour quarante nouveaux clients, un certificat pour chaque participant, une facture par commande : le même document, un enregistrement différent à chaque fois. Avec GroupDocs.Assembly.Mcp exécuté localement (dnx GroupDocs.Assembly.Mcp --yes), Claude Desktop, Cursor ou Copilot le font avec un seul appel d’outil, assemble_per_record, qui remplit votre modèle Word une fois par élément d’un tableau JSON, enregistre chaque résultat comme un PDF distinct nommé d’après un champ que vous choisissez, et signale les enregistrements qui ont échoué au lieu de s’arrêter au premier :
Créer un PDF de lettre de bienvenue pour chaque client dans customers.json en utilisant welcome-letter.docx, et nommer chaque fichier d’après le client.
La version étape par étape avec configuration et dépannage se trouve dans la documentation : Comment générer un document par enregistrement (mail merge) avec un agent IA.
Pourquoi ne pas laisser l’agent boucler ?
Il peut le faire, et pour cinq enregistrements c’est correct. Mais une boucle de quarante appels d’outil représente quarante occasions pour l’agent de perdre le compte, de sauter un enregistrement lorsque le contexte devient long, ou de « reformuler » un courrier « utile ». Un outil par enregistrement déplace la boucle vers le serveur : un appel, un modèle, un passage sur le tableau, et un rapport indiquant exactement combien de fichiers ont été écrits et quels enregistrements n’ont pas abouti. Le travail de l’agent est de choisir le modèle, le fichier de données et le champ de nommage, puis de vous lire le rapport.
Que vérifie d’abord l’agent ?
Deux choses : à quoi ressemblent les données, et ce que lit le modèle. Dans notre test, cinq clients dans customers.json et une lettre de bienvenue d’une page :
-> 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" ] }
Le modèle appelle un enregistrement customer ; le serveur le déduit lui‑même, donc l’agent n’a pas besoin de transmettre dataSourceName.
Un appel, cinq enregistrements, un échec
-> 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. ...
L’enregistrement 4, Wingtip Travel, n’avait pas de date de première facture dans les données. Les quatre autres lettres ont été rédigées, chacune nommée d’après le client, et l’échec est revenu avec le numéro d’enregistrement et le champ manquant. Un agent le rapporte ainsi : « quatre lettres terminées ; Wingtip Travel n’a pas de date de première facture, voulez‑vous que je laisse la ligne vide ou attendre la date ? ». C’est la conversation que vous souhaitez, plutôt que quarante fichiers sans savoir lequel est erroné.
Comment fonctionne la diffusion
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 ..."
Trois paramètres font le travail. fileNameField nomme chaque sortie à partir d’un champ d’enregistrement, customer.Name ou un numéro de facture ; sans cela, les fichiers reçoivent un numéro séquentiel. recordsPath pointe vers le tableau lorsque le JSON est un objet qui en contient un, comme "customers" ou "batch.items". Et maxDocuments est le frein.
Qu’est‑ce qui arrête un lot incontrôlé ?
maxDocuments, qui vaut par défaut 100 et peut aller jusqu’à 1000. Avant d’écrire quoi que ce soit, le serveur compte les enregistrements ; s’il y en a plus que la limite, il refuse. Nous l’avons fixé à 3 pour nos cinq clients :
-> 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.
Rien n’a été écrit. Pour un envoi qui s’adresse à de vraies personnes, c’est le bon comportement par défaut : une invite qui pointe accidentellement sur l’export complet du CRM reçoit une question en retour, et non pas dix mille PDF.
Mes données sont une feuille de calcul, pas du JSON
La génération par enregistrement ne lit que du JSON : un tableau d’objets, ou un objet contenant un tableau. Lorsque la liste se trouve dans un CSV ou une feuille de calcul, l’agent convertit d’abord les lignes en JSON, ce que les agents font bien, puis écrit le fichier dans le dossier de stockage. Si vous souhaitez un seul document qui répertorie chaque ligne, une liste de prix ou un registre, il faut utiliser assemble_document avec un <<foreach>> dans le modèle, et il lit directement les CSV et les feuilles de calcul.
Limites honnêtes
- L’assemblage par enregistrement ne lit que du JSON ; les données CSV et de feuilles de calcul doivent d’abord être converties.
- Mode évaluation : chaque fichier généré commence par “Evaluation Only. Created with GroupDocs.Assembly 26.7…”, et les modèles d’e‑mail ne conservent que leur corps en texte brut. Licencez le serveur avant un envoi réel.
- Un champ manquant fait échouer cet enregistrement.
allowMissingMembers: truel’écrit avec la ligne vide à la place ; décidez ce que vous voulez. - Dates : écrivez‑les sous la forme
2026-12-01T00:00:00et formatez‑les dans le modèle, comme notre lettre le fait avec<<[customer.FirstInvoice]:"d MMMM yyyy">>. Une chaîne de date seule décalée d’un jour sur une machine UTC+2 dans notre test. - Le serveur écrit les fichiers ; il ne les envoie pas. La livraison est une étape séparée.
FAQ
Puis‑je faire du mail merge avec Claude sans télécharger la liste des clients ?
Oui. Le serveur s’exécute localement et lit customers.json depuis votre dossier de stockage ; les PDF générés y sont également écrits.
Comment les fichiers de sortie sont‑ils nommés ?
Par le champ d’enregistrement que vous passez comme fileNameField, ici le nom du client, donc Contoso Pharma.pdf. Sans cela, un numéro séquentiel.
Chaque document peut‑il être un e‑mail au lieu d’un PDF ?
Oui : utilisez un modèle EML ou MSG, ou passez format: "eml". En mode évaluation, le corps HTML d’un e‑mail est remplacé par la ligne d’évaluation, donc testez la sortie e‑mail avec une licence.
Approfondir
- Documentation, guide canonique : Comment générer un document par enregistrement (mail merge) avec un agent IA
- Hub de documentation : GroupDocs.Assembly MCP Server
- Commencez ici : Laissez le modèle remplir les données, pas écrire le document
- Lié : De quoi ce modèle a‑t‑il besoin ? Demandez‑le.
- Lié : Le graphique vient du modèle, les chiffres viennent des données
- Lié : Votre dépôt possède déjà les données ; laissez l’agent créer le PDF
- Sur site et modèle de sécurité : 3 architectures pour le traitement de documents IA, et celle qui garde les fichiers à l’intérieur de votre réseau
- Questions : GroupDocs Assembly forum
- Source : GroupDocs.Assembly.Mcp on GitHub