🍎

Apple Foundation Models ハッカソンに参加してきました

に公開

はじめに

こんにちは、tattsun です 🙌

先日「Apple Foundation Models」をテーマとしたハッカソンに参加しました。今回は、参加レポートを記事にしました。

イベント概要

  • 日時: 2025-10-12(日)13:00 – 21:00
  • 会場/形式: Apple Japan(東京都港区六本木 6-10-1)/ オフライン限定
  • 主催: MeltingHack

https://melting-hack.connpass.com/event/368743/

参加した経緯

クラシルで例年、開催されているサマーインターンもハッカソン形式で、私はメンターとして参加しており、「ハッカソンって楽しそうだな」と感じていました。Apple Foundation Models は、私も気になっており、オンデバイスで LLM の利用が可能ということでプロダクトへの活用も可能なのではないかと考えていました。

そんな時にたまたま、X でハッカソンの募集を見かけて応募したという経緯です!

そのため、Apple Foundation Models に触れることとどんなことが出来るのかを知ることを今回の目的としています!

https://www.apple.com/jp/newsroom/2025/09/apples-foundation-models-framework-unlocks-new-intelligent-app-experiences/

取り組んだテーマ

今回は、Apple Foundation Models を利用して自由に成果物を作ることが目標でした。3~4 人でチームを組み、各々がやりたいことをやるような自由なハッカソンでした。

私たちのチームは、せっかくなので楽しいアプリを作ろうということで Apple Foundation Models を利用し、Image Playground から画像を生成、画像を生成するためのプロンプトをベースにイラスト同士を対戦するというコンセプトで作ることに決めました。

今回は、ハッカソンの時間は 4 時間(実際は 3 時間半程度)だったため、かなり急いで実装をする必要がありました 🏃

Apple Foundation Models について

今回の目的のひとつとして、Apple Foundation Models について知るというのがあるので改めて学びをまとめておきます。

Guided Generation

これは、Apple Foundation Models からのレスポンスを指定した型で受け取ることが出来るというものです。LLM からのレスポンスは表現に揺らぎがあることが多いので、この機能は非常に便利だなと感じました!

この機能があることによって、正規表現で特定の情報を取得する必要もありませんし、データのハンドリングがとてもしやすくなるのが良いですね!

@Generable
struct User {
    let name: String
    let age: Int
    let personality: String
}

let session = LanguageModelSession()
let prompt = "架空の人物を作成してください"

// User 構造体として直接受け取り
let response = try await session.respond(
    to: prompt,
    generating: User.self
)

print("名前: \(response.content.name)")
print("年齢: \(response.content.age)")
print("性格: \(response.content.personality)")

// MARK: - Output

名前: 田中 翔太
年齢: 29
性格: 翔太は非常に真面目な性格で、仕事や勉強に非常に熱心です。彼は周りの人の意見を尊重し、チームワークを大切にするタイプです。

Tool Calling

Apple Foundation Models には Tool Calling という機能が搭載されています。生成 AI を普段から利用している方なら MCP と呼ぶ方がわかりやすいかもしれません。つまり、これは Apple のエコシステムを Apple Foundation Models から呼び出すための機能ということです。

実際に今回のハッカソンでもこの機能を利用して、カレンダーやアラームなど Apple に搭載されたあらゆる機能を利用して、アプリを実装しているチームが数多くありました。

https://developer.apple.com/documentation/foundationmodels/tool

オンデバイスで動作する

Apple Foundation Models は、オンデバイスで動作するためインターネットを必要としません。機内モードやインターネットがない環境でも動作するのは他の LLM に比べて強みとしてあると思います。Apple のエコシステムでもインターネットがない環境下でも利用できるものも多いため、それらと組み合わせることでアプリの幅も広がりそうです!

チームのコンセプト

  1. Image Playground にプロンプトを渡して、イラストを生成する
  2. プロンプトをベースにイラスト同士を対戦させる
  3. 対戦の結果は Apple Foundation Models を利用して判定する
  4. 対戦に勝利したイラスト・プロンプトを次の対戦に持ち越し、新たに対戦させるイラストを生成する

成果とデモ

前述したコンセプト通り、取り組みましたが時間が間に合わず、1~3 の部分までしか実装することが出来ませんでした 😭

