아이폰 카메라로 B마트 상품을 찾는다고?
2026년 8월 배민 앱에 Visual Intelligence를 연동했습니다. 이제 아이폰에서 Visual Intelligence를 실행하면, 검색 결과에서 비슷한 B마트 상품을 바로 확인하실 수 있습니다.
이 글에서는 먼저 Visual Intelligence가 어떤 기능인지 소개하고, 배민 앱에 연동한 과정을 살펴보겠습니다. 이어서 AI 에이전트를 활용해 이미지 검색을 구성한 이야기를 나눠 보겠습니다.
Visual Intelligence 알아보고 연동하기
Visual Intelligence란?
Visual Intelligence는 Apple Intelligence 기능 중 하나로, 카메라나 화면에 보이는 것을 인식합니다. 관련 정보를 바로 보여 주기도 하고, 여러 앱의 검색 결과로 이어 주기도 합니다.

그림 1. 식물을 인식한 Visual Intelligence 화면(출처: iPhone에서 비주얼 인텔리전스로 주변 환경 알아보기, Apple 지원, https://support.apple.com/ko-kr/guide/iphone/iph12eb1545e/ios, 2026년 10월 27일 확인)
사용 조건
Apple Intelligence 기능이라 모든 아이폰에서 되는 것은 아닙니다. 아래 조건을 모두 갖춘 환경에서 Apple Intelligence를 켜야 쓸 수 있습니다.
| 항목 | 조건 |
|---|---|
| OS | iOS 26 이상 |
| 기기 | iPhone 15 Pro 이상 |
| 기기 설정 | Apple Intelligence ON |
표 1. Visual Intelligence 사용 조건(출처: 차세대 Apple Intelligence 시작하기, Apple 지원, https://support.apple.com/ko-kr/121115 , 2026년 10월 27일 확인 / Apple supercharges its tools and technologies for developers, Apple Newsroom, https://www.apple.com/newsroom/2025/06/apple-supercharges-its-tools-and-technologies-for-developers/ , 2026년 10월 27일 확인)
검색하는 방법
검색하는 방법은 카메라, 스크린숏, 사진 앱 세 가지입니다.
카메라로 비추고 바로 검색
카메라로 물건을 비추면 결과 시트에 여러 앱의 결과가 함께 뜹니다. 집에 있는 물건을 찍어 같은 상품을 다시 주문하거나, 매장에서 본 상품을 찍어 가격을 비교하는 식으로 쓸 수 있습니다.

그림 2. 카메라로 비추고 바로 검색하기
스크린숏으로 캡처하고 바로 검색
화면을 캡처하면 하단에 검색 버튼이 뜹니다. 쇼츠를 보다가 저 음식이 뭔지 궁금할 때 캡처해서 바로 검색할 수 있고, 쇼핑하다가 여러 앱의 결과를 한 번에 비교하고 싶을 때도 쓸 수 있습니다. 앱마다 따로 검색할 필요 없이 결과 탭에서 바로 비교하면 됩니다.

그림 3. 스크린숏을 찍고 바로 검색하기(영상 출처: JENNIE from BLACKPINK shares her favorite Korean snacks, YouTube The Jennifer Hudson Show 채널, https://www.youtube.com/shorts/LmN5nid-YvA, 2026년 10월 27일 확인)
스크린숏에서 특정 부분에 원을 그리거나 문질러서 하이라이트하면 그 부분만 검색할 수도 있습니다. 화면에 물건이 여러 개 있을 때 원하는 영역만 골라 검색할 수 있습니다.

그림 4. 원하는 부분만 하이라이트해서 검색하기(영상 출처: JENNIE from BLACKPINK shares her favorite Korean snacks, YouTube The Jennifer Hudson Show 채널, https://www.youtube.com/shorts/LmN5nid-YvA, 2026년 10월 27일 확인)
사진 앱에서 바로 검색
iOS 27부터는 사진 앱에서 사진을 위로 스크롤하면 이미지 검색 버튼이 나옵니다. 예전에 찍어 둔 사진으로도 검색할 수 있습니다.

그림 5. 사진 앱에서 이미지 검색하기(iOS 27)
OS 버전별 변화
Visual Intelligence는 OS 버전이 올라갈 때마다 쓸 수 있는 곳이 넓어졌습니다.
iOS 18: 카메라와 Google뿐
Visual Intelligence가 처음 등장한 iOS 18에서는 카메라에서만 검색할 수 있었습니다. 검색 결과도 Apple과 공식 제휴를 맺은 Google만 노출되었고, 서드파티 앱은 결과에 들어갈 수 없었습니다.

그림 6. iOS 18의 Visual Intelligence(출처: Apple Event — September 9, 2024, YouTube Apple 채널, https://www.youtube.com/watch?v=uarNiSl_uh4, 2026년 10월 27일 확인)
iOS 26: 스크린숏 검색과 서드파티 앱 통합
iOS 26부터는 카메라뿐 아니라 스크린숏으로도 검색할 수 있게 되었습니다. 가장 큰 변화는 Google 말고 다른 앱도 검색 결과에 들어갈 수 있게 된 것입니다. 이때부터 배민 앱의 결과도 넣을 수 있게 되었습니다.

그림 7. iOS 26에서 서드파티 앱 결과가 함께 노출되는 모습(출처: Apple supercharges its tools and technologies for developers, Apple Newsroom, https://www.apple.com/newsroom/2025/06/apple-supercharges-its-tools-and-technologies-for-developers/, 2026년 10월 27일 확인)
iOS 27: 기본 카메라와 사진 앱에서 바로
최근 출시된 iOS 27에서는 기본 카메라에 Siri 모드가 생겼습니다. 그전에는 카메라로 검색하려면 동작 버튼이나 잠금 화면에 사용자가 직접 설정해 둬야 했습니다. 이제는 Siri만 켜져 있으면 별도 설정 없이 기본 카메라를 열기만 해도 바로 검색할 수 있습니다.

그림 8. iOS 27 기본 카메라의 Siri 모드
![]() |
![]() |
그림 9. 직접 설정해야 했던 동작 버튼(왼쪽)과 잠금 화면(오른쪽)
앞에서 소개한 사진 앱 진입점도 iOS 27에서 추가되었습니다.

그림 10. iOS 27 사진 앱의 이미지 검색 버튼
Visual Intelligence 도입 가치
Apple이 소개한 사례, Etsy
Apple은 WWDC25에서 서드파티 통합을 열면서, 키노트와 뉴스룸에서 마켓플레이스 앱 Etsy를 대표 사례로 소개했습니다. 앱이 Visual Intelligence 화면 안에서 자체 시각 검색 결과를 보여 줄 수 있어서, 사용자가 상품을 더 빠르고 직관적으로 발견하도록 돕는다는 설명이었습니다. 보던 화면을 벗어나지 않고 SNS에서 본 상품을 바로 찾을 수 있다는 점이 핵심입니다.

그림 11. WWDC25에서 소개된 Etsy 연동 사례(출처: Apple supercharges its tools and technologies for developers, Apple Newsroom, https://www.apple.com/newsroom/2025/06/apple-supercharges-its-tools-and-technologies-for-developers/, 2026년 10월 27일 확인)
사용자 검색 경험 개선
배민이 기대한 도입 가치도 이와 비슷했습니다. 먼저 사용자에게 차별화된 검색 경험을 줄 수 있습니다. 텍스트 검색은 상품명을 직접 떠올려 입력해야 하지만, 이미지 검색은 이름을 몰라도 보이는 그대로 찾을 수 있습니다.

그림 12. 텍스트 검색과 이미지 검색의 차이
무엇보다 아이폰 기본 앱에서 바로 배민 앱 결과로 연결되기 때문에, 사용자가 기존에 거쳐야 했던 탐색 경로를 크게 단축해 줄 수 있다고 생각했습니다.

그림 13. 기존 탐색 경로와 Visual Intelligence 경로
앱 진입점 확대
사용자 입장에서 검색 경험이 좋아진다면, 서비스 입장에서는 새로운 진입점을 얻게 됩니다.
앱 아이콘 말고도 카메라, 스크린숏, 사진 앱이라는 문이 세 개 더 생깁니다. 아이폰 기본 앱에서 바로 배민이 노출되니, 배민을 떠올리지 않던 사용자도 유입될 수 있습니다.

그림 14. 앱 아이콘 말고도 생기는 세 개의 진입점
또한 전사적으로 퀵커머스를 더 알리고 키우려는 목표가 있습니다. 검색 결과에 B마트 상품이 뜨면 사용자는 “이것도 배민에서 살 수 있네?” 하고 알게 됩니다. 음식 배달을 넘어 장보기와 생활용품까지 자연스럽게 알릴 수 있습니다.

그림 15. 검색 결과로 알리는 배민 커머스
B마트 × Visual Intelligence 연동
이렇게 도입 가치가 크다고 봐서, Visual Intelligence를 연동했습니다. 상황에 따라 세 가지 경우를 구현했습니다.
결과가 있으면: B마트 상품
이미지 검색 결과가 있으면 B마트 상품의 이미지, 이름, 가격을 노출합니다. 상품을 누르면 상품 상세로 이동합니다.

그림 16. 검색 결과가 있을 때 노출되는 B마트 상품
결과가 없으면: ‘배민에서 검색하기’
결과가 없거나 서버 오류가 나면 ‘배민에서 검색하기’라는 폴백을 보여 줍니다. 누르면 장보기·쇼핑 검색으로 이동해서 텍스트 검색을 이어 갈 수 있습니다.

그림 17. 결과가 없을 때의 ‘배민에서 검색하기’ 폴백
B마트 미지원 지역: 따로 안내
B마트 배달 지역이 아닌 경우는 따로 대응했습니다. B마트 배달 지역이 아니라고 알려 주고, 마찬가지로 텍스트 검색을 이어 갈 수 있게 했습니다.
참고: B마트는 지원하지 않아도 배민스토어는 지원하는 지역이 있습니다.

그림 18. B마트 미지원 지역 안내
Visual Intelligence 동작 원리
이제부터는 Visual Intelligence가 배민 앱과 어떻게 연결되어 동작하는지 보겠습니다.
App Intents 위에서 동작하는 구조
Visual Intelligence는 단축어나 Spotlight처럼 시스템이 앱의 기능을 가져다 쓰는 방식으로 동작합니다. 이 셋은 모두 App Intents라는 프레임워크 위에서 동작합니다.
App Intents는 앱의 기능과 데이터를 시스템에 알려 주는 창구 역할을 하는 프레임워크입니다. 앱에서 import AppIntents로 프레임워크를 가져와 필요한 타입을 구현해 두면, 단축어, Siri, Spotlight, Visual Intelligence 같은 시스템 기능이 알아서 가져다 씁니다.

그림 19. App Intents를 기반으로 동작하는 시스템 기능
연동 흐름
사용자가 Visual Intelligence로 검색하면, 시스템이 앱의 검색 쿼리(IntentValueQuery)를 호출하면서 사진과 라벨(시스템이 사진 속 대상을 인식해 붙인 분류 이름)을 넘겨줍니다. 앱은 이 사진으로 이미지 검색 API를 호출하고, 찾은 상품 목록을 AppEntity 배열로 돌려줍니다. 시스템은 이 목록을 결과 시트에 그립니다.
사용자가 결과 항목을 누르면 시스템이 조회 쿼리(EntityQuery)를 호출하고, 앱은 누른 상품을 AppEntity로 돌려줍니다. 그러면 시스템이 그 상품을 target에 담아 상품 상세 열기 동작(OpenIntent)을 호출합니다.

그림 20. Visual Intelligence 연동 흐름
코드로 보는 연동 흐름
코드로 핵심만 간단히 보면 다음과 같습니다.
import AppIntents
// 검색 쿼리: 사진을 받아 상품 목록을 돌려준다
struct VisualSearchValueQuery: IntentValueQuery {
func values(for input: SemanticContentDescriptor) async throws -> [ProductEntity] {
try await imageSearchAPI.search(input.pixelBuffer)
}
}
// 상품 엔티티: 결과 화면에 그릴 값
struct ProductEntity: AppEntity {
let id: String
let deeplink: String
var displayRepresentation: DisplayRepresentation {
.init(title: "\(name)", subtitle: "\(price)", image: .init(url: imageURL))
}
}
// 조회 쿼리: 누른 결과를 id로 되찾는다
struct ProductQuery: EntityQuery {
func entities(for identifiers: [ProductEntity.ID]) async throws -> [ProductEntity] {
await resultStore.products(ids: identifiers) // 검색 때 저장해 둔 결과에서 꺼낸다
}
}
// 상품 상세 열기
struct OpenProductIntent: OpenIntent {
@Parameter var target: ProductEntity
func perform() async throws -> some IntentResult {
SchemeManager.processScheme(url: target.deeplink)
return .result()
}
}
연동 후 사용자 모르게 일어나는 일
이렇게 연동해 둔 앱을 사용자가 설치하거나 업데이트하면, 사용자 모르게 다음과 같은 일이 순서대로 일어납니다.
- 설치할 때 미리 등록됩니다. 연동한 앱을 사용자가 설치하거나 업데이트하면, 시스템이 App Intents 관련 데이터를 읽어 미리 등록해 둡니다. 그래서 앱을 한 번도 켜지 않아도 시스템은 이 기능을 쓸 수 있습니다.
참고: 인덱싱이 비동기로 이뤄져서 설치 직후에는 몇 초 정도 지연될 수 있습니다. - 검색하면 쿼리만 백그라운드에서 실행됩니다. 사용자에게 보이는 건 결과 시트뿐이고, 앱 화면은 뜨지 않습니다.
참고: 이때AppDelegate의didFinishLaunching이 호출되고, 배터리 통계에 백그라운드 활동으로 집계될 수 있습니다. - 결과 시트는 시스템이 그립니다. 앱이 넘긴 값을 시스템이 정해진 규격으로 렌더링합니다.
- 누르는 순간 앱이 켜집니다. 사용자가 결과를 누르면 앱이 포그라운드로 올라오고, 여기서부터는 일반적인 앱 실행과 같습니다.
시스템 제약과 대응
실제로 연동해 보니 시스템 제약이 꽤 많았습니다. 제약별로 정리하고, 대응할 수 있었던 부분은 방법도 함께 공유합니다.
결과 탭 순서는 시스템이 정한다
결과 탭의 순서는 앱이 정할 수 없습니다. Apple은 기기에서 사용 가능한 Image Search 제공자를 기준으로 시스템이 순서를 결정한다고만 설명합니다(출처: Best practices for integrating visual intelligence in your app, WWDC26, Apple Developer, https://developer.apple.com/videos/play/wwdc2026/297/, 2026년 10월 27일 확인). 구체적인 정렬 기준은 공개되지 않았고, 개발자 포럼 질문에도 답변이 없습니다.
직접 테스트해 본 바로는 공식 제휴 파트너인 Google이 항상 첫 번째 탭이었고, 그 뒤는 앱 사용 빈도순으로 정렬되는 것으로 보였습니다.

그림 21. 결과 탭 순서(출처: Apple supercharges its tools and technologies for developers, Apple Newsroom, https://www.apple.com/newsroom/2025/06/apple-supercharges-its-tools-and-technologies-for-developers/, 2026년 10월 27일 확인)
결과 UI는 바꿀 수 없다
결과 UI도 바꿀 수 없습니다. 앱이 DisplayRepresentation으로 타이틀, 서브타이틀, 이미지 값을 넘기면 시스템이 정해진 규격대로 그립니다. 다행히 서버에서 다양한 배지를 합성한 썸네일을 보내 주고 있어서, 이미지만큼은 자유롭게 구성할 수 있었습니다.

그림 22. 배지가 합성된 썸네일
페이징은 없고, 반환 개수 권장은 있다
결과 시트는 일반적인 목록 형태지만 페이징 기능은 없습니다. 대신 검색 속도와 사용자 경험을 위한 상한 가이드가 있습니다. 수백 개가 매칭되더라도 처음 100개까지만 반환하고, 나머지는 시스템의 ‘더보기(More results)’ 버튼으로 앱에서 보여 주라는 내용입니다(출처: Integrating your app with visual intelligence, Apple Developer Documentation, https://developer.apple.com/documentation/visualintelligence/integrating-your-app-with-visual-intelligence/, 2026년 10월 27일 확인).
저희는 최대 20개만 반환하기로 했습니다. 유사도 검색 특성상 사용자의 선택은 첫 화면에 보이는 상위 6개에서 대부분 결정되기 때문에, 많이 보여 줄 필요가 없다고 봤습니다.
응답이 늦으면 시스템이 쿼리를 포기한다
Visual Intelligence는 검색 쿼리 응답이 늦어지면 오래 기다리지 않고 쿼리를 포기한 뒤 시스템 오류 메시지를 띄웁니다. 그러면 검색 결과도, 더보기 버튼도 뜨지 않아 앱으로 들어올 수 있는 길이 아예 사라집니다.

그림 23. 응답이 늦어 시스템이 쿼리를 포기한 화면
그래서 시스템이 포기하기 전에 앱이 먼저 응답하도록 타임아웃을 기존 멀티파트 업로드(60초)보다 짧게 설정했습니다. 8초 안에 응답이 없으면 폴백 아이템을 돌려줍니다. 이미지 검색이 실패하더라도 사용자는 폴백으로 앱에 들어와 텍스트 검색을 이어 갈 수 있습니다.

그림 24. 타임아웃 시 노출되는 폴백 아이템
타임아웃을 짧게 잡은 만큼, 그 안에 업로드를 끝내도록 이미지 용량을 줄였습니다. 시스템이 화면 크기에 맞게 리사이징한 픽셀 데이터를 넘겨주기 때문에 따로 리사이징할 필요는 없었고, 픽셀 데이터를 JPEG로 변환할 때 압축 품질(quality, 0~1)만 0.7로 지정했습니다.
원본과 눈으로 구분하기 어려운 화질을 유지하면서도 업로드 용량을 약 40% 줄일 수 있었기 때문입니다.
| 네트워크 | quality 미지정(710KB) | quality 0.7(425KB) |
|---|---|---|
| 느린 LTE(~2Mbps) | 2.9초 | 1.7초 |
| 약한 신호(~0.5Mbps, 지하철·엘리베이터) | 11.6초(타임아웃 초과) | 7.0초(타임아웃 내) |
표 2. JPEG 압축 품질별 업로드 시간
지하철이나 엘리베이터 같은 약한 신호에서도 8초 안에 업로드가 끝나는 것을 확인하고, 타임아웃을 8초로 정했습니다.
시스템은 이미지를 걸러 주지 않는다
마지막 제약은 가드레일(유해하거나 민감한 내용을 걸러 주는 장치)입니다. 같은 Apple Intelligence 기능인 Foundation Models는 Apple 자체 가드레일을 통과해야만 앱이 온디바이스 LLM의 답변을 받을 수 있고, 걸리면 가드레일 오류가 돌아옵니다.
반면 Visual Intelligence에는 가드레일이 없어서, 모든 이미지가 그대로 앱으로 들어옵니다. 따라서 필요하다면 서비스에서 직접 가드레일을 두고 유해한 사진이나 개인정보가 담긴 사진을 걸러야 합니다.

그림 25. Foundation Models와 Visual Intelligence의 가드레일 차이
보안 솔루션 유의 사항: 스트리핑
시스템 제약 말고도, 보안 솔루션 때문에 생긴 문제가 하나 있었습니다. 배포용 빌드에서만 결과를 누르면 상품 상세로 넘어가지 않고 시스템 오류 얼럿이 떴습니다.

그림 26. 배포용 빌드에서 결과를 눌렀을 때 뜬 오류 얼럿
저희는 배포용 빌드에 외부 업체의 모바일 보안 솔루션을 적용하고 있습니다. 배포용 빌드는 링킹 단계에서 보안 솔루션을 거칩니다. 이때 보안 솔루션은 보호 코드를 넣고, 문자열을 암호화하고, 안 쓰는 타입 정보를 정리합니다. 그 덕분에 앱이 실행될 때 탈옥, 디버거, 변조를 탐지할 수 있습니다. 이번 문제는 안 쓰는 타입 정보를 정리하는 단계에서 생겼습니다.

그림 27. 개발용 빌드와 배포용 빌드의 차이
코드 어디에서도 참조하지 않는 타입 정보를 실행 파일에서 잘라내는 것을 스트리핑이라고 합니다. 그런데 OpenIntent 같은 타입은 앱 코드가 직접 부르지 않고 시스템이 찾아서 씁니다. 코드 안에 참조가 없으니 보안 솔루션이 OpenProductIntent와 OpenFallbackIntent를 안 쓰는 타입으로 보고 스트리핑해 버린 것이었습니다.

그림 28. 코드에서 참조하지 않아 스트리핑 대상이 된 OpenIntent 타입
앱 번들 안에는 실행 파일(Beadal)과 시스템이 읽는 인텐트 목록(Metadata.appintents)이 따로 들어 있습니다. 보안 솔루션은 실행 파일만 손대고 인텐트 목록은 그대로 둡니다. 그래서 결과를 누르면 시스템은 목록에서 OpenIntent를 찾는 데까지는 성공합니다. 하지만 실행 파일에서 그 타입을 찾으려고 하면 지워져서 없습니다. 결과를 눌러도 열리지 않았던 이유입니다.

그림 29. 인텐트 목록에는 있지만 실행 파일에서는 사라진 OpenIntent
그래서 OpenProductIntent와 OpenFallbackIntent를 코드에서 직접 참조하게 해서 스트리핑되지 않도록 했습니다.
final class AppDelegate {
func application(...) -> Bool {
OpenIntentPreserver.preserveTypes()
}
}
enum OpenIntentPreserver {
static func preserveTypes() {
let typeNames = [
String(describing: OpenProductIntent.self),
String(describing: OpenFallbackIntent.self)
]
logger.debug("preserved: \(typeNames)")
}
}
보안 솔루션 업체에 스트리핑 제외 대상을 설정으로 지정할 수 있는지 문의했고, 현재 해결 방안을 검토하고 있습니다. 빠른 시일 내에 반영되어 이런 불필요한 코드가 사라지길 기대하고 있습니다. 보안 솔루션마다 동작은 다를 수 있지만, 비슷한 문제를 만나면 보안 솔루션도 확인해 보시면 좋습니다.
AI 에이전트를 활용해 이미지 검색 만들기
지금부터는 앞에서 호출한 이미지 검색 API에서 동작하는 모델을 AI 에이전트와 함께 만든 과정을 소개합니다.

그림 30. 이미지 검색이 동작하는 방식
먼저 이미지 검색이 어떻게 동작하는지 간단하게 살펴보겠습니다. B마트에서 파는 상품의 이미지를 AI 모델에 넣어 특징을 뽑아 둡니다. 이렇게 뽑은 특징을 숫자 벡터로 나타낸 것을 임베딩이라고 합니다.
사용자가 사진을 넣으면 같은 모델로 그 사진의 임베딩을 뽑고, 상품마다 유사도를 계산해 높은 순서대로 보여 줍니다. 예를 들어 순댓국 포장 사진을 넣으면 같은 순댓국이 유사도 82%로 1위에 오릅니다.
결국 검색 품질은 모델이 같은 상품의 서로 다른 사진을 얼마나 비슷하게 보느냐에 달려 있습니다. 목표는 비슷한 상품 이미지를 더 잘 찾는 모델을 학습하는 것이었습니다.
처음에는 에이전트(Claude Code)에게 B마트 데이터로 상품 이미지 검색을 만들어 달라고 한 줄로 지시했습니다. 데이터를 조회하는 MCP(Model Context Protocol, 에이전트가 외부 도구와 데이터를 쓰게 해 주는 규약)와 서버 권한까지 갖춘 상태여서, 에이전트는 그럴듯하게 돌아가는 검색을 금방 만들어 냈습니다.
그런데 이미지 검색을 서비스로 내보내려니 두 가지 질문이 따라왔습니다. 품질은 어떤지, 서비스에 바로 적용할 수 있는지였습니다. 잘 동작하는 것처럼 보였을 뿐, 품질을 잴 기준이 없어 어느 질문에도 답할 수 없었습니다. 정말 서비스에 쓸 수 있을지 걱정이 됐습니다.
그래서 처음부터 다시 해 보기로 했습니다. 이번에도 AI 에이전트와 함께였지만, 데이터를 먼저 분석하고, 모델을 학습하고, 실시간 API로 서빙하는 단계를 하나씩 밟았습니다.

그림 31. 사람과 AI 에이전트의 루프
단계마다 사람이 조건을 정하면 에이전트가 설계와 조사, 실험과 검토를 빠르게 해냈습니다. 사람은 그 결과를 보고 다음 할 일을 정확하게 판단했습니다.
결과는 누가 볼지에 맞춰 남겼습니다. 실험 설정, 로그, 지표 같은 상세 기록은 에이전트가 읽고 다음 실험을 설계하는 데 씁니다. 대시보드 같은 시각화 자료는 사람이 보고 판단하는 데 씁니다. 에이전트를 위한 루프와 사람을 위한 루프를 따로 둔 셈입니다.
데이터 분석: 무엇으로 평가할지 정하기
첫 단계는 데이터 분석입니다. 분석에서는 평가셋을 만드는 데 집중했습니다. 평가셋이 있어야 품질을 잴 수 있고, 학습도 그 기준에 맞춰 더 잘 시킬 수 있습니다. AI 에이전트를 활용하면 흔히 하는 정량적인 분석뿐 아니라, 상품명을 읽거나 사진을 보며 패턴을 찾는 정성적인 분석도 할 수 있습니다.
상품명을 분석하게 했더니 비슷한 이름이 많았습니다. 코카콜라 제로 500ml는 단품, 2개 묶음, 4개 묶음이 따로 팔리고, 프링글스 스윗어니언 100g도 단품과 묶음, 골라담기 상품이 따로 있었습니다. 판매 상품의 17%가 이런 묶음 상품이었습니다.

그림 32. 상품명으로 찾은 묶음 상품
묶음 상품의 특징을 파악하다 보니 제품 단위 코드(SKU)의 존재를 알게 되었습니다. 묶음 상품은 단품과 같은 SKU로 묶여 있었습니다. 그래서 정답과 검색 결과를 판매 상품이 아니라 제품 단위로 정했습니다.
에이전트가 특히 쓸모 있었던 건 이미지 분석이었습니다. 상품 대표 이미지 1,000장을 뽑아, 흰 배경, 단색 배경, 장면 연출 등의 종류로 나누어 주었습니다.

그림 33. 카테고리별 상품 대표 이미지의 종류
흰 배경 사진이 53%로 가장 많았지만, 카테고리마다 비율이 달랐습니다. 신선식품과 냉장/냉동식품은 장면 연출 사진의 비중이 컸고, 특히 신선식품은 대부분이 장면 연출이었습니다. 이를 보고 이 카테고리들은 유사도 검색이 더 어렵겠다고 추측했고, 어려운 경우를 따로 평가할 기준을 두기로 했습니다. 나중에 실제로 측정해 보니 신선식품의 1위 정답률(검색 결과의 첫 번째가 정답 상품인 비율)이 75.5%로 카테고리 중 가장 낮았습니다(전체 85.1%).
원하는 부분만 골라 분석하는 것뿐만 아니라, 에이전트에게 최대한 다양한 분석을 시키고 그 결과에서 거꾸로 배울 점을 찾을 수도 있다는 걸 느꼈습니다.
다음으로, 리뷰 사진이 가장 중요했습니다. 실제 검색에 들어오는 사진도 고객이 직접 찍은 사진입니다. 상품마다 대표 이미지는 대부분 한 장뿐이라 같은 상품의 여러 모습을 배우려면 리뷰 사진이 필요했습니다. 다만 사람이 찍은 그대로라 정제되어 있지 않았습니다. 상품 하나만 찍은 사진도 있지만, 여러 상품을 펼쳐 놓은 사진이나 조리하거나 개봉한 사진, 화면 캡처도 있었고, 배달 봉투처럼 상품이 아예 보이지 않는 사진도 섞여 있었습니다.

그림 34. 리뷰 사진의 유형별 비율
유형은 에이전트가 사진을 직접 보며 정리했습니다. 일곱 가지로 표본 1,000장을 나눠 보니 상품 하나만 찍힌 사진이 39.8%, 여러 상품을 함께 찍은 사진이 36.5%로 대부분을 차지했습니다. 배달 봉투나 상품과 상관없는 사진은 정답을 가릴 수 없으니 평가에서 빼기로 했습니다. 화면 캡처는 실제로 캡처해서 검색하는 사용자도 있지만, 리뷰 속 캡처는 상품을 확인할 수 없는 경우가 많아 이번 평가셋에서는 뺐습니다. 학습 데이터에는 실제로 들어올 사진을 그대로 쓰고 중복만 뺐습니다.
평가셋 후보에서는 정답이 분명한 사진만 남겼습니다. 상품 하나가 찍혔고, 정답과 같은 상품이 확실하고, 개인정보가 없는 사진만 남겨 평가셋을 고정했습니다. 같은 상품인지 확인할 수 없어 빠진 사진이 가장 많았고, 여러 상품이 찍혀 빠진 사진이 뒤를 이었습니다.

그림 35. 평가셋을 고르는 과정과 제외 이유
사람이 사진을 전부 검수하지는 않았습니다. 대신 에이전트가 사진마다 평가셋에 적절한지 판정했습니다. 걸러진 사진은 제외 이유와 함께 남겨 두었습니다. 여러 상품 사진과 화면 캡처는 따로 평가셋을 만들어 씁니다.
모델 학습: 실험은 에이전트에게
후보 모델 고르기
평가셋을 만들었으니 모델을 학습할 차례입니다. 어떤 모델로 시작할지 찾을 때는 꼭 필요한 조건만 전달했습니다. 상업적으로 쓸 수 있는 라이선스일 것, 실시간으로 서빙할 수 있을 것, 가중치가 공개되어 있을 것 등입니다. 조건에 맞지 않는 모델을 차례로 빼고 나니 다섯 개가 남았습니다. 표로 보니 무엇을 골랐는지뿐 아니라 어떤 모델이 왜 빠졌는지도 한눈에 보였습니다.

그림 36. 후보 모델 조사표
다섯 모델 모두 가중치가 공개된 이미지 임베딩 모델입니다. 모델 A는 시각 언어 모델(Qwen3-VL)을 바탕으로 한 2B 크기의 모델이고, 나머지 네 개는 그보다 작은 이미지 인코더입니다. 이제부터는 아래 표처럼 모델 A~E로 부르겠습니다.
| 모델 | 이름 | 입력 해상도 |
|---|---|---|
| A | Qwen3-VL-Embedding 2B | 원본 비율 |
| B | SigLIP 2 L/16 | 512 |
| C | SigLIP 2 B/16 | 512 |
| D | SigLIP 2 So400m/16 | 384 |
| E | PE-Core L/14 | 336 |
표 3. 최종 후보 모델
고른 모델은 학습 없이 먼저 돌려 봤습니다. 숫자만 보는 대신, 리뷰 사진마다 모델별 검색 결과를 나란히 보는 페이지를 에이전트에게 만들게 했습니다. 같은 사진의 결과를 모델별로 비교하거나 점수가 낮은 순으로 훑으며 어떤 사진이 어려운지 눈으로 확인했습니다.

그림 37. 모델별 검색 결과 비교 화면
실험 대기열과 대시보드
학습은 실험을 돌리고, 결과를 보고, 새 실험을 추가하는 일의 반복입니다. 그래서 실험이 남길 기록의 형식부터 정했습니다. 진행률, 지표, 응답 시간, 자원 사용률을 실험마다 같은 형식으로 남기고, 모든 기록을 한곳에 파일로 모았습니다.
에이전트는 이 기록을 읽고 결과를 분석해 다음 실험을 설계합니다. 형식을 먼저 정해 두니 학습 코드와 대시보드를 서로 다른 에이전트가 동시에 만들었는데도 바로 맞물렸습니다. 사람은 같은 기록으로 만든 대시보드에서 진행 상황과 순위를 한 화면에 봅니다.
처음에는 여러 장비에서 여러 실험을 진행하고 반복하게 했습니다. 그러자 에이전트는 실험을 묶음으로 넣고, 모두 끝나면 결과를 보고 다시 실험을 진행했습니다. GPU 기록을 보니 빈 시간이 두 군데 있었습니다. 일부 실험이 일찍 끝나도 전체 결과를 본 뒤에야 다음으로 넘어갔습니다. 실험이 끝난 뒤에는 다시 다음 설계를 진행해 시간이 오래 걸렸습니다.

그림 38. 실험을 묶음으로 돌렸을 때의 GPU 타임라인
그래서 에이전트가 실험을 바로 띄우는 대신 대기열에 넣게 바꿨습니다. 대기열에 있는 실험은 GPU가 비는 대로 실행됩니다. 에이전트는 지금까지의 결과를 바탕으로 다음 실험을 설계해 대기열에 넣고, 필요하면 보류하거나 취소합니다. 끝난 실험은 리더보드에 정리합니다.
같은 실험 26개를 다시 돌리자 41분 걸리던 일이 14분에 끝났고, GPU가 일한 시간의 비율은 45%에서 99%로 올랐습니다. 빈 GPU가 대기열에서 바로 채워져 실험과 실험 사이에 GPU가 쉬는 시간은 평균 5분에서 1.6초로 줄었습니다. 결과가 나올 때마다 에이전트가 다음 후보를 채워 둬서 넣을 실험도 떨어지지 않았습니다.

그림 39. 대기열을 붙인 뒤의 GPU 타임라인
에이전트는 어떤 실험을 할지만 고민해 대기열에 넣고, 실험을 GPU에 나눠 주는 일은 대기열이 맡으니 실험이 훨씬 잘 돌아갔습니다. 에이전트에게 모든 일을 맡기기보다 작업을 적절히 나눠 맡기는 편이 좋다고 생각했습니다.
학습 과정에서 사람이 한 일은 주로 대시보드를 보는 것이었습니다. 대시보드는 클러스터에 쌓이는 실험 기록을 1분마다 가져와 보여 줍니다. 대기열 화면에서는 실험마다 우선순위와 상태, 어느 GPU에서 도는지를 보고, 실행 중인 실험은 진행률과 처리량, 학습 추이, 예상 종료 시각을 봅니다.

그림 40. 학습 대시보드
리더보드는 실험이 끝날 때마다 갱신되고, 에이전트와 사람이 같은 지표로 판단하는 기준이 됩니다. 화면을 계속 보고 있지 않아도 되도록, 실험이 끝날 때마다 에이전트가 결과를 한 줄로 알려 주게 했습니다.
최종 모델 선택
학습 후에는 다섯 모델 모두 1위 정답률이 83~86%로 올랐습니다. 학습 전 점수가 낮았던 모델일수록 많이 올라, 모델 E는 20.8%p, 모델 D는 19.8%p 높아졌습니다. 다만 특별히 뛰어난 모델 없이 결과가 비슷해서, 다른 지표도 같이 봐야 했습니다.
| 모델 | 학습 전 | 학습 후 | 차이 |
|---|---|---|---|
| A | 79.0% | 84.8% | +5.8%p |
| B | 70.4% | 85.7% | +15.3%p |
| C | 65.3% | 83.3% | +18.0%p |
| D | 65.3% | 85.1% | +19.8%p |
| E | 63.3% | 84.1% | +20.8%p |
표 4. 평가셋 기준 1위 정답률
최종 모델은 에이전트가 학습 결과를 분석해 추천하고, 선택은 사람이 했습니다. 정확도와 속도를 같이 봐야 해서, 후보 다섯 개를 테스트 서빙 환경에 따로 띄워 부하 테스트로 응답 시간도 측정했습니다.

그림 41. 최종 후보의 정답률과 응답 시간
에이전트는 정답률과 응답 시간을 함께 봤을 때 모델 D가 가장 낫다고 추천했습니다. 모델 D는 1위 정답률은 두 번째였지만, 상위 10개 정답률(결과 10개 안에 정답이 있는 비율)이 99.3%로 가장 높고 응답 시간 중앙값도 62ms로 두 번째로 빠릅니다. 1위 정답률이 가장 높은 모델 B는 응답 시간이 98ms로 모델 D보다 느렸습니다. 그래서 모델 D를 최종 모델로 골랐습니다.

그림 42. 한 줄 지시로 만든 모델과 지금 모델 비교
그렇다면 한 줄 지시로 만든 모델은 성능이 어땠을까요? 평가셋 중 학습에 쓰지 않은 사진으로 측정했더니, 상위 10개 정답률은 96.8%였습니다. 꽤 높은 정답률을 보였지만, 차근차근 만든 모델이 99.3%로 더 정확했습니다. 무엇보다 전에는 품질을 평가할 방법조차 없었는데, 이제는 평가할 수 있게 되었다는 점이 아주 큽니다.
모델 서빙: 정확도는 지키고 속도는 빠르게
실서비스에서는 응답 속도와 처리량이 중요합니다. 평가셋 결과를 그대로 유지하면서 속도와 처리량을 최대한 높이게 최적화를 지시했습니다. 평가셋마다 최적화 전후 임베딩의 코사인 유사도(두 벡터가 같은 방향을 가리키는 정도로, 1이면 같음)가 0.999 이상이고, 1위 정답률 차이가 0.5%p 이내일 때만 통과로 봤습니다.
먼저 에이전트에게 프로파일링(처리 과정을 구간별로 재는 것)을 시켜 어느 구간이 병목인지 찾게 했습니다. 요청 하나를 디코드(이미지 파일을 픽셀로 푸는 과정), 전처리, 모델 구간으로 나눠 재 보니, 요청을 하나씩 보낼 때 평균 73ms 가운데 전처리와 모델이 82%를 차지했습니다.

그림 43. 최적화 전 구간별 응답 시간
서빙 최적화 실험도 모델 학습 실험과 같은 방식으로 돌렸습니다. 에이전트는 프로파일링 결과를 보고 실험을 설계해 대기열에 넣고, 실험이 끝나면 그 결과를 보고 다음 실험을 정합니다. 실험 목록과 최적화 결과도 바로 볼 수 있게 화면으로 만들게 했습니다.

그림 44. 실제로 적용한 최적화 6단계와 응답 시간
서버는 동일한 환경으로 고정하고 실험마다 설정만 바꿔 다시 띄웠습니다. 무언가를 바꿀 때마다 평가셋으로 성능을 측정했습니다. 기법마다 얼마나 줄었는지 알 수 있게, 한 번에 하나만 바꿔 직전 결과와 비교했습니다. 통과한 기법을 하나씩 쌓아 가며 최종 결과를 확인했습니다.

그림 45. 구간별로 줄인 시간
디코드와 전처리는 아래 다섯 가지의 기법을 더해 38ms에서 15ms로 줄였습니다.
- 정사각 캔버스 전체 대신 이미지가 걸치는 부분만 크기 변환
- 정규화를 CPU 대신 GPU에서 계산
- 크게 줄일 때는 정수배로 먼저 줄이고 남은 배율만 다시 계산
- 이미지 라이브러리 Pillow를 벡터 연산 명령(SIMD)을 쓰는 빌드(Pillow-SIMD)로 교체
- JPEG 디코더를 simplejpeg로 교체
모델 계산은 NVIDIA의 추론 최적화 엔진인 TensorRT로 바꿔 33ms에서 24ms로 줄였습니다. 처리량은 모델 계산을 줄인 마지막 단계에서 가장 많이 올랐습니다. 가중치와 연산을 8비트로 줄이는 INT8 양자화도 시험했지만, 정확도 기준을 통과하지 못해 넣지 않았습니다.

그림 46. 서빙 최적화 최종 결과
그 결과 요청을 하나씩 보낼 때의 평균 응답 시간은 73ms에서 41ms로 44% 줄었습니다. 처리량은 초당 23.6건에서 32.9건으로 39% 늘었습니다. 정확도는 그대로였습니다. 모든 단계에서 임베딩 코사인 유사도 0.999 이상을 지켰고, 1위 정답률도 같았습니다.
처음 받은 두 질문에도 이제 답할 수 있습니다. 품질은 상위 10개 정답률 99.3%로 확인했고, 속도도 빨라 서비스에 바로 쓸 수 있습니다. 평가 기준이 생겼으니 앞으로도 계속 개선할 수 있습니다.
서비스 지표와 앞으로의 계획
서비스에서는 어떻게 쓰이고 있을까요? 모델은 앞으로도 계속 개선할 예정이라, 품질이 좋아졌는지 판단할 지표부터 정했습니다. 기본은 상품 클릭률, 즉 검색 결과에서 상품을 누른 비율입니다. B마트 배달 지역이면 상품 목록이 나오고, 아니면 ‘배민에서 검색하기’로 넘기는 폴백 화면이 나오기 때문에, 클릭률은 상품 목록이 나온 경우만 셉니다.
여기에 위치와 유사도를 같이 봅니다. 위치는 몇 번째 결과를 눌렀는지, 유사도는 검색 결과로 나온 상품 사진이 사용자가 찍은 사진과 얼마나 비슷한지입니다. 둘을 같이 보면 클릭률이 왜 오르고 내리는지 알 수 있습니다. 그래서 클릭 로그에 위치, 유사도, 모델 버전 등을 함께 남겨, 모델이나 인덱스가 바뀔 때마다 같은 기준으로 전후를 비교할 수 있게 했습니다.

그림 47. 결과 위치별 상품 클릭 비율(2026년 9월)
먼저 위치입니다. 2026년 9월 한 달 동안 결과 시트에서 몇 번째 상품을 눌렀는지 봤습니다. 1위 상품의 클릭이 가장 많았고, 한 화면에 보이는 6위까지가 대부분을 차지했습니다.
결과 시트를 열면 처음에 상품 6개가 한 화면에 보이고, 7번째부터는 스크롤해야 보입니다. 모델을 고를 때는 상위 10개 정답률을 봤지만, 실제 사용을 보니 1위 정답률과 6위까지의 정답률을 주요 지표로 봐야 한다는 걸 알 수 있었습니다. 다만 1위는 맨 앞에 있어서 먼저 보였기 때문에 눌렸을 수도 있습니다. 그래서 정말 비슷해서 누른 건지 유사도로 한 번 더 확인했습니다.

그림 48. 1위 클릭의 유사도별 비중(2026년 9월)
9월 검색을 1위 상품의 유사도 순으로 줄 세워 절반씩 나눠 보니, 유사도가 높은 쪽이 낮은 쪽보다 1위를 누른 비율이 1.8배 높았습니다. 같은 자리라도 더 비슷한 상품이 올라오면 더 많이 누른다는 뜻입니다. 그래서 이미지 검색 품질을 높여 원하는 상품을 1위에 올리면 클릭률도 오를 수 있다고 봅니다.
2026년 10월 27일에 출시된 iOS 27.2부터 한국어 Siri AI가 지원되어 카메라에서 바로 Siri로 검색할 수 있습니다(출처: Siri AI, 오늘부터 한국어로 이용 가능, Apple Newsroom, https://www.apple.com/kr/newsroom/2026/10/siri-ai-is-available-today-in-more-languages/, 2026년 10월 27일 확인). 그래서 요청이 늘 것으로 기대하며, 앞으로 지표를 좀 더 지켜보려고 합니다.
또한 앱 밖에서는 Visual Intelligence로, 앱 안에서는 B마트 검색창에서 바로 사진으로 찾을 수 있게 하는 걸 다음 단계로 보고 있습니다.

그림 49. 배민실험실에서 켜는 B마트 이미지 검색
2026년 10월 초에 배민실험실이 출시됐는데요, 새 기능을 정식으로 내놓기 전에 써 볼 수 있는 곳입니다. 이미지 검색도 여기서 먼저 선보이고 사용자 반응을 확인해 보려고 합니다.
마무리
Visual Intelligence를 연동하면 아이폰 기본 카메라, 스크린숏, 사진 앱에서 배민 이미지 검색 결과로 바로 연결할 수 있습니다. 배민 입장에서는 검색 경험을 차별화하고 앱 진입점을 넓힐 수 있는 기회였습니다.
연동할 때는 App Intents 프레임워크로 필요한 데이터와 동작을 구현해 두면, 시스템이 알아서 호출합니다. 다만 결과 탭 순서, UI 규격, 페이징, 타임아웃, 가드레일 같은 시스템 제약을 고려하셔야 합니다. 모바일 보안 솔루션을 쓴다면 스트리핑 현상도 함께 확인해 두시면 좋습니다.
이미지 검색 모델을 만들면서는 사람이 기준과 조건을 정확하게 정해야 했습니다. 무엇으로 평가할지 정하고, 꼭 지킬 조건을 지시하고, 나온 결과를 판단합니다. 이번에는 평가셋, 모델이 갖출 조건, 서빙의 통과 기준이 그 기준이었습니다. 그러면 에이전트는 조사하고 설계하고 실험하는 일을 빠르게 반복합니다. 그 결과를 사람이 잘 판단하는 것이 중요했습니다.

그림 50. 서비스 결정부터 출시까지 한 달
빠르게 한 건 AI 모델 개발만이 아니었습니다. 이 글에서 다루지 못한 보안 검토, 외부망 오픈, 인덱스 배치, 다른 API 연동 같은 일까지 포함해, 2026년 7월에 서비스를 결정하고 8월에 출시하기까지 한 달이 걸렸습니다.
AI 에이전트를 잘 활용한 덕분에 AI플랫폼 엔지니어가 모델 개발을 처음부터 끝까지 할 수 있었고, 앱 개발자가 처음으로 서비스 기획과 지표 설계를 할 수 있었습니다. 이 경험담이 AI 에이전트로 맡은 일의 범위를 넓혀 보고 싶은 분께 도움이 되면 좋겠습니다.

