Tutorial
Wie verbindet ein Apple AI Agent App, API und Tools? Welche Rolle spielt JSON?
Der System-Agent nutzt App Intents, das In-App-Modell nutzt Foundation Models Tool. JSON ist keine Dekoration, sondern die gemeinsame Form für Argumentverträge, strukturierte Ausgabe und HTTP-Nutzlasten.
„Apple AI Agent“ wird oft als Produktname behandelt. In der Praxis treffen Sie mindestens auf zwei völlig verschiedene Aufrufketten: Apple Intelligence wählt App und Aktion für den Nutzer, oder Ihre App führt ein On-Device-Modell aus, das entscheidet, welche Tools aufgerufen werden. Beide berühren App, API und Tools, aber wer die Sitzung besitzt, wer Argumente erzeugt und wo JSON erscheint, ist nicht gleich. Trennen Sie diese Schichten, sonst fehlen Schema, Logs und Debugging einen Anknüpfungspunkt.
Zuerst: Wer führt das Modell aus?
Beginnen Sie mit der Frage, wer diese Inferenz ausgelöst hat. Spricht die Person mit Siri oder systemweitem Apple Intelligence, läuft das Modell auf der Systemseite (auf dem Gerät oder Private Cloud Compute). Ihre App ist nur die angebundene Fähigkeit. Sie exponieren App Intents: typisierte Aktionen, Entitäten und Parameter. Der System-Agent entscheidet, wann aufgerufen wird, Ihr Code führt perform aus. Offizieller Einstieg: App Intents-Dokumentation.
Wenn der Nutzer bereits in Ihrer App ist und Sie eine LanguageModelSession von Foundation Models starten, ist das eine andere Kette: Ihr Prozess treibt das Modell, Sie injizieren die Tools. Das System wählt nicht „welche App öffnen“, weil die Sitzung bereits in der App lebt. Tools können Kontakte lesen, Kalender abfragen, Ihre eigene Netzwerk-API aufrufen und Ergebnisse in den transcript schreiben. Framework-Hinweise: Foundation Models. Für Tool-Aufrufe auf Sitzungsebene siehe WWDC25 Meet the Foundation Models framework.
Ein drittes Muster wird häufig: ein externer Host (Claude, ChatGPT, eigener Agent) ruft Ihren Dienst über MCP oder normales HTTPS auf. Das Modell läuft nicht auf dem Apple-Stack, aber die Nutzlast ist fast immer JSON. Dieselben Domänenfunktionen können App Intents, Foundation Models Tool und HTTP bedienen — nur die Adapter unterscheiden sich.
| Aufrufkette | Wer führt das Modell aus | Was die App bereitstellt |
|---|---|---|
| System-Agent | Apple Intelligence | App Intents / App Entity |
| In-App-Agent | Ihre LanguageModelSession | Tool-Protokoll und @Generable-Argumente |
| Externer Agent | Drittanbieter-Host | JSON-RPC oder REST JSON |
Fassen Sie die drei Ketten nicht zu einem „Universal-Agent“-Diagramm zusammen. Beim Debuggen zuerst die Kette identifizieren: System-Routing-Fehler → Intent-Deklarationen und Parametertypen; wilde In-App-Tool-Aufrufe → name, description und generierbare Arguments-Form; externe API passt nicht → HTTP JSON und Schema. Alles vermischen, und es wirkt, als „spinne das Modell herum“.
App Intents: wie der System-Agent Ihre App erreicht
Für den System-Agent ist eine App nicht „öffnen und umschauen“, sondern ein auffindbarer Fähigkeitskatalog. Mit AppIntent deklarieren Sie Aktionsnamen, natürlichsprachliche Beschreibungen, Parametertypen und Ergebnisse. Spotlight, Shortcuts, Siri und Apple Intelligence teilen diesen Katalog. Sagt jemand „diese Rechnung als bezahlt markieren“, muss das System die Äußerung auf Ihr MarkInvoicePaid mappen, nicht das Modell in der UI tippen lassen.
Parameter sind die Verbindung. Das System fasst Sprache zu typisierten Werten zusammen: Enums, Daten, AppEntity-Referenzen. In Swift sehen Sie Structs, keinen Fließtext. Über Prozesse oder Frameworks hinweg braucht diese Struktur eine serialisierbare Form — Debugging, Logs und Server-Replay landen als JSON oder gleichwertige Property-Liste. Entwerfen Sie Intent-Parameter als Feldmenge, die sich als JSON-Objekt schreiben lässt, dann werden API-Adapter deutlich günstiger.
Üblicher Kompromiss: Soll der Intent direkt ins Netz? Kurze Aktionen können in perform enden. Sobald Auth, Paginierung oder Idempotenz dazukommen, macht perform nur „Parameter prüfen + Domänenservice aufrufen“; der Service sendet die JSON-Anfrage. Der System-Agent braucht Ihren REST-Pfad nicht — er braucht Erfolgs-/Fehlersemantik des Intent. Den Pfad brauchen Sie, weil Abrechnung, Audit und Retries auf der API-Schicht liegen.
Foundation Models: wie das In-App-Modell Tools aufruft
Die In-App-Agent-Verbindung gleicht eher „dem Modell eine Funktionsspezifikation geben“. Sie implementieren Tool: geben Sie name, description, plus ein @Generable Arguments. Das Framework schreibt das in den prompt, damit das Modell entscheidet, wann aufgerufen wird. Beim Aufruf erzeugt es zuerst Argumente, dann führt das Framework call(arguments:) aus und fügt den Rückgabewert (meist String oder generierbarer Typ) in den transcript ein. Das Modell schreibt die finale Antwort. Sie lassen es keine URLs erfinden — es wählt aus erlaubten Tools.
Argumenterzeugung läuft über strukturierte Ausgabe, nicht „bitte in JSON antworten“. @Generable und dynamische Schema fixieren Felder, Enums und verschachtelte Objekte beim Dekodieren. In Swift erhalten Sie typisierte Instanzen; zum Persistieren, Loggen oder für URLSession danach in JSON encodieren. Apple fasst das als language understanding, structured output und tool calling zusammen — siehe Foundation Models-Überblick.
struct FindOrders: Tool {
let name = "findOrders"
let description = "Find recent orders by customer email and status."
@Generable
struct Arguments {
var email: String
var status: String
var limit: Int
}
func call(arguments: Arguments) async throws -> String {
// Call your domain API, then return a compact summary.
return "3 orders, latest is paid"
}
}
In diesem Abschnitt erfindet das Modell keine Feldnamen. Es muss email, status, limit ausfüllen. Die description entscheidet über Auswahl: zu breit und es feuert bei allem; zu eng und es schweigt, wenn Sie es brauchen. Tool-Ausgabe klein halten — ein ganzes Bestell-JSON in den transcript zu kippen verbrennt das Kontextfenster. Geben Sie eine Zusammenfassung zurück und rufen Sie bei Bedarf ein zweites Tool für eine ID auf.
Tools können verkettet werden. Das Modell nutzt die Ausgabe des ersten als Eingabe des zweiten; das Framework führt der Reihe nach aus. Idempotenz in der Domänenschicht sicherstellen: dieselbe orderId zweimal als bezahlt markieren darf nicht doppelt abbuchen. Die Agent-Schleife sieht Ihre Datenbankconstraints nicht. Gültige JSON-Argumente bedeuten nicht ein korrektes Geschäftsergebnis.
Welche Rolle JSON spielt
Swift-Typen sind der Compile-Time-Vertrag, JSON der Runtime-Vertrag. Sobald der Agent den Prozess verlässt — Backend-Aufrufe, Dateien, anderes Modell, Test-Fixtures — muss die Form sprachneutraler Text werden. JSON spielt auf dieser Kette mindestens drei Rollen. Mischen Sie zwei davon, erhalten Sie „es parst, aber jedes Feld ist falsch“.
1. Austauschformat für Tool-Argumente
Foundation Models repräsentiert strukturierte Werte intern als GeneratedContent. Die nützlichste Debug-Ansicht ist oft „wie dieses Arguments als JSON encodiert aussieht“. Namen, Optionalität, Array vs. Objekt müssen stabil bleiben. Argumente als JSON loggen, damit sie mit Produktions-API-Zugriffslogs übereinstimmen: hat dasselbe customerId den Server wirklich erreicht?
{
"email": "ada@example.com",
"status": "paid",
"limit": 5
}
2. Schema für strukturierte Ausgabe
Auch ohne Tools, wenn Sie nur eine Rechnungszusammenfassung wollen, brauchen Sie ein Schema: Pflichtschlüssel, Enum-Werte, Betrag als number oder string. Auf Apple-Seite nutzt man @Generable; Cloud-Modelle meist JSON Schema. Beschreiben beide dasselbe Domänenobjekt, teilen Sie eine Feld-Tabelle, damit die App nicht totalCents sagt, während die API amount sagt. Gemeinsame Regeln für Schema-Schreiben: Understanding JSON Schema.
3. Nutzlast von App zu API
Sobald das call eines Tools das Netz berührt, ist JSON der HTTP-Body. Der Agent ersetzt kein API-Design: Auth-Header, Idempotenz-Schlüssel und Fehlerobjekte bleiben Ihre Aufgabe. Das Modell füllt nur „Geschäftsparameter“; Transport, Paginierung und Rate-Limits bleiben normales Backend. Formen Sie Fehler als stabiles JSON (code, message, retryable), damit das Modell entscheiden kann, Tools zu wechseln oder den Fehler zu erklären.
Drei Schichten können ein Schema-Dokument teilen: Intent-Parameter ⊂ Tool Arguments ⊂ HTTP body. Teilmengen vereinfachen Tests: ein gültiges JSON-Fixture, dann API, dann Tool, dann Intent-Adapter. Eine Obermenge (HTTP hat drei interne Felder mehr) ist ok, aber zeigen Sie diese Felder dem Modell nicht, sonst füllt es „hilfsbereit“ Schlüssel aus, die Sie nicht veröffentlichen wollten.
HTTP-APIs und MCP anbinden
Wenn ein In-App-Tool REST aufruft, explizit encodieren. Senden Sie GeneratedContent nicht direkt als Data. Mappen Sie auf Ihr Codable-Modell, dann JSONEncoder. So kontrollieren Sie Enum-Raw-Values, Datumsformate und Schlüsselstrategie (snake_case). Das Modell erzeugt Domänenwerte; der Encoder kümmert sich um Protokolldetails.
{
"tool": "markInvoicePaid",
"arguments": {
"invoiceId": "inv_9f2",
"paidAt": "2026-08-20T09:00:00Z"
}
}
MCP macht aus „Tool-Name + Argumentobjekt“ JSON-RPC. Für Apple-Entwickler ist das nur ein dritter Adapter: dieselbe markInvoicePaid(invoiceId:paidAt:), App Intent über perform, Foundation Models über Tool.call, MCP über tools/call. Schreiben Sie keine separate Geschäftslogik für MCP. Externe Agents senden eher falsche Typen (Zahlen als Strings), also muss der Server weiter validieren — „es ist schon JSON“ ist kein Vertrauen.
Schreiben Sie Datenschutzgrenzen in Tool-Beschreibungen. Ein On-Device-Modell, das den Kalender lesen kann, ist keine Lizenz, Ereignisse an Ihren Server zu POSTen. Tool-Ausgabe für das Modell kann eine lokale Zusammenfassung sein; Upload-JSON nur bauen, wenn der Nutzer klar synchronisieren will. Datenabfluss-Richtlinien für System-Agent und In-App-Agent getrennt prüfen und die Quelle in Logs sichtbar machen.
JSON in der Produktion prüfen
Beim Agent-Integrations-Debugging ist ein weiterer Prompt weniger nützlich als drei Snapshots nebeneinander: vom Modell erzeugtes Argument-JSON, gesendetes HTTP-JSON und vom Server zurückgegebenes JSON. Weichen die Formen ab, liegt der Fehler fast immer in der Mapping-Schicht, nicht „das Modell ist nicht schlau genug“. Lokal formatieren, validieren und diffen — schneller als Optionals in der Xcode-Konsole anzustarren.
Gehen Sie zuerst ein Parameterbeispiel im Browser durch: JSON-Formatierung um parse zu bestätigen; JSON validieren um nachgestellte Kommas und falsche Typen zu fangen; fixieren Sie gemeinsame Intent / Tool / API-Felder mit JSON Schema; anschließend JSON Diff um „Modellausgabe“ und „tatsächlichen Request-Body“ zu vergleichen. Cloud Structured Output unterscheidet sich in der API, aber „Vertrag zuerst, dann parsen“ gilt gleich — siehe Wie die Gemini API JSON ausgibt.
Behalten Sie drei Fixture-Dateien: tool-args.valid.json, http-body.valid.json, http-error.json. In CI die ersten beiden mit demselben Schema validieren. Mit dem Fehler-Fixture prüfen, ob der Agent dem Nutzer einen handlungsfähigen Fehlergrund nennt, statt retryable: true.
Häufige Fragen FAQ
Können App Intents und Foundation Models Tool dieselben Parameter teilen?
Teilen Sie das Domänenmodell, aber nehmen Sie nicht an, das System kann Ihr Tool-Protokoll direkt ausführen. Intents dienen System-Discovery und Berechtigungen; Tools dem prompt der aktuellen Sitzung. Legen Sie ein Mapping dazwischen. JSON-Fixtures testen das Domänenmodell, nicht einen Framework-Typ.
Warum soll das Modell keine vollständige HTTP-Anfrage ausgeben?
URL, Header und Signaturen dürfen nicht vom Modell erfunden werden. Es füllt Geschäftsfelder; der Client sendet eine feste Vorlage. Sonst trifft eine Halluzination die falsche Umgebung oder falsche Credentials.
Stehen JSON und @Generable im Konflikt?
Nein. @Generable ist Swift-seitige Generierung und Dekodierung; JSON ist die sprach- und netzwerkübergreifende Form. Zuerst eine stabile Feld-Tabelle, dann Swift-Makros und JSON Schema generieren.
Müssen Tool-Rückgabewerte JSON sein?
Nicht zwingend. Das Modell kann eine kurze Textzusammenfassung sehen; der Server muss JSON bekommen. Mischen Sie beides nicht in einem String zum harten Parsen.
Fazit und nächste Schritte
Agents auf dem Apple-Stack sind keine einzelne Steckdose. Es sind drei kombinierbare Leitungen: der System-Agent entdeckt und ruft die App über App Intents auf; das In-App-Modell ruft Ihren Code über Tool auf; ein externer Host ruft denselben Domänendienst mit JSON auf. JSON lässt Argumente, Schema und API-Nutzlast dieselbe Form sprechen. Typsicherheit deckt Compile-Time ab, Schema die Runtime, Geschäftsprüfungen die Wahrheit.
Als Nächstes: drei bis fünf Domänenaktionen auflisten. Für jede ein minimales JSON-Objekt und ein Schema schreiben, dann entscheiden, ob es auf Intent, Tool oder HTTP erscheint. Form stabilisieren, bevor Sie Prompts und Multi-Tool-Orchestrierung hinzufügen.