메타데이터
- 발신자: TLDR
- 원문 URL: https://blog.bytebytego.com/p/why-doordash-instacart-and-uber-eats?utm_source=tldrnewsletter
- 발행일: 2026-07-29
- 카테고리: dev-engineering
직역
지난 몇 년 사이 가장 큰 음식 배달 회사 세 곳이 LLM을 중심으로 검색 시스템을 다시 만들었다. DoorDash, Instacart, Uber Eats는 사용자가 검색창에 무언가를 입력했을 때 그 의도를 이해하려는 동일한 문제를 풀고 있었다. 이들은 또한 거의 동일한 연구 기반에 접근하고 있었다. 그럼에도 이들이 실제로 배포한 아키텍처는 서로 상당히 다르게 생겼다.
이 차이야말로 오늘날 LLM을 활용한 개발에서 가장 흥미로운 지점 중 하나다. 각 회사가 왜 그 지점에 도달했는지 이해하면, AI를 어떤 프로덕션 시스템에든 통합하는 방법을 사고하기 위한 멘탈 모델을 얻게 된다.
기존 스택에 LLM을 추가하는 것은 결국 하나의 질문으로 귀결된다. LLM이 런타임 안으로 얼마나 깊이 들어가야 하는가?
궁극적으로 DoorDash, Instacart, Uber Eats는 이 질문에 각기 다르게 답했고, 각 회사가 어떤 LLM을 선택했는지는 부차적인 문제였다. 이미 갖추고 있던 인프라가 답을 결정한 핵심 요인이었다.
검색창에 "비 오는 저녁에 어울리는 건강한 음식"을 입력해 보면 무엇이 나오는지 보라. 오늘날 결과는 유용함과 인상적임 사이 어딘가에 있다. 5년 전이었다면 같은 쿼리는 무작위로 뒤섞인 결과를 반환했을 것이다. 키워드 검색은 단어를 의도가 아니라 토큰의 집합으로 다루기 때문이며, 이런 쿼리는 키워드 매칭에 거의 단서를 주지 못하기 때문이다.
이 패턴은 음식 검색 전반에서 반복되는 여러 실패 유형으로 나타난다.
- 동의어: "소다"와 "탄산음료"는 같은 제품을 가리키지만 키워드 엔진은 서로 다른 토큰으로 취급한다.
- 오타: "Mozzarela"는 모짜렐라 결과를 가져와야 하지만 철자 불일치로 검색이 깨진다.
- 줄임말: "Gf pizza"는 글루텐프리 피자를 뜻하는데, 시스템이 이 약어를 전체 문구의 동의어로 인식해야 한다.
- 언어 혼용: 스페인어 "pan"은 빵을 뜻하지만 영어 "pan"은 조리 기구를 뜻하므로 이중언어 검색창은 이를 구분해야 한다.
- 단어 의미의 모호성: 과일 "Apple"과 회사 "Apple"은 철자가 같지만 뜻이 다르며, 정답은 맥락에 달려 있다.
이보다 더 어려운 두 가지 문제도 그 밑에 깔려 있다.
- 롱테일: 식료품·레스토랑 플랫폼은 엄청난 수의 고유 쿼리를 본다. 전환 데이터로 학습된 특화 모델은 드물게 등장하는 쿼리에 취약한데, 애초에 희귀 쿼리는 정의상 희귀하기 때문이다.
- 제약 조건 문제: "비건 치킨 샌드위치" 같은 쿼리에는 엄격한 제약이 내재되어 있는데, 유사도 기반 검색은 이 제약을 위반하는 치킨 샌드위치를 반환할 수 있다. 유사도 점수는 여전히 가깝게 나오기 때문이다. 식이 제한, 알레르기, 수량 필터가 모두 이 범주에 속한다.
DoorDash는 LLM이 프로덕션에서 쓸만해지기 전부터 아이템과 레스토랑에 대한 지식 그래프를 이미 갖고 있었다. 이 그래프는 모든 아이템에 대해 요리 종류, 식이 선호, 요리 문화, 브랜드, 맛 등 구조화된 속성을 담고 있었다.
이들의 접근 방식은 LLM을 오프라인에서 사용해 SKU 데이터로부터 속성을 추출함으로써 이 그래프를 보강하고, 런타임에서는 오직 쿼리를 그래프에 연결할 수 있는 조각들로 파싱하는 데만 LLM을 사용하는 것이었다. 검색(retrieval) 자체는 여전히 키워드와 그래프 기반으로 이루어졌다.
"small no-milk vanilla ice cream" 쿼리를 생각해 보자. LLM은 이를 세 개의 조각으로 나눈다. "small"은 수량 속성이다. "no-milk"는 표준 라벨 "dairy-free"에 매핑되는 식이 선호 속성이다. "vanilla ice cream"은 다시 요리 종류("ice cream")와 맛("vanilla")으로 나뉜다.
각 조각은 지식 그래프의 특정 필드에 연결된다. 식이 선호는 하드 필터가 되어 유제품이 없는 아이템만 검색되도록 한다. 맛은 순위를 매기기 위한 소프트 선호가 된다. 요리 종류는 후보군을 좁힌다.
DoorDash의 접근에서 특히 눈에 띄는 부분은 LLM의 출력을 제약하는 방식이다. 이들은 검색 증강 생성(RAG)을 생성기가 아니라 가드레일로 사용한다. 각 쿼리 조각에 대해 근사 최근접 이웃(ANN) 조회가 기존 그래프에서 가장 가까운 상위 100개의 분류 개념을 가져온다. 그런 다음 LLM은 라벨을 새로 만들어내는 대신 그 목록에서 고르도록 프롬프트된다. 이는 일반적인 RAG 패턴을 영리하게 뒤집은 것이다. 보통 RAG는 생성기에 맥락을 주입하지만, 여기서는 RAG가 전체 출력 공간 자체를 정의하므로 시스템은 나머지 설계가 이미 처리할 줄 아는 개념만을 생성하게 된다.
측정된 효과는 인기 메뉴 캐러셀의 트리거율이 약 30% 상승한 것이며, 이는 런타임이 대부분 고전적인 방식으로 유지되는 아키텍처를 통해 달성됐다.
여기서 얻을 수 있는 결론은 DoorDash의 LLM이 대부분 오프라인에서, 대부분 배치 방식으로, 런타임의 주변부에서 작동한다는 것이다.
Instacart 엔지니어들이 처음 기성 LLM으로 검색 쿼리 "protein"을 분류해 보려 했을 때, 모델은 닭고기, 두부, 소고기 등 고단백 식품을 반환했다.
영어 문장으로만 보면 합리적인 답이다. 문제는 Instacart의 실제 사용자들이 "protein"이라고 입력할 때 찾는 것은 단백질 바와 단백질 파우더라는 점이다. 모델의 일반적인 세계 지식과 회사의 구체적인 사용자 행동이 서로 다른 방향을 가리키고 있었고, 이 작은 실패가 Instacart가 풀어야 했던 핵심 문제를 보여준다.
이들이 대체하려던 시스템은 복잡했다. 쿼리 카테고리 분류는 FastText 모델에서, 쿼리 재작성은 세션 행동을 마이닝하는 별도 엔진에서, 철자 교정·쿼리 태깅·아일(진열대) 분류는 각각 자체 데이터 파이프라인과 서빙 인프라를 가진 별도 모델에서 실행됐다. 유지보수 부담이 상당했고, 각 모델이 자체 라벨링 데이터를 필요로 했기 때문에 테일 쿼리는 여전히 성능이 떨어졌다. 희귀 쿼리에 대한 라벨은 정의상 부족하기 때문이다.
Instacart의 전략은 세 가지 접근을 층층이 쌓은 것이다.
- 컨텍스트 엔지니어링: 검색 증강 생성이 LLM이 쿼리를 보기 전에 Instacart 고유의 맥락(가장 많이 전환된 카테고리, 과거 전환 데이터, 카탈로그 세부 정보)을 프롬프트에 주입한다.
- 후처리 가드레일: 의미적 유사도 필터가 원래 쿼리에서 벗어난 LLM 출력을 걸러낸다.
- 파인튜닝: 가장 고난도 작업을 위해 팀은 Instacart의 자체 데이터로 Llama-3-8B를 파인튜닝하여 도메인 지식을 모델 가중치 자체에 새겨 넣는다.
서빙 아키텍처는 헤드 트래픽과 테일 트래픽의 분포에 따라 나뉜다. 헤드 쿼리는 지연에 관대하고 깊이 컨텍스트 엔지니어링된 오프라인 RAG-캐시 파이프라인을 거치는 반면, 테일 쿼리는 어댑터 병합, H100 GPU, 오토스케일링을 통해 지연을 300ms 이하로 유지하는 실시간 파인튜닝된 Llama-3-8B 모델을 거친다.
이 솔루션 이후 쿼리 재작성 커버리지는 50%에서 95% 이상으로 뛰었고, 대체어·확장 재작성·동의어 전반에서 90% 이상의 정밀도를 기록했다. 실시간 파인튜닝 모델은 하위 2% 쿼리(콜드스타트 테일)의 검색 품질을 개선해 스크롤 깊이를 6% 줄이고 테일 쿼리 결과에 대한 불만을 절반으로 낮췄다.
여기서 얻을 수 있는 결론은 Instacart의 LLM이 쿼리 이해 계층에 자리 잡고 있으며, 일부는 오프라인 캐시로, 일부는 온라인 파인튜닝으로 동작하는 반면, 다운스트림의 검색과 랭킹은 여전히 전통적인 머신러닝과 정보 검색 시스템이 담당한다는 점이다.
Uber Eats는 다른 두 회사와 같은 문제에 더해 복잡성까지 안고 있었다. 이들은 레스토랑, 식료품, 리테일을 포함한 여러 버티컬에서, 여러 시장에서, 그리고 긴 언어 목록에 걸쳐 운영된다.
기존 설정은 파편화되어 있었다. 버티컬별로 별도의 BERT 기반 임베딩 모델이 있었고, 일부는 어휘 기반 검색을 썼으며, 이 모든 것을 병렬로 유지보수하는 운영 부담이 있었다. 목표는 모든 버티컬, 모든 시장, 모든 언어를 하나의 일관된 임베딩 공간으로 처리하는 단일 검색 시스템이었다.
이들이 채택한 아키텍처는 전형적인 투 타워(two-tower) 구조로, 쿼리 인코더와 문서 인코더가 각각 공유된 공간에서 벡터를 생성하고, 매칭은 그 공간에서의 유사도로 이루어진다.
핵심은 각 타워 안에 무엇이 들어 있느냐다. 두 타워 모두 파인튜닝된 Qwen LLM을 백본 임베딩 레이어로 사용한다. 쿼리 타워는 온라인으로 실행되어 들어오는 각 쿼리를 실시간으로 임베딩하고, 문서 타워는 오프라인으로 실행되어 수십억 개의 문서를 HNSW 벡터 인덱스(대규모 유사도 검색을 위한 그래프 기반 구조)에 미리 임베딩해 둔다. 이 분리 덕분에 시스템이 경제적으로 가능해지는데, 쿼리 시점마다 모든 문서에 무거운 LLM을 돌리는 것은 비용이 지나치게 크지만, 한 번 미리 계산해 두고 검색 시점에 조회하는 것은 감당할 수 있기 때문이다.
파인튜닝은 아키텍처 선택만큼이나 중요하다. 기본 상태의 Qwen은 세계 지식과 다국어 능력을 제공하는데, 이것이 앞서 언급한 스페인어 "pan" 문제를 해결해 준다. Uber의 자체 쿼리-문서 상호작용 데이터로 파인튜닝하는 것은 임베딩 공간에 Uber Eats 사용자가 실제로 무엇을 중요하게 여기는지를 가르치는 과정이며, 이것이 시스템에 도메인 정합성을 부여한다. 기본 모델은 일반적인 의미론을 제공하고, 파인튜닝은 Uber Eats만의 구체적인 규칙을 더한다.
시스템을 규모 있게 작동하게 만드는 것은 일련의 최적화 기법들이다.
- Matryoshka 표현 학습은 임베딩을 다양한 길이로 잘라낼 수 있는 단일 모델을 학습시키며, Uber는 프로덕션에서 1,536차원 전체 대비 0.3% 미만의 리콜 손실로 256차원을 서빙한다.
- 스칼라 양자화(float32 대신 int7)는 지연을 다시 절반으로 줄인다.
- 헥사곤, 도시, 배달 유형에 대한 사전 필터가 ANN 검색이 실행되기도 전에 후보 집합을 줄여준다.
수치가 비용 이야기를 들려준다. ANN 파라미터 k를 튜닝해 리콜에 거의 영향을 주지 않으면서 지연을 34%, CPU를 17% 줄였고, 양자화는 리콜 0.95 이상에서 지연을 절반으로 줄였으며, MRL은 저장 공간을 거의 50% 줄였다. 이런 엔지니어링 선택들이 모여 파인튜닝된 LLM이 Uber Eats 규모의 프로덕션 검색 시스템에서 검색 기반(retrieval substrate) 역할을 하도록 만든다.
여기서 얻을 수 있는 결론은 Uber Eats의 LLM이 곧 임베딩 모델 그 자체라는 점이다. 모든 쿼리와 모든 문서가 LLM에서 파생된 벡터를 얻으며, 모든 단계의 검색이 LLM이 만든 표현에 의존한다.
세 회사를 "LLM이 런타임에 얼마나 깊이 자리 잡는가"라는 하나의 축 위에 나란히 놓으면 패턴이 드러난다.
- DoorDash는 왼쪽에 위치한다. LLM은 카탈로그를 오프라인에서 보강하고 제약된 출력으로 쿼리를 파싱하며, 런타임은 대부분 고전적인 방식을 유지한다.
- Instacart는 가운데에 위치한다. LLM이 헤드 쿼리에는 오프라인 RAG를 통해, 테일 쿼리에는 파인튜닝된 Llama-3-8B를 통해 쿼리 이해를 처리하지만, 다운스트림 검색은 여전히 전통적인 방식이다.
- Uber Eats는 오른쪽에 위치한다. 파인튜닝된 Qwen이 모든 쿼리마다 실행되고 모든 문서 벡터에 미리 구워지는 임베딩 백본이다.
각 회사가 이 스펙트럼에서 차지하는 위치는 대부분 이미 갖고 있던 인프라에 의해 결정됐다.
- DoorDash는 이미 지식 그래프를 갖고 있었고 고전적인 검색이 이를 활용할 수 있었으므로, 가장 저렴한 이득은 그래프를 더 풍부하게 만들고 쿼리가 그래프와 대화하는 법을 가르치는 데서 나왔다.
- Instacart는 유지보수하기 어려운 특화 쿼리 이해 모델들을 갖고 있었으므로, 가장 큰 승리는 통합된 LLM 전략 아래 이들을 통합하는 데서 나왔다.
- Uber Eats는 이미 버티컬별로 투 타워 임베딩 인프라를 운영하고 있었으므로, 자연스러운 다음 단계는 파인튜닝된 LLM을 공유 백본으로 교체해 하나의 모델이 모든 버티컬과 모든 언어를 처리하게 만드는 것이었다.
교훈은 어떤 작업에 어떤 LLM을 써야 하는지 묻기 전에, 더 나은 질문은 기존 스택 어디에서 LLM이 실제로 도움이 될지를 묻는 것이라는 점이다.
세 회사 모두에서 살아남은 세 가지 보편적 트레이드오프가 있다.
- 하이브리드 시스템이 어디서나 기본값이다. 고전적 검색, 지식 그래프, ANN 인덱스가 여전히 대부분의 작업을 수행한다.
- 사전 학습된 모델의 세계 지식은 그저 출발점일 뿐이다. 도메인 맥락은 RAG든 파인튜닝이든 어떤 식으로든 어딘가에 주입되어야 한다.
- 가드레일은 모든 프로덕션 LLM 시스템의 중요한 부분이다. 제약된 어휘, 유사도 필터, 분류 체계 강제가 조용히 출력이 카탈로그와 정합성을 유지하는지 여부를 결정한다.
4계층 심층 요약
핵심 주장
DoorDash, Instacart, Uber Eats는 같은 시기에 같은 연구 기반을 공유하며 음식 배달 검색을 LLM 중심으로 재구축했지만, 세 회사가 도착한 아키텍처는 서로 완전히 다르다. 그 차이를 결정한 것은 어떤 LLM을 골랐는가가 아니라 "LLM이 런타임에 얼마나 깊숙이 들어가야 하는가"라는 질문에 각 회사가 이미 보유한 인프라를 바탕으로 어떻게 답했는가이다.
근거
음식 검색은 동의어, 오타, 줄임말, 언어 혼용, 단어 의미 모호성 같은 표면적 실패에 더해 롱테일 쿼리와 제약 조건(비건, 알레르기, 수량 등) 처리라는 근본적으로 어려운 문제를 동시에 안고 있다. 키워드 기반 검색은 단어를 토큰 집합으로 취급하므로 "비 오는 저녁에 어울리는 건강한 음식"처럼 주관적이고 의도 중심적인 쿼리를 처리하지 못한다. 세 회사 모두 이 문제를 풀어야 했지만, 기존에 갖고 있던 시스템(지식 그래프, 특화 ML 모델 파이프라인, 버티컬별 두 타워 임베딩)이 LLM을 어디에 얼마나 깊이 꽂을지를 사실상 결정했다.
사례
DoorDash는 이미 있던 지식 그래프를 활용해 LLM을 오프라인 속성 추출과 쿼리 파싱에만 쓰고, RAG를 생성기가 아니라 "허용된 라벨 목록에서만 고르게 하는" 가드레일로 뒤집어 사용해 인기 메뉴 캐러셀 트리거율을 약 30% 끌어올렸다. Instacart는 FastText, 세션 마이닝 재작성 엔진, 개별 태깅·분류 모델로 파편화되어 있던 시스템을 컨텍스트 엔지니어링(RAG)·후처리 유사도 필터·Llama-3-8B 파인튜닝의 3단 전략으로 통합했고, 헤드 쿼리는 오프라인 RAG-캐시, 테일 쿼리는 300ms 이하 실시간 파인튜닝 모델로 서빙해 쿼리 재작성 커버리지를 50%에서 95% 이상으로, 테일 쿼리 불만을 절반으로 줄였다. Uber Eats는 다국어·다버티컬 복잡성 때문에 파인튜닝된 Qwen을 두 타워 구조의 임베딩 백본 자체로 삼아, 쿼리 타워는 온라인 실시간, 문서 타워는 오프라인 사전 임베딩으로 운영하며 Matryoshka 표현 학습(256차원, 리콜 손실 0.3% 미만)과 int7 양자화, 사전 필터로 대규모 서빙을 경제적으로 만들었다.
시사점
어떤 LLM을 쓸지 고르기 전에 "기존 스택의 어디에 LLM이 실제로 도움이 되는가"를 먼저 물어야 한다는 것이 핵심 교훈이다. 하이브리드 시스템(고전적 검색+지식그래프+ANN 인덱스가 대부분의 작업을 여전히 수행)이 세 회사 모두에서 기본값이었고, 사전학습 모델의 일반 지식은 출발점일 뿐 도메인 맥락은 RAG나 파인튜닝을 통해 반드시 별도로 주입해야 하며, 제약된 어휘와 유사도 필터, 분류체계 강제 같은 가드레일이 프로덕션 LLM 시스템의 신뢰성을 좌우한다는 점은 다른 도메인의 LLM 통합에도 그대로 적용될 수 있는 일반 원칙이다.
핵심 요약 (20줄)
- DoorDash, Instacart, Uber Eats는 최근 몇 년 사이 나란히 검색 시스템을 LLM 중심으로 재구축했다.
- 세 회사는 동일한 문제, 즉 사용자가 검색창에 입력한 의도를 이해하는 문제를 풀고자 했다.
- 세 회사는 거의 동일한 연구 기반을 참고했지만 실제로 배포한 아키텍처는 서로 완전히 달랐다.
- 이 차이는 어떤 LLM 모델을 선택했는지가 아니라 이미 보유한 인프라가 결정한 것이었다.
- 핵심 질문은 언제나 "LLM이 런타임 안으로 얼마나 깊이 들어가야 하는가"였다.
- 키워드 검색은 단어를 의도가 아닌 토큰 집합으로 취급하기 때문에 주관적인 쿼리를 제대로 처리하지 못한다.
- 동의어, 오타, 줄임말, 언어 혼용, 단어 의미 모호성은 음식 검색에서 반복적으로 나타나는 실패 유형이다.
- 롱테일 쿼리와 비건·알레르기 같은 제약 조건 처리는 훨씬 더 근본적으로 어려운 문제로 지목된다.
- DoorDash는 이미 보유한 지식 그래프를 바탕으로 LLM을 오프라인 속성 추출과 쿼리 파싱에만 사용했다.
- DoorDash는 RAG를 콘텐츠 생성기가 아니라 허용된 라벨 목록에서만 고르게 하는 가드레일로 뒤집어 사용했다.
- 이 접근으로 DoorDash는 인기 메뉴 캐러셀의 트리거율을 약 30% 끌어올리면서도 런타임을 대부분 고전적으로 유지했다.
- Instacart는 FastText와 여러 개별 모델로 파편화된 기존 시스템의 유지보수 부담이 컸다.
- Instacart는 컨텍스트 엔지니어링, 후처리 유사도 필터, Llama-3-8B 파인튜닝을 층층이 쌓는 전략을 택했다.
- Instacart는 헤드 쿼리를 오프라인 RAG 캐시로, 테일 쿼리를 300ms 이하 실시간 파인튜닝 모델로 나눠 서빙했다.
- 그 결과 Instacart의 쿼리 재작성 커버리지는 50%에서 95% 이상으로 뛰었고 테일 쿼리 불만은 절반으로 줄었다.
- Uber Eats는 여러 버티컬과 시장과 언어를 동시에 감당해야 하는 추가적인 복잡성을 안고 있었다.
- Uber Eats는 파인튜닝된 Qwen을 두 타워 구조의 임베딩 백본으로 삼아 쿼리와 문서를 동일한 벡터 공간에 매핑했다.
- Uber Eats는 Matryoshka 표현 학습과 양자화, 사전 필터를 조합해 대규모 서빙 비용을 크게 낮췄다.
- 세 회사의 위치는 결국 각자가 이미 갖고 있던 인프라, 즉 지식 그래프인지 특화 모델 파이프라인인지 두 타워 임베딩인지에 의해 결정되었다.
- 결론은 어떤 LLM을 쓸지 고르기 전에 기존 스택의 어디에서 LLM이 실제로 도움이 되는지를 먼저 물어야 한다는 것이다.