본문으로 건너뛰기
cccskills
무료GitHub에 공개

swift-mlx-lm

Build Swift apps that run language and vision-language models locally on Apple Silicon with MLX. The skill covers streaming responses, tool calls, memory coordination, LoRA fine-tuning, text embeddings for search, and porting model architectures to Swift.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

원문원문 설명 보기

MLX Swift LM - Run LLMs and VLMs on Apple Silicon using MLX. Covers local inference, streaming, wired memory coordination, tool calling, LoRA fine-tuning, embeddings, and model porting.

kellyvv/PhoneClaw스타 1,284(GitHub 1,284 + cccskills 0)
연동 도구Hugging Face

실행 점수 미검증

설치 방법 보기

이럴 때 유용합니다

  • Running a local language model in a Swift app
  • Streaming model responses or processing images and video
  • Adding tool calls to model responses
  • Fine-tuning a model with LoRA adapters
  • Generating embeddings or porting a model to Swift

포함된 파일(13)

  • SKILL.md14.4 KB
  • references/concurrency.md8.3 KB
  • references/embeddings.md8.0 KB
  • references/generation.md3.9 KB
  • references/kv-cache.md7.1 KB
  • references/lora-adapters.md7.6 KB
  • references/model-container.md8.7 KB
  • references/model-porting.md13.4 KB
  • references/supported-models.md7.2 KB
  • references/tokenizer-chat.md7.4 KB
  • references/tool-calling.md8.9 KB
  • references/training.md9.0 KB
  • references/wired-memory.md3.7 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

mlx-swift-lm Skill

1. Overview & Triggers

mlx-swift-lm is a Swift package for running Large Language Models (LLMs) and Vision-Language Models (VLMs) on Apple Silicon using MLX. It supports local inference, streaming generation, wired-memory coordination, tool calling, LoRA/DoRA fine-tuning, and embeddings.

When to Use This Skill

  • Running LLM/VLM inference on macOS/iOS with Apple Silicon
  • Streaming text generation from local models
  • Coordinating concurrent inference with wired-memory policies and tickets
  • Tool calling / function calling with models
  • LoRA adapter training and fine-tuning
  • Text embeddings for RAG/semantic search
  • Porting model architectures from Python MLX-LM to Swift

Architecture Overview

MLXLMCommon     - Core infra (ModelContainer, ChatSession, Evaluate, KVCache, wired memory helpers)
MLXLLM          - Text-only LLM support (Llama, Qwen, Gemma, Phi, DeepSeek, etc.)
MLXVLM          - Vision-Language Models (Qwen-VL, PaliGemma, Gemma3, etc.)
MLXEmbedders    - Embedding models and pooling utilities

2. Key File Reference

PurposeFile Path
Thread-safe model wrapperLibraries/MLXLMCommon/ModelContainer.swift
Simplified chat APILibraries/MLXLMCommon/ChatSession.swift
Generation & streaming APIsLibraries/MLXLMCommon/Evaluate.swift
KV cache typesLibraries/MLXLMCommon/KVCache.swift
Wired-memory policiesLibraries/MLXLMCommon/WiredMemoryPolicies.swift
Wired-memory measurement helpersLibraries/MLXLMCommon/WiredMemoryUtils.swift
Model configurationLibraries/MLXLMCommon/ModelConfiguration.swift
Chat message typesLibraries/MLXLMCommon/Chat.swift
Tool call processingLibraries/MLXLMCommon/Tool/ToolCallFormat.swift
Concurrency utilitiesLibraries/MLXLMCommon/Utilities/SerialAccessContainer.swift
LLM factory & registryLibraries/MLXLLM/LLMModelFactory.swift
VLM factory & registryLibraries/MLXVLM/VLMModelFactory.swift
LoRA configurationLibraries/MLXLMCommon/Adapters/LoRA/LoRAContainer.swift
LoRA trainingLibraries/MLXLLM/LoraTrain.swift

3. Quick Start

LLM Chat (Simplest API)

import MLXLLM
import MLXLMCommon
import MLXLMHuggingFace  // from swift-huggingface-mlx
import MLXLMTokenizers   // from swift-tokenizers-mlx

let modelContainer = try await LLMModelFactory.shared.loadContainer(
    from: HubClient.default,
    using: TokenizersLoader(),
    configuration: .init(id: "mlx-community/Qwen3-4B-4bit")
)

