RevCheck: 중고차 매물 두 개를 붙여넣으면 현장 점검 보고서가 나옵니다
요약
RevCheck는 중고차 매물 두 개를 붙여넣기만 하면 현장 점검 보고서와 판정(verdict)을 제공하는 도구입니다. Gemma 4가 사진의 흠집, 옵션 등을 검사하고, 시장 위치 분석 및 TabPFN 기반 가격 범위를 제시합니다. 이를 통해 구매자가 차량 방문 전 어느 매물이 더 가치가 있는지 판단할 수 있도록 돕습니다.
핵심 포인트
- 두 중고차 매물 비교를 위한 AI 도구 RevCheck 소개
- Gemma 4가 사진을 검사하여 옵션 및 흠집 확인 가능
- 시장 데이터와 TabPFN을 활용해 공정한 가격 범위 제시
- 엔진별 알려진 취약점과 일반적인 차량 점검 항목 제공
[Hacktoberfest 오픈소스 AI 챌린지 주차 2: 부업(Side Hustle) 제출물]
내가 만든 것
불가리아에서 중고차를 구매하는 과정은 이렇습니다. mobile.bg와 cars.bg에 열두 개의 탭을 띄워야 합니다. 그중 절반은 "нов внос"(신규 수입), "реални километри"(실제 주행거리), 그리고 "без забележки"(고칠 것 없음)라는 문구를 담고 있습니다. 같은 차가 두 사이트에 모두 올라와 있습니다. 그러다 보면, 플로브디프(Plovdiv)까지 운전해서 간 토요일을 날리게 되는데, 알고 보니 엔진이 다르거나, 좌석에 개 자국이 있거나, 다른 사람이 요구하는 가격대가 아닙니다.
그래서 저는 **RevCheck**를 만들었습니다. 두 개의 매물 정보를 어느 사이트에서 가져오든 붙여넣기만 하면, 약 30초 후에 비교 보고서와 판정(verdict)을 얻게 됩니다:
-
Gemma 4가 모든 사진을 검사합니다: 색상, 흠집, 스크래치, 맞지 않는 패널, 그리고 실제로 눈에 보이는 장비들(M Sport 범퍼, 파노라마 루프, 가죽 시트, 내비게이션 등)까지 확인합니다. 또한 판매자가 목록에 기재했지만 사진과 모순되는 추가 옵션도 알려줍니다.
-
시장 위치 분석: 두 사이트 모두에서 유사한 차량(동일 모델, 차체 유형, 연료 및 엔진 출력, 연식 ±1)을 찾아내고 "유사 매물 44개 중 상위 91%보다 비싸게 책정됨"과 같은 정보를 제공합니다. 두 사이트에 동시에 올라온 차량은 한 번만 계산됩니다.
-
TabPFN의 공정한 가격 범위: 요청 시점에 해당 비교 데이터를 학습한 TabPFN이 "€4,718 – €8,665이며, 따라서 이 차는 예상 가격보다 €2,276 높습니다"와 같은 정보를 제공합니다.
-
해당 엔진의 알려진 취약점: DeepSeek V4는 연식, 출력 및 배기량을 바탕으로(N47D20C, N52 또는 N53 등) 예상 엔진 코드를 명시하고, 차량을 볼 때 확인해야 할 사항들(냉간 시동 시 타이밍 체인 소음, 스월 플랩, ZF 기어박스, 고압 연료 펌프 등)을 나열합니다.
-
AI가 아닌 일반 검사: VIN 번호 누락 여부, 연식 대비 비정상적으로 낮은 또는 높은 주행거리(km), 사진 개수 부족 여부, 미국이나 캐나다 수입차 여부(VIN으로 확인 가능).
-
최종 판정: 어떤 차를 가서 봐야 하는지, 그 이유, 각 차량에서 무엇을 점검해야 하는지, 그리고 차에 타기 전에 판매자에게 무엇을 물어봐야 하는지를 알려줍니다.
-
영어와 불가리아어, 상단에 국기 표시가 있습니다. 보고서는 선택한 언어로 작성됩니다.
누가 비용을 지불할까요? 반나절과 연료통 가득한 기름값을 들여 차량을 직접 보러 갈 예정인 사람이라면 누구나 할 것입니다. 사람들은 이미 구매하기 전에 정비사나 검사관에게 차를 직접 봐달라고 돈을 지불합니다. RevCheck는 그 전 단계입니다. 두 대 중 어느 것이 방문할 가치가 있는지 알려줍니다. 저는 하루에 몇 쌍의 비교는 무료로 제공하고, 일주일에 수십 대의 차량을 비교하는 플리퍼(flippers)나 소규모 딜러들에게는 적은 월정액을 부과할 것입니다.
데모 (Demo)
실제 사이트: https://georgievalex.github.io/revcheck/
현재 판매 중인 BMW 320d 에스테이트 두 대를 가지고 시도해 보세요:
https://georgievalex.github.io/revcheck/?a=https://www.mobile.bg/obiava-11744111052659454-bmw-320-2-0d&b=https://www.mobile.bg/obiava-11787314145036432
두 링크를 붙여넣고, 상자를 체크하고, 'Compare'를 클릭하세요:

