Willkommensbriefe für vierzig neue Kunden, ein Zertifikat für jeden Teilnehmer, eine Rechnung pro Auftrag: dasselbe Dokument, jedes Mal ein anderer Datensatz. Mit lokal laufendem GroupDocs.Assembly.Mcp (dnx GroupDocs.Assembly.Mcp --yes) erledigt Claude Desktop, Cursor oder Copilot das mit einem Tool‑Aufruf, assemble_per_record, das Ihre Word‑Vorlage einmal pro Element eines JSON‑Arrays füllt, jedes Ergebnis als eigene PDF speichert, benannt nach einem von Ihnen gewählten Feld, und die Datensätze meldet, die fehlgeschlagen sind, anstatt beim ersten Abbruch zu stoppen:

Erstelle ein Willkommensbrief‑PDF für jeden Kunden in customers.json mit welcome-letter.docx und benenne jede Datei nach dem Kunden.

Die schrittweise Version mit Konfiguration und Fehlersuche finden Sie in der Dokumentation: Wie man ein Dokument pro Datensatz (Serienbrief) mit einem KI‑Agenten erzeugt.

Warum nicht den Agenten schleifen lassen?

Das kann er, und für fünf Datensätze ist das in Ordnung. Aber eine Schleife von vierzig Tool‑Aufrufen bedeutet vierzig Gelegenheiten für den Agenten, die Zählung zu verlieren, einen Datensatz zu überspringen, wenn der Kontext zu lang wird, oder „hilfreich“ einen Brief umzuformulieren. Ein per‑Datensatz‑Tool verlagert die Schleife in den Server: ein Aufruf, eine Vorlage, ein Durchlauf über das Array und ein Bericht, der genau angibt, wie viele Dateien geschrieben wurden und welche Datensätze nicht erfolgreich waren. Die Aufgabe des Agenten besteht darin, die Vorlage, die Datendatei und das Namensfeld auszuwählen und anschließend den Bericht für Sie zu lesen.

Was prüft der Agent zuerst?

Zwei Dinge: wie die Daten aussehen und was die Vorlage liest. In unserem Test fünf Kunden in customers.json und ein einseitiger Willkommensbrief:

-> 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" ] }

Die Vorlage bezeichnet einen Datensatz als customer; der Server ermittelt das selbst, sodass der Agent dataSourceName nicht übergeben muss.

Ein Aufruf, fünf Datensätze, ein Fehler

-> 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. ...

Datensatz 4, Wingtip Travel, hatte kein Datum für die erste Rechnung in den Daten. Die anderen vier Briefe wurden geschrieben, jeweils nach dem Kunden benannt, und der Fehler wurde mit der Datensatznummer und dem fehlenden Feld zurückgemeldet. Ein Agent meldet das als „vier Briefe fertig; Wingtip Travel hat kein Datum für die erste Rechnung, soll ich die Zeile leer lassen oder auf das Datum warten?“. Das ist die gewünschte Konversation, anstatt vierzig Dateien zu erhalten und nicht zu wissen, welche falsch ist.

Wie das Fan‑Out funktioniert

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 ..."

Drei Parameter erledigen die Arbeit. fileNameField benennt jede Ausgabe nach einem Feld des Datensatzes, z. B. customer.Name oder einer Rechnungsnummer; ohne dieses Feld erhalten die Dateien eine laufende Nummer. recordsPath zeigt auf das Array, wenn das JSON ein Objekt ist, das eines enthält, wie "customers" oder "batch.items". Und maxDocuments ist die Bremse.

Was stoppt einen unkontrollierten Batch?

maxDocuments, das standardmäßig 100 ist und bis zu 1000 gehen kann. Bevor etwas geschrieben wird, zählt der Server die Datensätze; wenn mehr als das Limit vorhanden sind, wird abgelehnt. Wir setzten es auf 3 gegenüber unseren fünf Kunden:

-> 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.

Nichts wurde geschrieben. Für einen Versand an echte Personen ist das die richtige Voreinstellung: Eine Eingabe, die versehentlich auf den gesamten CRM‑Export zeigt, führt zu einer Rückfrage, nicht zu zehntausend PDFs.

Meine Daten sind eine Tabellenkalkulation, nicht JSON

Die per‑Datensatz‑Erzeugung liest nur JSON: ein Array von Objekten oder ein Objekt, das eines enthält. Wenn die Liste in einer CSV‑Datei oder einem Arbeitsblatt liegt, konvertiert der Agent die Zeilen zuerst nach JSON, was Agenten gut können, und schreibt die Datei in den Speicherordner. Wenn Sie ein Dokument benötigen, das jede Zeile auflistet, z. B. eine Preisliste oder ein Register, verwenden Sie assemble_document mit einem <<foreach>> in der Vorlage, und es liest CSV‑ und Tabellenkalkulationsdateien direkt.

Ehrliche Grenzen

  • Per‑Datensatz‑Zusammenstellung liest nur JSON; CSV‑ und Tabellenkalkulationsdaten müssen zuerst konvertiert werden.
  • Evaluierungsmodus: jede erzeugte Datei beginnt mit “Evaluation Only. Created with GroupDocs.Assembly 26.7…”, und E‑Mail‑Vorlagen behalten nur ihren Nur‑Text‑Body. Lizenzieren Sie den Server vor einem echten Versand.
  • Ein fehlendes Feld lässt diesen Datensatz fehlschlagen. allowMissingMembers: true schreibt ihn stattdessen mit einer leeren Zeile; entscheiden Sie, was Sie wollen.
  • Datumsangaben: schreiben Sie sie als 2026-12-01T00:00:00 und formatieren Sie sie in der Vorlage, wie unser Brief es mit <<[customer.FirstInvoice]:"d MMMM yyyy">> tut. Ein reiner Datums‑String wurde in unserem Test auf einer UTC+2‑Maschine um einen Tag verschoben.
  • Der Server schreibt Dateien; er sendet sie nicht. Die Zustellung ist ein separater Schritt.

FAQ

Kann ich mit Claude einen Serienbrief erstellen, ohne die Kundenliste hochzuladen?
Ja. Der Server läuft lokal und liest customers.json aus Ihrem Speicherordner; die erzeugten PDFs werden dort ebenfalls geschrieben.

Wie werden die Ausgabedateien benannt?
Durch das Datensatz‑Feld, das Sie als fileNameField übergeben, hier der Kundenname, also Contoso Pharma.pdf. Ohne dieses Feld erhalten Sie eine laufende Nummer.

Kann jedes Dokument eine E‑Mail statt einer PDF sein?
Ja: Verwenden Sie eine EML‑ oder MSG‑Vorlage oder übergeben Sie format: "eml". Im Evaluierungsmodus wird der HTML‑Body einer E‑Mail durch die Evaluierungszeile ersetzt, testen Sie also die E‑Mail‑Ausgabe mit einer Lizenz.

Tiefer einsteigen