https://merbl-filter.vercel.app/posts
자주 들어가는 블로그가 있다. 글이 유용해서 댓글까지 챙겨보는 편인데, 블로그가 커지면서 올라오는 글이 많아지고 댓글도 같이 불어났다. 본문이야 정독해야 하니 그렇다 쳐도, 댓글 쪽엔 광고나 "ㅎㅎ" 같은 한 줄짜리가 섞이는 비율이 점점 커졌다. 매일 들이는 시간을 좀 줄이고 싶었다 — 그게 시작이었다.
원래는 RN으로 안드로이드 앱을 만들어 구글 플레이에 올려뒀다. 네이버 블로그를 WebView로 띄우고 그 안에서 댓글 가시성을 조절하는 식. 6개월 정도 잘 썼는데 두 가지가 걸렸다.
웹으로 다시 만들면서 댓글 분류와 요약을 온디바이스 LLM으로 처리하게 했다.
규칙 기반이 막힌 지점은 명확하다. "정말 좋은 글 감사합니다" 같은 댓글, 광고는 아닌데 정보값도 없다. 키워드로 못 거른다. 반대로 "이 부분은 좀 동의 안 됨, 왜냐하면…" 같은 진짜 토론은 살려야 한다.
이걸 가르려면 결국 댓글의 의미를 어느 정도 이해해야 한다. 그래서 LLM.
여기서 한참 고민했다. 무료로 풀 서비스라 API 비용이 사용자 수에 비례해서 그대로 부담으로 돌아온다. 그리고 댓글이 별 거 아니어 보여도 남의 글 일부다. 외부 API로 그걸 다 보내는 게 솔직히 좀 께름칙했다.
세 가지를 비교해봤다.
| 비용 | 데이터 | 채택 | |
|---|---|---|---|
| OpenAI/Claude API | 종량제 | 외부 전송 | ✗ |
| 자체 서버 LLM | GPU 고정비 | 서버에 남음 | ✗ |
| 브라우저 온디바이스 | 0원 | 단말 밖으로 안 나감 | ✓ |
제약을 한 줄로 줄이면 "무료로, 무한히, 사용자 데이터 안 건드리고 돌아야 한다" 였고, 그러면 답은 사실상 정해진다. 마침 WebLLM과 Transformers.js가 충분히 쓸만해진 시점이었다.
분류와 요약을 두 단계로 쪼개놨다.
[댓글 목록]
│
▼
Phase 1 — 분류 (Transformers.js + MiniLM 임베딩)
│ 각 댓글을 임베딩 → 예시와 코사인 유사도 → [읽을만함 / 노이즈 / 스팸] + 점수
▼
[필터링·정렬된 목록]
│
▼
Phase 2 — 요약·질의응답 (WebLLM + Qwen2.5-1.5B)
"본문 3줄 요약", "댓글 반응 분석" 등
paraphrase-multilingual-MiniLM-L12-v2 (120MB). 댓글을 384차원 벡터로 만든 뒤, "읽을만한 댓글" 예시 세트와의 코사인 유사도로 점수를 매긴다. 50점 이상이면 통과.Qwen2.5-1.5B (900MB). WebGPU 필요. 첫 다운로드만 좀 기다리면 이후엔 빠르다.Phase 1은 사실 처음엔 BERT 다국어 모델로 [긍정 / 부정 / 스팸] 식 감성 분류를 돌렸다. 근데 잘 안 맞았다. 그 모델이 별점 리뷰 데이터로 학습된 거라 "철렁했습니다", "놀랐어요" 같은 충격받은 독자 반응까지 죄다 부정으로 찍어버렸다. 사실 처음부터 어긋났던 건 — 내가 원한 건 긍정/부정이 아니라 "읽을만한 댓글이냐" 였는데, 도구가 다른 일을 하고 있던 셈이다. 임베딩 + 유사도 방식으로 갈아엎고 나서야 의도대로 동작하기 시작했다.
둘 다 Web Worker에서 돌려서 메인 스레드는 안 막는다. 이거 셋업하다가 엉뚱한 데서 한참 헤맸는데 그건 3편에서 따로 다룰 예정.
잘 되는 쪽:
안 되는 쪽이 더 솔직하게 적어둘 가치가 있다.
요약 품질이 가장 큰 숙제고, 모바일 지원이 그 다음이다.
같은 흐름에서 로컬 LLM 챗봇 도 따로 프로토타이핑 중이다. 서비스 형태를 어떻게 잡을지는 아직 고민 중. 댓글필터와 챗봇 둘 다 결국 "내 단말에서 도는 모델로 뭘 할 수 있을까" 라는 같은 호기심에서 갈라져 나온 것들이다.
이번 글은 왜 / 무엇을 만드는지에 집중했다. 어떻게 만들고 있는지는 다음 두 편에서 나눠 다룰 예정.