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/