davideisinger.com

My personal website
Log | Files | Refs | README

nshipster-com-b3vpys.txt (13094B)


      1 [1]
      2 
      3 [2]Ollama
      4 
      5 Written by [3]Mattt February 14^th, 2025
      6 
      7 
      8     “Only Apple can do this” Variously attributed to Tim Cook
      9 
     10 Apple introduced [4]Apple Intelligence at WWDC 2024. After waiting almost a
     11 year for Apple to, in Craig Federighi’s words, “get it right”, its promise of
     12 “AI for the rest of us” feels just as distant as ever.
     13 
     14 Can we take a moment to appreciate the name? Apple Intelligence. AI. That’s
     15 some S-tier semantic appropriation. On the level of jumping on “podcast” before
     16 anyone knew what else to call that.
     17 
     18 While we wait for Apple Intelligence to arrive on our devices, something
     19 remarkable is already running on our Macs. Think of it as a locavore approach
     20 to artificial intelligence: homegrown, sustainable, and available year-round.
     21 
     22 This week on NSHipster, we’ll look at how you can use Ollama to run LLMs
     23 locally on your Mac — both as an end-user and as a developer.
     24 
     25 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
     26 
     27 [5]What is Ollama?
     28 
     29 Ollama is the easiest way to run large language models on your Mac. You can
     30 think of it as “Docker for LLMs” - a way to pull, run, and manage AI models as
     31 easily as containers.
     32 
     33 Download Ollama with [6]Homebrew or directly from [7]their website. Then pull
     34 and run [8]llama3.2 (2GB).
     35 
     36 $ brew install --cask ollama
     37 $ ollama run llama3.2
     38 >>> Tell me a joke about Swift programming.
     39 What's a Apple developer's favorite drink?
     40 The Kool-Aid.
     41 
     42 Under the hood, Ollama is powered by [9]llama.cpp. But where llama.cpp provides
     43 the engine, Ollama gives you a vehicle you’d actually want to drive — handling
     44 all the complexity of model management, optimization, and inference.
     45 
     46 Similar to how Dockerfiles define container images, Ollama uses Modelfiles to
     47 configure model behavior:
     48 
     49 FROM mistral:latest
     50 PARAMETER temperature 0.7
     51 TEMPLATE """
     52 You are a helpful assistant.
     53 
     54 User: 
     55 Assistant: """
     56 
     57 Ollama uses the [10]Open Container Initiative (OCI) standard to distribute
     58 models. Each model is split into layers and described by a manifest, the same
     59 approach used by Docker containers:
     60 
     61 {
     62   "mediaType": "application/vnd.oci.image.manifest.v1+json",
     63   "config": {
     64     "mediaType": "application/vnd.ollama.image.config.v1+json",
     65     "digest": "sha256:..."
     66   },
     67   "layers": [
     68     {
     69       "mediaType": "application/vnd.ollama.image.layer.v1+json",
     70       "digest": "sha256:...",
     71       "size": 4019248935
     72     }
     73   ]
     74 }
     75 
     76 Overall, Ollama’s approach is thoughtful and well-engineered. And best of all,
     77 it just works.
     78 
     79 [11]What’s the big deal about running models locally?
     80 
     81 [12]Jevons paradox states that, as something becomes more efficient, we tend to
     82 use more of it, not less.
     83 
     84 Having AI on your own device changes everything. When computation becomes
     85 essentially free, you start to see intelligence differently.
     86 
     87 While frontier models like GPT-4 and Claude are undeniably miraculous, there’s
     88 something to be said for the small miracle of running open models locally.
     89 
     90   • Privacy: Your data never leaves your device. Essential for working with
     91     sensitive information.
     92   • Cost: Run 24/7 without usage meters ticking. No more rationing prompts like
     93     ’90s cell phone minutes. Just a fixed, up-front cost for unlimited
     94     inference.
     95   • Latency: No network round-trips means faster responses. Your /M\d Mac((Book
     96     ( Pro| Air)?)|Mini|Studio)/ can easily generate dozens of tokens per
     97     second. (Try to keep up!)
     98   • Control: No black-box [13]RLHF or censorship. The AI works for you, not the
     99     other way around.
    100   • Reliability: No outages or API quota limits. 100% uptime for your [14]
    101     exocortex. Like having Wikipedia on a thumb drive.
    102 
    103 [15]Building macOS Apps with Ollama
    104 
    105 Ollama also exposes an [16]HTTP API on port 11431 ([17]leetspeak for llama 🦙).
    106 This makes it easy to integrate with any programming language or tool.
    107 
    108 To that end, we’ve created the [18]Ollama Swift package to help developers
    109 integrate Ollama into their apps.
    110 
    111 [19]Text Completions
    112 
    113 The simplest way to use a language model is to generate text from a prompt:
    114 
    115 import Ollama
    116 
    117 let client = Client.default
    118 let response = try await client.generate(
    119     model: "llama3.2",
    120     prompt: "Tell me a joke about Swift programming.",
    121     options: ["temperature": 0.7]
    122 )
    123 print(response.response)
    124 // How many Apple engineers does it take to document an API? 
    125 // None - that's what WWDC videos are for.
    126 
    127 [20]Chat Completions
    128 
    129 For more structured interactions, you can use the chat API to maintain a
    130 conversation with multiple messages and different roles:
    131 
    132 let initialResponse = try await client.chat(
    133     model: "llama3.2",
    134     messages: [
    135         .system("You are a helpful assistant."),
    136         .user("What city is Apple located in?")
    137     ]
    138 )
    139 print(initialResponse.message.content)
    140 // Apple's headquarters, known as the Apple Park campus, is located in Cupertino, California.
    141 // The company was originally founded in Los Altos, California, and later moved to Cupertino in 1997.
    142 
    143 let followUp = try await client.chat(
    144     model: "llama3.2",
    145     messages: [
    146         .system("You are a helpful assistant."),
    147         .user("What city is Apple located in?"),
    148         .assistant(initialResponse.message.content),
    149         .user("Please summarize in a single word")
    150     ]
    151 )
    152 print(followUp.message.content)
    153 // Cupertino
    154 
    155 [21]Generating text embeddings
    156 
    157 [22]Embeddings convert text into high-dimensional vectors that capture semantic
    158 meaning. These vectors can be used to find similar content or perform semantic
    159 search.
    160 
    161 For example, if you wanted to find documents similar to a user’s query:
    162 
    163 let documents: [String] = …
    164 
    165 // Convert text into vectors we can compare for similarity
    166 let embeddings = try await client.embeddings(
    167     model: "nomic-embed-text",
    168     texts: documents
    169 )
    170 
    171 /// Finds relevant documents
    172 func findRelevantDocuments(
    173     for query: String,
    174     threshold: Float = 0.7, // cutoff for matching, tunable
    175     limit: Int = 5
    176 ) async throws -> [String] {
    177     // Get embedding for the query
    178     let [queryEmbedding] = try await client.embeddings(
    179         model: "llama3.2",
    180         texts: [query]
    181     )
    182 
    183     // See: https://en.wikipedia.org/wiki/Cosine_similarity
    184     func cosineSimilarity(_ a: [Float], _ b: [Float]) -> Float {
    185         let dotProduct = zip(a, b).map(*).reduce(0, +)
    186         let magnitude = { sqrt($0.map { $0 * $0 }.reduce(0, +)) }
    187         return dotProduct / (magnitude(a) * magnitude(b))
    188     }
    189 
    190     // Find documents above similarity threshold
    191     let rankedDocuments = zip(embeddings, documents)
    192         .map { embedding, document in
    193             (similarity: cosineSimilarity(embedding, queryEmbedding),
    194              document: document)
    195         }
    196         .filter { $0.similarity >= threshold }
    197         .sorted { $0.similarity > $1.similarity }
    198         .prefix(limit)
    199 
    200     return rankedDocuments.map(\.document)
    201 }
    202 
    203 For simple use cases, you can also use Apple’s [23]Natural Language framework
    204 for text embeddings. They’re fast and don’t require additional dependencies.
    205 
    206 import NaturalLanguage
    207 
    208 let embedding = NLEmbedding.wordEmbedding(for: .english)
    209 let vector = embedding?.vector(for: "swift")
    210 
    211 [24]Building a RAG System
    212 
    213 Embeddings really shine when combined with text generation in a RAG (Retrieval
    214 Augmented Generation) workflow. Instead of asking the model to generate
    215 information from its training data, we can ground its responses in our own
    216 documents by:
    217 
    218  1. Converting documents into embeddings
    219  2. Finding relevant documents based on the query
    220  3. Using those documents as context for generation
    221 
    222 Here’s a simple example:
    223 
    224 let query = "What were AAPL's earnings in Q3 2024?"
    225 let relevantDocs = try await findRelevantDocuments(query: query)
    226 let context = """
    227     Use the following documents to answer the question.
    228     If the answer isn't contained in the documents, say so.
    229 
    230     Documents:
    231     \(relevantDocs.joined(separator: "\n---\n"))
    232 
    233     Question: \(query)
    234     """
    235 
    236 let response = try await client.generate(
    237     model: "llama3.2",
    238     prompt: context
    239 )
    240 
    241 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    242 
    243 To summarize: Different models have different capabilities.
    244 
    245   • Models like [25]llama3.2 and [26]deepseek-r1 generate text.
    246       □ Some text models have “base” or “instruct” variants, suitable for
    247         fine-tuning or chat completion, respectively.
    248       □ Some text models are tuned to support [27]tool use, which let them
    249         perform more complex tasks and interact with the outside world.
    250   • Models like [28]llama3.2-vision can take images along with text as inputs.
    251 
    252   • Models like [29]nomic-embed-text create numerical vectors that capture
    253     semantic meaning.
    254 
    255 With Ollama, you get unlimited access to a wealth of these and many more
    256 open-source language models.
    257 
    258 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
    259 
    260 So, what can you build with all of this?
    261 Here’s just one example:
    262 
    263 [30]Nominate.app
    264 
    265 [31]Nominate is a macOS app that uses Ollama to intelligently rename PDF files
    266 based on their contents.
    267 
    268 Like many of us striving for a paperless lifestyle, you might find yourself
    269 scanning documents only to end up with cryptically-named PDFs like
    270 Scan2025-02-03_123456.pdf. Nominate solves this by combining AI with
    271 traditional NLP techniques to automatically generate descriptive filenames
    272 based on document contents.
    273 
    274 
    275 The app leverages several technologies we’ve discussed:
    276 
    277   • Ollama’s API for content analysis via the ollama-swift package
    278   • Apple’s PDFKit for OCR
    279   • The Natural Language framework for text processing
    280   • Foundation’s DateFormatter for parsing dates
    281 
    282 Nominate performs all processing locally. Your documents never leave your
    283 computer. This is a key advantage of running models locally versus using cloud
    284 APIs.
    285 
    286 [32]Looking Ahead
    287 
    288     “The future is already here – it’s just not evenly distributed yet.”
    289     William Gibson
    290 
    291 Think about the timelines:
    292 
    293   • Apple Intelligence was announced last year.
    294   • Swift came out 10 years ago.
    295   • SwiftUI 6 years ago.
    296 
    297 If you wait for Apple to deliver on its promises, you’re going to miss out on
    298 the most important technological shift in a generation.
    299 
    300 The future is here today. You don’t have to wait. With Ollama, you can start
    301 building the next generation of AI-powered apps right now.
    302 
    303 NSMutableHipster
    304 
    305 Questions? Corrections? [33]Issues and [34]pull requests are always welcome.
    306 
    307 This article uses Swift version 6.0. Find status information for all articles
    308 on the [35]status page.
    309 
    310 Written by Mattt
    311 [36]Mattt
    312 
    313 [37]Mattt ([38]@mattt) is a writer and developer in Portland, Oregon.
    314 
    315 🅭 🅯 🄏 NSHipster.com is released under a [39]Creative Commons BY-NC License.
    316 
    317 
    318 References:
    319 
    320 [1] https://nshipster.com/
    321 [2] https://nshipster.com/ollama/
    322 [3] https://nshipster.com/authors/mattt/
    323 [4] https://www.apple.com/apple-intelligence/
    324 [5] https://nshipster.com/ollama/#what-is-ollama
    325 [6] https://brew.sh/
    326 [7] https://ollama.com/download
    327 [8] https://ollama.com/library/llama3.2
    328 [9] https://github.com/ggerganov/llama.cpp
    329 [10] https://opencontainers.org/
    330 [11] https://nshipster.com/ollama/#whats-the-big-deal-about-running-models-locally
    331 [12] https://en.wikipedia.org/wiki/Jevons_paradox
    332 [13] https://knowyourmeme.com/photos/2546581-shoggoth-with-smiley-face-artificial-intelligence
    333 [14] https://en.wiktionary.org/wiki/exocortex
    334 [15] https://nshipster.com/ollama/#building-macos-apps-with-ollama
    335 [16] https://github.com/ollama/ollama/blob/main/docs/api.md
    336 [17] https://en.wikipedia.org/wiki/Leet
    337 [18] https://github.com/mattt/ollama-swift
    338 [19] https://nshipster.com/ollama/#text-completions
    339 [20] https://nshipster.com/ollama/#chat-completions
    340 [21] https://nshipster.com/ollama/#generating-text-embeddings
    341 [22] https://en.wikipedia.org/wiki/Word_embedding
    342 [23] https://developer.apple.com/documentation/naturallanguage/
    343 [24] https://nshipster.com/ollama/#building-a-rag-system
    344 [25] https://ollama.com/library/llama3.2
    345 [26] https://ollama.com/library/deepseek-r1
    346 [27] https://ollama.com/blog/tool-support
    347 [28] https://ollama.com/library/llama3.2-vision
    348 [29] https://ollama.com/library/nomic-embed-text
    349 [30] https://nshipster.com/ollama/#nominateapp
    350 [31] https://github.com/nshipster/nominate
    351 [32] https://nshipster.com/ollama/#looking-ahead
    352 [33] https://github.com/NSHipster/articles/issues
    353 [34] https://github.com/NSHipster/articles/blob/master/2025-02-14-ollama.md
    354 [35] https://nshipster.com/status/
    355 [36] https://nshipster.com/authors/mattt/
    356 [37] https://github.com/mattt
    357 [38] https://twitter.com/mattt
    358 [39] https://creativecommons.org/licenses/by-nc/4.0/