Skip to main content
Constrained generation forces the model to emit JSON matching a schema. Use the language’s native facility — Swift macros (@Generatable / @Guide) or Kotlin annotations (@Generatable / @Guide) — to define the structure, then set it on GenerationOptions. The schema is computed at compile time (Swift) or built from the kotlinx.serialization descriptor at runtime (Kotlin), and the model’s output decodes directly into your type.

Define the structured type

The @Generatable macro analyzes your struct at compile time and synthesizes the jsonSchema() method. All stored properties must carry a @Guide description.
Requires Swift 5.9+ (Swift macros). The @Generatable / @Guide macros ship in the LeapSDKMacros SPM product — add it to your target alongside LeapModelDownloader (or LeapSDK) if you use constrained generation.

Apply the schema in GenerationOptions

Embedding the schema in the prompt

Some models do better when the JSON Schema is also included in the prompt text. Both platforms expose a helper.
JSONSchemaGenerator.getJSONSchema(for:) ships in the LeapSDKMacros product (no try needed; it’s non-throwing — it just forwards to the macro-synthesized Joke.jsonSchema()).

Supported types

Composition types are supported as long as the leaf types are supported.

Complex nested structures

Best practices

Write descriptive @Guide annotations

The model uses them as natural-language hints about what each field should contain. Specific descriptions outperform generic ones.

Keep structures focused

Smaller, single-responsibility types produce better output than sprawling structures with twenty fields. If a type starts mixing concerns (profile + preferences + history), split it.

Lower temperature for structured output

Temperature 0.1–0.3 typically improves adherence to the schema — high-temperature sampling adds variation that doesn’t help when you need parseable JSON. Use the per-model defaults the LFM model cards recommend (e.g. 0.1 for instruct/VL, 0.3 for LFM2 text) and lower from there if the model strays.

Validate the decoded output

Even with constrained generation, you should handle parse failures gracefully. The model’s output is constrained against the schema but not against business invariants.

How it works

  1. Compile/load time@Generatable produces a JSON Schema for your type. (Swift: compile-time macro emits jsonSchema(); Kotlin: built at runtime from the kotlinx.serialization descriptor.)
  2. Configuration — Swift options.with(jsonSchema: T.jsonSchema()) (or GenerationOptionsCompat.setResponseFormat(jsonSchema:)) / Kotlin setResponseFormatType<T>() installs the schema as jsonSchemaConstraint on the generation options.
  3. Generation — the SDK constrains decoding so only tokens that produce schema-valid JSON are emitted. The model’s output is guaranteed to parse.

Error handling

Troubleshooting

“External macro implementation could not be found” (Swift) — clean the build folder, restart Xcode, verify Swift 5.9+. Generated JSON includes prose alongside the JSON object — common with low-quality prompts. Add “Reply with only the JSON object” to the user message, lower temperature, and filter .text content fragments before decoding. Model produces empty or trivial JSON — verify each @Guide description gives the model a concrete sense of what to fill in. Generic descriptions (“a string”) leave the model guessing.