Foundation Models:Tool calling の複数同時呼び出しができればいいのに

<追記:2025/8/26>
「できればいいのに」というタイトルだが、できることが分かったので、記事後半の参考記事や、記事下にあるピンバックを参照。


大規模なテキストベースである日記を Spotlight にインデクシングさせ、Foundation Models と組み合わせて何かできないか実験中。

前回で、ツール呼び出しで日記のテキスト(ダミー)を取得して、その内容をもとに回答できることは分かった。が、コンテクストウィンドウサイズの都合上、以下を考慮する必要があることも分かった。

  • 日記は全文でなく細分化してツールに渡すべき
  • 細分化したうえでも、ヒットした全件をツールに返すわけにはいかない

となると、1度の検索で回答に足る情報が得られるかは怪しい。自律的にキーワードを変えながら、少なくとも2、3度はモデルに検索してもらいたい。

そこで、インストラクションを以下のようにして、前回作成したダミーデータには存在しないエピソードについて尋ねることで、1どのやりとりで複数回同じツール呼び出しをするか実験してみた。

ユーザーは自分の日記について質問を投げかけます。あなたはその質問に答えるために、必ず以下のStepをすべて実行した上で答えてください。
Step1. 検索キーワードを考えます
Step2. Step1で考えたキーワードをもとに日記を検索します
Step3. Step2で得られた結果を確認し、質問に回答できる内容があればそれをもとに回答します。なければStep4に進みます
Step4. Step1とは別の検索キーワードを考えます
Step5. Step4で考えたキーワードをもとに日記を検索します
Step6. Step5で得られた結果を確認し、質問に回答できる内容があれば、それをもとに回答します。なければStep7に進みます
Step7. 該当する記録がないことをユーザーに答えて、終了です。

が、2度呼び出されることはなかった。

po session.transcript

Transcript(entries: [
(Instructions) ユーザーは自分の日記について質問を投げかけます。あなたはその質問に答えるために、必ず以下のStepをすべて実行した上で答えてください。
...省略, 
(Prompt) 壺を買ったのはいつ?
Response Format: Message, 
(ToolCalls) searchDiaryDatabase: {"queries": ["壺"]}, 
(ToolOutput searchDiaryDatabase) ["日付2025-04-08 21:54:00 +0000 本文: 鏡の前で前髪とにらめっこ。..省略.. 他愛ない近況を話しながら、帰り道の影まで軽くなった気分。"], 
(Response) {"text": "壺を買ったことは2025年04月08日の日記には記録されていません。"}
]

プロンプト上、強制的に2度検索するよう指示してもダメ。ちなみに、おなじ日記検索ツールを名前(searchDiaryDatabase/searchDiaryDatabase2/searchDiaryDatabase3)と説明文を変えた異なる定義を増やしたところ、それらを同時並行で呼び出すことは稀にあった。

つまり、ToolCalls→ToolOutput→ToolCalls→… という自律的な再呼び出しは、今のところできなさそう?


ChatGPT に聞いた。

iOS の Foundation Models で tool calling という機能がありますが、1回のレスポンスに対して同じツールを複数回呼び出すことはできるのでしょうか。たとえば、データベースを検索するtoolがあったとして、1度の検索で回答に必要な情報が揃わなかった場合、2度、3度とキーワードを変えながら検索し直す、など。

iOS の Foundation Models フレームワークにおける Tool Calling(ツール呼び出し)では、1 回のレスポンス(session.respond(…) の呼び出し)に対して、モデルが“同じツールを複数回呼び出す”ことが可能です。

実際の動作例として:

  • Medium によるデモでは、「Pikachu と Bulbasaur に“love”を送って」というプロンプトに対し、モデルが同じツールを 2回呼び出し、それぞれのキャラクターに処理を行っている様子が確認できます  。
  • また、「モデルは複数のツールを並行して呼び出すこともあり、特定の都市ごとに天気情報を取得するような場合には、同じツールを複数回呼ぶ可能性がある」と明記されています  。

このように、同一のツールでも、モデルの判断によって必要に応じて複数回呼び出され、各呼び出しの結果がセッション内のトランスクリプトに含まれて、最終レスポンスに組み込まれます。

動作例で参照しているふたつの事例は、同じ Medium 記事だった。

SwiftUI: Demystify Foundation Model in SUPER Detail! With a Chat App! | by Itsuki | Jun, 2025 | Level Up Coding

The model decides to whether to use a tool (or multiple tools) or not, which tool to use, how many times it should use it. (That is the model can call a tool multiple times in parallel to satisfy the request, like when retrieving weather details for several cities.)

As we can see here, the model decided that it needed to call my tool twice, first time with the name Pikachu, and second time with Bulbasaur.

まさにこういうことをしたいのだけど。つまり、できるっちゃできるのか?


ちなみに、この記事にある PromptBuilder というのは知らなかった。条件付きなど動的なプロンプトを生成できるらしい?

Foundation Models の RAG に Core Spotlight を活用できそうか超簡単な実験:その2

大規模なテキストベースである日記と、ローカルLLMとを組み合わせて何かできないか、Foundation Models で実験する試みの、前回の続き。

Spotlight に日記の文章をインデクシングできたとして、その情報をうまいこと Foundation Models の tool calling で引き出すことができるのか。仮に「散髪を最後にしたのはいつ?」という質問を想定して、モックデータをもとに検証してみた。

  1. Foundation Models の tool calling の挙動を確認
    • タイミング、回数、使うキーワード、日本語でも可能か など)
  2. ツールから得た日記本文を回答に活用できるか
    • 本文のように長い文章を読んで解釈してくれるか/一問一答でピンポイントな情報がツールから得られる必要があるか
    • 複数日分の本文が返っても、区別して情報処理できるか

