ブログ • Foundation Models

Apple Intelligence 2026:Foundation Models と App Intents の間で交換する JSON

2026 年、同じ App には入口が二つある。端末上の LanguageModelSession は型どおりに値をデコードし、システムは App Intent の perform() を呼ぶ。残すのはどちらの値でもそのままではなく、自分で定義した交換用の封筒だ。

製品の話は iPhone 18 がハードウェア以上である理由。Siri が Agent になるかは Siri AI は AI Agent になるか。ここでは封筒だけを書く。どのフィールドを残すか、いつ実行しないか。

先にこれだけ:フレームワークは Generable を schema にして値をデコードする。それはモデルセッションの中の話だ。保存し、突き合わせ、実行するかを決めるために残すのが封筒だ。以下は、二つの契約、フィールド、一つの JSON、止める四つの場合の順だ。

二つの契約は一回の呼び出しではない

端末上のモデルが型どおりに値を埋める仕組みは Generable に書いてある。型は schema になり、モデルが埋め、フレームワークがデコードする。静的な型は @Generable。静的な型がなければ、セッションは GenerationSchema から GeneratedContent を返せる。封筒に書くときはどちらも content だ。

App Intent は別の呼び出しだ。パラメータは @Parameter に書く。説明は App Intent にパラメータを追加する。システムが perform() を呼ぶとき、LanguageModelSession はなく、Generable の content もない。

  1. 1
    セッションが内容を出す

    respond(to:generating:) は Response を返す。生成が終わる前は PartiallyGenerated で、フィールドは空のままであり得る。まだ実行できるパラメータはない。

  2. 2
    パラメータを射影する

    Intent が受け取るフィールドだけを parameters に写す。モデルが足した rationale は content に残す。名前は同じでも、同じオブジェクトではない。

  3. 3
    実行の前に封筒を書く

    source、sessionId、schemaVersion、complete、content、intent、parameters を一つの JSON にする。complete が true でなければ perform() を呼ばない。

封筒のフィールド

次のキーは自分の封筒のもので、Apple のデコード結果のフィールドではない。

フィールド誰が書くか役割
sourceあなたの Appfoundation-models か app-intent。値がどちらの入口から来たかを示す。
sessionIdあなたの Appモデルセッションだけが持つ。例は lm_01。システム呼び出しでは null。
schemaVersionあなたの AppGenerable のフィールド表につける世代。この例は 3。フィールドが変わったら一つ増やし、古い封筒をそのまま再実行しない。
generableあなたの App型名。例は OrderDraft。システムが直接呼ぶときは null。
complete生成状態から写すfalse はまだ生成中で、フィールドはまだ変わり得る。true になってから射影し、実行を検討する。
contentモデルのデコード結果モデルがデコードしたオブジェクト。動作よりフィールドが多くてよい。例は rationale。システム呼び出しでは null。
intentあなたの Appこれから呼ぶ、またはシステムが呼んでいる App Intent の識別子。例は PlaceOrderIntent。
parametersあなたの射影、またはシステムの引数perform() に渡すオブジェクト。未完了のときは null。システム呼び出しでは、システムがすでに渡した引数。

content と parameters は同じフィールド名を持てるが、別のオブジェクトだ。content をそのまま perform() に渡すと、モデルが足した rationale が動作に入る。

残せる交換 JSON

次の封筒と Schema は自分の契約で、Apple の通信形式ではない。JSONNote の JSON Schema は型、列挙、必須を見る。complete が true のときだけ実行できる、という規則はこの Schema では表せない。判断は App 側で行う。

生成が終わったあとの封筒。rationale は content に残り、parameters にはない。
{
  "source": "foundation-models",
  "sessionId": "lm_01",
  "schemaVersion": 3,
  "generable": "OrderDraft",
  "complete": true,
  "content": {
    "itemId": "sku_42",
    "quantity": 1,
    "fulfillment": "pickup",
    "rationale": "User asked for pickup."
  },
  "intent": "PlaceOrderIntent",
  "parameters": {
    "itemId": "sku_42",
    "quantity": 1,
    "fulfillment": "pickup"
  }
}
1つ目の欄に封筒、2つ目の欄にこの Schema。操作する を Schemaで確認してください にする。
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["source", "sessionId", "schemaVersion", "generable", "complete", "content", "intent", "parameters"],
  "properties": {
    "source": { "enum": ["foundation-models", "app-intent"] },
    "sessionId": { "type": ["string", "null"] },
    "schemaVersion": { "type": "integer" },
    "generable": { "type": ["string", "null"] },
    "complete": { "type": "boolean" },
    "content": { "type": ["object", "null"] },
    "intent": { "type": "string" },
    "parameters": { "type": ["object", "null"] }
  }
}

rationale は content だけに残す。動作パラメータの型の対応は App の動作フィールドと JSON Schema。ここではその表を繰り返さない。

未完了なら perform しない

