-
Core Spotlightを利用したLLM検索
SpotlightSearchToolとLanguageModelSessionを活用することで、基本的な検索を検索拡張型のシステムへと進化させることができます。このセッションでは、Core Spotlightの統合やデリゲートベースのハイドレーションパターンについて、およびメタデータの品質が検索結果に与える影響について解説します。感情分析などのタスクにカスタムのPipelineStageを活用する方法や、アプリにおけるインデックス作成および豊富なコンテキストに基づく柔軟な検索体験の構築のためのベストプラクティスを学びましょう。
関連する章
- 0:00 - Introduction
- 1:41 - Grounding answers with Spotlight tool-calling
- 4:00 - Configure and add SpotlightSearchTool
- 6:44 - Displaying results and partial replies
- 6:46 - Provide full items with an index delegate
- 8:12 - Customizing with guidance profiles
- 11:02 - Reference resolution with a contact resolver
- 11:24 - Custom pipeline stages
- 12:47 - Evaluating response quality
- 15:53 - Next steps
リソース
-
このビデオを検索
こんにちは、Jenniferです。 Spotlightエンジニアリングチームのメンバーです。 今年、私たちは検索を まったく新しいレベルへと引き上げます。 Foundation ModelとCore Spotlightを使って。 アプリ内でリッチな 会話型エクスペリエンスを構築できます。 アプリのコンテンツを 大規模言語モデルで推論と レスポンス生成に利用できるようにするだけで。 私はカリフォルニア出身で、この地域には素晴らしい ハイキングコースがたくさんあります。 素晴らしいトレイルをゆっくりと 巡り歩いてきました。 そこで、それをサポートする アプリを作ることにしました。 私のハイキングトレイルアプリでは、すでに 州立公園やトレイルを閲覧できます。 トレイルを完歩した後は、 ハイキングで最も楽しかったことについて 自分でメモを書くのが好きです。 でも、言語モデルに 質問できたら素晴らしいですよね。 すでに行ったハイキングについて または、次に試すべき新しいハイキングについても。 Foundation Modelフレームワークなら 簡単に始められます。 アプリに言語モデルセッションを導入することで、 幅広い質問をすることができ、 モデルはその世界の知識だけを使って 答えてくれます。 私は、アプリが知っているハイキングについての 回答だけを求めています。 ここで、Spotlightが役立ちます。 ハイキングトレイルアプリは、 素晴らしいハイキングのすべてを Core Spotlight検索インデックスに登録しています。 そのため、特定のハイキングに関する 質問にモデルが答えられるよう、 アプリのCore Spotlight 検索インデックスを使用できます。 Foundation Modelフレームワークからの ツール呼び出しを通じて。 Foundation ModelのToolプロトコルは 強力なコンセプトで、 モデルの機能を拡張するために 使用できます。 リクエストに対してアクションを取ることも、 モデルがレスポンスを生成するために必要な コンテキストを検索することも。
ツールは、引数と出力を宣言することで動作します。 ツールが何をするかについての 説明とともに。 そして、モデルがツールの使用が 必要と判断したとき、 そのツールを呼び出すための 引数を生成し、 その出力をレスポンス生成に 使用します。 まだご覧になっていない方は、 いくつかの素晴らしいセッションがあります。 「Foundation Modelフレームワークの 詳細解説」など、 ツール呼び出しの仕組みについて 詳しく学べます。 では、モデルがアプリのCore Spotlight インデックスで検索を生成できる ツールがあったらどうでしょう? 本日、SpotlightSearchToolをご紹介します。 これはToolプロトコルを採用したツールで、 言語モデルがCore Spotlight内の アプリのコンテンツを直接検索し、 文脈に応じたレスポンスを生成できます。 SpotlightSearchToolはiOS、iPadOS、 macOS、visionOSで利用できます。
始める前に、 アプリがCore Spotlightで 検索可能なコンテンツを提供していることを 確認してください。 過去のセッションをご覧ください。 「Core Spotlightによるセマンティック 検索のサポート」では、 Spotlightへの検索可能なコンテンツの 提供方法について解説しています。 デリゲートとインデックス再作成拡張を使った 提供管理の方法、 アイテム属性に対する 構造化検索の実行方法、 そしてセマンティックインデックスへの 検索方法。
アプリがCore Spotlightに 検索可能なアイテムを提供したら、 またはApple Intelligenceのために エンティティをインデックス登録したら、 準備完了です。 このビデオでは多くのことをカバーします! 新しいSpotlightSearchToolを 提供する方法をご紹介します。 言語モデルセッションへの追加方法。 次に、ガイダンスを使ってSpotlightSearchToolを カスタマイズする方法、 ナレッジプロバイダー、 および特殊な機能について探ります。 最後に、モデルのレスポンスを 評価する方法を見ていきます。 評価フレームワークを使って。 では、始めましょう。 まず、SpotlightSearchToolが 文脈に応じたレスポンス生成に どのように使えるか見ていきます。 ハイキングトレイルアプリでは、 検索可能なアイテムを提供し、 ハイキングトレイルを表す Spotlightインデックスを作成しました。 各トレイルには、トレイルの名前や 場所などのメタデータがあります。 一部のハイキングには、 個人的な詳細も含まれています。 ハイキングを完了した日付や、 そのハイキングがどうだったかについて 書いたメモなど。 「私が行ったハイキングは何ですか?」 と聞きたい場合、 モデルは完了日などの属性で アイテムを検索する必要があります。 場所なども含めて、 レスポンスを作成するために。 この機能をアプリに 組み込みましょう。 SpotlightSearchToolを採用する際には 3つのことを確認します。
ツールを設定する必要があります。 モデルに実行させたい 検索の種類に合わせて。 次に、モデルに 追加のコンテキストを提供します。 検索がアクティブな間、 最適なレスポンスを得るために。 最後に、 アプリのユーザーインターフェースで 結果を表示するさまざまな方法を探ります。
ツールの設定は、Spotlightクエリを 直接実行することとあまり変わりません。 CoreSpotlightとFoundationModelの 両方をインポートすることから始めます。 そして、1行のコードで、ツールはアプリの Core Spotlightインデックスを検索する準備が整います。 SpotlightSearchToolにカスタム設定を 提供することもできます。 ここではFileSourceを指定して、 アプリのサンドボックス内の ファイルパスに対して検索を実行します。 次に、アプリに適したモデルを 選択します。 SystemLanguageModelか お好みのモデルか、 新しいModel Provider APIを使って 選択できます。 モデルを選択したら、 新しいSpotlightSearchToolインスタンスを LanguageModelSessionに追加し、 レスポンスの取得を開始します。 まるで魔法のようですが、 レスポンスはツール呼び出しと 生成のパスを辿ります。 「私が行ったハイキングは何ですか?」 のような質問の場合、 モデルがSpotlightSearchToolを 使用する必要があると判断するところから始まります。 モデルは生成したクエリで ツールを呼び出し、 Spotlightがそのクエリを実行して、 結果セットの説明を返します。 モデルはその出力を推論して 最終的なレスポンスを生成します。
「私が行ったハイキングは 何ですか?」と聞くと、 モデルはアプリのコンテンツに基づいた 回答を生成できます。
一部のレスポンスからお気づきかもしれませんが、 モデルがすべてのメタデータを 確認できなかったことに お気づきかもしれません。 これは、Spotlightインデックス内の一部のメタデータが、 テキストコンテンツやHTMLなど、 検索可能だが言語モデルが 読める形では復元できない 高度に圧縮された表現で 保存されているためです。 このような場合、アイテムに追加のメタデータを 提供することを検討してください。 SpotlightSearchToolが 検索を実行している間に。 アプリがCore Spotlightに 検索可能なコンテンツを提供している場合、 インデックスデリゲートプロトコルに すでに精通しているでしょう。 アプリはCSSearchableIndexに インデックスデリゲートを設定して インデックス再作成のリクエストを処理します。 Spotlightが移行または復元を 行う必要がある場合などに。 SpotlightSearchToolのために、 デリゲートに、一意の識別子によって 完全なCSSearchableItemを復元するための メソッドを追加しました。 これにより、モデルは 潜在的に数百万件の結果に対して レスポンスを効率的に管理できます。 インデックスデリゲートで、 新しいsearchableItems(forIdentifiers:)を 採用するだけで 完全なCSSearchableItemを返せます。
アプリに、検索に提供することは 意味がないが、 モデルが推論する際に 役立つメタデータがある場合、 モデルが参照できるよう、アイテムに 追加の属性を設定するのに 適切なタイミングです。
ツールを設定して検索を実行できるようになったので、 結果の表示方法を 考える必要があります。
ユーザーインターフェースでの レスポンスについて。 セッションのレスポンスは、 結果セットの簡潔な説明です。 アシスタントスタイルのインターフェースでは、 このレスポンスが通常 アプリが表示したいものです。 ただし、検索結果は SpotlightSearchTool自体からも 直接利用できます。 リスト形式の表示には、 検索可能なアイテムにアクセスするのに 最適な方法です。 特に結果セットが大きい場合に。 検索リプライは、検索中に バッチで結果を返します。 クエリトークンを使って 会話ストリームを管理できるため、 ユーザーインターフェースが モデルと同期した状態を保てます。 SpotlightSearchToolから 結果にアクセスするには、 アプリは検索リプライを 待ち受けて リプライのコンテンツ内の CSSearchableItemを確認します。 検索リプライは 非同期イベントシーケンスとして届き、 各リプライにはバッチの結果が含まれ、 ツール呼び出しが完了するまで続きます。 なお、特定のレスポンスに対して、 モデルはSpotlightSearchToolを 複数回呼び出す場合があります。 最終的なレスポンスを生成する前に。 そのため、各リプライのqueryTokenを使用して、 ユーザーインターフェースを 更新するタイミングを判断してください。
SpotlightSearchToolは 豊富な検索機能を提供します。 テキストのセマンティック検索から、 メタデータの構造化検索まで、 日付、人物、場所など多岐にわたります。 ただし、選択した 言語モデルによっては、 SpotlightSearchToolを カスタマイズすることが モデルとアプリのコンテンツの両方に 適している場合があります。 SpotlightSearchToolをカスタマイズする 方法はいくつかあります。 ガイダンスプロファイルを使用して、 ツールの検索機能の範囲を絞れます。
ツールに世界の知識を提供することで、 参照解決に役立てられます。 カスタムパイプラインステージを実装することで、 アプリのコンテンツに対する モデルの推論を改善できます。 SpotlightSearchToolは、 ガイドされた生成のために モデルに全検索機能のセットを提供します。 ただし、ガイダンスプロファイルを使用すると、 アプリが必要とするものだけに ガイダンスを絞れます。 ハイキングトレイルアプリは 人物の関係を提供していないので、 著者や受信者の検索方法に関して モデルをガイドすることは、 コンテキストが限られたモデルでは 省略できます。 人物や日付などの検索機能に対して 選択的にガイダンスを有効にするには、 GuidanceProfileを使用します。 検索時にモデルが考慮すべき メタデータ属性の正確なリストを 指定することもできます。 次に、プロファイルを使って 動的なガイドレベルを設定します。 SpotlightSearchToolを作成する際に。 オンデバイスモデルは モデルコンテキストサイズがより制限されているため、 より単純な検索機能には 集中したガイダンスを使用するのが最善です。 参照解決は、アプリが 検索インデックスで直接利用できない コンテキストを提供するもう一つの方法です。 例えば、ハイキングトレイルアプリが 人物の関係を提供していた場合、 アプリを使用している人が トレイルの他の参加者について 尋ねたいかもしれません。 その場合、モデルはプロンプト内で その人物が誰を指しているかを 知る必要があります。 アプリがすでにその人物が 誰であるかを知っている場合、 コンタクトリゾルバーを使用してツールが 正しい結果セットに絞り込めるようにしてください。 contactResolverは返す必要があります。 ユーザーのアイデンティティに関連する 連絡先情報を、 検索インデックス内のメタデータと 照合できるよう。
最後に、アプリはカスタム パイプラインステージを活用して、 ドキュメント推論をさらに発展させることができます。 非常に複雑なリクエストに対して、 言語モデルは単純な 検索クエリを避け、 パイプライン検索を選ぶかもしれません。 パイプライン検索は、 インデックスへのクエリと 結果セットへの計算を組み合わせて、 最大効率を実現します。 例えばこう尋ねられます: 今年何本のトレイルをハイキングしたか、 また各月ごとに 平均何マイル歩いたか? モデルは単純な検索を実行して、 メモリ内で集計して 質問に答えることもできます。 または、結果セットが 大きくなる可能性がある場合、 SpotlightSearchToolを使って モデルがリクエストできます。 Spotlightが検索と計算ステージの パイプラインを実行することを。 パイプライン検索を使えば、 モデルはこの複雑なクエリを 一連のステップに分解できます。 モデルは完了したハイキングの 検索を生成し、 月ごとのテーブルを構築する カウントステージと合わせて、 すべての件数の平均を計算する ステージを追加します。 パイプラインステージにより、ツールはモデルの代わりに 効率的な計算や変換を実行できます。 検索結果セットに対して。 アプリは独自のカスタムステージを登録して 参加することができます。 パイプラインステージはGenerableです。 そのため、モデルはユーザーのプロンプトに基づいて オンデマンドでステージを生成します。 ステージが生成されるたびに、 モデルは意味があると判断した場合に アプリにデータを返すことができます。
Foundation Modelの詳細解説には ガイドされた生成に関する 素晴らしいセグメントと Generableタイプについての説明があります。 ハイキングトレイルアプリを もう一度見てみましょう。 いくつかのトレイルには、各ハイキングに ついての個人的なメモが含まれています。 そこで、こう尋ねたいとします: とても幸せな気分になったハイキングは どれでしたか? モデル単独では、メモを読むだけで 私の幸福度を最善の形で 推測することができます。
または、アプリがカスタムステージを登録して、 各アイテムに対して 幸福スコアを計算し、 モデルがレスポンスを生成できるように することもできます。 計算された上位スコアの 結果だけに基づいて。 幸福スコアを計算する カスタムステージを構築するには、 CSSearchableItemを入力として 操作し、 スコア付きのバージョンを 出力として返します。 スコアは、アイテムのnotesアトリビュートに 対して感情分析モデルを実行することで 計算できます。 または他のカスタムロジックで、 5つ星評価のハイキングを 考慮に入れるなど。 これはGenerableタイプなので、 ガイドを持つプロパティを追加して どの結果を優先するかについて モデルに情報を提供できます。 次に、ツールの設定に追加することで ステージを登録します。 もう一つあります: SpotlightSearchToolが表示用の検索結果と 共にリプライを返すことを覚えていますか? モデルは送り返すことがあります。 パイプラインステージの出力データを含む 検索リプライを 別の部分的な結果として。 集計カウントやテーブルから、 自由形式のテキストや 計算された数値まで、 アプリはこれらのデータ型の 一部またはすべてを表示できます。 各リプライには、LLMが生成した 便利なラベルが付属しており、 コンテンツを説明することで、 アプリのユーザーインターフェースに 最大の柔軟性を提供します。 カスタマイズのオプションが こんなにあると、 選択するモデルから アプリが提供する 検索可能なコンテンツまで、 ガイダンスレベルやカスタム推論まで、 幅広い意味で、どのように確認できますか? モデルがアプリでどれだけうまく レスポンスしているかを。
評価フレームワークが いくつかの重要な方法で役立ちます。 迅速に評価を構築できるだけでなく、 モデルがどれだけうまく ツールを呼び出しているか、 レスポンスがどれだけ意味のあるものかを確認できます。 アプリの検索可能なコンテンツを 迅速に反復することもでき、 SpotlightSearchTool自体の さまざまなガイダンスプロファイルと組み合わせて。 評価フレームワークには 優れたAPIがあります。 エンドツーエンドの 評価スイートを構築するための。 大規模なデータセット生成から、 カスタムメトリクスを使った 評価実行とレポートまで。 サンプルデータ生成APIについて 詳しく解説した素晴らしいセッションがあります。 エージェンティックアプリの堅牢な評価を 作成するためのビデオも 始めるのに最適なリソースです。 ツール呼び出しを使ったモデルのレスポンスを 評価するための。 私たちの目的では、結果カバレッジに 焦点を当てます。 ハイキングトレイルの会話型エクスペリエンスを 評価する方法として。 Core Spotlightでインデックス登録された データセットが与えられた場合、 モデルが見つけることを期待するアイテムに基づいて どれだけうまくレスポンスを生成するか。 まず、ModelSampleProtocolを採用する データセットを定義することから始めます。 TrailRequestには、アプリ内のトレイルについて 人が尋ねる 自然言語の入力がすでに含まれています。 出力は言語モデルのレスポンスと リクエストのトラジェクトリの 期待値です。 また、検索可能なアイテムの 一意の識別子のセットも追加します。 そのプロンプトに対して ツールが返すと期待されるもの。
テストに使用できる実際のデータがあれば 素晴らしいことです。 ない場合は、 サンプル生成APIを使用して プロンプトに基づいてデータを生成できます。 Xcodeでこれを見てみましょう。 評価のために、ハイキングトレイルの セットを定義できます。 アプリがCore Spotlightに 提供することが期待されるメタデータと共に。 次に、評価で使用する シードサンプルのセットを構築します。 サンプルは任意のCodable形式で シリアライズできます。 JSONはその目的に 適しています。 サンプルには、クエリと検索で 返されることを期待する アイテム識別子のセットが含まれています。 後で使用するサンプルレスポンスも 提供できます。 モデルの実際のレスポンスとの 品質比較に使用するために。 コマンドラインツールでサンプル生成APIを 使用することで、 このシードセットをさらに多くの バリエーションに拡張できます。 人々がトレイルについて 尋ねたいと思う方法を幅広くカバーするために。
次のステップは、メトリクスと トラジェクトリで評価を定義することです。 サンプルでは、レスポンスの トラジェクトリが クエリを実行するためにSpotlightSearchTool への呼び出しを含むことを期待します。 その期待をどのように定義するか 見てみましょう。 そして、評価フローの概要を ご紹介します。 最終レスポンスに含まれた期待アイテムの数を 考慮に入れた。 テストターゲットでは、 評価は生成されたデータセットから トレイルアイテムとサンプルを読み込みます。 次に、トレイルアイテムを Core Spotlightに提供し、 この評価のために SpotlightSearchToolを設定します。 評価の実行が完了したら、 含めたすべてのメトリクスに対して 期待値を設定できます。 結果カバレッジなど。
これは、包括的な評価を構築するための 出発点に過ぎません。 アプリに最高のエクスペリエンスを 提供するために役立ちます。
Foundation Modelにとって大きな年となり、 最大限に活用していただければと思います。 サンプルコードをダウンロードして、ハイキング トレイルアプリの動作を確認してください。 アプリに独自のカスタム機能を追加して、 何が可能かを実際に確かめてください。 独自の評価スイートを追加することも 検討してください。 評価エージェンティックの 詳細解説からインスピレーションを得て。 そして、私たちはもう 検索クエリを書いていません。 コンテンツを提供して、 インテリジェンスに残りを任せましょう。
-
-
0:59 - Ask the model with a Foundation Models session
let response = try await session.respond(to: "What are some nice hikes near water?") -
4:20 - Set up SpotlightSearchTool
// Set up SpotlightSearchTool import CoreSpotlight import FoundationModels // In one line, the tool is ready to search your app's Core Spotlight index let tool = SpotlightSearchTool() // Or provide a custom configuration — e.g. search file paths in your app's sandbox let fileTool = SpotlightSearchTool( configuration: .init( sources: [ .files ] ) ) -
4:50 - Add SpotlightSearchTool to a session
// Add SpotlightSearchTool to a session import CoreSpotlight import FoundationModels let tool = SpotlightSearchTool() let session = LanguageModelSession(model: model, tools: [tool], instructions: instructions) let response = try await session.respond(to: "What hikes have I gone on?") -
6:24 - Implement an index delegate
// Implement an index delegate import CoreSpotlight class IndexDelegate: NSObject, CSSearchableIndexDelegate { // Called when the index requests searchable items for the provided identifiers func searchableItems(forIdentifiers identifiers: [String]) async -> [CSSearchableItem] { let entries = await mystore.fetchEntries(ids: identifiers) return entries.map { makeSearchableItem(from: $0) } } } -
7:37 - Track the query token for refresh
// Track the query token for refresh import CoreSpotlight import FoundationModels let tool = SpotlightSearchTool() for await reply in tool.searchResults { if reply.queryToken != currentToken { // New query — start a new display section currentToken = reply.queryToken } switch reply.content { case .items(let searchItems): } } -
8:42 - Set a dynamic guidance profile
// Set a dynamic guidance profile import CoreSpotlight import FoundationModels let profile = SpotlightSearchTool.GuidanceProfile( textMatch: true, dates: true, people: false, attributes: [.title, .altitude, .completionDate] ) let tool = SpotlightSearchTool( configuration: .init( guide: .init(level: .dynamic(profile)) ) ) // On-device models have smaller context — prefer focused guidance let focusedTool = SpotlightSearchTool( configuration: .init( guide: .init(level: .focused(.items)) ) ) -
9:32 - Implement a ContactResolver
// Implement a ContactResolver import CoreSpotlight import FoundationModels struct MyContactResolver: ContactResolver { func userIdentity() -> ResolvedContact { // Pull from whatever identity source your app has — // account profile, Contacts framework, sign-in session, etc. var contact = ResolvedContact(displayName: "Jane Doe") contact.emailAddresses = ["jane@example.com", "jdoe@work.com"] contact.names = ["Jane", "JD"] return contact } } tool.contactResolver = MyContactResolver() -
11:34 - Define a custom stage
// Define a custom stage import CoreSpotlight import FoundationModels @Generable struct HappinessStage: CustomStage { static var name = "happiness" static var description = "Scores hike by how happy the author was" static var inputTypes: [SearchPipelineDataType] = [.items] static var outputTypes: [SearchPipelineDataType] = [.scoredItems] @Guide(description: "Minimum happiness score (0.0-1.0) to include in results") var threshold: Double? func execute(on input: SearchPipelineData) async throws -> SearchPipelineData { return SearchPipelineData(payload: .scoredItems(sorted)) } } // Register the stage by adding it to the tool's configuration let tool = SpotlightSearchTool(configuration: .init( customStages: [.happinessBoost(threshold: 0.5)]) ) -
12:10 - Handle a reply data types
// Handle a reply data types import CoreSpotlight import FoundationModels for await reply in tool.searchResults { let label = reply.label case .items(let searchItems): case .scoredItems(let scored): case .groupedItems(let groups): case .count(let count): case .table(let table): case .statistic(let statistic): case .text(let text): continue } } -
13:47 - Define an evaluation dataset with ModelSampleProtocol
// Evaluations import Evaluations struct TrailRequest: ModelSampleProtocol { typealias ExpectedValue = String // sample response typealias Expectation = TrajectoryExpectation var input: ModelSampleInput var output: ModelSampleOutput<String, TrajectoryExpectation> var expectedIdentifiers: [String] } -
15:06 - Define the trajectory expectation
// Evaluations import Evaluations TrajectoryExpectation( unordered: [ ToolExpectation("searchSpotlight", arguments: [.keyOnly(argumentName: "query")]) ] ) -
15:17 - Run the evaluation test —
@Test("Trail search evaluation meets quality thresholds") func trailSearchEval() async throws { let items = try Self.loadItems() let samples = try Self.loadSamples() try await Self.indexDelegate.indexSearchableItems(items) let tool = Self.makeSearchTool() let evaluation = TrailSearchEvaluation( tool: tool, dataset: ArrayLoader(samples: samples) ) let result = try await evaluation.run() let coverageMean = result.aggregateValue(.mean(of: Metric("ResultCoverage"))) #expect(coverageMean >= 0.5, "Result coverage should be at least 50% across queries") }
-
-
- 0:00 - Introduction
Build conversational search by making app content available to a language model. Sets up the running example: a hiking trails app that browses state parks and trails and stores personal notes on completed hikes.
- 1:41 - Grounding answers with Spotlight tool-calling
A LanguageModelSession answers broad questions from world knowledge, but to answer only about the app's hikes you ground it in the Core Spotlight index via the Foundation Models Tool protocol. Introduces SpotlightSearchTool (iOS, iPadOS, macOS, visionOS) and the prerequisite of donating searchable content.
- 4:00 - Configure and add SpotlightSearchTool
Import CoreSpotlight and FoundationModels, create the tool (optionally with a custom configuration like a FileSource), choose a model (SystemLanguageModel or a Model Provider), and add the tool to a session. Walks the tool-call trajectory from query to grounded response.
- 6:44 - Displaying results and partial replies
The session response suits an assistant-style UI, while the tool's searchable items suit a list UI. Search replies arrive as an async sequence of batched results; use the query token to know when to refresh, since the model may call the tool multiple times per response.
- 6:46 - Provide full items with an index delegate
Some donated metadata is stored compactly and isn't readable by the model. Implement searchableItemsForIdentifiers on the CSSearchableIndexDelegate to recover the full CSSearchableItem on demand and attach extra attributes for the model to reason over.
- 8:12 - Customizing with guidance profiles
SpotlightSearchTool exposes its full search capabilities for guided generation; a GuidanceProfile scopes that guidance to only what the app needs (such as specific attributes or a dynamic guide level), which matters for the smaller context of on-device models.
- 11:02 - Reference resolution with a contact resolver
When a query references a person ("Who did I go hiking with?"), supply a ContactResolver that returns contact information matching the user's identity, so the tool can disambiguate and filter to the right results.
- 11:24 - Custom pipeline stages
For complex requests the model can run a pipeline of search plus computation stages instead of a simple query. Register your own @Generable stages (such as a happiness-score stage over notes); the model generates stages on demand and may return computed data back to the app for display.
- 12:47 - Evaluating response quality
Use the Evaluations framework to measure tool-calling and response quality. Define a dataset via ModelSampleProtocol with expected item identifiers and trajectory, expand seed samples with the Sample Generation APIs, and assert metrics like result coverage in a test.
- 15:53 - Next steps
Download the hiking trails sample, add your own custom functionality and evaluation suite, and lean into the deep-dive sessions. The takeaway: stop writing search queries, provide the content and let intelligence do the rest.