The Evaluations framework in iOS 27 lets developers iteratively improve AI-powered features by running structured evaluations, scoring outputs with a model judge, and measuring alignment between model and human ratings using Cohen's kappa coefficient. This hill-climbing workflow enables systematic prompt and feature quality improvement with confidence.
⢠Provides a scientific, repeatable process for improving AI prompt quality ā replacing guesswork with measurable alignment scores (Cohen's kappa)
⢠Catches model judge 'drift' early by quantifying how much the AI rater diverges from your own expert human ratings
⢠Integrates directly into Swift Testing and Xcode's Evaluations report, making AI quality a first-class CI/CD concern
Demonstrates how to write an alignment evaluation that computes Cohen's kappa between a human expert's ratings and a ModelJudgeEvaluator's scores, enabling hill-climbing of a prompt used to generate book tags.
import Evaluations
import FoundationModels
import Testing
// MARK: - Score Dimensions
struct TagScoreDimensions: ScoreDimensions {
@ScoreDimension(scale: 1...4, description: "How well tags represent plot, theme, and book info")
var relevance: Score
@ScoreDimension(scale: 1...4, description: "How useful the tags are as search terms")
var usefulness: Score
}
// MARK: - Dataset Entry
struct TagAlignmentEntry: EvaluationInput {
let bookSummary: String
let generatedTags: [String]
let expertRelevance: Int // Human expert rating 1-4
let expertUsefulness: Int // Human expert rating 1-4
}
// MARK: - Cohen's Kappa Helper
func cohensKappa(expertRatings: [Int], modelRatings: [Int]) -> Double {
guard expertRatings.count == modelRatings.count, !expertRatings.isEmpty else { return 0 }
let n = Double(expertRatings.count)
// Observed accuracy
let matches = zip(expertRatings, modelRatings).filter { $0.0 == $0.1 }.count
let po = Double(matches) / n
// Expected accuracy (chance agreement)
let scale = 1...4
let pe = scale.reduce(0.0) { sum, k in
let expertFrac = Double(expertRatings.filter { $0 == k }.count) / n
let modelFrac = Double(modelRatings.filter { $0 == k }.count) / n
return sum + expertFrac * modelFrac
}
guard pe < 1.0 else { return 1.0 }
return (po - pe) / (1.0 - pe)
}
// MARK: - Alignment Evaluation
struct TagJudgeAlignmentEvaluation: Evaluation {
typealias Input = TagAlignmentEntry
typealias Output = [String]
typealias Dimensions = TagScoreDimensions
let dataset: [TagAlignmentEntry] = [
TagAlignmentEntry(
bookSummary: "A young boy joins pirates on a treasure hunt, facing loyalty vs betrayal.",
generatedTags: ["adventure", "pirates", "treasure", "coming-of-age"],
expertRelevance: 4,
expertUsefulness: 2
),
TagAlignmentEntry(
bookSummary: "Four sisters navigate love and loss in Civil War-era New England.",
generatedTags: ["poignant", "quiet-steadiness", "family", "women"],
expertRelevance: 4,
expertUsefulness: 2
)
]
func subject(for input: TagAlignmentEntry) async throws -> [String] {
// Return pre-generated tags from the dataset (no model call needed here)
return input.generatedTags
}
var evaluators: [any Evaluator<[String], TagScoreDimensions>] {
[
ModelJudgeEvaluator(
model: SystemLanguageModel.default,
prompt: """Rate these book tags on relevance (how well they capture plot/theme) \
and usefulness (how good they are as search terms). Scale: 1=poor, 4=excellent."""
)
]
}
func aggregate(
results: [EvaluationResult<TagAlignmentEntry, [String], TagScoreDimensions>]
) -> [String: Double] {
let expertRel = results.map { $0.input.expertRelevance }
let expertUse = results.map { $0.input.expertUsefulness }
let modelRel = results.compactMap { $0.scores.relevance.map { Int($0.value.rounded()) } }
let modelUse = results.compactMap { $0.scores.usefulness.map { Int($0.value.rounded()) } }
let kappaRel = cohensKappa(expertRatings: expertRel, modelRatings: modelRel)
let kappaUse = cohensKappa(expertRatings: expertUse, modelRatings: modelUse)
let overallKappa = (kappaRel + kappaUse) / 2.0
return [
"kappa.relevance": kappaRel,
"kappa.usefulness": kappaUse,
"kappa.overall": overallKappa
]
}
}
// MARK: - Swift Testing Integration
@Test func judgeAlignmentMeetsThreshold() async throws {
let evaluation = TagJudgeAlignmentEvaluation()
let metrics = try await evaluation.run()
let overallKappa = metrics["kappa.overall"] ?? 0
// 0.6+ = substantial agreement per Cohen (1960)
#expect(overallKappa >= 0.6, "Judge drift detected: kappa=\(overallKappa). Refine judge prompt.")
}Foundation Models is a new Apple framework introduced in iOS 27 that gives developers on-device access to the same Apple Intelligence language model powering system features, enabling text generation, structured output, and tool-calling entirely on-device without a network connection.
iOS 27 opens the Foundation Models framework to third-party LLM providers via a new public LanguageModel protocol, enabling anyone to integrate custom, server-based, or open-source models using the same Swift API as Apple's on-device system model.
App Schemas let developers describe their app's content and actions using pre-defined domain schemas (like the Calendar domain) so Siri can understand, search, and act on app data without custom NLP. Entities conforming to IndexedEntity are donated to Spotlight's semantic index, enabling natural-language queries over app content.
In-depth guide
iOS 27 On-Device AI & Apple Intelligence ā⢠A Cohen's kappa score ā„ 0.6 is the recommended minimum threshold for 'substantial' alignment ā scores below this mean your judge's ratings cannot be trusted as a proxy for human judgment ⢠The alignment evaluation requires a pre-generated dataset from a prior evaluation run (stored as Xcode attachments) ā you cannot run alignment checks without first having human expert ratings to compare against ⢠Custom aggregation methods for Cohen's kappa must be implemented manually; the framework does not ship a built-in kappa calculator
Apple Intelligence device required; on-device model judge requires A17 Pro / M-series chip
Visual Intelligence brings iOS 17's Visual Look Up capabilities to a new developer-facing API surface in iOS 27, letting apps pipe live camera frames or static images through on-device scene understanding to extract subjects, text, barcodes, and rich semantic labels without any cloud round-trip.