Apple Foundation Models: o framework de LLM on-device, explicado
O framework Foundation Models dá a um app acesso direto, gratuito e offline ao mesmo modelo de linguagem grande no dispositivo que move o Apple Intelligence1. Sem chave de API, sem conta por token, sem ida e volta pela rede, sem dados saindo do dispositivo. Para uma categoria de recursos que antes significava uma LLM na nuvem e uma revisão de privacidade, o custo agora arredonda para zero. A troca é a capacidade: o modelo on-device é pequeno, a janela de contexto é finita e o framework traça linhas rígidas em torno do que ele faz e do que não faz. Conhecer essas linhas é o jogo inteiro.
Esta é a referência sobre o próprio framework: os tipos que você de fato chama, o único recurso que torna o uso dele valioso e o ponto em que você deveria parar e recorrer a algo maior.
TL;DR
LanguageModelSessioné o ponto de entrada. Crie uma, chamerespond(to:), receba o texto de volta. O contexto de múltiplos turnos vive na sessão; trabalho de turno único recebe uma sessão nova a cada vez2.- A geração guiada é a razão para usar este framework. Anote um tipo Swift com
@Generablee o modelo retorna esse tipo, preenchido e com tipos verificados, em vez de uma string que você precisa parsear3. - O protocolo
Toolpermite que o modelo chame seu código no meio da geração para buscar dados ou executar uma ação e, em seguida, incorpore o resultado de volta à resposta4. - Verifique
SystemLanguageModel.default.availabilityantes de fazer qualquer coisa. O modelo está ausente em dispositivos não elegíveis, com o Apple Intelligence desligado ou enquanto ele é baixado5. - A janela de contexto é real e pequena.
SystemLanguageModel.default.contextSizeinforma o orçamento de tokens compartilhado entre o prompt e a resposta6. Planeje para isso, ou a sessão lança um erro. - Requer iOS 26 e um dispositivo compatível com Apple Intelligence. Abaixo desse piso, o framework não existe.
O que o framework é, e o que não é
O Foundation Models não é um invólucro em torno de um endpoint na nuvem. O modelo vive no dispositivo, é distribuído junto com o sistema operacional e roda sobre o Neural Engine. Esse único fato orienta cada decisão de design na API e cada decisão que você toma ao usá-la.
O que você ganha: geração de texto, sumarização, classificação, extração, reescrita de formato curto e saída estruturada, tudo on-device e tudo de graça. O que você não ganha: um modelo de fronteira. A Apple construiu o modelo on-device para tarefas de linguagem focadas dentro de um app, não para raciocínio aberto, não para análise de documentos longos, não para conhecimento de mundo que você possa sondar. A Apple diz exatamente isso, e o enquadramento importa porque define expectativas que a API, de outra forma, deixaria você violar1.
O modelo mental que mantém você longe de problemas: trate o modelo on-device como um estagiário rápido, privado e gratuito, excelente em moldar texto e péssimo em conhecer fatos. Entregue a ele material e uma tarefa clara. Não faça perguntas que ele não tem como responder.
LanguageModelSession: o ponto de entrada
Toda interação começa com uma sessão.
import FoundationModels
let session = LanguageModelSession()
let response = try await session.respond(to: "Summarize this review in one sentence: \(reviewText)")
print(response.content)
A sessão mantém o estado da conversa. Cada chamada a respond(to:) é acrescentada à transcrição em andamento, então uma sessão que você mantém por perto lembra do que veio antes. Para um recurso de chat, é isso que você quer. Para tarefas independentes de uma única passada (resumir isto, classificar aquilo), crie uma sessão nova por chamada para que contexto velho não vaze e consuma seu orçamento de tokens2.
respond(to:) é async throws. Ela suspende enquanto o modelo trabalha e lança um erro quando a requisição excede a janela de contexto, quando o modelo está indisponível ou quando as salvaguardas rejeitam o conteúdo. Cada um desses casos é um ramo real que você trata, não uma exceção que você ignora.
Para uma UI responsiva, faça streaming em vez de esperar. streamResponse(to:) entrega saída parcial conforme o modelo a produz, o que transforma um travamento de três segundos em texto que aparece à medida que se forma7.
Geração guiada: o recurso que justifica o framework
Aqui está a parte que vale o preço da entrada. A maioria das integrações de LLM gasta um terço do código convencendo o modelo a cuspir JSON válido e os outros dois terços se defendendo das vezes em que ele falha mesmo assim. O Foundation Models elimina esse trabalho.
Anote um tipo Swift com @Generable, peça à sessão para gerá-lo, e o modelo retorna uma instância desse tipo, preenchida e com tipos seguros3:
@Generable
struct Recipe {
@Guide(description: "The dish name")
let title: String
@Guide(description: "Ingredients, each as 'quantity item'")
let ingredients: [String]
@Guide(description: "Total minutes, start to finish", .range(5...240))
let minutes: Int
}
let session = LanguageModelSession()
let response = try await session.respond(
to: "A weeknight pasta for two.",
generating: Recipe.self
)
let recipe = response.content // a Recipe, not a String
Sem parsing. Sem JSONDecoder. Sem laço de retentativa para saída malformada. A macro @Guide restringe campos individuais: uma descrição que o modelo lê como instrução, e limites opcionais como uma faixa numérica ou uma expressão regular que a saída precisa satisfazer8. O framework não pede educadamente ao modelo um número entre 5 e 240; ele restringe a decodificação para que o campo não possa vir de outra forma.
A disciplina que isso impõe é o valor de verdade. Você projeta o tipo de saída primeiro, em Swift, com o compilador conferindo. O modelo preenche um contrato que você definiu em vez de retornar prosa que você decifra por engenharia reversa. Para extração, preenchimento de formulários e qualquer recurso que transforme linguagem em dados, a geração guiada é a diferença entre uma demonstração e código que vai para produção.
Vale conhecer um controle: respond(to:generating:) deixa includeSchemaInPrompt com o padrão true, o que injeta a forma do seu tipo no prompt para inclinar o modelo em direção a ela. Deixe ligado, a menos que o modelo já conheça o formato do treinamento ou de turnos anteriores na sessão; desligar para economizar tokens em um formato que o modelo nunca viu é como você recebe lixo de volta9.
Chamada de ferramentas: deixando o modelo alcançar seu código
A geração guiada molda o que sai. A chamada de ferramentas muda o que entra. Uma ferramenta é um trecho do seu código que o modelo pode invocar no meio da geração para buscar uma informação que não tem ou executar uma ação e, então, continuar sua resposta usando o resultado4.
Uma ferramenta segue o protocolo Tool: um name, uma description que o modelo lê para decidir quando chamá-la, um tipo Arguments marcado com @Generable e um método call(arguments:) que faz o trabalho4:
struct FindContacts: Tool {
let name = "findContacts"
let description = "Find a specific number of contacts from the address book"
@Generable
struct Arguments {
@Guide(description: "How many contacts to return", .range(1...10))
let count: Int
}
func call(arguments: Arguments) async throws -> [String] {
// Fetch contacts, return formatted names.
}
}
let session = LanguageModelSession(tools: [FindContacts()])
let response = try await session.respond(to: "Draft a dinner invite to three of my contacts.")
O fluxo: o modelo decide que precisa de contatos, chama sua ferramenta com um count validado, você retorna dados e o modelo escreve o convite usando nomes reais. Os argumentos chegam com os tipos verificados pela mesma maquinaria de geração guiada, então você nunca extrai a intenção do modelo de texto livre. A descrição da ferramenta é sua única alavanca sobre quando o modelo decide recorrer a ela, então escreva-a como a documentação de uma função que outro engenheiro (sem nenhum outro contexto) precisa ler e usar corretamente.
Esta é também a costura onde o Foundation Models encontra o restante da história do agente. Uma ferramenta que o modelo on-device chama e um App Intent que o Apple Intelligence chama são superfícies diferentes com a mesma forma: uma capacidade nomeada, descrita e tipada. Projete a capacidade uma vez e você poderá expô-la pelas duas.
Disponibilidade: a verificação que você não pode pular
O modelo nem sempre está lá. Ele está ausente em dispositivos que não suportam o Apple Intelligence, quando o usuário o desligou e durante a janela em que o sistema operacional ainda está baixando os ativos do modelo. Distribua código que assume que o modelo existe e ele vai travar, degradar em silêncio ou congelar para uma parcela dos seus usuários que você nunca testou.
Verifique SystemLanguageModel.default.availability e ramifique conforme o motivo5:
switch SystemLanguageModel.default.availability {
case .available:
// Show the intelligence feature.
case .unavailable(.deviceNotEligible):
// Hide it. This device will never have the model.
case .unavailable(.appleIntelligenceNotEnabled):
// Prompt the user to turn on Apple Intelligence.
case .unavailable(.modelNotReady):
// Downloading or otherwise not ready yet. Try again later.
case .unavailable(let other):
// Unknown reason. Fail closed.
}
Os três motivos exigem três respostas de produto diferentes, e confundi-los é a forma mais comum de esses recursos parecerem quebrados. deviceNotEligible é permanente: esconda o recurso, não fique insistindo. appleIntelligenceNotEnabled é uma configuração que o usuário controla: um aviso único é justo. modelNotReady é temporário: tente de novo, não mostre um erro. Construa o caminho do indisponível com o mesmo cuidado que o caminho feliz, porque para uma fatia real de dispositivos ele é o único caminho.
Quando o modelo está disponível e você sabe que uma requisição está chegando, prewarm() na sessão aquece o modelo para que a primeira resposta real chegue mais rápido10. Vale a pena numa tela em que o usuário está prestes a agir, desperdício se você o chamar especulativamente.
A janela de contexto, e onde ela deixa de ser suficiente
SystemLanguageModel.default.contextSize informa o orçamento de tokens dentro do qual o modelo trabalha, e esse orçamento é compartilhado: prompt mais resposta, juntos, precisam caber6. O número é pequeno em relação a um modelo na nuvem, e você sente isso rápido em entradas reais. Um documento longo, um histórico de chat completo, um resultado de ferramenta gordo: qualquer um deles pode estourar o orçamento e fazer respond lançar um erro.
Daí decorrem dois modos de falha, e ambos cabem a você prevenir. Primeiro, o acúmulo lento: uma sessão de múltiplos turnos acumula transcrição até que mais um turno transborde. Administre isso iniciando sessões novas para trabalhos não relacionados e mantendo enxuta a entrada por turno. Segundo, a requisição única grande demais: um PDF de 20 páginas não cabe, ponto-final. Fatie-o, resuma os pedaços e então raciocine sobre os resumos (o map-reduce que engenheiros de LLM conhecem bem), ou aceite que a tarefa tem a forma errada para um modelo on-device.
A janela de contexto é o sinal mais limpo para a decisão que de fato importa com este framework: quando ficar no dispositivo e quando partir.
Quando não usar o Foundation Models
O framework é gratuito, privado e offline, o que torna tentador recorrer a ele em todo lugar. Resista. Vá além dele quando:
- Você precisa de raciocínio de verdade ou amplitude de conhecimento de mundo. O modelo on-device é pequeno por design. Raciocínio aberto, geração de código e análise profunda pertencem a um modelo de fronteira na nuvem. Pedir isso ao modelo on-device produz respostas confiantes e erradas.
- A entrada não cabe na janela de contexto e fatiar destruiria o significado. Algumas tarefas precisam enxergar tudo de uma vez.
- Você precisa de um modelo que você controla: um checkpoint específico, um fine-tune, pesos personalizados, versionamento determinístico ao longo das atualizações do sistema. A Apple distribui e atualiza o modelo no cronograma dela, não no seu.
- Você está abaixo do iOS 26 ou em um dispositivo não elegível. O framework simplesmente não está lá, e a verificação de disponibilidade vai dizer isso a cada execução.
Para os casos on-device que o framework não cobre (um modelo personalizado, seus próprios pesos, treinamento no dispositivo), a camada abaixo é o Core ML e o MLX da Apple. Para os casos que genuinamente precisam de escala, uma LLM na nuvem por trás de uma fronteira de privacidade ainda é a resposta honesta. O Foundation Models não substitui nenhum dos dois. Ele é a primeira escolha certa para trabalho de linguagem focado sobre texto que você já tem em mãos, e a escolha errada para todo o resto.
A habilidade que este framework recompensa não é o artesanato de prompts. É o bom gosto quanto ao escopo: alimentar o modelo com tarefas em que ele é bom, projetar tipos @Generable que capturam exatamente o que você precisa e reconhecer o momento em que o trabalho ultrapassa o tamanho do dispositivo. Construa com esses instintos e o modelo on-device faz uma quantidade surpreendente de trabalho real de graça. Ignore-os e você entrega um recurso que quebra para todo usuário cuja entrada passou um token do limite.
-
Apple Developer, visão geral do framework “Foundation Models”. A Apple descreve o framework como acesso ao modelo on-device que move o Apple Intelligence, adequado a tarefas de linguagem focadas como geração de texto, sumarização, classificação e saída estruturada, em vez de raciocínio aberto ou conhecimento de mundo. ↩↩
-
Apple Developer, “LanguageModelSession” e “Generating content and performing tasks with Foundation Models”. Uma sessão mantém o contexto de múltiplos turnos; a orientação da Apple é criar uma nova sessão para cada interação distinta de turno único. ↩↩
-
Apple Developer, “Generable” e “Prompting an on-device foundation model”. A macro
@Generablepermite que o framework retorne um valor Swift preenchido e com tipos verificados, em vez de uma string. ↩↩ -
Apple Developer, protocolo “Tool”. Define
protocol Tool<Arguments, Output>: Sendablecomname,descriptioneparameters: GenerationSchemaobrigatórios, além decall(arguments:) async throws -> Output. O tipoArgumentssegueConvertibleFromGeneratedContente normalmente é declarado@Generable. ↩↩↩ -
Apple Developer, “SystemLanguageModel.Availability” e seu
UnavailableReason. Casos:.availablee.unavailable(...)com os motivosdeviceNotEligible,appleIntelligenceNotEnabledemodelNotReady.SystemLanguageModel.default.isAvailableé o booleano de conveniência. ↩↩ -
Apple Developer, “SystemLanguageModel.contextSize”. Uma propriedade de instância (acessada por
SystemLanguageModel.default) documentada como o tamanho máximo de contexto, representando o total de tokens entre o prompt de entrada e a resposta gerada. ↩↩ -
Apple Developer, “LanguageModelSession.streamResponse(to:)”. Faz streaming da saída parcial gerada conforme o modelo a produz, para atualizações incrementais de UI. ↩
-
Apple Developer, “Guide(description:_:)”. Uma macro de mesmo nível que anexa uma descrição em linguagem natural e restrições opcionais (faixas numéricas, guias de expressão regular) a uma propriedade
@Generable. Requer iOS 26.0+. ↩ -
Apple Developer, “respond(to:schema:includeSchemaInPrompt:options:)”.
includeSchemaInPrompttemtruecomo padrão; a discussão da Apple recomenda manter o padrão a menos que o modelo já conheça o formato esperado. ↩ -
Apple Developer, “LanguageModelSession.prewarm()”. Pede ao framework para carregar os recursos do modelo antes de uma requisição conhecida que está por vir, para reduzir a latência da primeira resposta. ↩
-
Análise relacionada do autor: LLMs on-device com o Foundation Models da Apple, Adaptadores personalizados para o Foundation Models, Casos de uso do Foundation Models e Fluxos de trabalho agênticos no Foundation Models. O argumento sobre App Intents e a superfície de ferramentas é desenvolvido em App Intents são a nova API da Apple para o seu app. ↩