Макросы @Generable и @Guide для генерации данных с LLM в Swift | AiManual
AiManual Logo Ai / Manual.
05 Апр 2026 Гайд

Макросы @Generable и @Guide в Foundation Models: гайд по структурированной генерации данных

Как использовать макросы Swift @Generable и @Guide для структурированной генерации данных с Foundation Models. Полное руководство на 2026 год.

Зачем эти макросы? (Потому что вручную - это ад)

Представьте: вы пишете приложение, которое использует LLM для генерации структурированных данных. Например, создание описаний товаров из сырого текста. Или извлечение сущностей из документов. Каждый раз вам нужно определить структуру Swift, сделать ее Codable, написать валидацию, сериализацию... Это сотни строк кода. И если модель меняется, вы переписываете все.

Звучит знакомо? Тогда читайте дальше.

@Generable и @Guide: магия, но с документацией

Эти два макроса - часть экосистемы Swift для работы с LLM. На 05.04.2026, они входят в состав Swift Transformers 2.3 и полностью совместимы с Apple Foundation Models 2.2. Если вы работаете на Mac с M-серией, это ваш выбор.

@Generable автоматически генерирует код для структур, которые могут быть использованы с LLM. @Guide добавляет метаданные-инструкции для модели, подсказывая, как генерировать данные для каждого поля.

Важно: макросы в Swift все еще развиваются. В Swift 6.2 они стабильны, но иногда компилятор может ругаться на сложные случаи. Держите документацию под рукой.

1Установка: добавляем зависимости

Откройте ваш Package.swift. Добавьте зависимость от Swift Transformers. На 05.04.2026, последняя версия - 2.3.1.

dependencies: [
    .package(url: "https://github.com/apple/swift-transformers", from: "2.3.1")
]

Затем добавьте цель в ваш target.

Если вы используете Foundation Models, убедитесь, что у вас установлена версия 2.2 или выше. Подробнее в нашем гайде по Foundation Models.

2Определяем модель с @Generable

Допустим, мы хотим генерировать данные о книгах. Вот как это выглядит с @Generable.

import SwiftTransformers

@Generable
struct Book {
    var title: String
    var author: String
    var year: Int
    var genres: [String]
}

Макрос @Generable автоматически генерирует расширение, которое делает Book совместимым с LLM. Он добавляет протоколы, Codable, и даже базовую валидацию.

Как это работает? Во время компиляции макрос разворачивается в код. Вы можете увидеть сгенерированный код в Xcode, нажав на стрелку рядом с макросом.

Совет: если макрос не разворачивается, проверьте, включена ли поддержка макросов в схеме проекта. В Xcode 16 (2025) это включено по умолчанию.

3Добавляем инструкции с @Guide

Теперь, чтобы LLM понимала, что генерировать, мы добавляем @Guide к свойствам. Это как промпты, но на уровне свойств.

@Generable
struct Book {
    @Guide("Название книги, максимально креативное")
    var title: String
    
    @Guide("Автор книги в формате 'Фамилия Имя'")
    var author: String
    
    @Guide("Год издания, от 1800 до 2026")
    var year: Int
    
    @Guide("Жанры, например: фантастика, драма, детектив")
    var genres: [String]
}

Эти инструкции используются LLM при генерации. Они превращаются в системный промпт, который направляет модель.

Вы можете добавлять сложные инструкции. Например, для числовых полей можно указать диапазон. Для массивов - минимальное и максимальное количество элементов.

4Интеграция с LLM: отправляем запрос

Теперь, используем нашу структуру с Foundation Models. Предположим, у нас есть модель afm-2b-small.

import FoundationModels

let model = try await AFMModel.load("afm-2b-small")
let prompt = "Сгенерируйте данные о книге в стиле фэнтези."

let result: Book = try await model.generate(from: prompt, as: Book.self)
print(result.title) // Например: "Путь ветра"

Модель вернет экземпляр Book, заполненный на основе промпта и инструкций @Guide.

Это работает, потому что @Generable генерирует все необходимое для сериализации и десериализации. А @Guide обеспечивает контекст для модели.

Если вы используете другие LLM, например, через Swift Transformers, процесс аналогичен. Подробнее о локальных LLM в статье по Swift Transformers.

