Environment setup
Same Xcode 27 app as lesson 02. Add a LanguageModelSession backed by SystemLanguageModel for this first cache. You can swap in CoreAILanguageModel later if you ship a custom chat model. Confirm initializers in the installed SDK.
import FoundationModels
// Illustrative session shape. Verify names in the installed SDK.
@MainActor
final class CachedAsk {
let embedder: QuestionEmbedder
let session: LanguageModelSession
var rows: [CacheRow] = []
var stats = CacheStats()
var minimum: Float = 0.92
func answer(_ question: String) async throws -> String {
let vector = try await embedder.vector(for: question)
stats.lookups += 1
if let row = lookup(question: vector, rows: rows, minimum: minimum, now: .now) {
stats.hits += 1
return row.answer
}
stats.misses += 1
let response = try await session.respond(to: question)
let text = String(describing: response)
rows.append(CacheRow(
id: UUID(),
question: question,
answer: text,
embedding: vector,
createdAt: .now,
expiresAt: .now.addingTimeInterval(30 * 60)
))
return text
}
}
If the session uses Dynamic Profiles, the cache still sits outside the profile body. Profiles pick instructions, tools, and the model. The cache decides whether to call the session at all. One Profile is active when you do generate. See Run an agent with a state machine for that rule.
Do not cache tool-using turns until you can key the row on tool results as well. A cached "next meeting" that ignored a calendar refresh is a product bug.
Sources: WWDC26 session 241 (usage and models), Foundation Models, and Core AI.
Key concepts
- The cache sits before
LanguageModelSession. A hit returns the stored answer. - A miss calls
session.respond, then writes the pair. - Dynamic Profiles pick instructions and tools. The cache decides whether to call the session.
- Do not cache tool-using turns until rows can key on tool results.
Takeaways
- Ask the cache first on every question.
- Tool turns need richer cache keys than question text alone.
- You now have an on-device semantic cache, a high threshold, and hit-rate counters.