API 키 없이 브라우저에서만 도는 RAG를 만들었습니다
경제 뉴스를 모아서 보여주는 도구를 만들다가 이런 생각이 들었습니다. “이 뉴스들한테 질문할 수 있으면 좋겠는데.”
문제는 RAG를 붙이려면 보통 임베딩 API와 LLM API가 필요하다는 겁니다. 키를 받아야 하고, 서버가 있어야 하고, 돈이 들어요. 개인 프로젝트에서는 꽤 큰 진입장벽이죠.
그래서 반대로 접근했습니다. 전부 브라우저 안에서 돌리면 되지 않을까?
1. 임베딩부터 브라우저로 내렸습니다
먼저 검색 부분입니다. Transformers.js로 multilingual-e5-small 모델을 브라우저에서 직접 돌립니다. 한국어와 영어를 같이 다뤄야 해서 다국어 모델 중 작은 걸 골랐어요.
기사 제목과 요약을 임베딩해서 메모리에 벡터 인덱스를 만들고, 질문이 들어오면 코사인 유사도로 관련 기사를 찾습니다. 서버가 없으니 인덱스도 그냥 자바스크립트 Map입니다.
모델은 처음 한 번 약 112MB를 받고, 그 뒤로는 브라우저 캐시에서 꺼내 씁니다.
2. 생성까지 브라우저로 옮겼는데, 모델 선택이 함정이었습니다
검색만으로는 “관련 기사 목록”밖에 안 나오니 답변 생성도 필요했습니다. WebLLM으로 Qwen2.5-1.5B-Instruct를 브라우저에서 구동했어요.
여기서 하나 배웠습니다. 같은 모델도 양자화 방식이 여러 개인데, 저는 q4f32_1 버전을 골랐습니다. 성능이 아니라 호환성 때문이었어요.
f16 계열 빌드는 GPU가 shader-f16을 지원해야 합니다. 이걸 요구하는 순간 돌아가는 기기가 확 줄어들어요. 조금 무겁더라도 더 많은 GPU에서 뜨는 쪽을 택했습니다.
3. 세 단계로 내려가게 만들었습니다
브라우저 LLM은 만능이 아닙니다. WebGPU를 못 쓰는 기기도 있고, 1.5B 모델의 답변 품질에 만족 못 할 수도 있어요. 그래서 이렇게 설계했습니다.
- 로컬 WebGPU 모델 — 기본값. 키도 서버도 필요 없음
- OpenAI — 설정에서 키를 넣으면 이쪽으로 승격
- 순수 검색 — 위 둘 다 안 되면 생성 없이 관련 기사만 제시
세 경로가 같은 프롬프트를 공유하고, 답변 형식도 [1] [2] 식 출처 인용으로 통일했습니다. 그래서 어느 단계로 떨어져도 사용자가 보는 결과의 모양은 그대로예요.
💡 삽질 기록 & 주의할 점
- 삽질:
@xenova/transformers를 그냥 import 하면 CRA 5에서 번들링이 안 됩니다. eject 하지 않고서는 방법이 없더라고요. 결국import(/* webpackIgnore: true */ CDN주소)형태로 번들러를 우회해서 런타임에 CDN에서 직접 불러왔습니다. 브라우저 ML 라이브러리를 붙일 땐 번들러 호환성부터 확인하세요. - 주의할 점: 첫 방문자는 모델 다운로드로 100MB 넘게 받습니다. 진행률 표시(
progress_callback)를 꼭 붙이세요. 안 그러면 사용자 입장에선 그냥 멈춘 화면입니다.
정리
“API 키 없이 RAG”는 생각보다 현실적이었습니다.
대신 모델을 고르는 기준이 성능에서 호환성으로 옮겨갑니다. 서버 방식과 가장 다른 지점이 여기였어요.
그리고 브라우저에서 도는 이상 어떤 기기에서는 반드시 실패합니다. 미리 내려갈 계단을 만들어두는 게 필수더라고요.
태그: #RAG, #WebGPU, #WebLLM, #TransformersJS, #브라우저LLM, #온디바이스AI, #Qwen, #AI개발, #클로드코드, #개인프로젝트