Exploring the @Generable and @Guide Macros in FoundationModels


Greetings, traveler!

Swift macros offer a powerful mechanism for code generation, enabling developers to reduce boilerplate and improve clarity. The FoundationModels framework introduces a new macros, designed to streamline data generation for specific model types using language models.

Overview of @Generable

The @Generable macro can be applied to a Swift struct to indicate that instances of this type may be generated by a language model. When this macro is used, the compiler automatically synthesizes necessary conformances and methods to support streaming responses from a language model session.

@Generable
struct ShoppingItem: Identifiable {
    let id: String
    let value: String
}

In this example, the ShoppingItem struct becomes compatible with automatic generation logic provided by the framework. Each instance of ShoppingItem is expected to be created based on structured output from a language model.

Optionally, a description can be provided to define the context or intent behind the generation:

@Generable(description: "Generate items for a grocery shopping list")
struct ShoppingItem: Identifiable {
    let id: String
    let value: String
}

This description helps guide the language model toward more accurate results during the generation process.

Using @Guide for Property-Level Context

For more granular control over how individual properties are interpreted by the language model, the @Guide macro can be applied to specific properties. This allows developers to provide additional instructions directly related to each property’s expected content.

@Generable(description: "Generate items for a grocery shopping list")
struct ShoppingItem: Identifiable {
    let id: String

    @Guide(description: "Name of the product to buy")
    let value: String
}

Each @Guide annotation serves as a directive for the language model when generating values for corresponding fields.

Integration in an App

Once a model is marked with @Generable, it can be used within a LanguageModelSession to request data. A typical use case involves triggering a generation task in response to user input.

private func generateShoppingList() {
    let prompt = "Create 15 shopping list items"
    Task {
        do {
            let session = LanguageModelSession()
            
            let response = session.streamResponse(
                generating: [ShoppingItem].self
            ) {
                prompt
            }
            
            isGenerating = true
            
            for try await chunk in response {
                self.shoppingList = chunk.compactMap {
                    guard let id = $0.id, let task = $0.value else {
                        return nil
                    }
                    
                    return ShoppingItem(id: id, value: task)
                }
            }
            
            isGenerating = false
        } catch {
            print(error.localizedDescription)
            isGenerating = false
        }
    }
}

In this snippet, the streamResponse(generating:prompt:) method initiates a streaming request for an array of ShoppingItem instances. As chunks of results arrive, they are processed and appended to the view’s state.

Now, let’s integrate it into our SwiftUI View:

struct ContentView: View {
    @State private var shoppingList: [ShoppingItem] = []
    @State private var isGenerating: Bool = false
    
    var body: some View {
        List(shoppingList) { item in
            Text(item.value)
        }
        .toolbar {
            ToolbarItem(placement: .bottomBar) {
                Button(
                    "Generate shopping list",
                    systemImage: "cart.fill.badge.plus"
                ) {
                    generateShoppingList()
                }
                .disabled(isGenerating)
            }
        }
    }
    
    private func generateShoppingList() {
        ...
    }
}

Conclusion

The @Generable macro provides a clean and declarative way to integrate language model-based generation into Swift applications. Combined with @Guide, it offers a structured approach to defining both model-level and field-level expectations for generated data.