SwiftPM
Swift local retrieval guide
Install RetrievalKit with SwiftPM, build a local corpus, choose a query path, and persist native state on Apple platforms.
On this page
Install
Add the signed v0.1.0 package once, then select the smallest product your app needs.
.package(
url: "https://github.com/gungorbasa/RetrievalKit.git",
from: "0.1.0"
)
RetrievalKitprovides flat retrieval.RetrievalKitGraphprovides graph-only and graph-scoped retrieval.EmbeddingKitis an independent local embedding provider.RetrievalKitPipelinecomposes chunking, embedding, and indexing.
The published preview is qualified for macOS 14+ arm64 and iOS 15+ arm64 on physical devices and Apple-silicon simulators. Intel macOS and x86_64 iOS simulators are not claimed.
Build a retrieval database
The application owns document IDs, text, metadata, and embeddings. The first non-empty embedding fixes the database dimension.
import RetrievalKit
let builder = try RetrievalDatabase.Builder(
corpusID: "project-notes",
encoding: .f32
)
try await builder.upsert(
Document(
id: "decision-swift",
text: "Apollo chose Swift for its Apple platform client.",
metadata: [
"project": .string("apollo"),
"status": .string("approved"),
]
),
embedding: [1, 0]
)
let database = try await builder.build()
Empty embeddings and dimension drift fail before the mutation is committed. Every document and query embedding in one database must come from the same model.
Search
One method covers exact vector, BM25, and hybrid retrieval. The provided arguments choose the mode.
let vectorHits = try await database.search(
embedding: queryEmbedding,
limit: 10
)
let textHits = try await database.search(
text: "private search",
limit: 10
)
let hybridHits = try await database.search(
text: "Why did we choose Swift?",
embedding: queryEmbedding,
alpha: 0.6,
limit: 10,
filter: .equals("project", .string("apollo"))
)
alpha is the vector weight. Use 1 for vector-only, 0 for BM25-only, or a
value between them for hybrid ranking. Metadata filters are hard constraints.
Scope with relationships
Use GraphDatabase when traversal is the result and no retrieval is needed.
Use GraphRetrievalDatabase when relationships should select candidates before
the same exact ranker runs.
let selection = try await graphRetrievalDatabase.query(
from: [GraphNodeID(nodeType: "Project", recordID: "apollo")],
traversing: [GraphTraversal(relationship: "contains")]
)
let hits = try await graphRetrievalDatabase.search(
text: "Why did we choose Swift?",
embedding: queryEmbedding,
alpha: 0.6,
within: selection,
limit: 1,
filter: .equals("status", .string("approved"))
)
The graph chooses the eligible neighborhood. It does not add a hidden score.
Persist and reload
Native persistence publishes a complete, checksummed database generation.
let snapshot = URL(fileURLWithPath: "project-notes.rk")
try await database.save(to: snapshot)
try RetrievalDatabase.validate(at: snapshot)
let reloaded = try RetrievalDatabase.load(from: snapshot)
Use the corresponding static methods on GraphDatabase or
GraphRetrievalDatabase for graph-capable snapshots.
Run the source quickstart
From the RetrievalKit repository root:
scripts/build-xcframework.sh --macos-only
scripts/run-swift-quickstart.sh base-retrieval
The expected first document ID is decision-swift.
Choose the database boundary
Three query paths
Compare the same job in Swift. These are separate APIs, not modes hidden behind one query.
Hybrid vector + BM25
RetrievalDatabaseRank the whole corpus with exact vector similarity and BM25.
let hits = try await retrievalDatabase.search(
text: "What did we decide about offline sync?",
embedding: queryEmbedding,
alpha: 0.6,
limit: 5
)Graph query alone
GraphDatabaseSelect records by relationship. No embedding or retrieval ranker is involved.
let selection = try await graphDatabase.query(
from: [GraphNodeID(
nodeType: "Notebook",
recordID: "product-research"
)],
traversing: [GraphTraversal(
relationship: "references"
)]
)Graph + vector + BM25
GraphRetrievalDatabaseSelect candidates with the graph, then rank only that scope with vector + BM25.
let selection = try await graphRetrievalDatabase.query(
from: [GraphNodeID(
nodeType: "Project",
recordID: "mobile-app"
)],
traversing: [GraphTraversal(
relationship: "contains"
)]
)
let hits = try await graphRetrievalDatabase.search(
text: "Why is cold start slow on Android?",
embedding: queryEmbedding,
alpha: 0.6,
within: selection,
limit: 5
)