Qwen3.5 Chat (LLM no dispositivo)
Qwen3.5-0.8B e um modelo hibrido DeltaNet (atencao linear) + GatedAttention com 24 camadas (18 DeltaNet + 6 GatedAttention), quantizado para INT4 em MLX (GPU Metal) e INT8 em CoreML (Neural Engine). Roda em Mac via MLX ou em iPhone e Mac via CoreML com geracao de tokens em streaming. Projetado para voice pipelines onde um LLM no dispositivo fornece o "cerebro" entre ASR e TTS.
Qwen3.5 Chat integra-se com o VoicePipeline do SpeechCore como componente LLM em cadeias ASR → LLM → TTS. A arquitetura hibrida DeltaNet fornece atencao eficiente em tempo linear para contextos longos.
Inicio rapido
import Qwen3Chat
let chat = try await Qwen35MLXChat.fromPretrained()
// Single response
let response = try chat.generate(messages: [
ChatMessage(role: .system, content: "Answer briefly."),
ChatMessage(role: .user, content: "What is Swift?")
])
print(response)
// Streaming tokens
let stream = chat.generateStream(messages: [
ChatMessage(role: .system, content: "Be funny."),
ChatMessage(role: .user, content: "Tell me a joke")
])
for try await token in stream {
print(token, terminator: "")
}
Arquitetura
Qwen3.5-0.8B e um modelo hibrido com 24 camadas: 18 camadas DeltaNet (atencao linear com recorrencia de regra delta gated e RMSNormGated) e 6 camadas GatedAttention (scaled dot-product attention padrao). O backend MLX roda inferencia na GPU Metal com pesos safetensors. O backend CoreML usa uma arquitetura de modelo duplo (prefill + decode) otimizada para o Neural Engine. Ambos suportam KV cache com prompt caching e sampling configuravel (temperatura, top-k, top-p, penalizacao de repeticao).
I/O do modelo
| Direcao | Nome | Formato | Descricao |
|---|---|---|---|
| Entrada | input_ids | [1, seq_len] | IDs de token (Int32) |
| Entrada | attention_mask | [1, seq_len] | Mascara de atencao (Int32) |
| Entrada | kv_cache | por camada | Estado do key-value cache |
| Saida | logits | [1, 1, 151936] | Logits do proximo token (Float16) |
| Saida | kv_cache_out | por camada | KV cache atualizado |
Variantes do modelo
| Variante | Quantizacao | Tamanho | Computacao | HuggingFace |
|---|---|---|---|---|
| Qwen3.5-0.8B Chat | INT4 | 418 MB | GPU Metal (MLX) | aufklarer/Qwen3.5-0.8B-Chat-MLX |
| Qwen3.5-0.8B Chat | INT8 | 981 MB | Neural Engine (CoreML) | aufklarer/Qwen3.5-0.8B-Chat-CoreML |
Configuracao de sampling
let config = ChatSamplingConfig(
temperature: 0.7,
topK: 40,
topP: 0.9,
maxTokens: 128,
repetitionPenalty: 1.1
)
let response = try chat.generate(
messages: [ChatMessage(role: .user, content: "Explain gravity")],
sampling: config
)
| Parametro | Padrao | Descricao |
|---|---|---|
temperature | 0.6 | Aleatoriedade (0 = greedy, 1 = criativo) |
topK | 50 | Manter os K melhores candidatos |
topP | 0.95 | Limiar de nucleus sampling |
maxTokens | 512 | Maximo de tokens de resposta |
repetitionPenalty | 1.1 | Penalizar tokens repetidos |
disableThinking | false | Pular o modo de pensamento |
maxThinkingTokens | 100 | Limitar tokens de pensamento |
Conversa multi-turno
let chat = try await Qwen35MLXChat.fromPretrained()
let history = [
ChatMessage(role: .system, content: "Remember the user's name."),
ChatMessage(role: .user, content: "My name is Alex"),
ChatMessage(role: .assistant, content: "Nice to meet you, Alex!"),
ChatMessage(role: .user, content: "What's my name?")
]
let response = try chat.generate(messages: history)
print(response) // "Your name is Alex!"
chat.resetState() // Clear inference state for a new conversation
Gerenciamento de memoria
// Check memory state
print(chat.isLoaded) // true
print(chat.memoryFootprint) // 438304768 (~418 MB)
// Free memory under pressure
chat.unload()
print(chat.isLoaded) // false
// Reload when needed
let chat = try await Qwen35MLXChat.fromPretrained()
No iPhone, descarregar o LLM antes da inferencia TTS libera ~418 MB (MLX INT4) ou ~981 MB (CoreML INT8), evitando terminacao por jetsam ao rodar pipelines completos ASR → LLM → TTS.
Desempenho
| Dispositivo | Prefill | Decode | Tokens/seg |
|---|---|---|---|
| M2 Max | ~50ms | ~65ms/tok | ~15 tok/s |
| iPhone 16 Pro | ~1.5s | ~450ms/tok | ~2.2 tok/s |
Conversao
Os pesos MLX sao convertidos a partir do checkpoint original Qwen3.5-0.8B usando o script de conversao MLX. Os modelos CoreML usam um script de conversao separado para implantacao no Neural Engine. Pesos pre-convertidos estao disponiveis no HuggingFace em aufklarer/Qwen3.5-0.8B-Chat-MLX (INT4: 418 MB) e aufklarer/Qwen3.5-0.8B-Chat-CoreML (INT8: 981 MB).