AI 프로젝트가 약해지는 순간은 모델 호출이 아니라 근거가 빈약할 때입니다. BattleBots 승부 예측기를 예로 웹 데이터 수집, 벡터 검색, LLM 구조화 출력까지 어떻게 묶어야 사용자가 납득하는 앱이 되는지 정리해보겠습니다.
Bright Data와 BattleBots의 개발자 대회 예시는 꽤 좋은 출발점입니다. 겉으로는 "로봇 격투 경기의 승자를 AI가 맞힌다"는 재미있는 장난감처럼 보이지만, 안쪽으로 들어가면 웹 스크래핑, 데이터 정규화, 임베딩, RAG, UI 설계가 모두 들어갑니다.
이 글은 특정 대회의 현재 참가 안내가 아니라, 그 예시에서 뽑아낼 수 있는 프로젝트 설계법에 가깝습니다. 작고 구체적인 도메인에서 공개 데이터를 모아, 근거가 보이는 AI 앱으로 만드는 흐름을 이해하면 스포츠, 상품 리뷰, 채용 공고, 오픈소스 이슈, 논문 검색 같은 다른 도메인에도 거의 그대로 응용할 수 있습니다.

이 예제가 좋은 이유: AI보다 데이터가 먼저 보입니다
흔한 AI 사이드 프로젝트는 이렇게 끝납니다. 화면에서 질문을 입력하면 LLM이 답합니다. 기능은 돌아가지만, 왜 이 앱이 필요한지 설명하기 어렵습니다. 기존 챗봇과 차이가 흐립니다.
BattleBots 예측기는 다릅니다. 사용자는 Uppercut과 Bite Force 같은 두 봇을 고르고, 앱은 어느 쪽이 이길 가능성이 높은지 보여줍니다. 예측 결과에는 승률만 있으면 약합니다. 설득력은 그 아래에 붙는 근거에서 나옵니다.
- 각 봇의 전적
- 무기와 구동 방식
- 경기 기록과 시즌 맥락
- 승/패/무승부 이력
- 특정 상대와의 상성
- 팬 커뮤니티의 반응과 감성
이런 정보가 함께 나오면 "AI가 찍었다"가 아니라 "수집한 데이터로 판단했다"는 느낌이 생깁니다. 대회 제출물이든 포트폴리오든, 보는 사람은 여기서 기술 실행력을 봅니다.
만들 앱은 단순해야 합니다. 대신 근거는 깊어야 합니다
사용자 경험은 복잡할 필요가 없습니다.
- 봇 A를 선택합니다.
- 봇 B를 선택합니다.
- 예측 버튼을 누릅니다.
- 예상 승자, 신뢰도, 핵심 근거, 참고한 경기/커뮤니티 신호를 봅니다.
겉보기에는 간단합니다. 하지만 내부 데이터는 얇으면 안 됩니다. "Bite Force가 강하다" 같은 문장 몇 개로는 금방 티가 납니다. 최소한 봇 정보, 경기 기록, 토너먼트 맥락, 팬 반응이 분리되어 있어야 합니다.
특히 팬 감성 데이터는 조심해서 다뤄야 합니다. Reddit 같은 커뮤니티 반응은 경기력의 직접 지표가 아닙니다. 대신 "사람들이 어떤 무기를 두려워하는지", "최근 경기 이후 평가가 어떻게 바뀌었는지", "특정 매치업에서 자주 언급되는 약점이 무엇인지"를 보조 신호로 쓰면 좋습니다.
여기서 중요한 기준은 하나입니다. 예측 결과를 본 사람이 "왜 그렇게 판단했는지"를 따라갈 수 있어야 합니다.
첫 번째 실패 지점: 스크래핑은 생각보다 빨리 막힙니다
초보자는 보통 Playwright나 Puppeteer로 페이지를 열고, CSS selector로 값을 뽑으면 끝이라고 생각합니다. 작은 데모에서는 맞습니다. 하지만 수백 개 페이지를 돌기 시작하면 상황이 달라집니다.
막히는 지점은 대략 이렇습니다.
| 문제 | 실제로 생기는 증상 | 설계에서 필요한 대응 |
|---|---|---|
| Rate limit | 처음 몇 페이지는 되다가 갑자기 실패 | 요청 속도 제어, 재시도, 큐 |
| IP block | 특정 환경에서만 계속 차단 | 프록시/언블로킹 인프라 |
| CAPTCHA | 자동화 브라우저가 사람 확인에 걸림 | 수동 우회가 아니라 수집 전략 재설계 |
| HTML 변경 | 어제 되던 selector가 오늘 깨짐 | 파서 테스트, fallback selector |
| 커뮤니티 데이터 | 댓글 구조와 정렬이 불안정 | 수집 범위 제한, 정책 확인, 중복 제거 |
이 예시에서는 Bright Data의 Web Unlocker API를 사용합니다. 공식 문서 기준으로 이 API는 target URL을 보내면 HTML 또는 JSON 응답을 돌려주고, 프록시, 헤더, fingerprint, CAPTCHA, anti-bot challenge 같은 운영 복잡성을 API 쪽에서 처리하도록 설계되어 있습니다.
다만 이걸 "아무 사이트나 마음대로 긁어도 된다"는 뜻으로 받아들이면 안 됩니다. 공개 데이터 범위, 사이트 약관, robots 정책, 개인정보 여부는 별개의 문제입니다. 기술적으로 가능하다는 것과 발행 가능한 프로젝트라는 것은 다릅니다.
이미 웹 데이터 수집형 앱을 만들어보고 싶다면, 비슷한 흐름의 내부 예제로 Python으로 아마존 경쟁사 분석 대시보드 만드는 법을 같이 보면 좋습니다. 상품 데이터 수집을 대시보드와 LLM 분석으로 연결한다는 점에서 이 프로젝트와 결이 가깝습니다.
DB와 벡터 DB를 분리해서 생각해야 합니다
BattleBots 예측기에서 모아야 할 데이터는 한 종류가 아닙니다. 봇 기본 정보, 경기 기록, 시즌 정보, 커뮤니티 반응이 섞입니다. 이걸 전부 긴 프롬프트에 붙여 LLM으로 보내면 비용도 늘고, 결과도 흐려집니다.
그래서 저장 계층을 두 개로 나눠 생각하는 편이 좋습니다.
일반 DB에는 정규화된 사실 데이터를 둡니다.
- bot_id
- name
- weapon_type
- record
- match_id
- opponent
- result
- season
- source_url
벡터 DB에는 검색해야 하는 텍스트 조각을 둡니다.
- 봇 설명
- 경기 요약
- 특정 무기와 상성에 대한 문장
- 커뮤니티 반응 요약
- 시즌별 맥락 설명
OpenAI의 Embeddings 문서에서도 임베딩은 텍스트를 숫자 벡터로 바꿔 관련성을 비교하는 방식으로 설명됩니다. 이 프로젝트에서는 "Bloodsport에 대한 모든 문서"를 통째로 넣는 게 아니라, Bloodsport와 상대 봇에 관련 있는 조각을 찾아 LLM에 넘기는 데 씁니다.
즉, 벡터 DB는 멋있어 보이려고 넣는 부품이 아닙니다. "이번 예측에 필요한 근거만 뽑기 위한 필터"입니다.
RAG는 예측을 똑똑하게 만드는 장치가 아니라, 근거를 좁히는 장치입니다
RAG를 붙이면 AI가 갑자기 전문가가 된다고 생각하기 쉽습니다. 실제로는 조금 다릅니다. RAG의 가장 큰 역할은 LLM이 볼 근거를 좁혀주는 것입니다.
예를 들어 Uppercut vs Bite Force를 예측한다고 해봅시다. 전체 데이터에는 다른 봇 수십 개, 여러 시즌, 관련 없는 댓글까지 들어 있습니다. 여기서 필요한 것은 두 봇의 전적, 무기 특성, 비슷한 매치업, 최근 평가 정도입니다.
흐름은 이렇게 잡으면 됩니다.
- 사용자가 두 봇을 선택합니다.
- 각 봇 이름과 관련 키워드로 벡터 검색을 합니다.
- 경기 기록 DB에서 직접적인 match history를 가져옵니다.
- 커뮤니티 감성은 요약된 보조 신호만 붙입니다.
- LLM에는 "이 근거 안에서만 판단하라"고 지시합니다.
- 결과에는 승자와 신뢰도뿐 아니라 근거 목록을 함께 반환하게 합니다.
핵심은 데이터를 많이 넣는 것이 아니라, 이번 질문에 필요한 근거만 좁혀서 LLM이 덜 헷갈리게 만드는 것입니다.
이때 프롬프트에서 가장 중요한 문장은 "모르는 것은 모른다고 표시하라"입니다. 데이터가 부족한데도 87% 같은 숫자를 자신 있게 내면 프로젝트의 신뢰도가 바로 무너집니다.
RAG 개념 자체가 낯설다면 사이트의 RAG: 대규모 언어 모델의 지식 간극 극복하기를 먼저 읽고 돌아와도 좋습니다. 이 글에서는 개념보다 실제 앱 설계 쪽에 더 초점을 맞춥니다.
구조화 출력은 예쁜 UI보다 먼저 필요합니다
LLM 응답을 그냥 자연어 문단으로 받으면 처음에는 편합니다. 하지만 UI를 붙이는 순간 골치가 아파집니다.
예측 화면에는 보통 이런 필드가 필요합니다.
{
"winner": "Bite Force",
"confidence": 0.76,
"method": "record + matchup + sentiment",
"key_factors": [
"weapon reliability",
"historical win rate",
"driver control"
],
"evidence": [
{
"type": "match_history",
"summary": "..."
}
],
"limitations": [
"recent unverified community sentiment"
]
}
이런 형태로 받아야 승률 카드, 핵심 요인 리스트, 근거 패널, 주의사항 박스를 안정적으로 그릴 수 있습니다. OpenAI의 Structured Outputs 문서는 JSON Schema에 맞는 응답을 받는 방식을 설명합니다. 이 기능의 실전 가치는 "모델이 예쁘게 말하게 하는 것"이 아니라 "앱이 파싱 가능한 형태로 받는 것"입니다.
여기서 한 가지 더 챙기면 좋습니다. confidence는 모델의 주관적 확률입니다. 실제 통계 모델의 검증된 승률처럼 보이게 표시하면 안 됩니다. UI에는 "AI confidence"나 "prediction confidence"처럼 성격을 분명히 적고, 근거와 한계를 바로 아래에 붙이는 편이 안전합니다.
좋은 제출물은 데이터 파이프라인이 보입니다
대회든 포트폴리오든, 심사자가 보는 것은 "AI를 썼다"가 아닙니다. 이제 그건 너무 흔합니다. 차이가 나는 부분은 다음 네 가지입니다.
| 평가 포인트 | 약한 구현 | 강한 구현 |
|---|---|---|
| 명확성 | 버튼 누르면 결과만 나옴 | 어떤 데이터를 썼는지 단계별로 보임 |
| 창의성 | 흔한 챗봇 UI | BattleBots라는 도메인에 맞는 예측 경험 |
| 기술 실행 | LLM API 호출 중심 | 수집, 정제, 검색, 구조화 출력까지 연결 |
| 실제 가치 | 재미는 있지만 근거 없음 | 경기 기록과 팬 반응을 함께 비교 |
이런 프로젝트에서는 "라이브 활동 로그"가 꽤 강한 장치가 됩니다. 예측 버튼을 누른 뒤 앱이 무엇을 하고 있는지 보여주는 것입니다.
- bot profile 로딩 중
- match history 검색 중
- tournament data 정리 중
- community sentiment 요약 중
- LLM prediction 생성 중
이 로그는 단순 장식이 아닙니다. 사용자는 기다리는 이유를 이해하고, 심사자는 내부 파이프라인을 봅니다.
AI 에이전트 구조까지 확장하고 싶다면 파이썬으로 AI Agents 구축하는 법도 이어서 볼 만합니다. 이 예측기를 단일 API 호출이 아니라 "수집 도구, 검색 도구, 분석 도구를 호출하는 에이전트 실행 흐름"으로 바꿀 수 있기 때문입니다.
실제 구현 순서는 이렇게 잡는 게 덜 망합니다
처음부터 React UI를 예쁘게 만들면 재미는 있지만, 데이터가 비어 있을 때 되돌리기 힘듭니다. 순서는 반대로 가는 편이 낫습니다.
- 봇 5개만 골라 수동으로 데이터 샘플을 만듭니다.
- 예측 JSON schema를 먼저 정합니다.
- 샘플 데이터로 LLM 응답이 쓸 만한지 확인합니다.
- 그 다음 스크래퍼를 붙입니다.
- 파서 테스트를 만듭니다.
- DB 저장 구조를 고정합니다.
- 임베딩과 벡터 검색을 붙입니다.
- 마지막에 UI를 얹습니다.
이 순서의 장점은 어디가 문제인지 빨리 보인다는 겁니다. 예측이 별로라면 데이터가 부족한지, 검색이 엉뚱한지, 프롬프트가 약한지 분리해서 볼 수 있습니다.
반대로 처음부터 전체 자동화를 만들면 실패 지점이 한 덩어리로 섞입니다. 스크래핑이 실패한 건지, 파싱이 깨진 건지, 벡터 검색이 빗나간 건지, 모델이 근거를 무시한 건지 찾는 데 시간이 다 갑니다.
체크리스트: 이 정도면 "괜찮은 AI 프로젝트"처럼 보입니다
마지막으로 구현 전에 이 체크리스트를 통과하는지 보면 좋습니다.
- 사용자가 선택할 수 있는 대상이 명확한가?
- 예측에 쓰는 데이터 종류가 최소 3개 이상인가?
- 원본 URL 또는 출처를 저장하는가?
- LLM에 모든 데이터를 넣지 않고 검색된 근거만 넣는가?
- 결과가 JSON schema로 고정되어 UI가 깨지지 않는가?
- confidence의 의미와 한계를 표시하는가?
- 커뮤니티 감성을 사실 데이터처럼 과장하지 않는가?
- 스크래핑 실패, 빈 데이터, 중복 데이터에 대한 fallback이 있는가?
- 결과 화면에서 "왜 이 예측이 나왔는지" 확인할 수 있는가?
여기까지 갖추면 단순 AI 데모가 아니라 데이터 제품에 가까워집니다. 작은 주제라도 구조가 탄탄하면 훨씬 오래 기억됩니다.
FAQ
꼭 Bright Data 같은 언블로킹 도구를 써야 하나요?
작은 실험에서는 필요 없을 수 있습니다. 하지만 여러 페이지를 안정적으로 수집하거나 CAPTCHA, rate limit, IP block이 반복된다면 직접 우회 코드를 늘리는 것보다 전용 API를 쓰는 편이 관리하기 쉽습니다. 다만 사이트 약관과 데이터 사용 범위는 별도로 확인해야 합니다.
벡터 DB 없이도 만들 수 있나요?
처음에는 가능합니다. 데이터가 작다면 일반 DB 검색이나 BM25만으로도 충분합니다. 하지만 봇 설명, 경기 요약, 팬 반응처럼 비정형 텍스트가 많아지면 임베딩 기반 검색이 훨씬 편해집니다.
마무리: 모델보다 근거가 남는 앱을 만드세요
BattleBots AI 예측기의 재미는 로봇이 싸운다는 소재에 있습니다. 하지만 프로젝트로서의 힘은 그보다 안쪽에 있습니다. 흩어진 웹 데이터를 모으고, 정리하고, 필요한 근거만 검색하고, LLM이 구조화된 답을 내게 만드는 흐름입니다.
AI 프로젝트를 하나 만들고 싶다면 "무슨 모델을 쓸까"보다 먼저 "어떤 데이터를 모으면 사용자가 판단을 바꿀까"를 정해보세요. 그 질문이 잡히면 RAG, 벡터 DB, structured output은 유행어가 아니라 필요한 부품이 됩니다.
'SW > 인공지능' 카테고리의 다른 글
| Claude Cowork는 언제 써야 할까: Chat 대신 일을 맡기는 기준 (0) | 2026.08.03 |
|---|---|
| Hermes Agent로 AI 직원 사업 만들기: 설치보다 먼저 봐야 할 기준 (0) | 2026.08.02 |
| AI 코딩 도구가 갑자기 막혔을 때, 개발자가 점검할 것 (0) | 2026.07.30 |
| 로컬 LLM 도구 선택 가이드: Ollama, LM Studio, vLLM까지 언제 쓰나 (0) | 2026.07.29 |
| VS Code에서 로컬 AI 코딩하기: LM Studio 모델 선택부터 자동완성까지 (0) | 2026.07.26 |