let session = ChatSession(modelContainer)

let response = try await session.respond(to: "What is Swift?")
print(response)

for try await chunk in session.streamResponse(to: "Explain structured concurrency") {
    print(chunk, terminator: "")
}

VLM with Image

import MLXVLM
import MLXLMCommon
import MLXLMHuggingFace  // from swift-huggingface-mlx
import MLXLMTokenizers   // from swift-tokenizers-mlx

let modelContainer = try await VLMModelFactory.shared.loadContainer(
    from: HubClient.default,
    using: TokenizersLoader(),
    configuration: .init(id: "mlx-community/Qwen2-VL-2B-Instruct-4bit")
)

let session = ChatSession(modelContainer)
let image = UserInput.Image.url(imageURL)

let response = try await session.respond(
    to: "Describe this image",
    image: image,
    video: nil
)

Embeddings

import MLXEmbedders
import MLXEmbeddersHuggingFace  // from swift-huggingface-mlx
import MLXLMTokenizers          // from swift-tokenizers-mlx

let container = try await loadModelContainer(
    from: HubClient.default,
    using: TokenizersLoader(),
    configuration: ModelConfiguration(id: "mlx-community/bge-small-en-v1.5-mlx")
)

let embeddings = await container.perform { model, tokenizer, pooler in
    let tokens = tokenizer.encode(text: "Hello world")
    let input = MLXArray(tokens).expandedDimensions(axis: 0)
    let output = model(input)
    let pooled = pooler(output, normalize: true)
    eval(pooled)
    return pooled
}

4. Primary Workflow: LLM Inference

ChatSession API (Recommended)

ChatSession manages conversation history and KV cache automatically:

let session = ChatSession(
    modelContainer,
    instructions: "You are a helpful assistant",
    generateParameters: GenerateParameters(maxTokens: 500, temperature: 0.7)
)

let r1 = try await session.respond(to: "What is 2+2?")
let r2 = try await session.respond(to: "And if you multiply that by 3?")

await session.clear()

Streaming with ModelContainer.generate(...)

For lower-level control, prepare UserInput and generate directly:

let userInput = UserInput(prompt: "Hello")
let lmInput = try await modelContainer.prepare(input: userInput)

let stream = try await modelContainer.generate(
    input: lmInput,
    parameters: GenerateParameters()
)

for await generation in stream {
    switch generation {
    case .chunk(let text):
        print(text, terminator: "")
    case .toolCall(let call):
        print("Tool call: \(call.function.name)")
    case .info(let info):
        print("\nStop reason: \(info.stopReason)")
        print("\(info.tokensPerSecond) tok/s")
    }
}

Generation API Surface (Evaluate.swift)

Use these depending on your control needs:

  • generate(input:..., context:..., wiredMemoryTicket:) -> AsyncStream<Generation>: decoded text + tool calls.
  • generateTask(..., wiredMemoryTicket:) -> (AsyncStream<Generation>, Task<Void, Never>): same output, plus task handle for deterministic cleanup when consumers stop early.
  • generateTokens(..., wiredMemoryTicket:) -> AsyncStream<TokenGeneration>: raw token IDs.
  • generateTokensTask(..., wiredMemoryTicket:) -> (AsyncStream<TokenGeneration>, Task<Void, Never>): raw tokens + task handle.
  • GenerateStopReason: .stop, .length, .cancelled in final .info.

See references/generation.md for full patterns.

Tool Calling

struct WeatherInput: Codable { let location: String }
struct WeatherOutput: Codable { let temperature: Double; let conditions: String }

let weatherTool = Tool<WeatherInput, WeatherOutput>(
    name: "get_weather",
    description: "Get current weather",
    parameters: [.required("location", type: .string, description: "City name")]
) { _ in
    WeatherOutput(temperature: 22.0, conditions: "Sunny")
}

let userInput = UserInput(
    prompt: .text("What's the weather in Tokyo?"),
    tools: [weatherTool.schema]
)

let lmInput = try await modelContainer.prepare(input: userInput)
let stream = try await modelContainer.generate(input: lmInput, parameters: GenerateParameters())

for await generation in stream {
    switch generation {
    case .chunk(let text):
        print(text, terminator: "")
    case .toolCall(let call):
        let result = try await call.execute(with: weatherTool)
        print("\nWeather: \(result.conditions)")
    case .info:
        break
    }
}

