ReplyDesk: 구글 리뷰에 답하고 줄 수 없는 환불을 약속하는 4B 모델
요약
ReplyDesk는 소규모 가게들의 구글 리뷰에 사장님 특유의 목소리로 답변을 작성해주는 도구입니다. Qwen3.5-4B 모델을 파인튜닝하고, 상점의 사실 정보와 과거 기록을 결합하여 진정성 있는 초안 답변을 제공합니다. 이는 단순한 AI 답변 생성을 넘어선 '상황 맥락' 기반의 솔루션입니다.
핵심 포인트
- 소규모 가게를 위한 구글 리뷰 자동 응답 툴
- Qwen3.5-4B 모델을 파인튜닝하여 사장님 목소리 구현
- 사실 정보 및 과거 답변 기록을 활용한 '상점 맥락' 제공
- 단순 프롬프트 입력 이상의 전문적인 솔루션 제시
이 글은 Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle에 제출된 내용입니다.
제가 만든 것
ReplyDesk는 작은 가게들(차고, 미용실, 치과, 카페, 배관공사 업체, 소매점 등)의 구글 리뷰에 답장을 작성해 줍니다.
제가 아는 모든 가게 주인들은 답변하지 않은 리뷰 더미를 가지고 있습니다. 답변하는 것은 중요합니다. 왜냐하면 사람들은 가게를 고르기 전에 답변을 읽기 때문입니다. 하지만 좋은 답변을 하는 데는 시간이 열 분이 걸리며, 채팅 비서가 작성한 것들은 모두 비슷하게 들립니다: "소중한 피드백을 공유해 주셔서 감사합니다. 저희는 노력하고 있습니다..." 고객들은 알아차릴 수 있습니다.
그래서 ReplyDesk는 한 가지 일을 합니다. 리뷰 인박스를 받습니다. 하나를 클릭하면 다음을 얻게 됩니다:
- 제가 미세 조정(fine-tuned)한 작은 오픈 모델에서 나온, 사장님의 목소리로 작성된 초안 답변
- 가게의 사실 정보로 뒷받침되지 않는 모든 약속(
공정한 질문: 이것은 그저 리뷰를 ChatGPT에 붙여넣는 것 아닌가요? 부분적으로는 그렇습니다. 작은 모델에 긴 프롬프트를 넣으면 괜찮은 답변이 나옵니다. 저는 정확히 그것을 테스트해 보았고, 제 모델이 강점을 보이는 부분과 약점을 보이는 부분을 보여드리겠습니다. 제가 판매하는 것은 모델 자체와 그 주변의 상점 맥락(shop context)입니다. 즉, 귀하의 사실 정보, 과거 답변 기록, 그리고 지킬 수 없는 약속에 대한 점검 기능입니다.
데모 (Demo)
실시간: https://replydesk-shop.vercel.app (데모 상점은 제 첫 사용자 카페입니다. 첫 번째 리뷰는 그 사용자가 작성한 것입니다. 나머지 다섯 개는 공개 데이터셋의 실제 리뷰를 가져와 이름과 이니셜로 줄인 것이므로, 직접 테스트해 보실 수 있습니다.)
네 개의 페이지: 받은 편지함(Inbox) (리뷰, 초안, 약속 점검, 유사 답변), 상점 설정(Shop setup) (유형, 사실 정보, 과거 답변), 더 나을까?(Is it better?) (전체 평가, 데이터베이스에서 실시간 읽기), 그리고 블라인드 테스트(Blind test) (하나의 리뷰에 대한 두 가지 답변, 보내고 싶은 것을 선택).
코드 (Code)
GitHub logo Sarcastic-Soul / replydesk
소규모 상점의 구글 리뷰 답변, 실제 사장님 답변으로 파인튜닝된 Qwen3.5-4B 모델이 작성
ReplyDesk
소형 오픈 모델(Qwen3.5-4B)을 사용하여 구글 리뷰에 대한 짧고 따뜻한 답변을 상점 주인 특유의 목소리로 작성합니다. 이 모델은 대규모 오픈 모델과 실제 사장님들의 답변 기록을 활용하여 파인튜닝되었습니다. Hacktoberfest 2026 DEV 챌린지(
flowchart LR
B[브라우저(Browser)] -- 리뷰 텍스트 --> E[bge-small (Web Worker 내)
]
B -- 서버 액션(server action) --> S[Vercel의 Next.js]
S -- 초안(draft) --> T[Tinker: fine-tuned Qwen3.5-4B]
S -- 사실 정보 for
…
제작 과정 (How I Built It)
데이터 (The data)
UCSD의 McAuley 연구실에서 제공하는 Google 지역 리뷰(Google Local Reviews) 데이터셋에는 가게 주인의 답글이 포함된 리뷰들이 있습니다. 저는 4개 주(와이오밍, 버몬트, 몬태나, 아이다호)를 사용했으며, 총 590,054쌍의 데이터를 확보했습니다. 대부분의 주인 답글은 학습할 가치가 없습니다: 붙여넣기 된 템플릿, 기계 번역문, 전화번호, 소셜 미디어 팀이 작성한 일련의 글 등입니다. 필터링을 거쳐 50,954쌍의 데이터(영어, 60일 이내, 연락처 정보 없음, 연속된 글 아님, 6가지 상점 유형 중 하나, 템플릿 아님, 리뷰와 단어 공유)를 남겼습니다. 학습 세트와 테스트 세트는 사업체별로 분리되었기 때문에, 테스트 리뷰는 모델이 이전에 본 적 없는 가게의 것입니다.
Tinker에서 미세 조정 (Fine-tuning on Tinker), 네 번의 시도
모델: Qwen3.5-4B, LoRA rank 32, tinker-cookbook 지도 학습 레시피(supervised recipe), 답글에 대한 손실(loss)만 계산, 생각하는 과정(thinking off)을 생략.
- v1: 모든 깨끗한 쌍으로 학습했습니다. 이로 인해 나쁜 습관까지 배웠습니다:
- 두 개의 더 큰 오픈 모델(gpt-oss-120b와 Qwen3.6-35B-A3B, 둘 다 Tinker 사용)이 훈련 리뷰 2,500건에 대해 각각 두 번씩 답글을 작성했습니다. 프롬프트에는 스타일 가이드와 동일한 거래 및 별점 수준의 실제 소유자 답변 세 개가 포함되었습니다.
- 리뷰 중 절반에는 '상점 정보(shop facts)' 1~3개가 추가되었는데, 이는 상점이 Setup에서 저장하는 것과 같은 사실들입니다. 교사 모델에게는 정보에 명시된 내용만 약속하도록 지시했습니다. 앱은 동일한 정보 블록을 미세 조정된 모델로 전송합니다.
- 일반 코드는 너무 길거나 짧은 모든 답변, 리뷰어가 말한 내용을 건너뛰고, 재고 문구(stock phrases)를 사용하거나, 논쟁하거나, 서명하거나, 또는 정보가 뒷받침하지 않는 환불, 할인, 무료 제공품 또는 콜백을 약속하는 모든 답변을 걸러냈습니다. 확인 비용은 전혀 들지 않습니다.
- 동일한 검사를 통과한 실제 소유자 답변들이 섞여 들어갔습니다. 결과: 2,584개의 훈련 행(training rows), 2 에포크(epochs)입니다.
서비스 제공 시: 앱은 Tinker의 OpenAI 호환 엔드포인트를 통해 미세 조정된 모델을 호출합니다. 공유할 만한 함정(gotcha)이 있습니다. Qwen3.5에서는 reasoning_effort: false (불리언)를 사용하여 사고 과정을 끌 수 있습니다. 문자열 `
다섯 명의 작가, 모델이 본 적 없는 상점의 보류된 리뷰 300개(그중 절반은 상점 정보 포함): 짧은 프롬프트와 함께 사용된 4B 모델, 긴 규칙서 프롬프트와 함께 사용된 4B 모델, v3, v4, 그리고 실제 소유자의 답변.

| 짧은 프롬프트 | 긴 프롬프트 | v3 | v4 | 실제 소유자 | |
|---|---|---|---|---|---|
| 모든 규칙 통과율 | 27% | 87% | 38% | 87% | 18% |
| ... |
이것이 의미하는 바를 간단히 말하자면:
- v4는 프롬프트가 절반만 되면서 규칙 측면에서는 긴 프롬프트 모델과 동일한 성능을 보이며, 비용도 더 저렴합니다. 같은 모델의 짧은 프롬프트와 비교했을 때, 통과율이 27%에서 87%로 향상되었습니다.
- v4는 대체하는 v3보다 훨씬 뛰어납니다.
- 판단 모델(gpt-oss-120b, 4B와 다른 계열)은 100개의 리뷰를 가지고 v4를 다른 작가들과 비교했습니다. v4는 v3보다 81%의 시간 동안, 그리고 실제 소유자보다 76%의 시간 동안 우수했습니다. 긴 프롬프트와 비교했을 때는 동률 (55%)이었고, 짧은 프롬프트와 비교했을 때도 마찬가지였습니다 (52%).
- 제가 입 밖에 내야 할 주의사항: 규칙들은 학습 데이터를 만든 것과 동일한 스타일 가이드에서 작성되었습니다. 따라서 규칙 항목에서는 v4가 더 나아 보입니다. 판단 모델의 결과와 블라인드 테스트는 독립적인 것입니다.
진짜 어려운 테스트. 동률이라는 점이 저를 신경 쓰이게 했습니다. 왜냐하면 동률은 미세 조정(fine-tune)이 프롬프트 토큰 일부만 절약했다는 의미이기 때문입니다. 그래서 저는 더 어려운 세트를 만들었습니다: 제 학습, 검증 또는 테스트 데이터에 포함되지 않았던 상점의 실제 1점 및 2점 리뷰 150개로, 이들은 환불, 무료 상품 제공 또는 전화 통화를 요구합니다. 여기서 꾸며낸 약속은 상점에 실제 돈을 지출하게 만듭니다.
| | short prompt | long prompt | v3 | v4 | real owner |
| --- | --- | --- | --- | --- |
| Passes every rule | 5% | 49% | 21% | 69% | 7% |
| ... |
여기서 v4가 long prompt보다 우수하며, 두 가지 확인 방식 모두 일치합니다. 즉, 사실을 넘어선 약속(반품 환불)을 하는 경우가 절반 수준으로 적고 (31% 대비 14%), 평가자가 100번 중 79번 선택했습니다. long prompt는 모델에게 '절대 환불을 약속하지 말라'고 지시했지만, 분노한 환불 요구에 대해서도 여전히 그렇게 했습니다. 하지만 미세 조정된(tuned) 모델은 그렇지 않습니다. 이것은 프롬프트로는 얻을 수 없었던 것입니다.
정직한 한계: n=150과 n=100은 대략 플러스 마이너스 10점 차이를 보였고, 평가자는 하나의 모델이며, 미끼 리뷰들은 여전히 상점 주인이 아닌 텍스트 더미에 불과합니다.
Tiger Data: '우리는 이전에 어떻게 답변했었지?'라는 단일 질의
Tiger Cloud 무료 서비스는 Postgres 18을 pg_textsearch (BM25) 및 vectorscale (DiskANN)과 함께 실행합니다. 이곳에는 상점, 리뷰, 전송된 답글, 평가 결과, 블라인드 테스트 투표, 그리고 교육용 비즈니스에서 나온 11.5k개의 예시 답변이 저장되어 있습니다.
리뷰를 열면, 하나의 SQL 문이 사용자의 상점 유형 및 평점 범위 내에서 BM25로 상위 20개와 벡터 거리로 상위 20개를 가져와 이를 상호 순위 융합(reciprocal rank fusion)으로 병합합니다. 사용자 자신의 과거 답변이 가장 먼저 나옵니다. 저는 Hugging Face 크레딧을 절반쯤 사용했기 때문에, 질의 임베딩은 사용자의 브라우저에서 실행됩니다 (bge-small-en-v1.5를 Web Worker에서 사용). 로드가 될 때까지 검색은 BM25만으로 실행됩니다. 임베딩 서버는 전혀 없습니다.
융합이 도움이 되나요? 제가 테스트해 보았습니다. 120개의 홀드아웃(held-out) 리뷰에 대해, 평가 모델은 어떤 검색이 그것을 찾았는지 알지 못한 채 상위 3개 결과 각각이 동일한 종류의 상황이었는지를 표시했습니다:
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기