生成は未完了。quantity はまだなく、parameters は null のまま。
{
  "source": "foundation-models",
  "sessionId": "lm_01",
  "schemaVersion": 3,
  "generable": "OrderDraft",
  "complete": false,
  "content": {
    "itemId": "sku_42"
  },
  "intent": "PlaceOrderIntent",
  "parameters": null
}

この封筒は上の Schema を通る。parameters が null を許すからだ。形が通っても実行しない。PartiallyGenerated は、後続のトークンが既にあるフィールドをまだ変え得る、という意味だ。complete が true になってから、揃った content を parameters に射影する。未完了のまま parameters をオブジェクトにしても、Schema は止めない。

封筒なぜ止めるか
complete が false後続のトークンが既にあるフィールドをまだ変え得る。
schemaVersion が今のフィールド表ではない古い content は今の Intent に合わない。
foundation-models で、parameters に content にないキーがある射影は、モデルが書いていない値を作ってはいけない。
app-intent なのに content が null ではないシステムの引数はモデル出力ではない。content に書き戻して生成結果のふりをしない。

余分なキーは JSON の比較で見る。この確認は source が foundation-models の封筒だけに使う。システム呼び出しでは content が null なので、parameters の各キーが content に出ていた、とは要求できない。

Tool と App Intent の受け渡し

Foundation Models の Tool は自分のセッションが呼ぶ。説明は ツール呼び出しで生成を広げる。call(arguments:) が受け取る Arguments も Generable だ。まず content に書き、parameters に射影してから perform() を検討する。

システムが Intent を直接呼ぶときは、source を app-intent にし、sessionId、generable、content を null にする。parameters はシステムがすでに渡した値だ。sessionId を作って、モデル生成のふりをしない。

Foundation Models ToolApp Intent
誰が呼ぶかあなたの LanguageModelSessionSiri、ショートカット、Spotlight
入力Generable の Arguments@Parameter の値
実装するメソッドcall(arguments:)perform()
封筒の sourcefoundation-modelsapp-intent

ほかの記事との分担

製品と Siri の二本動作フィールドの記事本記事
答えることなぜハードウェア以上か。Siri は Agent になるかどのフィールドがこの動作に入れるかモデルの値と動作パラメータの間にどの JSON を残すか
ここで探さないもう一本の発表まとめAppEnum とエンティティ id の型対応content をそのまま perform() の引数にすること

JSONNote でこの封筒を合わせる

  1. 1
    操作を選ぶ

    JSON Schema を開く。操作する を Schemaで確認してください にする。1つ目の欄に封筒、2つ目の欄に上の Schema を貼る。source は foundation-models か app-intent。complete はブール。parameters はオブジェクトか null。

  2. 2
    壊れたデータを三つぶつける

    source を siri にする、complete を文字列 true にする、または parameters を消す。この三つは失敗する。未完了の封筒(complete が false、parameters が null)は通る。通っても perform() は呼ばない。

  3. 3
    二つのオブジェクトを比べる

    JSON 比較Diff を開く。1つ目の欄に content、2つ目の欄に parameters を貼る。rationale は1つ目の欄だけにあるべきだ。2つ目の欄だけにあるキーは射影が書いたもので、モデルが書いたものではない。この比較は source が foundation-models のときだけ使う。

よくある質問

Generable の出力をそのまま perform() に渡せるか?

渡せない。出力は content に書く。perform() が受け取るのは射影した parameters だけだ。封筒は両方を残し、突き合わせに使う。

Schema を通ったら実行してよいか?

まだだ。この Schema は型、列挙、必須だけを見る。complete が false で parameters が null でも形は合法だ。実行前に complete が true であること、そしてモデル入口では parameters に content にないキーがないことを確認する。

Tool と App Intent は同じ一回の呼び出しか?

同じ呼び出しではない。Tool は LanguageModelSession が呼ぶ。App Intent は Siri、ショートカット、Spotlight が呼ぶ。同じ仕事を両方に出せる。入力は先にこの封筒へ書く。

schemaVersion が変わったら、古いログを再実行できるか?

そのままは再実行できない。版は Generable のフィールド表の世代だ。フィールドが変わると、古い content は今の Intent に合わない。一度止め、明示的な対応を書いてから実行するかを決める。

動作フィールドと JSON Schema の記事と同じか?

同じ記事ではない。あちらはパラメータ型をフィールド表に揃える。こちらはモデルの値とその表の間に残す封筒だ。入口、完了状態、版、そして content と parameters を分ける。

まとめ

Foundation Models と App Intents は二つの入口だ。交換用の封筒は、入口、完了状態、schema の版、content、parameters を一つの JSON に置き、perform() の前に止まれるようにする。

結論:content は封筒に残す。perform() が受け取るのは parameters だけ。complete が false なら実行しない。schemaVersion が合わなければ再実行しない。parameters に、content にないキーを置かない。

次:この交換 JSON を Schema に通し、それから content と parameters を比べる。

ブログへ戻る