See references/tool-calling.md for multi-turn tool loops.

GenerateParameters

let params = GenerateParameters(
    maxTokens: 1000,            // nil = unlimited
    maxKVSize: 4096,            // Sliding window (RotatingKVCache)
    kvBits: 4,                  // Quantized cache (4 or 8)
    kvGroupSize: 64,            // Quantization group size
    quantizedKVStart: 0,        // Token index to start KV quantization
    temperature: 0.7,           // 0 = greedy / argmax
    topP: 0.9,                  // Nucleus sampling
    repetitionPenalty: 1.1,     // Penalize repeats
    repetitionContextSize: 20,  // Penalty window
    prefillStepSize: 512        // Prompt prefill chunk size
)

Wired Memory (Optional)

Use policy tickets to coordinate concurrent inference memory:

let policy = WiredSumPolicy()
let ticket = policy.ticket(size: estimatedBytes, kind: .active)

let userInput = UserInput(prompt: "Summarize this text")
let lmInput = try await modelContainer.prepare(input: userInput)

let stream = try await modelContainer.generate(
    input: lmInput,
    parameters: GenerateParameters(),
    wiredMemoryTicket: ticket
)

for await generation in stream {
    if case .chunk(let text) = generation {
        print(text, terminator: "")
    }
}

For policy selection, reservations, and measurement-based budgeting, see references/wired-memory.md.

Prompt Caching / History Re-hydration

let history: [Chat.Message] = [
    .system("You are helpful"),
    .user("Hello"),
    .assistant("Hi there!")
]

let session = ChatSession(modelContainer, history: history)

5. Secondary Workflow: VLM Inference

Image Input Types

let imageFromURL = UserInput.Image.url(fileURL)
let imageFromCI = UserInput.Image.ciImage(ciImage)
let imageFromArray = UserInput.Image.array(mlxArray)

Video Input

let videoFromURL = UserInput.Video.url(videoURL)
let videoFromAsset = UserInput.Video.avAsset(avAsset)
let videoFromFrames = UserInput.Video.frames(videoFrames)

let response = try await session.respond(to: "What happens in this video?", video: videoFromURL)

Multiple Images

let images: [UserInput.Image] = [.url(url1), .url(url2)]
let response = try await session.respond(to: "Compare these two images", images: images, videos: [])

VLM-Specific Processing

let session = ChatSession(
    modelContainer,
    processing: UserInput.Processing(resize: CGSize(width: 512, height: 512))
)

6. Best Practices

DO

// DO: Prefer ChatSession for multi-turn chat UX
let session = ChatSession(modelContainer)

// DO: Prepare UserInput before container-level generation
let userInput = UserInput(prompt: "Hello")
let lmInput = try await modelContainer.prepare(input: userInput)

// DO: Use task-handle variants for early-stop scenarios
let (stream, task) = generateTask(
    promptTokenCount: lmInput.text.tokens.size,
    modelConfiguration: context.configuration,
    tokenizer: context.tokenizer,
    iterator: iterator
)
for await item in stream {
    if shouldStop { break }
}
await task.value

// DO: Use wired tickets when coordinating concurrent workloads
let ticket = WiredSumPolicy().ticket(size: estimatedBytes)
let _ = try await modelContainer.generate(input: lmInput, parameters: params, wiredMemoryTicket: ticket)

DON'T

// DON'T: Skip prepare(input:) before container-level generation.
// ModelContainer.generate expects LMInput, not UserInput.

// DON'T: Share MLXArray across tasks (not Sendable)
let array = MLXArray(...)
Task { _ = array.sum() } // wrong

// DON'T: Ignore task completion after early-break on low-level streams
for await item in stream {
    if shouldStop { break }
}
// await task.value is required for deterministic cleanup

Thread Safety

  • ModelContainer is Sendable and thread-safe.
  • ChatSession is not thread-safe; use one session per task/flow.
  • MLXArray is not Sendable; keep it inside one isolation domain or use SendableBox transfer patterns.

Memory Management

let slidingWindow = GenerateParameters(maxKVSize: 4096)
let quantizedKV = GenerateParameters(kvBits: 4, kvGroupSize: 64)
await session.clear()

7. Reference Links

