Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating an English conversation app using the ...

Creating an English conversation app using the Foundation Models framework

Avatar for Asakura Shinsuke

Asakura Shinsuke

June 19, 2026

More Decks by Asakura Shinsuke

Other Decks in Technology

Transcript

  1. 自己紹介 あさしん @asashin227 株式会社スタメン エンジニアリングマネージャ iOS開発 / Claude Code・AIエージェント /

    自作キーボード 最近はオンデバイスAIで英会話アプリを試作中 今日は Apple の Foundation Models で英会話アプリを作った話を LT で mobile.stmn #18 / 2026-06-19 2
  2. 作ったもの:オンデバイス英会話アプリ 端末内のLLMと英語で会話して練習 会話 / ロールプレイ / ディベート の複数モード 会話を自動で添削:文法フィードバック・CEFRレベル推定 発音評価・ヒント・学習統計・カリキュラム

    … 学習を一通り サーバーに会話を送らない(オンデバイス完結) SwiftUI製。AIは Foundation Models(オンデバイス)で動かしている mobile.stmn #18 / 2026-06-19 3
  3. Foundation Models framework とは Apple が提供する オンデバイスLLM(iOS 26+ / Apple

    Intelligence) LanguageModelSession で respond / ストリーミング / 構造化出力 / ツール 前提:iPhone 15 Pro 以降+Apple Intelligence 有効・実機必須 メリット 内容 無料 API課金なし(端末内で推論) オフライン 通信不要で動く プライバシー 会話が端末から出ない 英会話はターン数が膨大 → クラウドAPIだと課金がきつい。オンデバイスが効く mobile.stmn #18 / 2026-06-19 4
  4. availability でデバイスを出し分け(実コード) SystemLanguageModel の可用性を判定して、AI機能の出し方を分岐。 switch SystemLanguageModel.default.availability { case .available: return

    .foundationModels // オンデバイスAI が使える case .unavailable(let reason): switch reason { case .modelNotReady: // モデルDL 中 return .downloading case .appleIntelligenceNotEnabled, // AI 無効 .deviceNotEligible: // 非対応端末 return .cloudAPIOnly // → クラウドAPI へ退避 @unknown default: return .cloudAPIOnly } } 「実機必須/未対応端末」をここで吸収して画面・プロバイダを出し分け mobile.stmn #18 / 2026-06-19 5
  5. 最小コード:セッション生成 → 応答取得 import FoundationModels // ① セッション生成:system 指示は instructions

    に(履歴とは分離) let session = LanguageModelSession( instructions: "You are a friendly English tutor. Reply in simple English." ) // ② ユーザー発話を渡し、モデルに考えさせて応答を受け取る let response = try await session.respond(to: userText) let reply = response.content // モデルの返答テキスト 逐次表示は session.streamResponse(to:) (累積スナップショットが返る) mobile.stmn #18 / 2026-06-19 7
  6. @Generable とは?(guided generation) 「自由テキスト」ではなく “この型で答えて” とモデルに制約をかける仕組み。 構造体に @Generable → その型に沿った出力をモデルが生成

    @Guide で各フィールドに説明・制約(値域・列挙など)を与える 受け取りは respond(to:, generating: 型.self).content → 型そのもので返る 利点 JSONパース不要(壊れたJSON・try? の失敗が原理的に起きない) 文字列プロンプトに「JSONで返して」と書かなくてよい 非対応モデルは LanguageModelError.unsupportedGenerationGuide を投げる(黙って劣化し ない) 出力の“形”をコードで保証=AI機能をただのSwiftの型として扱える mobile.stmn #18 / 2026-06-19 8
  7. 設計②:@Generable で型安全な構造化出力 構造体に @Generable を付けるだけで、型安全に直接受け取れる(JSONパース不要) @Generable struct GrammarFeedback { @Guide(description:

    " 誤りがあれば true") var hasError: Bool var correction: String var explanation: String } // 呼び出し側:型を渡すと、その型で返ってくる let fb = try await session.respond( to: text, generating: GrammarFeedback.self ).content // → GrammarFeedback (誤り箇所・訂正・説明) 数秒かかるので 会話終了後に非同期実行 すればUX影響なし mobile.stmn #18 / 2026-06-19 9
  8. 対策の実コード:GenerationOptions 出力を短く・安定にして“非力”をカバー(アプリの実コード) 。 guard SystemLanguageModel.default.isAvailable else { throw … }

    let options = GenerationOptions( temperature: 0.7, // 既定1.0 は高め → 会話は0.7 が落ち着く maximumResponseTokens: 200 // 長すぎる応答を抑える ) let response = try await session.respond(to: prompt, options: options) temperature / maximumResponseTokens で短く・安定に トークン計測 response.usage ・ model.contextSize も用意あり(本アプリは未使用・シン プル運用) 軽く絞るほどオンデバイスは安定する mobile.stmn #18 / 2026-06-19 11
  9. その他のハマりどころ try? のサイレント失敗:AIが ```json 付きで返すと黙ってデフォルト値に落ちる → @Generable を使えばそもそもJSONパース自体が不要 temperature は既定1.0が高め

    → 会話は 0.7 が落ち着く テストでシミュレータが実モデルを実走し1呼び出し19秒 → Mockをクロージャ注入で0.1秒 に mobile.stmn #18 / 2026-06-19 12
  10. 拡張:同じAPIのまま Claude へ(ハイブリッド) Claude for Foundation Models で、同じ LanguageModelSession のままクラウドのClaude

    に切替可能 使い分け:軽い会話=オンデバイス/重い処理・Web検索・大コンテキスト=Claude 429(レート制限)時はオンデバイスに退避、という分岐をアプリ側で自動化 ※ Claude for Foundation Models は iOS 27+(ベータ)が前提(要確認) プロバイダ切替UIは隠しつつインターフェースは温存 → 後から足せる設計に mobile.stmn #18 / 2026-06-19 13
  11. コード:429 ならオンデバイスに退避 同じ LanguageModelSession API なので、モデルを差し替えるだけ。 // クラウド(Claude) 用セッション(本番は .proxied

    で鍵を埋めない) let claude = LanguageModelSession( model: ClaudeLanguageModel(name: .sonnet4_6, auth: .proxied(headers: headers)) ) do { let reply = try await claude.respond(to: userText).content } catch LanguageModelError.rateLimited { // 429 → オンデバイスに退避(同じAPI ) let reply = try await onDevice.respond(to: userText).content } 重い処理はClaude/レート制限時はオンデバイス、を同じコードで mobile.stmn #18 / 2026-06-19 14
  12. 今後の展望:iOS 27 で広がる(WWDC 2026) オンデバイスAIの選択肢が純正で増える。今日の構成の“本命”が来る。 LanguageModel プロトコルが外部モデルに正式対応 → Claude/Gemini 等を同じAPIで(今

    日のハイブリッドが本格化) PrivateCloudComputeLanguageModel (Apple純正サーバーモデル) APIキー不要・プロンプト非保存・32Kコンテキスト=オンデバイスで足りない時の純正 エスカレーション先 DynamicProfile :1セッションを状態で切替 → 会話/ロールプレイ/ディベートのモード切替 をきれいに システムツール(OCR / Spotlight=ローカルRAG)→ 教材・履歴を絡めた英会話へ ※ いずれも iOS 27(ベータ・2026 Fall 正式予定) 。要キャッチアップ mobile.stmn #18 / 2026-06-19 15