-
Profundización en la estructura Foundation Models
Sube de nivel con la estructura Foundation Models. Aprende cómo funciona la generación guiada y usa guías, expresiones regulares y esquemas de generación para obtener respuestas estructuradas personalizadas. Te mostraremos cómo usar la llamada de herramientas para permitir que el modelo acceda de forma autónoma a información externa y realice acciones, para una experiencia personalizada.
Para aprovechar al máximo este video, recomendamos ver primero “Conoce la estructura Foundation Models”.Capítulos
- 0:00 - Introducción
- 0:49 - Sesiones
- 7:57 - Generable
- 14:29 - Esquemas dinámicos
- 18:10 - Llamada de herramientas
Recursos
- Generate dynamic game content with guided generation and tools
- Human Interface Guidelines: Generative AI
Videos relacionados
WWDC25
-
Buscar este video…
-
-
1:05 - Prompting a session
import FoundationModels func respond(userInput: String) async throws -> String { let session = LanguageModelSession(instructions: """ You are a friendly barista in a world full of pixels. Respond to the player’s question. """ ) let response = try await session.respond(to: userInput) return response.content } -
3:37 - Handle context size errors
var session = LanguageModelSession() do { let answer = try await session.respond(to: prompt) print(answer.content) } catch LanguageModelSession.GenerationError.exceededContextWindowSize { // New session, without any history from the previous session. session = LanguageModelSession() } -
3:55 - Handling context size errors with a new session
var session = LanguageModelSession() do { let answer = try await session.respond(to: prompt) print(answer.content) } catch LanguageModelSession.GenerationError.exceededContextWindowSize { // New session, with some history from the previous session. session = newSession(previousSession: session) } private func newSession(previousSession: LanguageModelSession) -> LanguageModelSession { let allEntries = previousSession.transcript.entries var condensedEntries = [Transcript.Entry]() if let firstEntry = allEntries.first { condensedEntries.append(firstEntry) if allEntries.count > 1, let lastEntry = allEntries.last { condensedEntries.append(lastEntry) } } let condensedTranscript = Transcript(entries: condensedEntries) // Note: transcript includes instructions. return LanguageModelSession(transcript: condensedTranscript) } -
6:14 - Sampling
// Deterministic output let response = try await session.respond( to: prompt, options: GenerationOptions(sampling: .greedy) ) // Low-variance output let response = try await session.respond( to: prompt, options: GenerationOptions(temperature: 0.5) ) // High-variance output let response = try await session.respond( to: prompt, options: GenerationOptions(temperature: 2.0) ) -
7:06 - Handling languages
var session = LanguageModelSession() do { let answer = try await session.respond(to: userInput) print(answer.content) } catch LanguageModelSession.GenerationError.unsupportedLanguageOrLocale { // Unsupported language in prompt. } let supportedLanguages = SystemLanguageModel.default.supportedLanguages guard supportedLanguages.contains(Locale.current.language) else { // Show message return } -
8:14 - Generable
@Generable struct NPC { let name: String let coffeeOrder: String } func makeNPC() async throws -> NPC { let session = LanguageModelSession(instructions: ...) let response = try await session.respond(generating: NPC.self) { "Generate a character that orders a coffee." } return response.content } -
9:22 - NPC
@Generable struct NPC { let name: String let coffeeOrder: String } -
10:49 - Generable with enum
@Generable struct NPC { let name: String let encounter: Encounter @Generable enum Encounter { case orderCoffee(String) case wantToTalkToManager(complaint: String) } } -
11:20 - Generable with guides
@Generable struct NPC { @Guide(description: "A full name") let name: String @Guide(.range(1...10)) let level: Int @Guide(.count(3)) let attributes: [Attribute] let encounter: Encounter @Generable enum Attribute { case sassy case tired case hungry } @Generable enum Encounter { case orderCoffee(String) case wantToTalkToManager(complaint: String) } } -
13:40 - Regex guide
@Generable struct NPC { @Guide(Regex { Capture { ChoiceOf { "Mr" "Mrs" } } ". " OneOrMore(.word) }) let name: String } session.respond(to: "Generate a fun NPC", generating: NPC.self) // > {name: "Mrs. Brewster"} -
14:50 - Generable riddle
@Generable struct Riddle { let question: String let answers: [Answer] @Generable struct Answer { let text: String let isCorrect: Bool } } -
15:10 - Dynamic schema
struct LevelObjectCreator { var properties: [DynamicGenerationSchema.Property] = [] mutating func addStringProperty(name: String) { let property = DynamicGenerationSchema.Property( name: name, schema: DynamicGenerationSchema(type: String.self) ) properties.append(property) } mutating func addArrayProperty(name: String, customType: String) { let property = DynamicGenerationSchema.Property( name: name, schema: DynamicGenerationSchema( arrayOf: DynamicGenerationSchema(referenceTo: customType) ) ) properties.append(property) } var root: DynamicGenerationSchema { DynamicGenerationSchema( name: name, properties: properties ) } } var riddleBuilder = LevelObjectCreator(name: "Riddle") riddleBuilder.addStringProperty(name: "question") riddleBuilder.addArrayProperty(name: "answers", customType: "Answer") var answerBuilder = LevelObjectCreator(name: "Answer") answerBuilder.addStringProperty(name: "text") answerBuilder.addBoolProperty(name: "isCorrect") let riddleDynamicSchema = riddleBuilder.root let answerDynamicSchema = answerBuilder.root let schema = try GenerationSchema( root: riddleDynamicSchema, dependencies: [answerDynamicSchema] ) let session = LanguageModelSession() let response = try await session.respond( to: "Generate a fun riddle about coffee", schema: schema ) let generatedContent = response.content let question = try generatedContent.value(String.self, forProperty: "question") let answers = try generatedContent.value([GeneratedContent].self, forProperty: "answers") -
18:47 - FindContactTool
import FoundationModels import Contacts struct FindContactTool: Tool { let name = "findContact" let description = "Finds a contact from a specified age generation." @Generable struct Arguments { let generation: Generation @Generable enum Generation { case babyBoomers case genX case millennial case genZ } } func call(arguments: Arguments) async throws -> ToolOutput { let store = CNContactStore() let keysToFetch = [CNContactGivenNameKey, CNContactBirthdayKey] as [CNKeyDescriptor] let request = CNContactFetchRequest(keysToFetch: keysToFetch) var contacts: [CNContact] = [] try store.enumerateContacts(with: request) { contact, stop in if let year = contact.birthday?.year { if arguments.generation.yearRange.contains(year) { contacts.append(contact) } } } guard let pickedContact = contacts.randomElement() else { return ToolOutput("Could not find a contact.") } return ToolOutput(pickedContact.givenName) } } -
20:26 - Call FindContactTool
import FoundationModels let session = LanguageModelSession( tools: [FindContactTool()], instructions: "Generate fun NPCs" ) -
21:55 - FindContactTool with state
import FoundationModels import Contacts class FindContactTool: Tool { let name = "findContact" let description = "Finds a contact from a specified age generation." var pickedContacts = Set<String>() ... func call(arguments: Arguments) async throws -> ToolOutput { contacts.removeAll(where: { pickedContacts.contains($0.givenName) }) guard let pickedContact = contacts.randomElement() else { return ToolOutput("Could not find a contact.") } return ToolOutput(pickedContact.givenName) } } -
22:27 - GetContactEventTool
import FoundationModels import EventKit struct GetContactEventTool: Tool { let name = "getContactEvent" let description = "Get an event with a contact." let contactName: String @Generable struct Arguments { let day: Int let month: Int let year: Int } func call(arguments: Arguments) async throws -> ToolOutput { ... } }
-
-
- 0:00 - Introducción
Obtén información sobre la estructura Foundation Models para dispositivos Apple, que proporciona un modelo de lenguaje grande en el dispositivo accesible a través de la API de Swift. Se explica cómo usar Generable para obtener resultados estructurados, esquemas dinámicos y llamadas de herramientas para funcionalidades personalizadas.
- 0:49 - Sesiones
En este ejemplo, Foundation Models mejora un juego de cafetería de pixel art generando diálogos y contenido de juego dinámicos. Mediante la creación de una LanguageModelSession, se proporcionan instrucciones personalizadas al modelo, lo que le permite responder a las preguntas de los jugadores. El modelo procesa la entrada del usuario y las instrucciones de la sesión en tokens, pequeñas subcadenas, que luego utiliza para generar nuevas secuencias de tokens como salida. LanguageModelSession tiene estado y registra todas las indicaciones y respuestas en una transcripción. Puedes usar esta transcripción para depurar y mostrar el historial de conversaciones en la interfaz de usuario del juego. Sin embargo, existe un límite para el tamaño de la sesión, conocido como límite de contexto. La generación de respuestas no es determinista por defecto. El modelo utiliza muestreo, creando una distribución de probabilidades para cada token, lo que introduce aleatoriedad. Esta aleatoriedad se puede controlar mediante la API GenerationOptions, que permite ajustar el método de muestreo o la temperatura, o incluso configurarlo como codicioso para obtener una salida determinista. Más allá del diálogo simple, Foundation Models se puede utilizar para generar resultados más complejos, como nombres y pedidos de café para personajes no jugables (NPC). Esto agrega profundidad y variedad al mundo del juego, de modo que es más real e interactivo. También debes considerar posibles problemas como idiomas no compatibles y manejarlos con cuidado para brindar una experiencia de usuario fluida.
- 7:57 - Generable
La API Generable de Foundation Models es una herramienta poderosa que simplifica la obtención de datos estructurados de modelos de lenguaje de gran tamaño. Al aplicar la macro @Generable a las estructuras o enumeraciones de Swift, se genera un esquema en tiempo de compilación que guía el resultado del modelo. Generable genera automáticamente un inicializador y maneja el análisis del texto generado del modelo en objetos Swift de tipo seguro usando decodificación restringida. Esta técnica garantiza que el resultado del modelo se adhiera al esquema especificado, evitando alucinaciones y errores estructurales. Puedes personalizar aún más el proceso de generación utilizando “Guías”, que proporcionan restricciones, rangos o descripciones en lenguaje natural para propiedades específicas. Esto permite un mayor control sobre los datos generados, como especificar formatos de nombres, recuentos de matrices o rangos numéricos. Generable permite una generación de datos eficiente y confiable, de modo que los desarrolladores se pueden concentrar en aspectos más complejos de sus aplicaciones.
- 14:29 - Esquemas dinámicos
En el creador de niveles del juego, los esquemas dinámicos permiten a los jugadores definir entidades personalizadas en tiempo de ejecución. Estos esquemas, similares a las estructuras de tiempo de compilación, tienen propiedades con nombres y tipos, lo que permite matrices y referencias a otros esquemas dinámicos. A partir de la entrada del jugador, se crea un esquema de acertijo con una pregunta (cadena) y una matriz de respuestas (tipo personalizado con cadena y propiedades booleanas). Estos esquemas dinámicos se validan y, luego, se utilizan para generar contenido mediante Foundation Models, lo que garantiza que el resultado coincida con la estructura definida. Este enfoque dinámico permite que el juego muestre acertijos creados por los jugadores y otras entidades en una IU dinámica, lo que proporciona un alto grado de flexibilidad y creatividad para los jugadores y, al mismo tiempo, mantiene un manejo de datos estructurado.
- 18:10 - Llamada de herramientas
Con Foundation Models, los desarrolladores de juegos pueden crear DLC personalizado mediante llamadas a herramientas. Esto permite que el modelo obtenga de forma autónoma información del dispositivo del jugador, como contactos y calendario, preservando al mismo tiempo la privacidad porque los datos nunca salen del dispositivo. Definir una herramienta implica especificar un nombre, una descripción y argumentos de entrada. El modelo utiliza esta información para decidir cuándo y cómo llamar a la herramienta. Luego, la implementación de la herramienta interactúa con API externas, como la API de Contacts, para recuperar datos.