ReferenceWhen to Use
references/model-container.mdLoading models, ModelContainer API, ModelConfiguration
references/generation.mdgenerate, generateTask, raw token streaming APIs
references/wired-memory.mdWired tickets, policies, budgeting, reservations
references/kv-cache.mdCache types, memory optimization, cache serialization
references/concurrency.mdThread safety, SerialAccessContainer, async patterns
references/tool-calling.mdFunction calling, tool formats, ToolCallProcessor
references/tokenizer-chat.mdTokenizer, Chat.Message, EOS tokens
references/supported-models.mdModel families, registries, model-specific config
references/lora-adapters.mdLoRA/DoRA/QLoRA, loading adapters
references/training.mdLoRATrain API, fine-tuning
references/embeddings.mdEmbeddingModel, pooling, use cases
references/model-porting.mdPorting models from Python MLX-LM to Swift

8. Deprecated Patterns Summary

If you see...Use instead...
generate(... didGenerate:) callbackAsyncStream-based generation APIs
perform { model, tokenizer in }perform { context in }
TokenIterator(prompt: MLXArray)TokenIterator(input: LMInput)
ModelRegistry typealiasLLMRegistry or VLMRegistry
createAttentionMask(h:cache:[KVCache]?)createAttentionMask(h:cache:KVCache?)

9. Automatic vs Manual Configuration

Automatic Behaviors

FeatureDetails
EOS token loadingLoaded from config.json
EOS overridegeneration_config.json > config.json > defaults
EOS mergingAll sources merged at generation time
EOS detectionStops generation when EOS encountered
Chat template applicationApplied by tokenizer / processor path
Tool call format detectionInferred from model_type in config.json
Cache type selectionDriven by GenerateParameters (maxKVSize, kvBits)
Tokenizer loadingLoaded automatically from model assets
Model weight loadingDownloaded and loaded from Hugging Face/local directory

Optional Configuration

FeatureWhen to Configure
extraEOSTokensModel has unlisted stop tokens
toolCallFormatOverride auto-detected tool parser format
maxKVSizeEnable sliding window cache
kvBits, kvGroupSize, quantizedKVStartEnable and tune KV quantization
prefillStepSizeTune prompt prefill chunking/perf tradeoff
wiredMemoryTicketCoordinate policy-based wired-memory limits

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Calendar

무료

Create calendar events, check schedules, and review how busy a day or week is. It can summarize key appointments and use available time windows to help identify when a meeting might fit.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Adding a product review meeting to the calendar
  • Checking today’s or tomorrow’s schedule
  • Reviewing this week’s workload and open time
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

Clipboard

무료

Read the current text from the system clipboard or copy text into it when asked. This skill helps check copied content and prepare text for pasting elsewhere, with writing performed only when the user explicitly requests it.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Checking what is currently on the clipboard
  • Copying a drafted message for pasting
  • Reading copied text before using it
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

Contacts

무료

Search contacts for phone numbers or email addresses, save new contact details, update existing records, or delete a selected contact. When a deletion could match multiple people, the skill asks which entry the user means.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Looking up a contact's phone number
  • Saving a new contact with a name and phone number
  • Updating a contact's company or email
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

Health

무료

Summarizes HealthKit data such as steps, activity, sleep, heart rate, and weight on the device. Use it to check a single metric or request a combined report for a chosen period; it only reads data and does not upload it.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Checking today's or yesterday's step count
  • Reviewing recent sleep or heart-rate readings
  • Getting a weekly or monthly health summary
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

Reminders

무료

Create a reminder with a title and the time the user specifies. The skill asks for whichever detail is missing before creating it, so each reminder has both something to remember and a time to be notified.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Setting a reminder to send a file at a stated time
  • Creating a reminder to buy something tomorrow
  • Adding a timed task after providing its title and due time
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

swift-mlx

무료

Use MLX in Swift to work with arrays and build neural networks on Apple Silicon. The skill covers automatic differentiation for gradients, model training with optimizers, performance compilation, custom Metal kernels, and memory coordination for concurrent work.

한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.

  • Creating and manipulating MLX arrays
  • Building a neural network in Swift
  • Calculating gradients and training a model
kellyvv/PhoneClaw1.3천2026년 8월 6일 업데이트

kellyvv의 스킬 모두 보기

이 스킬의 문제 신고