5Обработка и валидация: что делать, если модель ошибается

LLM не идеальны. Иногда они генерируют некорректные данные. Например, год может быть вне диапазона.

@Generable автоматически добавляет валидацию? Не совсем. Он генерирует код, который может выбросить ошибку при декодировании, если типы не совпадают. Но для сложной валидации нужно добавить свое.

Расширим нашу структуру:

@Generable
struct Book {
    // ... свойства с @Guide ...
    
    func validate() throws {
        if year < 1800 || year > 2026 {
            throw ValidationError.invalidYear
        }
        if genres.isEmpty {
            throw ValidationError.noGenres
        }
    }
}

Затем, после генерации, вызывайте validate().

Или используйте макрос @Validate, если он доступен в вашей версии. В Swift Transformers 2.3 есть экспериментальный макрос @Validate, но он не стабилен.

Полный пример: от промпта до данных

Вот как выглядит полный цикл в приложении.

import SwiftTransformers
import FoundationModels

@Generable
struct Product {
    @Guide("Название продукта, краткое и запоминающееся")
    var name: String
    
    @Guide("Цена в рублях, целое число")
    var price: Int
    
    @Guide("Категории, например: электроника, одежда, продукты")
    var categories: [String]
    
    @Guide("Описание продукта, 2-3 предложения")
    var description: String
}

struct ProductGenerator {
    let model: AFMModel
    
    init() async throws {
        model = try await AFMModel.load("afm-2b-small")
    }
    
    func generate(from text: String) async throws -> Product {
        let prompt = "Сгенерируйте описание продукта на основе: \(text)"
        let product: Product = try await model.generate(from: prompt, as: Product.self)
        try product.validate()
        return product
    }
}

// Использование
let generator = try await ProductGenerator()
let product = try await generator.generate(from: "Смартфон с хорошей камерой и долгим временем работы")
print(product.name) // Например: "Фотофон X"

Этот код готов к использованию. Вы можете адаптировать его под свои нужды.

Если вам нужно генерировать много продуктов, используйте асинхронные потоки. Но помните о ограничениях модели.

Для сложных задач, таких как генерация игровых миров, ознакомьтесь с этим туториалом. Там используются другие техники, но принципы похожи.

Нюансы, которые заставят вас плакать

1. Производительность: каждый макрос разворачивается во время компиляции. Если у вас сложные структуры с множеством полей, компиляция может замедлиться. Но в Swift 6.2 это оптимизировано.

2. Ошибки компиляции: если макрос не может сгенерировать код, вы получите неясную ошибку. Читайте сгенерированный код, чтобы понять проблему. Часто дело в типах, которые не поддерживаются.

3. Поддержка типов: @Generable работает с базовыми типами Swift, массивами, словарями, опционалами. Но для пользовательских типов нужно, чтобы они тоже были @Generable. Это может привести к рекурсии.

4. Инструкции @Guide: они превращаются в текст, который добавляется в промпт. Если инструкций много, промпт становится длинным. Это может повлиять на производительность LLM и стоимость (если вы используете облачные модели).

5. Совместимость с другими библиотеками: если вы используете другие методы структурированного вывода, могут быть конфликты. Убедитесь, что вы не смешиваете подходы.

Сравнение: макросы vs. ручное определение

КритерийМакросыРучной код
Объем кодаМинимальныйБольшой
Поддержка измененийЛегкоТрудоемко
Производительность компиляцииМедленнееБыстрее
ГибкостьОграничена макросамиПолная

Что в будущем? (Спойлер: больше макросов)

На 05.04.2026, Apple анонсировала Foundation Models 3.0, которая будет включать встроенную поддержку макросов @Generable и @Guide. Это значит, что интеграция станет еще проще.

Также, сообщество Swift работает над макросами для валидации, трансформации данных и даже для генерации UI из моделей LLM. Загляните в LoopCoder для вдохновения.

Мой совет: начните с макросов сейчас. Да, они имеют недостатки, но они экономят время. И когда вы привыкнете, вы не захотите возвращаться к ручному коду.

А если вы столкнетесь с проблемами, напишите мне. Я помогу. (Шутка. Но вы можете поискать ответы в других статьях, например, про SAE Steering или Knowledge Graph.)

Подписаться на канал