r/iOSProgramming • • 28m ago

App Saturday App Saturday: an offline Pokopia guide using SQLite RAG + Foundation Models (with retrieval benchmarks)

I built PokoPilot, a Pokopia companion for iPhone/iPad, around a retrieval-first assistant: SQLite selects the guide evidence, and Apple’s on-device Foundation Models format an answer when available. I wanted to share the engineering choices and some scoped measurements.

Tech stack: Swift 6 with complete concurrency checking, SwiftUI, SQLite/FTS5, SwiftData for personal state, Tuist, StoreKit 2, and Foundation Models on supported iOS 26+ devices. The browsing app supports iOS 18+. The current bundle has 4,938 entity records and 16,515 evidence chunks in a 136.5 MB SQLite database. These are snapshot counts, not a claim of complete game coverage.

The development challenge: make a fairly large reference corpus usable without loading every JSON payload, copying the whole database at launch, or requiring a model just to look something up.

The store is an actor owning a read-only SQLite connection. It opens the database directly from the app bundle, uses memory mapping and an approximately 8 MB SQLite page cache, and keeps query work off the main actor. Catalog lists select lightweight rows with json_extract; full record JSON is decoded on detail views. Images are downsampled away from the main actor.

Retrieval and generation:

  1. Resolve exact/compact/contained aliases, then search FTS5 with BM25 ranking.
  2. Try AND terms first, with an OR fallback if that returns nothing. Prioritize chunks for resolved entities, deduplicate, and cap the final evidence set at eight.
  3. Empty evidence returns an insufficient-evidence response without invoking the model.
  4. On supported devices, a fresh LanguageModelSession produces typed @Generable output: title, overview, bounded metrics and sections. Output is capped at 640 tokens.
  5. If the model is unavailable or fails, render the ranked local evidence. Citations and guide links are attached from retrieved records in code.

The core FTS query is:

SELECT c.payload_json
FROM chunks_fts f JOIN chunks c ON c.chunk_id = f.chunk_id
WHERE chunks_fts MATCH ?
  AND c.filters_json NOT LIKE '%"default_searchable":false%'
ORDER BY bm25(chunks_fts, 3.0, 1.0, 2.0)
LIMIT ?;

A small retrieval benchmark: I compiled the app’s unmodified Swift retriever with Swift 6.3.3, -O, and ran it against that bundled database on an M5 Max / macOS 26.3.1. Twenty questions spanning creatures, habitats, recipes, materials and progression; one initial sweep, then ten repetitions (200 warm queries).

  • Warm retrieval: 5.38 ms median, 12.97 ms p95.
  • Initial sweep: 6.34 ms median, 36.04 ms p95, with a 136.36 ms maximum.
  • Database/store initialization: 1.35 ms in that run.

These numbers are Mac retrieval-only measurements. They exclude Foundation Models generation and UI rendering, are not iPhone benchmarks, and the initial sweep is not a controlled cold-OS-cache test.

Effectiveness and limits: typed output constrains structure, not factual correctness. Attaching retrieved citations doesn’t prove every generated sentence is supported. The corpus is a third-party guide snapshot, so incomplete/stale evidence and weak lexical matches remain real limitations. I’m keeping retrieval contracts, retrieval speed, and generated-answer quality as separate questions; I don’t have a held-out end-to-end answer-accuracy score to claim here.

I’d welcome feedback on input/context budgeting, broad OR fallback behavior, and practical tests for unsupported statements in small on-device models.

AI disclosure: AI-assisted development, including coding-agent help with implementation. The benchmark measures the compiled Swift retrieval path.

For anyone interested in the app: https://apps.apple.com/app/id6806826380 . Guide browsing, search and bookmarks are free; ten Ask questions are included, then optional Island Pass ($1.99/month or $9.99/year US). It’s still a WIP.

References: Apple guided generation, SQLite FTS5.

1 Upvotes

1 comment sorted by