결과가 먼저 나옵니다. 각 차량 카드는 해당 차량 처리가 완료되는 즉시 채워집니다:

시장 포지션, TabPFN 공정 가격 범위, 그리고 사진이 보여주는 것:

그리고 엔진의 알려진 약점과, 현장에서 확인해야 할 사항들입니다:}<tool_call|>jsonjson
{

Code
GitHub logo GeorgievAlex / revcheck
mobile.bg 또는 cars.bg의 중고차 매물 두 개를 오픈 웨이트 AI (Gemma 4 vision + TabPFN)로 비교하기
RevCheck
RevSofia 가족이 만든 사전 구매 점검 서비스입니다. mobile.bg 또는 cars.bg에서 가져온 중고차 매물 두 개를 붙여넣으면, 나란히 비교하는 보고서와 어떤 차량이 더 좋은 구매인지에 대한 판정(verdict)을 얻을 수 있습니다.
2026년 10월 15일~18일에 DEV Hacktoberfest Open-Source AI Challenge, Week 2: Side Hustle를 위해 처음부터 구축되었습니다.
사이트: https://georgievalex.github.io/revcheck/
DEV에 작성된 글: https://dev.to/alexgeorgiev17/revcheck-paste-two-used-car-listings-get-a-second-opinion-before-you-drive-across-town-1e7e
매물 읽는 방법
mobile.bg와 cars.bg는 DigitalOcean의 요청을 거부합니다 (Cloudflare 챌린지 또는 403). Cloudflare 자체 네트워크를 통해서만 응답이 옵니다. 따라서 이 함수는 작은 Cloudflare Worker인 revcheck-reader (cloudflare/reader/)를 통해 페이지를 읽습니다:
- 누구인지 정직하게 밝힘:
RevCheck/0.1 (+github link)User-Agent와, Cloudflare가 모든 Worker 요청에 추가하는CF-Worker헤더를 사용합니다. 두 사이트 모두 하나의 규칙으로 차단할 수 있으며, 만약 그렇게 한다면 저희는 중단합니다. - 공개 프록시가 아님: DigitalOcean 함수만이 가진 공유 비밀(shared secret)이 필요하며, mobile.bg 매물만 가져옵니다...
제가 구축한 방법
이전 두 항목과 동일한 규칙을 적용했습니다: 프레임워크는 없고, 데이터베이스도 없고, npm 의존성도 없습니다. GitHub Pages에 호스팅되는 정적 페이지와 DigitalOcean Function 하나, 그리고 작은 Cloudflare Worker 하나로 구현했습니다.
browser ── GitHub Pages (정적) + Cloudflare Turnstile
│ start → 봇 확인 후, 이 두 링크에 대한 3분 유효 서명 티켓을 반환
│ car ×2 → 차량당 하나의 요청, 병렬 처리
...
| 작업 (Job) | 모델 (Model) | 선택 이유 (Why this one) |
|---|---|---|
| 사진 보기 (Look at the photos) | gemma-4-31B-it (오픈 웨이트) | 불가리아어 또는 영어로 대시보드, 범퍼, 좌석을 한 번에 읽음 |
| ... |
제가 만족하는 몇 가지 점이 있습니다:
- 브라우저 데이터는 신뢰할 수 없습니다. 판정 단계(verdict step)에서는 각 차량의 결과를 페이지로부터 받기 때문에, 모든 필드는 모델에게 도달하기 전에 크기 제한을 둔 알려진 목록으로 재구성됩니다. 사진 URL은 Gemma가 다운로드해야 하므로 두 사이트의 이미지 서버를 가리켜야 합니다.
- 무서운 부분(scary stuff)은 모델이 아니라 코드로 결정됩니다. 주행거리계 플래그, VIN 확인, 연간 km당 거리, 미국 수입 여부 등 모든 것이 규칙입니다. 모델은 단지 확인할 것을 _제안_할 수만 있습니다 (자세한 내용은 아래에서).
- 느린 단계마다 마감 기한이 있습니다. 알려진 문제(known-issues) 조회 작업이 멈추더라도, 아예 차량을 못 보는 대신 해당 정보가 빠진 차량이라도 얻게 됩니다.
- 26개의 테스트를 모두
node:test로 사용하며, 다음 섹션의 보기 싫은 실제 사례들까지 포함합니다.
커밋 기록에는 아래 각 학습 내용마다 하나의 커밋이 있습니다. 확인해 보고 싶다면 참고하세요.
제가 잘못한 점 (What I got wrong on the way)
The listing sites block DigitalOcean. 처음에는 함수에서 목록을 가져오는 방식으로 구현했고, 제 노트북에서는 완벽하게 작동했습니다. 하지만 배포하자마자 mobile.bg는 Cloudflare의 "잠시만 기다려 주세요..." 페이지를 반환했고, cars.bg는 403 에러를 반환했습니다. 그들은 클라우드 서버를 차단하는 것이 당연합니다. 스크래퍼에 지쳤기 때문이죠. 브라우저로도 읽을 수 없는데, 두 사이트 모두 다른 웹사이트가 접근하는 것을 허용하지 않기 때문입니다 (CORS 헤더 없음). 저는 작은 브라우저 확장 프로그램(browser extension)을 만들었다가 버렸습니다. 아무도 들어본 적 없는 곳의 확장을 설치할 리가 없으니까요. 효과를 본 것은 목록, 검색 페이지 또는 모델 목록만 가져오는 Cloudflare Worker였습니다. 이 워커는 User-Agent로 RevCheck/0.1과 레포지토리 링크를 전송하며, Cloudflare는 워커 이름을 담은 헤더를 추가하여 두 사이트 모두 누가 요청하는지 정확히 알 수 있게 합니다. 따라서 한 가지 규칙으로 차단할 수 있습니다. 만약 그들이 차단한다면 그것은 그들의 결정이고 저는 멈출 것입니다. 이것은 오직 제 함수만이 가진 비밀(secret)이 필요하며, 다른 URL은 거부하기 때문에 공개 프록시가 아닙니다.
Gemma는 판매자를 주행거리계 조작(odometer fraud) 혐의로 고발했습니다. 104,000km에 올라온 2012년식 Audi Q5 차량의 경우, 대시보드 사진을 266,777km로 읽었고 그 판정은 "심각한 주행거리계 조작"이라고 했습니다. 제가 직접 사진을 확대해 보니: 계기판에는 104,677이 적혀 있습니다. 흐릿하게 찍힌 숫자 하나 때문에 공공 페이지에서 실제 사람이 사기꾼으로 오인받을 뻔했습니다. 이제 이 모델은 주행거리계만 읽고 판독 결과를 명확(clear)하거나 불명확(unclear)하다고 평가하며, 코드가 최종적으로 결정합니다. 플래그가 표시되는 경우는 판독 결과가 명확하고 차이가 15%를 초과할 때뿐이며, 그 경우에도 "직접 계기판을 확인하세요"라고 안내합니다. 이제 프롬프트는 아예 주장을 금지합니다.
사진 10장이 있는 목록에 "사진이 충분하지 않음". DigitalOcean의 엔드포인트(endpoint)는 한 번의 호출로 최대 8개의 이미지 링크만 처리할 수 있기 때문에, 저는 사진을 8개씩 병렬 배치(parallel batches)로 확인합니다. 마지막 배치는 내부 사진 단 2장뿐이었고, 모델은 이 사진들만 보고 "사진이 매우 적으며, 내부 사진만 있음"이라고 작성했습니다. 이제 모델은 사진 개수를 판단하지 않습니다. 코드가 판단합니다.
쿠페와 세단 비교. cars.bg의 한 판매자가 차체 유형을 라틴 문자 K로 "Kупе"라고 입력했습니다. 제 차체 유형 필터는 이를 인식하지 못하고 조용히 검색을 진행했습니다. 재미있게도, cars.bg 자체 검색 양식에서도 라틴 문자 K를 사용합니다. 이제 차체 유형은 라틴어와 유사한 키릴 문자를 매핑하여 비교하며, 해당 정확한 문자열로 테스트하는 기능이 추가되었습니다.
AI가 리콜 정보를 발명했습니다. 저는 RevCheck가 제조사 캠페인, 예를 들어 "VANOS 볼트" 같은 내용을 나열하기를 원했습니다. DeepSeek은 N52 엔진에 대한 VANOS 볼트 캠페인을 자신 있게 나열했는데, 제가 알기로 그것은 다른 엔진용이었습니다. 또한 테스트 과정에서 저도 실수를 했습니다. 2007년식 272마력의 330i가 N53이어야 한다고 말했지만, 그 해까지는 N52가 동일한 출력을 내고 있었습니다. 따라서 두 가지 수정 사항이 생겼습니다. 리콜 정보 자체가 생성되지 않습니다. 페이지에서는 VIN(차대번호)으로 열려 있는 캠페인을 딜러에게 확인하도록 안내하며, VIN 디코더 링크를 제공합니다. 그리고 엔진이 연중에 변경된 경우, 모델은 둘 다 제시하고 "가능성이 높다"고 말해야 하며, 절대 "확실하다"고 해서는 안 됩니다.
요청이 정확히 40초에 실패했습니다. 사진과 TabPFN 및 알려진 문제점 조회 기능을 사용한 전체 비교에는 33~45초가 걸렸으며, 가끔 페이지에서 "비교기를 사용할 수 없습니다(couldn't reach the comparer)"라는 메시지를 표시했습니다. 저는 단순히 대기하는 테스트 함수를 배포했습니다. DigitalOcean의 웹 게이트웨이는 해당 함수 자체의 타임아웃과 상관없이 정확히 40초 후에 202 Response not yet ready 응답을 반환합니다. 따라서 비교는 이제 세 가지 종류의 짧은 요청(시작 약 2초, 각 차량당 병렬로 약 19초, 최종 판정 약 8초)으로 구성되며, 봇 검사가 여전히 모든 것을 커버할 수 있도록 서명된 티켓으로 연결됩니다. 보너스로, 이제 차량들이 최종 판정보다 먼저 표시됩니다.
개방형 혁신은 왜 중요한가요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기