WWDC25 "Foundation Models 프레임워크 만나보기"

Ios_Roy·2025년 10월 21일

WWDC

목록 보기
9/13
post-thumbnail

1. Foundation Models 프레임워크란?

Foundation Models는 Swift 환경에서 프롬프트(prompt) 기반의 언어 모델을 쉽고 안전하게 사용할 수 있게 해주는 공식 Apple 프레임워크입니다. 핵심 특징은 다음과 같습니다:

  • 최신 LLM을 코드 한 줄로 연결
  • 자연어 텍스트/구조화 데이터 모두 생성 가능
  • Swift 구조체(type-safe)로 모델 출력을 바로 받음
  • 스트리밍(부분 생성), 툴(Tool) 프로토콜로 외부 API 연동까지 지원

실전 시나리오 예시: 챗봇, 키워드 추천, 일정 생성, 감정 분석, 자동 태깅 등


2. 기본 작업: 세션 만들기 & 단순 텍스트 생성

아주 기본적인 LLM 활용 흐름은 LanguageModelSession을 만들고, 프롬프트와 함께 respond(to:)를 호출하는 것부터 시작합니다.

let session = LanguageModelSession()
let response = try await session.respond(to: "What's a good name for a trip to Japan? Respond only with a title")
print(response.content)
// 예시: "Sakura Expedition"와 같이 이름만 출력

실제 프로젝트에서는 배열 등 여러 건에 대해 반복 호출할 수 있습니다.

for landmark in ModelData.shared.landmarks {
    let response = try await session.respond(to: "What's a good name for a trip to \(landmark.name)? Respond only with a title")
    print(response.content)
}

3. 구조화 데이터 생성: @Generable과 @Guide 완벽 이해

@Generable이란?

@Generable은 Swift의 구조체(struct)가 언어 모델의 프롬프트 결과로 자동 생성될 수 있음을 선언하는 속성입니다. 쉽게 말해,

  • 주어진 프롬프트 + 구조체 정의 → 딱 맞는 JSON 타입의 응답 자동 생성
  • 이 과정에서 @Guide로 각 필드에 설명이나 제약조건도 줄 수 있음

예시1: 추천 검색어 4개 얻기

@Generable
struct SearchSuggestions {
    @Guide(description: "A list of suggested search terms", .count(4))
    var searchTerms: [String]
}

let prompt = """
Generate a list of suggested search terms for an app about visiting famous landmarks.
"""
let response = try await session.respond(to: prompt, generating: SearchSuggestions.self)
print(response.content) // ["Landmark explorer", "Historic journeys", ...]와 같이 리스트 출력

예시2: 구조체 중첩/복합 타입 생성

@Generable
struct Person {
    var name: String
    var phone: String
}

@Generable
struct Itinerary {
    var destination: String
    var days: Int
    var budget: Float
    var rating: Double
    var requiresVisa: Bool
    var activities: [String]
    var emergencyContact: Person
    var relatedItineraries: [Itinerary]
}

이 구조체는 내부에 다시 구조체, 배열, Bool 등 실전 데이터 모델을 다양하게 받을 수 있습니다.

예시3: PartiallyGenerated(부분 생성) 지원

프롬프트 결과가 크거나 스트리밍할 때는 부분 생성 타입(PartiallyGenerated)으로 중간중간 결과를 받을 수 있습니다.

@Generable
struct Itinerary {
    var name: String
    var days: [Day]
}

let stream = session.streamResponse(to: "Craft a 3-day itinerary to Mt. Fuji.", generating: Itinerary.self)
for try await partial in stream {
    print(partial)
}

4. 실전 활용: SwiftUI–AI 연동, Tool 및 외부 데이터 연결

SwiftUI 뷰와 프롬프트 스트리밍 결합

struct ItineraryView: View {
    let session: LanguageModelSession
    let dayCount: Int
    let landmarkName: String
    @State private var itinerary: Itinerary.PartiallyGenerated?
    var body: some View {
        Button("Start") {
            Task {
                let prompt = """
                Generate a \(dayCount) itinerary to \(landmarkName).
                """
                let stream = session.streamResponse(to: prompt, generating: Itinerary.self)
                for try await partial in stream {
                    itinerary = partial
                }
            }
        }
    }
}

Tool 프로토콜로 외부 API까지 연결

외부 날씨 API 등과 연동하는 예시도 내장 지원됩니다.

import WeatherKit
import CoreLocation
import FoundationModels

struct GetWeatherTool: Tool {
    let name = "getWeather"
    let description = "Retrieve the latest weather information for a city"
    @Generable
    struct Arguments {
        @Guide(description: "The city to fetch the weather for")
        var city: String
    }
    func call(arguments: Arguments) async throws -> ToolOutput {
        let places = try await CLGeocoder().geocodeAddressString(arguments.city)
        let weather = try await WeatherService.shared.weather(for: places.first!.location!)
        let temperature = weather.currentWeather.temperature.value
        let content = GeneratedContent(properties: ["temperature": temperature])
        return ToolOutput(content)
    }
}

let session = LanguageModelSession(tools: [GetWeatherTool()], instructions: "Help the user with weather forecasts.")
let response = try await session.respond(to: "What is the temperature in Cupertino?")
print(response.content) // 예시: "Cupertino의 현재 온도는 71˚F입니다."

5. 모델 세션 세부 옵션 활용: Instruction, 멀티턴, 내장 사용 사례

  • Instruction 활용: 특정 어투, 응답 스타일, 목적 등을 세션에 직접 지시
  • 멀티턴 대화: 대화 이력 유지로 자연스러운 연속 응답
  • Use case 옵션: Content tagging 등 내장된 특화 모델 바로 사용
let session = LanguageModelSession(
    instructions: "You are a helpful assistant who always responds in rhyme."
)
let response = try await session.respond(to: "Write a haiku about fishing")
print(response.content)

6. @Generable로 구현하는 Tip · 주의사항

  1. @Guide 설정 꼭 사용: 리스트나 특수 제약 조건(예: 최대 개수)은 꼭 @Guide로 명시하세요. 모델이 예측 가능한 구조의 데이터를 반환합니다.
    • 예)
      @Guide(description: "A list of suggested search terms", .count(4))
      var searchTerms: [String]
  2. 프로퍼티 순서 주의: 구조체 내 프로퍼티 순서가 모델 응답의 field mapping에 직접 영향을 미칩니다.
  3. 중첩 구조체/배열 가능: @Generable는 내부에 또 @Generable 구조체, 배열, Bool, String 등 자유롭게 조합 가능.
  4. 딥타입 통합: 여러 차례 호출 없이 한 번에 복합 데이터 타입을 생성할 때 유리.

7. 마치며

Foundation Models 프레임워크와 @Generable은 Swift 기반 AI 서비스 개발에서 타입 안정성과 예측력을 동시에 확보할 수 있는 강력한 도구입니다. 프롬프트와 구조체 조합, 스트리밍, 툴 API 연동까지 모두 지원해서, SwiftUI 앱을 만들 때 직접 써보면 빠르게 진가를 체감할 수 있습니다.

  • 이 글의 코드를 직접 Playgrounds나 Xcode에서 실행하며 실습해보세요.
  • 실전 프로젝트에 응용할 땐, 요구사항(구조, 조건)에 따라 구조체·가이드·tool을 정교하게 설계하면 안정적인 AI 서비스가 구현됩니다.

어떤 시나리오가 궁금한지, 혹은 세부 기능별로 추가 해설이 필요하다면 댓글이나 추가 질문 남겨주세요!

1

profile
iOS 개발자 공부하는 Roy

0개의 댓글