ツールから得られる情報の処理の仕方が知りたいので、今回は一旦常に同じデータを返すようにする。

import FoundationModels
import Foundation

struct DiarySearchTool: Tool {
    let name = "searchDiaryDatabase"
    let description = "検索キーワードで日記のエントリーを検索する"
    
    @Generable
    struct Arguments {
        @Guide(description: "検索キーワード")
        var queries: [String]
    }
    
    
    struct Entry {
        var date: Date
        var content: String
    }
    
    func call(arguments: Arguments) async throws -> [String] {
        // Foundation Modelsがtool callingしたか/どんなクエリで検索しようとしたか出力
        print("### augumantes: \(arguments)") 
        
        let entries = dummyEntries // 常に同じモックデータを返す
        let formattedEntries = entries.map {
            "日付\($0.date) 本文: \($0.content)"
        }
        return formattedEntries
    }
}

モックデータとして3日分、それぞれ以下を取り入れるよう ChatGPT に考えさせた。これは、単純に「散髪」というキーワードに反応するだけでなく、日記の中身をモデルが理解した上でレスポンスするかを確かめるため。

1. 散髪に行こうか迷っている
2. 散髪に行った
3. 散髪に行ったことを友達に気がついてもらえた

let dummyEntries: [Entry] = [
    .init(date: "2025-07-18 20:13:00".toDate()!,
          content:
              """
              鏡の前で前髪とにらめっこ。伸ばすか切るか、天秤は揺れっぱなし。
              散髪に行こうか迷っているうちにコーヒーは冷め、予定は延び、前髪だけが視界を奪う。
              雨予報も背中を押さず、今日は見送るか、どうするか。
              """),
    .init(date: "2025-06-09 17:02:00".toDate()!,
          content:
              """
              雲の切れ間みたいに決心が差した午後、散髪に行った。
              軽くなった頭皮に風が通る。落ちた髪の山を見下ろし、スマホの自撮りで角度を研究。
              鏡越しの自分と握手。担当さんのハサミとシャンプーの柑橘の香り。肩の荷まで落ちた気がする。
              """),
    .init(date: "2025-04-08 21:54:00".toDate()!,
          content:
              """
              駅前で友達と合流。開口一番「なんか爽やか!」と笑われ、
              散髪に行ったことを友達に気がついてもらえた。前髪の軽さだけでなく、
              歩幅まで半歩分広がった気がする。他愛ない近況を話しながら、帰り道の影まで軽くなった気分。
              """),
]

なんかムズムズする日記、、笑
プロンプトを与えて、いよいよ Foundation Models に質問してみる。

let session = LanguageModelSession(
    tools: [DiarySearchTool()],
    instructions:
        "ユーザーは自分の日記について質問を投げかけます。あなたは関連するキーワードを使用して日記のデータを検索し、その質問に回答します。"
)

予想以上にうまく答えられている。内容を理解した上で答えていそうなことはわかった。

以下ログを見ると、モデルがツールに渡している検索キーワードが、質問文そのままだったりしてイマイチなので、ここはプロンプトなどで調整の余地がありそう。(あるいは Core Spotlight のセマンティックサーチが吸収してくれるかも?)

Send message: 最後に髪を切ったのはいつですか?
### augumantes: Arguments(queries: ["髪を切ったのはいつですか?"])
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("最後に髪を切ったのは2025年6月9日の午後です。"))

Send message: 散髪を友達に気づいてもらえたのはいつですか?
### augumantes: Arguments(queries: ["散髪", "友達に気づいてもらえた"])
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("散髪を友達に気づいてもらったのは日付2025-07-18です。"))

Send message: 散髪を迷っていたのはいつですか?
### augumantes: Arguments(queries: ["散髪を迷っていたのはいつですか?"])
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("散髪を迷っていたのは2025年4月8日のことです。"))

最後に、ここまででいくつか失敗があったのでまとめておく。

Tool calling 経由で大規模な文章が渡るとコンテクストウィンドウ超過になる

予想はしていたがやはりそうだった。初めは、筆者の日記の実データを用いて検証したのだが、1日分だけで2千〜5千文字近くあり、余裕で “Exeeded models context window size” エラーとなった。

これは、たとえば長文の日記本文を小分けにして Spotlight にインデクシングさせることで解決するかもしれない。

指示文が不十分だとうまくtool calling してくれない

当初、インストラクション、ツール説明、プロンプトは以下のように記述していた。

struct DiarySearchTool: Tool {
    let name = "searchDiaryDatabase"
    let description = "日記のエントリを条件に従って検索します"


    @Generable
    struct Arguments {
        @Guide(description: "検索キーワード")
        var queries: [String]
    }
...

let session = LanguageModelSession(
    tools: [DiarySearchTool()],
    instructions: "あなたは日記データをもとにユーザーからの質問に答える役をします。"
)

しかし以下の通り、珍紛漢紛な返答ばかりで、そもそもツールを呼び出していないことが判明。最終的に、`searchDiaryDatabase` というツールを認識しているか、という直接的な質問をして、はじめて「AI」という謎キーワードでツールを呼び出すようになった。

Send message: 最後に散髪に行ったのはいつ?
... // ←ツールを呼び出していない
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("最後に散髪に行ったのは2024年7月15日のことです。"))

