Section 9/171 menit

9. Embeddings, Semantic Search, dan RAG di Device

9. Embeddings, Semantic Search, dan RAG di Device

Konsep Embeddings

Embedding = representasi vektor (array float) dari teks/image yang mencerminkan makna. Teks yang mirip secara makna → vektor yang mirip.

iOS punya NLEmbedding (built-in) — embedding kata atau kalimat tanpa cloud:

swift
// embeddings: Semantic similarity dengan NLEmbedding
import NaturalLanguage

let embedding = NLEmbedding.sentenceEmbedding(for: .english)!
let v1 = embedding.vector(for: "I love pizza")!
let v2 = embedding.vector(for: "Pizza is my favorite food")!
let v3 = embedding.vector(for: "The weather is sunny")!

func cosineSimilarity(_ a: [Double], _ b: [Double]) -> Double {
    let dot = zip(a, b).map(*).reduce(0, +)
    let normA = sqrt(a.map { $0 * $0 }.reduce(0, +))
    let normB = sqrt(b.map { $0 * $0 }.reduce(0, +))
    return dot / (normA * normB)
}

print(cosineSimilarity(v1, v2))  // ~0.85 (mirip)
print(cosineSimilarity(v1, v3))  // ~0.15 (beda)

RAG (Retrieval-Augmented Generation) di Device

RAG = mengirim konteks relevan ke LLM agar jawaban lebih akurat. Untuk dokumen pribadi user (notes, dokumen), RAG on-device adalah pendekatan privacy-friendly.

Arsitektur:

swift
1. Indexing (saat user tambah dokumen):
   - Chunk dokumen ke potongan 200-500 token
   - Generate embedding per chunk
   - Simpan ke local DB (SwiftData / SQLite)

2. Query (saat user tanya):
   - Generate embedding query
   - Cari chunk dengan similarity tertinggi (top-K)
   - Kirim chunk + query ke LLM (Foundation Models atau cloud)
   - Tampilkan jawaban dengan citation
swift
// rag: Simple on-device vector store
@Model
final class DocumentChunk {
    var documentID: UUID
    var content: String
    var embedding: [Double]
    var order: Int

    init(documentID: UUID, content: String, embedding: [Double], order: Int) {
        self.documentID = documentID
        self.content = content
        self.embedding = embedding
        self.order = order
    }
}

actor VectorStore {
    private let context: ModelContext
    private let embedder: NLEmbedding

    init(context: ModelContext) {
        self.context = context
        self.embedder = NLEmbedding.sentenceEmbedding(for: .english)!
    }

    func index(documentID: UUID, content: String) async throws {
        let chunks = chunkText(content, maxTokens: 300)
        for (i, chunk) in chunks.enumerated() {
            guard let vector = embedder.vector(for: chunk) else { continue }
            let docChunk = DocumentChunk(
                documentID: documentID,
                content: chunk,
                embedding: vector,
                order: i
            )
            context.insert(docChunk)
        }
        try context.save()
    }

    func search(query: String, topK: Int = 5) async throws -> [DocumentChunk] {
        guard let queryVec = embedder.vector(for: query) else { return [] }
        let all = try context.fetch(FetchDescriptor<DocumentChunk>())
        let scored = all.map { chunk in
            (chunk, cosineSimilarity(chunk.embedding, queryVec))
        }
        return scored.sorted { $0.1 > $1.1 }.prefix(topK).map { $0.0 }
    }

    private func chunkText(_ text: String, maxTokens: Int) -> [String] {
        // Simple paragraph splitter; production pakai tokenizer proper
        text.components(separatedBy: "\n\n").filter { !$0.isEmpty }
    }
}

Cara Pakai dengan LLM

swift
// rag: Compose RAG dengan Foundation Models
import FoundationModels

func answer(query: String, store: VectorStore) async throws -> String {
    let relevantChunks = try await store.search(query: query, topK: 3)
    let context = relevantChunks.map(\.content).joined(separator: "\n\n")

    let prompt = """
    Berdasarkan konteks berikut:

    \(context)

    Jawab pertanyaan: \(query)

    Kalau jawaban tidak ada di konteks, katakan tidak tahu.
    """

    let session = LanguageModelSession()
    let response = try await session.respond(to: prompt)
    return response.content
}

Kapan RAG Penting

  • App notes / journal / dokumen pribadi user.
  • Knowledge base perusahaan yang harus privat.
  • Q&A atas dataset spesifik (legal, medical, financial).