成果物のデモ

実装について

Guided GenerationImage Playground を利用して、実装しました。

Image Playground を利用して、画像を生成する

実装しながら後で気付かされいたのですが、Image Playground は iOS のシミュレータでは利用出来ないそうです 😭 Mac のアプリでは利用可能なようですが、実機だと iPhone 15 以上が必要なようです。

今回のコンセプトには必要な実装であり、チームで iPhone 15 以上の端末を持っている人もいなかったため、別の手段を考えるしかありませんでした。

とりあえず、Mac に標準搭載されている Image Playground を利用して同じプロンプトを直接アプリに入力するという方針に切り替えました。そのため、画像はアルバムから選択する実装へと切り替えました。

イラスト・プロンプトを対戦させる

Apple Foundation ModelsGuided Generation を利用して、対戦結果の判定を行います。

以下の構造体を @Generable マクロを利用して、実装しました。

import FoundationModels

@Generable
enum User: Equatable {
    case enemy
    case player

    var label: String {
        switch self {
        case .enemy:
            return "対戦相手"
        case .player:
            return "自分"
        }
    }
}

@Generable
struct BattleResult: Sendable {
    @Guide(description: "対戦の勝者")
    let winner: User

    @Guide(description: "具体的な勝利理由")
    let description: String

    @Guide(description: "臨場感のある戦闘シーン")
    let battleScene: String

    @Guide(description: "戦闘全体の評価とコメント")
    let overallReview: String
}

そして、この構造体を利用して、対戦結果を Apple Foundation Models に判定してもらいます。

private func createBattlePrompt(
    playerCharacter: String,
    enemyCharacter: String
) -> String {
    return """
    【戦闘判定要請】

    プレイヤーキャラクター: \(playerCharacter)
    VS
    敵キャラクター: \(enemyCharacter)

    【判定項目】
    1. キャラクターの特性と能力比較
    2. 属性の相性と戦略的優位性
    3. 運命と偶然の要素
    4. 創造性と意外性

    【出力形式】
    【勝者】: (勝利者名)
    【勝因】: (具体的な勝利理由)
    【戦闘描写】: (臨場感のある戦闘シーン)
    【総評】: (戦闘全体の評価とコメント)
    """
}

let battlePrompt = createBattlePrompt(
    playerCharacter: playerImagePrompt,
    enemyCharacter: enemyCharacter
)

// Foundation Modelに戦闘判定を送信
let response = try await session.respond(
    to: battlePrompt,
    generating: BattleResult.self
)

// 対戦結果
print(response.content.winner)

今回のハッカソンで学んだこと

今回のハッカソンの参加者の約半数は、iOS エンジニアではない方でした。業務として、iOS をやっていなかったり、個人開発だけで触っているという方が多く参加しており、新しい刺激を貰えた気がします。

普段、がっつりコーディングしていないが故に生成 AI を上手く使おうとする姿勢が見られ、今回のハッカソンではあまり生成 AI を利用しませんでしたが、やはり 0->1 は生成 AI の方が圧倒的に早いのでそういったところは見習っていくべきだなと強く痛感しました。

また、技術的な面での足りない部分も見つかり、普段の業務だと 1->10 が多いため、0->1 視点で足りない知識が少し分かった気がしました。また、Guided Generation の実装したことが個人的に大きく、静的型付け言語を大きな恩恵を得られた実感があり、感動しました!

今後の展望

今回、実装した成果物はあまり時間をかけられなかったため、もう少しやりたかった実装を進めていきたいと思います!

セッションの制限などまだまだ改善の余地があると感じますが、同時に新しい可能性も感じる良い体験でした。今後は、クラシルのプロダクトにどのように転用できそうかをさらに具体的に考えていこうと思います!

インターネットも不要なので、そういう観点でも個人で Apple Foundation Models を利用した新しいアプリを作ってみたいです!

最後に

一緒にチームを組んでくださった皆さん、本当にありがとうございました。なんとか形にできたのは、みんなのおかげです。

そして、運営の MeltingHack の皆さま、会場や食事・飲み物をご提供くださった Apple Japan の皆さま、素晴らしい成果物を発表してくださった参加者の皆さまにも心から感謝します。最高の一日でした!🙇

Kurashiru Tech Blog

Discussion