/ IOS

WWDC25: 온디바이스 AI, 새로운 가능성을 열다 - MapKit 주차장 정보 활용 사례

WWDC25: 온디바이스 AI, 새로운 가능성을 열다 - MapKit 주차장 정보 활용 사례

WWDC25에서 발표된 Apple Foundation Models, iOS 개발자들에게 새로운 지평을 열어주었습니다. 특히, 온디바이스(on-device) AI의 등장은 기존 클라우드 기반의 거대 LLM(Large Language Model)과는 다른 접근 방식과 활용 전략이 필요함을 시사합니다. 네트워크 연결 없이 기기 자체에서 구동되는 온디바이스 AI는 제한된 정보와 특정 작업에 최적화되어야 한다는 점에서 더욱 흥미롭습니다.

오늘은 MapKit 주차장 정보를 활용하여 온디바이스 AI의 6가지 핵심 활용 분야(요약, 추출, 분류, 태깅, 구성, 교정)를 어떻게 iOS 앱에 녹여냈는지, 그리고 왜 이러한 접근 방식이 중요한지 함께 살펴보겠습니다.

Jul-29-2025 23-08-20.gif

1. 온디바이스 AI, 왜 다른 관점이 필요한가?

기존의 LLM 서비스는 방대한 클라우드 데이터를 기반으로 하여 범용적이고 복잡한 질의응답이 가능했습니다. 하지만 이는 필연적으로 네트워크 연결과 서버 비용이라는 제약을 가집니다. 반면, Apple Foundation Models의 온디바이스 AI는 기기 내에서 직접 연산을 수행함으로써 다음과 같은 이점을 제공합니다.

  • 즉각적인 응답: 네트워크 지연 없이 빠른 결과 제공
  • 개인 정보 보호: 사용자 데이터가 기기 외부로 전송되지 않아 높은 보안성
  • 오프라인 사용: 네트워크 연결이 불안정하거나 없는 환경에서도 기능 수행

하지만 이러한 장점 뒤에는 “제한된 정보”라는 현실적인 제약이 따릅니다. 클라우드의 무한한 데이터에 접근할 수 없으므로, 온디바이스 AI는 우리가 가진 정제된 데이터를 최대한 활용하고, 각 기능에 필요한 정보를 명확하게 정의하며, AI가 이를 효율적으로 가공하도록 설계해야 합니다. 이것이 바로 기존 LLM과 다른, 온디바이스 AI에 대한 접근 관점의 핵심입니다.

2. MapKit 주차장 정보로 구현하는 온디바이스 AI 6가지 활용 사례

저희는 ParkingInfo (MapKit의 MKMapItem 기반)와 AI가 생성할 ParkingSummary 모델을 활용하여 온디바이스 AI의 6가지 핵심 기능을 구현했습니다.

MKMapItem 이 가지고 있는 정보

[주차장 정보]
주차장 이름: **새장골공영주차장**
주소: 대한민국 서울특별시 은평구 불광동 480-352, 03340
현재 위치로부터 **898m** 거리에 있습니다.
문의 전화: +82 2-355-5947
카테고리: MKPOICategoryParking

1. 요약 (Summarization)

목표: 주차장의 핵심 정보를 한 문장으로 간결하게 요약하여 사용자가 빠르게 정보를 파악할 수 있도록 돕습니다.

구현ParkingSummary 모델에 summary: String? 필드를 추가하고, AI에게 주차장의 이름, 주소, 특징 등을 종합하여 간결한 문장을 생성하도록 지시했습니다.

예시: “강남역과 가까워 대중교통 이용이 편리한 지하 주차장입니다.”

@Guide(description: "해당 주차장을 한 문장으로 요약")
public let summary: String?

2. 추출 (Extraction)

목표: 주소와 같은 비정형 텍스트에서 특정 의미를 가진 데이터를 정확하게 뽑아냅니다.

구현ParkingSummary 모델에 district: String? 필드를 추가하여, AI가 주소 문자열에서 ‘강남구’, ‘종로구’와 같은 ‘구’ 정보를 추출하도록 했습니다. 이는 지역 기반 검색 및 필터링에 필수적입니다.

예시: 주소 “서울특별시 강남구 역삼동 123-45”에서 “강남구” 추출

@Guide(description: "주차장이 위치한 '구' 정보 (예: 강남구, 종로구). 주소 정보에서 추출되어야 한다.")
public let district: String?

3. 분류 (Classification)

목표: 주차장을 특정 기준에 따라 미리 정의된 카테고리로 나눕니다.