Send message: 日記から最後に散髪に行った日のエントリーを検索して、その日付を教えてください。
... // ←ツールを呼び出していない
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("検索結果は以下の通りです。最後に散髪に行った日に関するエントリーは存在しません。"))

Send message: searchDiaryDatabase というツールを使って、最後に散髪へ行った日を検索して、その日付を教えてください。
... // ←ツールを呼び出していない
PartiallyGenerated(id: FoundationModels.GenerationID(value: "E042ADEE-3C46-424C-9B2F-DD572136FC2B"), text: Optional("散髪に行く日についての情報は取得できませんでした。"))

Send message: searchDiaryDatabase というツールを認識していますか?
### augumantes: Arguments(queries: ["AI"]) // ←ツールを呼び出した
...
PartiallyGenerated(id: FoundationModels.GenerationID(value: ..., text: Optional("以下に日記のエントリを3つ返します。\n1. 日付2025-07-18 20:13:00 +0000 本文: 鏡の前で前髪とにらめっこ。伸ばすか切るか、天秤は揺れっぱなし。散髪に行こうか迷っているうちにコーヒーは冷め、予定は延び、前髪だけが視界を奪う。雨予報も背中を押さず、今日は見送るか、どうするか。\n2. 日付2025-06-09 17:02:00 +0000 本文: 雲の切れ間みたいに決心が差した午後、散髪に行った。軽くなった頭皮に風が通る。落ちた髪の山を見下ろし、スマホの自撮りで角度を研究。鏡越しの自分と握手。担当さんのハサミとシャンプーの柑橘の香り。肩の荷まで落ちた気がする。\n3. 日付2025-06-08 21:54:00 +0000 本文: 駅前で友達と合流。開口一番「なんか爽やか!」と笑われ、散髪に行ったことを友達に気がついてもらえた。前髪の軽さだけでなく、歩幅まで半歩分広がった気がする。他愛ない近況を話しながら、帰り道の影まで軽くなった気分。"))

インストラクション、プロンプトを英語に直したことで期待通りにツールを呼び出すようになったので、日本語と英語の違いか、と思ったがその後この英語をそのまま日本語に訳して適用したところ、問題なくレスポンスしてくれるようになった。やはりプロンプトの設計が重要。

WWDC25:Integrate privacy into your development process

プライバシーをプロダクトに組み込むための観点、手法を開発ステップごとに解説。


0:00 – Intro

  • プライバシーは単なるバズワードではなく、誰もがデータを注意深く尊重して扱われるべき
  • Steve Jobs の定義:人々が何にサインアップしているかを平易な言葉で繰り返し理解できること → 人々がデータに対して正しい選択ができるようになる
    • 人々の意図に対する一貫性をためつためにできること:尋ねること
  • プライバシーの 3 つの重要な概念:人々(People)、データ処理の影響(Data)、情報の文脈(Context)
  • Apple のプライバシー原則:data minimization, on-device processing, transparency and control, security protections

0:38 – How does Apple think of privacy?

  • People:プライバシーとは人々がテクノロジーとどのように相互作用し、それがどのように影響するか
  • Data:データ処理の影響:アプリを使用する人々について知っていることを何に使用するか
  • Context:情報の文脈、特に期待と好みを考慮する必要がある
  • 人々のデータを委託された際に、その文脈を尊重すること
  • データを使って「何ができるか」ではなく、ユーザー利益のために「何をすべきか」を問うこと
  • データ最小化、オンデバイス処理、透明性と制御、セキュリティ保護の 4 つの柱
  • ソフトウェア開発のライフサイクル:計画→設計→開発→テスト→展開

3:47 – Planning (計画)

  • プライバシー保証(privacy assurances)を定義して、アプリのプライバシーストーリーを書き始める
  • プライバシーは開発の最初から組み込む必要があり、後から追加するのは困難
  • Data minimization: 人々の期待に合わせるために必要最低限のデータのみを使用
  • Strong defaults: 人々のプライバシー選択について最小限の仮定から始める
    • e.g. 近くの場所を検索するときのデフォルト→現在地は保存されない
  • On-device processing: データが文脈を越えてデバイス→サーバー、アプリ間などの境界を越える際の必要性を慎重に検討
  • Transparency and control: データの使用方法について期待を設定し、カスタマイズオプションを提供
    • e.g. 「アップロードした写真はAI機能改善目的にopt-inした場合のみ利用される」
  • Security protections: 技術的制御でプライバシーをサポート
    • e.g. end-to-end encryption

7:13 – Design (設計)

  • 優れたデザインにより、人々とコミュニケーションし、教育することができる
  • Proactive expectation setting (積極的に期待を設定): 起動時に提示し、アプリが収集するデータや使用方法について、人々が不意を突かれることがないようにする
  • Clear state changes: プライバシーに影響するデータフローの変更を理解できるようにする
  • Meaningful and contextual choices: データに関する選択は意味があり、文脈に適したものであるべき
    • アクセスが必要になった際に初めて有効オプションを提示する
  • 選択が最も関連性が高いときに表示し、適切なバランスの粒度を研究する

9:27 – Development : User interface

  • デバイスリソースへのアクセスは、異なる文脈間で機密データを共有することを意味
  • PhotosPicker: 写真ライブラリのプロンプトを完全に回避し、選択された写真のみを受け取る
  • Location Button: ワンタップで現在位置を共有でき、ユーザーインタラクションでトリガーされることを検証
  • Secure UI elements: 連絡先の out-of-process picker, UIPasteControl button, ハードウェアアクセサリの設定フロー
  • 必要最小限のデータにアクセスするオプションを確認してから、より広範な API を使用

12:48 – Development : Client-server

  • Advanced Data Protection: iCloud に保存されたデータの end-to-end 暗号化を有効化
  • CloudKit: 暗号化されたデータ型を使用し、encryptedValues API でデータを取得・保存
  • Homomorphic encryption: 暗号化されたペイロード上で計算を実行
  • Private Information Retrieval (PIR): サーバーがクエリや結果を復号化された形式で利用できないようにする
  • Private Access Tokens: 正当なデバイスからのリクエストを保証し、使用する人々を特定しない
  • DeviceCheck: デバイス識別子を追跡せずに、特定のデバイスに最大 2 ビットの情報を関連付け
  • AdAttributionKit: プライバシーを維持しながら広告キャンペーンの成功を測定

18:20 – Development : local resources

  • Core ML: 機械学習モデルを完全にオンデバイスで実行、トレーニング、ファインチューニング
  • App group containers: 異なるアプリ間でデータを共有し、そのデータを保護
  • Process cleanup: macOS でアプリを終了する際にすべてのプロセスを終了
  • Third-party SDKs: プライバシーマニフェストファイルで収集するデータと使用する API を記述

20:46 – Testing (テスト)

  • プライバシー保証を提供することを確認するテストを構築することは重要なベストプラクティス
  • Testing Pyramid
    • Unit tests: 個々の関数を検証し、プライバシー制御をサポートするアプリロジックを検証
    • Integration tests: 異なるコンポーネントが正しく連携することを確認し、システム間のデータフローを検証
    • UI tests: ユーザー向けの動作を観察し、オンボーディングやプライバシー設定の変更などの一般的なシナリオを確認
  • App Privacy Report: iOS 15.2 以降で、データアクセス、センサーアクセス、ネットワークアクティビティを確認

22:28 – Deployment (展開)

  • Privacy nutrition labels: App Store がアプリのプライバシー慣行を理解するのに役立つ重要な方法
    • アプリアップデートなしに更新が可能
  • Privacy policy: 明確なプライバシーポリシーが必要
  • Privacy manifests: アプリとすべてのサードパーティ SDK のプライバシーマニフェストを Xcode に含める
  • Purpose strings: デバイスリソースにアクセスする権限プロンプトに必要 (Info.plist)
  • Privacy Choices link: App Store のリストに含めて、データの管理について詳しく学べるようにする (Optional)

WWDC25:Evaluate your app for Accessibility Nutrition Labels

Accessibility Nutrition Labels の解説に加えて、アクセシビリティ機能のひとつひとつを説明。以前聴講したアクセシビリティLT会の内容を思い出した。

当事者でなければ障害により生じる困りごとや不便は想像がつかないもの、、かくいう筆者も左耳難聴。某オーディオメーカー大手の某MP3プレイヤーにモノラル再生がなく驚いた経験があるが、多くの人にとってはなぜその機能が必要かは、すぐには理解できないとも思う。

かたや自らの携わるアプリが、Dynamic Type に対応できているか、Voice Over で不自由なく操作できるか、と問われると耳が痛い。このセッションビデオでは、4分以上にわたって Voice Over によるアプリ操作が実演されており、それを眺めるだけでも大きな示唆が得られた。標準的なデザインシステムに則ることが、単に視覚的一貫性をもたらしているだけではなく、その標準性を頼りにせざるを得ないユーザーがいることを、意識から欠いてはいけない。

あるアクセシビリティの専門家が、アクセシビリティ対応ができていないことは「バグ」であると声を大にして言い続けていた。しかし実情は残念ながら、多くの開発現場では「アクセシビリティ対応」に優先的に工数を割くことはない。ただ開発者が常日頃、アクセシビリティの担保を念頭に実装することはできる(レイアウトの組み方やアクセシビリティラベルの付与)。

またいきなり完璧を目指さずとも、Principles of inclusive app design のセッションでも語られていたように、できていない現状を分析し、計画立てて段階的に解消していきたい。そういう意味で、Accessiblity Nutrition Labels の存在は対応状況を可視化し、他アプリとの比較を容易とするので、対応の取り組みを後押ししてくれそうである。


0:00 – Welcome

  • Accessibility のソフトウェアエンジニアとデザイナーによる、Accessibility Nutrition Labels の評価方法について紹介
  • アプリのアクセシビリティを App Store の商品ページでハイライトする方法
  • コアとなるアプリアクセシビリティの原則と、サポートできる機能の説明
  • VoiceOver, Voice Control でのテスト方法、アクセシブルなメディアの提供方法をカバー

0:58 – Meet Accessibility Nutrition Labels

  • 最高のテクノロジーは誰もが使えるものであるという信念
  • Accessibility を考慮したアプリデザインにより、より多くの人々にアプリを提供
  • Accessibility Nutrition Labels は App Store でアプリがサポートする機能を紹介
  • ユーザーが依存する重要な機能をサポートしているかを知ることができる
  • アプリの common tasks(主要機能)すべてをユーザーが実行できなくてはならない
    • 主要機能を定義する
      • ダウンロードしたきっかけとなる機能
      • それ以前に不可欠な機能(e.g. 初回起動、ログイン、購入、設定)
    • 基本タスクに対し Accessibility Nutrition Labels の機能ごとにアプリを評価する
    • 対応できている機能/できていない機能を特定する
  • アプリがサポートするすべてのデバイスでテストする必要がある
  • 機能がアプリの機能に関連しない場合は、サポートを示さない
  • 正確性を確保するため、Accessibility Nutrition Labels のドキュメントを参照

3:06 – Evaluate your app

  • アクセシビリティはデザインから始まる(Design for everyone)
  • アクセシビリティ機能について理解する(Learn accessibility features)
  • 障害者コミュニティとつながる(Connect with community)
    • 障害当事者によるテストが、アプリのアクセシビリティを知る上で重要
    • “Nothing about us withou us”(私たちのことを私たち抜きに決めないで)
  • Sufficient Contrast: 前景色と背景色の間に十分なコントラストが必要、Increase Contrast 設定でも確認
    • Light/Dark mode 両方で対応が必要
  • Dark Interface: 光に敏感な人や暗い背景を好む人のため、dark mode 設定をサポート
    • Smart Invert の有効時に、どのメディアの色も反転しないように
  • Larger Text: テキストサイズを少なくとも 200% 大きくできるように設計、Dynamic Type の使用を推奨
  • Differentiate Without Color Alone: 色だけでなく、形状、アイコン、テキストも使用して情報を伝達
  • Reduced Motion: めまいや吐き気を引き起こす可能性のあるアニメーションを特定し、変更または削除
    • ズーム、スライドトランジション、フラッシュ、点滅、自動再生アニメーション、視差エフェクト
    • Reduced Motion 設定をオンにして、上記アニメーションがないか確認
  • Voice Control: 音声コマンドでアプリのすべての部分とインタラクションできるようにする
    • ボタンタップ、スワイプジェスチャー、文字入力、といった操作がもれなくできるか確認
    • accessiblityLabel に設定されたボタン名をシステムがオーバーレイ表示、その名前が読み上げられたら Voice Control が操作してくれる(e.g. ボタン名)
  • VoiceOver: 画面を見ずにインターフェースをナビゲートできるようにする
    • 使い方:VoiceOver を有効にし、右スワイプしてボタンをひとつずつフォーカスしてみる(名前と要素タイプが読み上げ)
    • 指をドラッグして VoiceOver に読み上げさせ、画面のレイアウトを把握する
    • (VoiceOvevr で特定タスクの完遂を実演)
  • Captions: 動画や音声コンテンツにキャプションを提供
  • Audio Descriptions: 視覚コンテンツの説明を音声で提供
    • ADアイコン

21:44 – Indicate feature support

  • App Store Connect で商品ページに Accessibility Nutrition Labels を追加
  • アプリのアクセシビリティに関する追加詳細を提供するウェブサイトへのリンクも追加可能
  • サポートする機能を選択し、準備ができたら公開
  • 障害を持つ人々とパートナーシップを組み、VoiceOver, Voice Control などの機能の使い方を学ぶ
  • デザイン段階からアクセシビリティを考慮し、common tasks を通じて各機能をテスト
  • アプリのアクセシビリティサポートを Accessibility Nutrition Labels で紹介

OS 26 beta 5 の Foundation Models framework アップデート内容

Foundation Models の開発者からこんな投稿があったのでチェック。


  • ガードレイルに permissiveContentTransformations オプションが追加
    • 要約やスタイル調整といったユースケースにおいて原文にセンシティブなトピックを含む可能性があるケースを想定(政治記事など)
    • 含んでいてもテキスト応答にへ関することを許容し、LanguageModelSession.GenerationError.guardrailViolation エラーを投げないガードレイル設定
    • permissiveContentTransformations | Apple Developer Documentation
  • 新しい「拒否」エラーの追加
  • #Praiground 使用時にフィードバックボタンを追加
    • Xcode 上で直接、モデル動作に関するフィードバックを送信可能に
  • GeneratedContent を透明化(“no longer opaque”
    • GeneratedContent.Kind が追加され、任意の生成コンテンツを表示するビューの構築が可能
    • プリミティブ型、配列、構造化オブジェクトを含む、JSON互換のデータ種類を表す
      • .array([GeneratedContent]), .bool(Bool), .number(Double), .string(String), .structure(properties: [String.: GeneratedContent], orderedKeys: [String]), .null
    • ユーザーが設定可能な生成スキーマの取り扱いに有用
  • 推論スタックの最適化が含まれており、トークンの処理速度が向上

聴講メモ:SPARKS #1 – AR/AI Glass Hands on!

MESONさん主催の新企画・XR/空間コンピューティング系ミートアップの第1弾が開催されたので参加してきた。

イベントページ:https://meson.connpass.com/event/362171/

今回特に期待していたのは、トークセッションやクリエイターLTも然ることながら、さまざまなARグラスが集結し、体験できるというハンズオンが設けられているということだった。特にここ最近はAR系の新製品が目まぐるしい勢いで登場し、それぞれが高額なのもあってまったくキャッチアップできていなかったので、大変ありがたかった。


共催4社の代表4名によるトークセッションは、AI時代におけるARデバイスのありかた、HMDとグラス型との対比に関するトピックが主軸。(以下、4名の登壇者の発言が混在しているので、どんなトピックが話されたかの参考程度)

最近注目しているグラスデバイス

  • Even G1
    • 1日中着用可能、Apple Watch をつけなくなった、食事中スマホ見なくなった
    • デフォの時計:商談中コミュニケーションが分断しない
    • 通知、時計機能メインで利用
      • マイク x AI の機能はあるが、使ってない
      • デフォルトは精度高くない、3rd Party がアプリ開発可能
    • Even G1 のような AR グラスは、カメラ相性が良さそう
      • 視界のコンテクストを共有できることが重要、言葉で説明せず指示語が使える
  • XREAL One Pro
    • ディスプレイ使用。視野角狭いことでかえって目の前の作業に集中できる
    • 映像で使うシーンがライフスタイルにない
      • これから出てきそう?
  • カメラの要不要はデバイス将来を決定づける分岐点
    • マイクスピーカーだけで良いか、映像含めたマルチモーダルか、まだ未知数
    • AIの精度を上げるためには、コンテクストとしての映像、カメラが必要
    • 気づかないものにAIが先に気づいてヒントを与えてくれる世界(ゼルダの妖精)
    • AIのパーソナル化、パーソナルアシスタントとしての機能性
      • データ量が重要、ユーザーどこでなにをしたか、AIグラス経由でスキャンできることで収集

HMD vs Glasses

  • HMD は「やるぞ」のモードが必要 → グラスは日常でカジュアルに利用可能
    • HMD:企業向け、家、仕事使い
    • グラス:日常使い
  • コンテンツの作りやすさでは HMD > グラス
  • 来年は AR グラスがますます浸透する
  • HMD とグラスとで、ユースケースが収斂し始めている
    • 技術登場当初から社会に受け入れられるまでに形態は変化する
    • 例)電話:ラジオ的な 1toN から、1to1 の受話器型へ
    • スクリーンレス、AIとの融合、へ収斂するのでは
  • 現状 AVP はディスプレイの代替になっていっている
    • 目や手の操作の快適性は企業に刺さってない
    • それよりもディスプレイの高精細さ

ビッグテックのグラス戦略

  • 「ディスプレイいらない」となりそう
  • リアルタイム性とファッション性、マルチモーダル(マイクスピーカーカメラ)の形態が普及しそう
    • その後、AR Glass「Pro」で、ディスプレイ付きが普及する?
  • 普及のしやすさで言えば、カメラなし、ディスプレイあり
  • ハードウェア側のエコシステムが整うことで、クリエイターが未来創造の速度が加速する
  • コンシューマー側は 3D を扱うための学びのハードルが高い
    • 普及するまでの時間は予想よりも長引く(グラス型の普及期が長く続く)かも
トークセッションの様子
“聴講メモ:SPARKS #1 – AR/AI Glass Hands on!” の続きを読む

WWDC25:Make a big impact with small writing changes

UXライティングに関するセッション。Don’t use をまとめるのは良さそう。


0:00 – Introduction

  • UX ライターによる、アプリの文章を改善するための 4 つの小さな変更について紹介:簡素化が重要
  • Apple の新しいデザインシステムを考える際に、文章も見直す絶好の機会
  • 4 つの修正を提案:フィラーワードの削除、繰り返しの回避、why を先に述べる、word list の作成
  • これらの小さな変更がアプリに大きな影響を与える

1:18 – Remove fillers

  • アプリには最小文字数がないため、不要な単語を削除することが重要
  • 副詞(easily, quickly)や形容詞(fast, simple)は多くの場合 filler として機能
  • 例:「Simply enter your license plate number to quickly pay for parking」→「Enter your license plate number to pay for parking」
  • 感嘆詞(oops, oh no)や丁寧語(sorry, thank you, please)も意味を追加しない場合は削除
  • 配達遅延の通知例:「Uh oh. We’re running late」→「We’re running late」
  • 各単語に付加価値があるかを確認し、そうでない場合は削除

6:12 – Avoid repetition

  • 繰り返しの言語も filler の一種
  • 同じことを異なる方法で言うことで空きスペースを埋めようとしない
  • 例:「Your delivery driver won’t make it on time」→「We’re running late」は同じ意味。「Delivery delayed 10 minutes」のように 1 つの文にまとめる
  • UX writing は言語の経済性が重要
  • 利用可能なスペースを繰り返し情報で埋めようとしない

7:13 – Lead with the why

  • メッセージは、次のステップを取ることが楽しい、興味深い、有益である理由を最初に伝えると最も効果的
  • 「To do or get one thing, first do another thing」のパターン
  • 例:「Enter your phone number to get reservation updates」→「To get reservation updates, enter your phone number」
  • エラーメッセージ、プッシュ通知、指示文でよく見られる
  • 利益を文の最後ではなく最初に移動することで、メッセージの影響力を向上

9:23 – Make a word list

  • アプリで使用する単語と使用しない単語をリスト化
  • 開発の初期段階で行うのが理想的だが、どの段階でも可能
  • 表形式で、使用する単語、使用しない単語、簡単な定義を整理(Use / Don’t Use / Definition)
    • 例:ゲームアプリで「alias」を使用し、「Handle, User Name, Title」は避ける
  • 包括的な word list を作成することに圧倒されず、まずは一度に 1 つの単語を追加
  • Apple Style Guide を参考にすることも推奨
  • ボタンラベルなども word list に追加することで一貫性を保つ
    • 同じアクションに同じボタン名(e.g. Next)
    • 一貫性により、アプリを使用する人々に明確さを提供

Foundation Models の RAG に Core Spotlight を活用できそうか超簡単な実験

WWDC24:Support semantic search with Core Spotlight で記したように、日記データを処理するオンデバイス LLM の実験のために Foundation Models の活用を検討しており、エントリ検索のための RAG として Core Spotlight が使えないか考えている。

ユーザー質問を受けた Foundation Models 側で、適切なクエリを生成できることが分かれば何かは作りだせそう。しかし以前の反省のとおりいきなりモデルの実装をし始めるのは悪手。まずは Foundation Models に対し自然言語でやりとりをし、狙う用途を満たす知識や能力があるかを先に検証するべき。

ということで、次のプロンプトを投げてみた。

あなたはCore Spotlightにインデックスされた日記データをもとにユーザーからの質問に答える役をします。Core Spotlightから情報を引き出すためには、ユーザーの質問を解釈し、Core Spotlightに投げるクエリを考える必要があります。ユーザーから「最後に散髪したのはいつ?」と尋ねられたら、どんなクエリを投げますか?

返ってきた答えは以下。

「最後に散髪したのはいつ?」という質問に対して、Core Spotlightに投げるクエリを考えるには、以下のようなアプローチが考えられます。このクエリは、ユーザーの行動履歴や、関連するキーワードを考慮して作成されます。

```plaintext
Core Spotlight Query:

- Type: Query
- Language: Natural Language
- Query: 最後に散髪したのはいつ?

- Context:
  - Keywords: 散髪、カット、美容室、ヘアスタイル、ヘアサロン
  - Date Range: 最近までの履歴を考慮

- Filters:
  - Category: Personal Care
  - Action: Haircut
  - Location: Salon/Barber Shop
  - Date: Last occurrence

- Constraints:
  - Language: Japanese
  - Language Preference: Japanese

```

このクエリは、ユーザーの行動履歴を基に「散髪」に関連するキーワードを特定し、最近までの履歴を考慮して「最後に散髪したのはいつ?」という質問に応答します。また、日付範囲を最近のものに限定し、具体的な場所やアクションを強調することで、より正確な情報 retrieval を促進します。

Context / Filters / Constraints をクエリ設計に含めているあたり、同じ Apple の技術である Core Spotlight のコンセプトを理解できているのかは怪しいが、少なくとも質問内容から的確にキーワード抽出ができそうなことは分かった。(まあここはさすがにLLMの得意分野だろう、、)

WWDC25:Principles of inclusive app design

インクルーシブデザインの中でも障害(disability)に焦点を当てたセッション。インクルーシブデザインやアクセシビリティデザインの文脈において、身体的に永続的な障害に目が向けられがちだが、環境要因で誰しもその状態に当てはまりうることは常々意識したい。またインクルージョンへの考慮は果てしないものだと思っていたが、現状理解と計画を持って解決していくこと、ギャップをイノベーションの機会と捉え取り組むことというメッセージに心に火がついた。


0:00 – Introduction

  • アクセシビリティデザイナーによる、障害を持つ人々を含むインクルーシブなアプリデザインについて紹介
  • 世界の約 7 人に 1 人が何らかの障害を持っており、障害は人間の普遍的な部分
  • 障害をデザインに含めることで、より多くの人々にアプリを提供し、創造性も向上
  • インクルーシブデザインにはアプリ多言語の翻訳、人種、民族への影響への配慮、世界中の文化の包摂などの観点もあるが、今回は障害に絞る
  • 大音響後の一時的難聴、大声の会話ができない、多言語環境に身を置くといった環境的要因で障害を経験することもある
  • Vision, Hearing, Motor, Speech, Cognitive の 5 つのカテゴリで障害を考える
    • 障害の有無は全か無かだけでなく、その間の「いくらか」の程度が存在する

3:55 – The inclusion gap

  • 障害は身体や心の特性ではなく、環境に大きく依存
  • 社会が期待することと個人が実際にできることの間にギャップが生じる
    • 生まれて死ぬまでの能力の曲線は人により様々
    • この「インクルージョンギャップ」が障害を生み出す
  • 人のできることは、環境のデザイン、構築により左右される→「できる力」を与えるモノ作り
    • エレベーター、マイク、メガネ、curb cuts など、多くのイノベーションがこのギャップから生まれた
  • 「Nothing about us without us(私たちのことを私たち抜きに決めないで)」の原則で、障害を持つ人々を意思決定に参加させる重要性
  • アプリをよりインクルーシブにするための4つの実践を紹介

8:55 – Support multiple senses(複数の感覚に配慮する)

  • 複数の感覚を通じてアプリとインタラクションできる方法を提供
    • 動画のキャプション、視覚的な情報、音声での体験など、様々な方法で情報にアクセス可能に
  • 情報の取得方法、入力方法を多様化(視覚、聴覚、触覚、声、認知能力)することが、インクルージョンギャップを埋める第一歩
    • Accessibility Reader の例:視覚的テキスト、音声読み上げ、ハイライト付き読み上げの 3 つの方法
    • Crouton アプリの例:画像、カメラ、テキスト、Hands Free モードなど多様な入力方法

12:36 – Provide customization(カスタマイズ性を持たせる)

  • UI とインタラクションを個人のニーズに合わせてカスタマイズ可能に
    • Accessibility Reader の例:テキストサイズ、色、フォント、音声設定の調整
    • Carrot Weather の例:データ豊富なレイアウトからシンプルなインターフェースまでカスタマイズ可能
  • アプリが人に適応するのではなく、人がアプリに適応することを期待しない

14:27 – Adopt Accessibility API(Accessiblity API を採用する)

  • アシスティブテクノロジーと連携するために Accessibility API を採用
  • VoiceOver, Switch Control, Voice Control, Larger Text などの機能をサポート
  • Accessibility API により、開発者が独自に実装することなく、障害者インクルージョンを簡単にサポート
  • アクセシビリティリーダー:Accessibility API を統合、スイッチコントロールにより画面に触れずに操作可能(iPhone とペアリング可能な物理ボタンにアクション割り当て)
  • Blackbox ゲームの例:オーディオや触覚デザインに加えて VoiceOver API で視覚障害者もパズルを解けるように設計

18:46 – Track inclusion debt

  • インクルージョンは旅であり、一度限りのものではない
  • inclusion debt(インクルージョン不足)を認識し、計画を立てて意識的な決定を行う
  • アプリに存在するギャップを理解し、障害を持つ人々と協力してギャップを埋める
  • インクルージョンギャップは創造性とイノベーションの機会
  • App Store でアプリのアクセシビリティをハイライトすることで、ユーザーが重要な機能をサポートしているかを知ることができる

WWDC25:Design foundations from idea to interface

デザインに関するセッション。情報設計が主な内容。普遍的な内容なので開発者やデザイナーだけでなく、プロダクトに携わるあらゆるロール・ポジションが把握するべき内容。


0:00 – Introduction

  • デザインエバンジェリズムチームによる、アイデアからインターフェースまでのデザイン基盤について紹介
  • アプリが「うまく動作する」体験と「動作しない」体験の違いを理解し、シームレスな体験を構築する方法を説明
  • 構造、ナビゲーション、コンテンツ、ビジュアルデザインの 4 つの基盤要素を体系的に解説

1:11 – Structure

  • 次の質問に明確に答えられるか?
    • Where am I?:現在地と、どう辿り着いたかがすぐに分かる
    • What can I do?:動作は明確で理解しやすく、推測が不要である
    • Where can I go?:次のステップを明確に意識できる
  • 情報アーキテクチャの重要性:情報を整理し、優先順位をつけて、ユーザーが必要なものを簡単に見つけられるようにする
  • 1 List every feature:アプリの機能、ワークフロー、ニーズをリストアップし、ユーザーの使用シーンを想像して整理(ここでは省かない)
  • 2 Learn from peaple:ユーザーがどう使うかを想像する。いつどこで?ルーチンにどう合わせる?助けや邪魔になるもの。答えをリスト化
  • 3 Organize insight:本質的でない機能を削除し、明確でないものを名前変更し、自然にグループ化
  • 明確な構造により、ユーザーが「どこにいるか」「何ができるか」「どこに行けるか」を理解しやすくなる

4:55 – Navigation

  • Tab bar コンポーネントを使用して主要機能へのアクセスを提供
    • What deserves a tab?:タブ数を最小限に抑え、本質的な機能のみをタブに配置
    • アクション(Add)はタブではなく、使用される場所(Records)に配置
    • 迷ったら HIG に立ち返る
    • SF Symbols を使用して視覚的に一貫性のあるアイコンを提供
  • Toolbar でスクリーン固有のアクションを配置し、ユーザーの方向感覚を向上
    • タイトルと画面の名称を表示:画面が明確になり、移動やスクロール時の方向感覚を維持
    • アクション:タブバーの代わりに使用
  • Where am I? / What can I do? が明確化

8:19 – Content

  • コンテンツを重要度順に整理し、ユーザーが期待する順序で表示
  • Progressive disclosure(段階的開示)で、必要最小限の情報から始めて、インタラクションに応じて詳細を表示
    • Disclosure control の使用
    • 遷移前後でレイアウトを一致させ、前後の繋がりを与える
  • Grid の代わりに List コンポーネントを使用して構造化された情報を効率的に表示
  • コンテンツを時間、進捗、パターンでグループ化して整理
  • Collection を使用して画像やビデオのグループを動的に表示

13:28 – Visual Design

  • カラフルな要素にまっさきに目がいってしまう
  • 視覚的階層でユーザーの視線を重要な要素から順に誘導
    • 重要なものを大きく、コントラストを高く
    • テキストを長く、大きくしたり、言語を変えて検証:柔軟性が重要
    • System text styles を使用して一貫した階層と可読性を実現
    • テキストと画像の重なりでは、グラデーションやブラーで可読性を確保
  • 必要なのはまとまりのあるビジュアルスタイル(Use a cohesive style)
    • アプリの個性を表現する色パレットとビジュアルスタイルを確立
    • Semantic colors(label, secondarySystemBackground など)を使用して動的な色の変化に対応(外観でなく目的にちなんで命名)
      • コントラスト設定、画面環境、ダーク/ライトモード…