
裝置端語意搜尋:無需伺服器的 AI 搜尋
如何建構完全在使用者手機上運行的語意搜尋。本地嵌入、向量相似度和自然語言查詢,無需伺服器或 API 即可搜尋使用者內容。
當使用者不知道確切的詞彙時,關鍵字搜尋就會失敗。「上週那封關於預算會議的電子郵件」無法匹配主旨為「第三季財務審查」的郵件。語意搜尋理解意義,而非僅僅是關鍵字。
標準做法是將語意搜尋放在具有向量資料庫的伺服器上。但對於使用者內容在本地的行動應用(筆記、訊息、照片、文件),將該內容發送到伺服器就違背了將其保留在裝置 上的初衷。
裝置端語意搜尋讓一切保持在本地。嵌入模型在手機上運行。向量索引存在本地儲存中。搜尋查詢永遠不會離開裝置。
語意搜尋的工作原理
- 索引: 每段內容使用小型模型轉換為嵌入向量(一組代表其意義的數字)
- 儲存: 嵌入向量與內容一起儲存在本地資料庫中
- 查詢: 使用者的搜尋查詢使用相同的模型轉換為嵌入向量
- 比對: 查詢向量使用餘弦相似度與所有已儲存的向量進行比較
- 排序: 結果按相似度分數排序返回
奧妙在於嵌入。關於同一主題的兩段文字會產生相似的向量,即使它們沒有共同的關鍵字。
嵌入模型
裝置端嵌入模型小巧且快速。 不同於生成式 LLM(600MB-1.7GB),嵌入模型通常為 20-80MB:
| 模型 | 大小 | 維度 | 速度(iPhone 15) |
|---|---|---|---|
| all-MiniLM-L6-v2 | 23MB | 384 | 500+ 嵌入/秒 |
| nomic-embed-text-v1.5 | 55MB | 768 | 200+ 嵌入/秒 |
| bge-small-en-v1.5 | 33MB | 384 | 400+ 嵌入/秒 |
以每秒 200-500 個嵌入的速度,索引 1,000 則筆記只需 2-5 秒。查詢嵌入幾乎是即時的(5ms 以內)。
運行嵌入模型
你可以透過以下方式運行嵌入模型:
ONNX Runtime Mobile: 支援 ONNX 格式的嵌入模型。可用於 iOS(透過 Swift)和 Android(透過 Kotlin)。對於行動端嵌入推論來說,這是最成熟的選項。
// iOS 使用 ONNX Runtime
let session = try ORTSession(env: env, modelPath: embeddingModelPath)
let inputTensor = try ORTValue(tensorData: tokenizedInput, shape: shape)
let outputs = try session.run(withInputs: ["input_ids": inputTensor])
let embedding = outputs["embeddings"]!.tensorData()
llama.cpp 嵌入模式: llama.cpp 可以使用嵌入旗標從 GGUF 模型生成嵌入。這讓你可以使用同一個推論引擎進行生成和嵌入。
向量儲存
SQLite 搭配自訂擴充
行動端最簡單的方法:將向量作為 BLOB 儲存在 SQLite 中,並在應用程式碼中計算相似度。
// Android:儲存嵌入
fun storeEmbedding(db: SQLiteDatabase, contentId: Long, embedding: FloatArray) {
val blob = ByteBuffer.allocate(embedding.size * 4)
embedding.forEach { blob.putFloat(it) }
db.execSQL(
"INSERT INTO embeddings (content_id, vector) VALUES (?, ?)",
arrayOf(contentId, blob.array())
)
}
// 按相似度搜尋
fun search(db: SQLiteDatabase, queryEmbedding: FloatArray, limit: Int): List<SearchResult> {
val cursor = db.rawQuery("SELECT content_id, vector FROM embeddings", null)
val results = mutableListOf<SearchResult>()
while (cursor.moveToNext()) {
val blob = cursor.getBlob(1)
val stored = FloatArray(blob.size / 4)
ByteBuffer.wrap(blob).asFloatBuffer().get(stored)
val similarity = cosineSimilarity(queryEmbedding, stored)
results.add(SearchResult(cursor.getLong(0), similarity))
}
return results.sortedByDescending { it.similarity }.take(limit)
}
這種方法簡單,適用於最多約 10,000 個項目的集合 。超過此數,線性掃描會變慢。
SQLite 搭配向量擴充
對於更大的集合,使用支援近似最近鄰(ANN)搜尋的 SQLite 向量擴充:
- sqlite-vss: 使用 Faiss 進行向量搜尋的 SQLite 擴充。支援 iOS 和 Android。
- sqlite-vec: 專為嵌入式使用設計的輕量級向量搜尋擴充。
這些擴充在向量上建立索引,使數十萬個項目的搜尋在毫秒以下完成。
完整流程
步驟 1:索引內容
當使用者建立或修改內容(筆記、訊息、文件)時,生成並儲存其嵌入:
func indexContent(_ content: Content) async {
let embedding = await embeddingModel.encode(content.text)
database.storeEmbedding(contentId: content.id, vector: embedding)
}
在背景運行索引。使用者不應等待嵌入計算完成。
步驟 2:搜尋
當使用者輸入搜尋查詢時:
func search(query: String) async -> [Content] {
let queryEmbedding = await embeddingModel.encode(query)
let results = database.similaritySearch(queryEmbedding, limit: 10)
return results.map { fetchContent($0.contentId) }
}
搜尋按語意相似度排序返回結果。「預算會議筆記」能匹配到「第三季財務審查」,因為嵌入捕捉了語意關係。
步驟 3:混合搜尋
結合語意搜尋與關鍵字搜尋以獲得最佳結果:
- 運行關鍵字搜尋(SQLite FTS5)進行精確匹配
- 運行語意搜尋進行基於意義的匹配
- 合併並去除重複結果
- 按綜合分數排序(關鍵字匹配優先提升)
這同時處理了精確查詢(「與 John 的會議」)和模糊查詢(「那封關於專案時程的郵件」)。
效能預算
| 元件 | 儲存 | RAM | 速度 |
|---|---|---|---|
| 嵌入模型 | 23-55MB | 推論時 50-100MB | 200-500 嵌入/秒 |
| 向量索引(10K 項,384d) | 約 15MB | 約 15MB | 每次搜尋 5ms 以內 |
| 向量索引(100K 項,384d) | 約 150MB | 約 30MB(使用 ANN 索引) | 每次搜尋 10ms 以內 |
語意搜尋的總額外佔用:40-200MB 儲存、65-130MB 搜尋時 RAM。這只是生成式 LLM 所需的一小部分,即使在受限裝置上也是可行的。
使用案例
筆記應用
按意義搜尋所有筆記。「上週關於產品發布的會議記錄」能找到相關筆記,無論確切用詞為何。
郵件用戶端
按主題而非僅按寄件者或主旨找到郵件。「關於合約續約的對話」找出正確的郵件串。
照片應用
搭配影像描述(裝置端)實現基於文字的照片搜尋。「海邊的日落」即使沒有手動標記也能找到匹配的照片。
文件管理器
按內容和意義搜尋 PDF、文件和檔案。
搭配裝置端 LLM 使用
語意搜尋與裝置端生成模型自然搭配。使用搜尋結果作為 LLM 的上下文:
- 使用者提出問題
- 語意搜尋從使用者資料中檢索相關內容
- LLM 使用檢索到的內容作為上下文生成答案
這就是裝置端 RAG。無需伺服器。整個流程(嵌入、搜尋、生成)都在本地運行。
對於生成元件,使用像 Ertas 這樣的平台在你的領域資料上微調模型。微調模型搭配本地語意搜尋,創造出強大且完全私密的 AI 助手。
Ship AI that runs on your users' devices.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Ship AI that runs on your users' devices.
Early bird pricing starts at $14.50/mo — locked in for life. Plans for builders and agencies.
Keep reading

Building an On-Device AI Assistant for Your Mobile App
Architecture patterns for building a conversational AI assistant that runs entirely on the user's device. Model selection, conversation management, UI patterns, and production considerations.

On-Device Text Classification for Mobile Apps
How to build fast, accurate text classification that runs on the user's phone. Sentiment analysis, content categorization, intent detection, and spam filtering without an API call.

On-Device Content Generation: AI Drafts That Work Offline
How to build AI-powered drafting features that work without internet. Email replies, message suggestions, note expansion, and content templates generated entirely on the user's device.