구현ParkingSummary 모델에 distanceCategory: String? 필드를 추가했습니다. AI는 사용자와의 거리를 분석하여 주차장을 ‘초근접’, ‘근거리’, ‘원거리’와 같은 범주로 분류합니다. 이는 사용자가 거리에 따라 주차장을 직관적으로 이해하고 필터링하는 데 도움을 줍니다.

예시: 290m 거리의 주차장을 “초근접”으로 분류

@Guide(description: "사용자의 현재 위치로부터 주차장의 상대적인 거리 분류 (예: '초근접', '근거리', '원거리').")
public let distanceCategory: String?

4. 태깅 (Tagging)

목표: 주차장의 주요 특징을 나타내는 키워드 태그를 자동으로 부여하여 검색성을 높이고 정보를 한눈에 보여줍니다.

구현ParkingSummary 모델의 tags: [String] 필드를 활용했습니다. AI는 주차장 설명, 카테고리 등에서 핵심 특징(예: #24시간, #공영, #지하주차장, #전기차충전)을 추출하여 태그로 변환합니다.

예시: [“#지하주차장”, “#역주차장”, “#24시간”]

@Guide(description: "주차장 정보에서 가장 핵심적인 특징을 나타내는 태그, 앞에 #으로 시작해야 한다.", .maximumCount(3))
public let tags: [String] 

5. 구성 (Composition)

목표: 여러 정보를 조합하여 사용자에게 더 유용하고 해석된 형태의 새로운 텍스트 콘텐츠를 생성합니다.

구현ParkingSummary 모델에 estimatedDrivingTime: String? 필드를 추가했습니다. AI는 주차장과의 distanceInMeters 정보를 기반으로 “차량 약 N분”과 같은 예상 이동 시간을 구성하여 제공합니다. 이는 단순 거리 숫자보다 사용자에게 더 실질적인 정보입니다.

예시: “약 7분” (차량 이동 시간)

@Guide(description: "사용자의 현재 위치에서 주차장까지 차량으로 이동하는 데 걸리는 예상 시간 (예: '약 5분', '10분 미만').")
public let estimatedDrivingTime: String?

6. 교정 (Revision)

목표: 기존 데이터의 오류를 수정하거나 형식을 표준화하여 정보의 신뢰성과 가독성을 높입니다.

구현ParkingSummary 모델에 correctedPhoneNumber: String? 필드를 추가했습니다. AI는 +82 2-385-2193과 같은 국제 또는 비표준 형식의 전화번호를 02-385-2193과 같은 한국 국내 표준 형식으로 교정합니다. 이는 사용자 경험을 크게 향상시킵니다.

예시: “+82 2-385-2193”을 “02-385-2193”으로 교정

@Guide(description: "주차장 전화번호를 한국 국내 형식으로 교정 (예: '02-385-2193' 또는 02) 385-2193.")
public let correctedPhoneNumber: String?

마치며

WWDC25에서 선보인 Apple Foundation Models의 온디바이스 AI는 iOS 개발자들에게 새로운 도전이자 기회입니다. 제한된 자원 속에서 어떻게 사용자에게 의미 있는 가치를 전달할 것인가에 대한 깊은 고민이 필요하며, 오늘 살펴본 6가지 핵심 활용 분야는 그 해답을 제시합니다.

클라우드 LLM처럼 모든 것을 할 수는 없지만, 온디바이스 AI는 우리가 가진 데이터와 앱의 맥락을 최대한 활용하여 사용자에게 더 빠르고, 안전하며, 개인화된 경험을 제공할 수 있습니다. 이제 iOS 앱에서 AI를 활용하는 방식은 단순히 API를 호출하는 것을 넘어, 데이터의 정제부터 정보의 가공, 그리고 최종 사용자 경험까지 아우르는 종합적인 AI 설계 능력을 요구할 것입니다.

프롬프트

let prompt = """
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보]를 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다. 각 필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을 한 문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '구' 정보를 주소에서 추출해 주세요. (예: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과) 중 하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요. 각 태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #먼, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는 데 걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만'과 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193'은 '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
\(await parkingInfo.description)
"""

로그

평균 10초 정도 걸렸습니다.

(6.63+10.26+13.71+5.12+8.33+16.33)/6=60.38/6≈10.06

DEBUG: Model responded in 6.63 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **연신내유료주차장**
주소: 대한민국 서울특별시 은평구 불광동 81-8, 03338
현재 위치로부터 **485m** 거리에 있습니다.
문의 전화: +82 2-353-3217
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "연신내유료주차장은 은평구에 위치하며, 가까운 거리에 있습니다.",
  District: 은평구,
  Tags: [#유료주차장, #은평구, #서울특별시],
  Estimated Driving Time:  2,
  Corrected Phone: +82 2-353-3217
)

DEBUG: Model responded in 10.26 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **수양유료주차장**
주소: 대한민국 서울특별시 은평구 불광동 13-5, 03360
현재 위치로부터 **887m** 거리에 있습니다.
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "수양유료주차장은 은평구에 위치하며, 무료 주차 서비스를 제공합니다.",
  District: 은평구,
  Distance Category: 근거리,
  Tags: [#무료, #유료주차장, #은평구],
  Estimated Driving Time:  10,
  Corrected Phone: +82 2-385-2193
)

DEBUG: Model responded in 13.71 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **불광2동거주자우선주차장**
주소: 대한민국 서울특별시 은평구 불광동 131-4, 03347
현재 위치로부터 **807m** 거리에 있습니다.
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "불광2동거주자우선주차장: 은평구 불광동에 위치한 공공 주차장.",
  District: 은평구,
  Tags: [#공공주차장, #주차장, #근거리],
  Estimated Driving Time:  3,
  Corrected Phone: +82 2-385-2193
)

DEBUG: Model responded in 16.33 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **연신중학교**
주소: 대한민국 서울특별시 은평구 연서로33길 16-32, 03342
현재 위치로부터 **804m** 거리에 있습니다.
문의 전화: +82 70-3721-3619
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "연신중학교 근처 주차장 MKPOICategoryParking",
  District: 은평구,
  Tags: [#근거리, #주차장, #학교주차장],
  Estimated Driving Time:  10,
  Corrected Phone: +82 70-3721-3619
)

DEBUG: Model responded in 5.12 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **새장골공영주차장**
주소: 대한민국 서울특별시 은평구 불광동 480-352, 03340
현재 위치로부터 **898m** 거리에 있습니다.
문의 전화: +82 2-355-5947
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "새장골공영주차장은 은평구에 위치한 공영 주차장입니다.",
  District: 은평구,
  Distance Category: 근거리,
  Tags: [#공영주차장, #은평구주차장, #서울특별시주차장],
  Estimated Driving Time:  10,
  Corrected Phone: +82 2-355-5947
)

DEBUG: Model responded in 8.33 seconds for prompt:
당신은 사용자의 주차장 검색 요청에 응답하는 전문 AI입니다. 다음 [주차장 정보] 분석하여 JSON 형식의 'ParkingSummary' 객체를 생성해야 합니다.  필드의 설명을 정확히 따르세요.

---
[필드 설명]
- summary: 해당 주차장을  문장으로 간결하게 요약해 주세요.
- district: 주차장이 위치한 '' 정보를 주소에서 추출해 주세요. (: 강남구, 종로구)
- distanceCategory: 사용자의 현재 위치로부터 주차장의 상대적인 거리를 '초근접'(500m 이내), '근거리'(500m ~ 2km), '원거리'(2km 초과)  하나로 분류해 주세요.
- tags: 주차장 정보에서 가장 핵심적인 특징을 나타내는 태그를 최대 3개까지 생성해 주세요.  태그는 '#'으로 시작해야 합니다.
  예시 태그: [#24시간, #공영, #무료, #넓은, #지하주차장, #야외주차장, #마트주차장, #병원주차장, #쇼핑몰주차장, #식당주차장, #공항주차장, #역주차장, #환승주차장, #전기차충전, #가까운, #, #경차할인, #발렛파킹, #주차대수많음]
- estimatedDrivingTime: 주차장까지 차량으로 이동하는  걸리는 예상 시간을 추정하여 '약 N분', 'N분 미만' 같이 표시해 주세요. (교통 상황은 고려하지 않은 대략적인 시간)
- correctedPhoneNumber: 주차장의 전화번호가 있다면 한국 국내 형식으로 교정해 주세요. '+82 2-385-2193' '02-385-2193' 또는 '02) 385-2193'처럼 변경해 주세요. 전화번호가 없는 경우 null로 표시합니다.

---
[주차장 정보]
주차장 이름: **연광초등학교지하공동주차장**
주소: 대한민국 서울특별시 은평구 연서로35길 37, 03342
현재 위치로부터 **910m** 거리에 있습니다.
문의 전화: +82 2-385-2193
카테고리: MKPOICategoryParking
- ParkingSummary(
  Summary: "연광초등학교지하공동주차장은 은평구에 위치한 편리한 지하 주차장입니다.",
  District: 은평구,
  Distance Category: 근거리,
  Tags: [#지하주차장, #공영, #초근접],
  Estimated Driving Time:  10,
  Corrected Phone: +82 2-385-2193
)