01 — RESEARCH ·R-001 ·2026.06.05

월드컵을 통째로 서비스에 담아보기로 했다

월드컵 RAG 개발기 1편 — 프로젝트 개요, 아키텍처, 그리고 "숫자는 코드가, 문장은 LLM이"라는 설계 결정.

목차
  1. 뭘 만들었나
  2. 시작은 Hugging Face Spaces였다
  3. 가장 중요한 설계 결정 — 숫자는 코드가, 문장은 LLM이
  4. 역할 기반 워크플로
  5. 이 연재에서 다룰 것

연재 · 월드컵 RAG 프로젝트 개발기 (1/5) 2026 북중미 월드컵을 데이터로 다루는 웹 서비스를 혼자 만들고 운영하며 겪은 것들.

  1. 월드컵을 통째로 서비스에 담아보기로 했다 ← 지금 글
  2. 크롤러가 죽었다 — 데이터 수집 잔혹사
  3. 배포했더니 데이터가 사라졌다 — Railway 운영의 함정들
  4. LLM은 숫자를 지어낸다 — 환각과 싸운 기록
  5. 손흥민 리포트 제작기 — 이벤트 데이터로 기사급 리포트 만들기

뭘 만들었나

2026 북중미 월드컵을 앞두고, 경기 데이터를 모아서 프리뷰·리뷰 기사를 자동 생성하고, 챗봇으로 질문에 답하는 웹 서비스를 만들기로 했다. 목표는 단순했다 — 경기가 끝나면 몇 분 안에 데이터 기반 리뷰가 올라오고, “이번 조별리그에서 크로스 성공률이 제일 낮았던 팀은?” 같은 질문에 근거를 갖고 답하는 것.

최종 형태는 이렇다:

  • Streamlit 멀티페이지 앱 — 관리자/기자 역할 구분, 경기 리뷰·커스텀 리뷰·프리뷰·챗봇·데이터 관리 페이지
  • 데이터: sofascore 경기 통계(팀/슛맵/선수 CSV) + WhoScored 이벤트 데이터(경기당 1,500여 개 이벤트) + 웹 기사 수집(48개 본선 팀, 2,400여 건)
  • 생성: OpenAI API로 리뷰·프리뷰·챗봇 답변. RAG로 수집 기사를 컨텍스트로 주입
  • 배포: Railway (커스텀 도메인), 영구 데이터는 Volume에

211커밋을 지나 지금은 본선 96경기(조별리그 72 + 32강 16 + 16강 8) 데이터가 올라가 있고, 대회 진행에 맞춰 매일 업데이트 중이다.

시작은 Hugging Face Spaces였다

처음엔 Streamlit 템플릿을 복제해서 HF Spaces에 올렸다. 프로토타입엔 충분했지만 곧 한계가 왔다. 재시작마다 데이터가 날아가서 HF Dataset 동기화로 버텼는데, 서비스가 커지니 어색한 구조가 됐다. 결국 Railway로 옮기고 Dockerfile 배포 + Volume 마운트 구조로 정리했다. (이 과정에서 겪은 함정들은 3편에서.)

가장 중요한 설계 결정 — 숫자는 코드가, 문장은 LLM이

이 프로젝트에서 제일 잘한 결정을 하나 꼽으라면 이거다.

초기에 LLM에게 원시 데이터를 주고 “표로 정리해서 리뷰 써줘”라고 하면, 표의 숫자를 지어냈다. 합계가 안 맞고, 없는 선수가 등장하고, 슛 분포를 골 시간으로 착각했다. 몇 번 데인 후 역할을 완전히 갈랐다:

  • 집계·표·수치 = 파이썬 코드가 확정 생성 (pandas로 계산, 마크다운 표까지 코드가 만듦)
  • LLM = 확정된 수치를 “인용”만 — 프롬프트에 “이 표를 그대로 복사해 넣어라, 재계산 금지”를 박았다

이 원칙은 이후 모든 기능(리뷰, 챗봇, 기자용 리포트)의 뼈대가 됐다. 자세한 건 4편에서 다룬다.

역할 기반 워크플로

기자가 실제로 쓰는 도구가 되려면 “생성 → 검토 → 발행” 흐름이 필요했다. 그래서:

  • admin: 데이터 검수·승인, 경기 공개 여부, 발행 권한
  • reporter: 커스텀 리뷰 작성(관점·형식·분량 지정), 본인 초안 열람

커스텀 리뷰는 “관전 포인트를 자유 서술로 입력 → LLM이 청크(섹션) 구성을 제안 → 스트리밍 생성” 구조다. 형식(서술형/개조식/요약)과 분량(짧게/보통/길게)을 고르게 했더니 실사용 만족도가 확 올라갔다.

이 연재에서 다룰 것

만들면서 “이건 글로 남겨야겠다” 싶었던 순간이 많았다:

  • 크롤러가 403으로 전멸하고, 알고 보니 기관망 IP가 Cloudflare에 차단돼 있었던 날 (2편)
  • 배포만 하면 승인·발행 상태가 사라져서 한참 헤맨 끝에 찾은 휘발성 디렉토리 (3편)
  • 맥에서 올린 한글 폴더가 서버에서 두 개로 보이던 유니코드 정규화(NFC/NFD) 사건 (3편)
  • LLM이 골 시간을 슛 분포에서 “추론”해서 지어내던 문제와 단일 출처 원칙 (4편)
  • 손흥민 3경기 리포트를 만들며 발견한 WhoScored 데이터의 함정들 — 후반 시계는 45분부터 다시 시작한다 (5편)

한 편씩, 삽질의 기록을 정리해 본다.