AI 서비스인데, AI를 하나 빼버렸다
첫날 커밋 메시지에 이렇게 적어뒀었다.
Tech stack: React 18 / FastAPI / SQLite / Claude·Groq·Ollama (Multi-LLM)
Claude를 메인으로 두고, 실패하면 Groq로, 그것도 안 되면 Ollama(로컬)로 넘어가는 구조였다. 그런데 4일 뒤, 2026년 4월 20일 오전 9시 23분에 이런 커밋이 올라갔다.
fix: remove Claude from LLM chain, fix Groq fallback bug
Claude를 체인에서 통째로 뺐다. AI로 서비스를 만들면서, 정작 서비스 두뇌에서는 Claude를 뺀 셈이다.
이유는 버그였다. 코드를 열어보면 이렇다.
if provider in ("groq", "auto") and groq_available():
...
provider 기본값이 "claude"였는데, 이 조건문은 provider가 "groq"이거나 "auto"일 때만 참이 된다. 즉 provider가 "claude"로 설정된 상태에서 Claude 호출이 실패하면, Groq로 넘어가는 분기 자체가 아예 실행되지 않았다. Fallback을 만들어놨는데, fallback으로 가는 문이 잠겨있었던 거다. Claude가 막히면(비용 문제든 rate limit이든) 서비스가 그냥 죽는 구조였다.
고친 방법은 간단했다. provider 기본값을 "auto"로 바꾸고, Claude는 체인에서 빼버렸다. 10분 뒤(9시 33분) Gemini를 추가해서 체인을 다시 짰다.
Groq (무료, 빠름) → Gemini (무료 백업) → Ollama (로컬) → Mock (최후)
전부 무료 또는 로컬로만 구성했다. 똑똑한 모델 하나가 아니라, 안 죽는 조합을 선택한 것. 실제 서비스에서는 "제일 잘하는 모델"보다 "언제든 대답은 하는 모델"이 이긴다는 걸 이때 처음 체감했다.

실시간 스트리밍을 26분 만에 갖다 버린 이야기
4월 23일 오후 2시. AI가 계약서를 분석하는 동안 사용자에게 진행 상황을 실시간으로 보여주고 싶었다. 그래서 SSE(Server-Sent Events)로 스트리밍을 구현했다.
오후 2시 00분 — 첫 삽을 떴다.
fix: SSE buffering + LLM timeout for Render deployment
Render 무료 호스팅에서 연결이 자꾸 끊겼다. 버퍼링 헤더를 추가하고 타임아웃을 조정했다.
오후 2시 13분 — 13분 뒤, 여전히 끊겼다.
fix: add SSE heartbeat during LLM/law API calls
알고 보니 Render는 10초간 데이터가 안 오면 연결을 끊는다. LLM 응답을 기다리는 동안은 당연히 데이터가 안 온다. 그래서 3초마다 가짜 신호("아직 분석 중이에요")를 계속 보내는 하트비트를 백그라운드로 돌렸다.
오후 2시 26분 — 그리고 13분 뒤, 결국 포기했다.
fix: replace SSE with regular JSON API for analysis (Render fix)
하트비트를 붙였는데도 불안정했다. 결국 스트리밍을 통째로 버리고, 그냥 평범한 JSON 응답 하나로 바꿨다. 대신 프론트엔드에서 2초 간격으로 가짜 진행률 애니메이션을 돌려서 "그래도 뭔가 되고 있다"는 느낌만 줬다.
26분 사이에 세 번을 갈아엎었다. 기술적으로 더 정교한 방법(실시간 스트리밍)이 항상 이기는 게 아니라는 걸, 무료 호스팅이라는 제약 앞에서 몸으로 배웠다. 더 단순한 방법(그냥 기다렸다가 한 번에 응답)이 결국 더 안정적이었다.

무료 호스팅은 잠든다
한 달쯤 지난 5월 18일, 이런 커밋 하나가 올라갔다.
docs: mark UptimeRobot as active (sleep prevention applied)
Render 무료 티어는 일정 시간 요청이 없으면 서버를 재워버린다. 다음 요청이 오면 그제야 깨어나는데, 그 사이 사용자는 10초 넘게 로딩 화면만 본다. 이걸 막으려고 UptimeRobot이라는 외부 서비스로 5분마다 가짜 요청을 보내서 서버를 계속 깨워뒀다.
효과는 있었지만 근본적인 해결책은 아니었다. 결국 이 문제는 두 달 뒤(6월 30일) 호스팅을 Fly.io로 정식 이전하면서 해결됐다 — 그 이야기는 5장에서 다룬다.
이 장에서 남는 것
전부 "기술이 부족해서"가 아니었다. Claude API 비용, Render 무료 티어의 제약, 스트리밍이 버틸 수 없는 인프라 — 돈이 없어서 생긴 문제를 기술로 메꾸려다가, 결국 다시 돈(또는 더 나은 인프라) 문제로 돌아오는 패턴이 반복됐다. AI로 서비스를 만드는 속도는 빨라졌지만, 그 서비스를 계속 켜두는 비용은 그대로였다.
다음 장 예고
법제처 API와 Groq, 거짓말 안 하게 섞기 — LLM에게 진짜 데이터를 주는 것과, 그 데이터를 실제로 쓰게 만드는 것은 완전히 다른 문제였다.
이 글은 개인 개발 프로젝트의 기록이며, 실제 코드는 일부 축약·각색되었습니다.
'프로젝트 기록 > 누구나법률 서비스 개발기' 카테고리의 다른 글
| 완성 그 이후 — 운영이라는 두 번째 산, 방치된 버그와 흔적 청소기 (6장) (0) | 2026.08.07 |
|---|---|
| 그래서 직접 벌기로 했다 — 경쟁사 분석과 유료화 전환기 (5장) (0) | 2026.08.07 |
| 공짜로 메꿔보려 두 번 걸었다 — 사회적기업 인증 탈락과 해커톤 철회기 (4장) (0) | 2026.08.07 |
| 법제처 API와 Groq, 거짓말 안 하게 섞기 — RAG 그라운딩 실전기 (3장) (0) | 2026.08.07 |
| 법 앞에 누구나 — AI 법률 서비스 하루 만에 MVP 완성기 (1장) (0) | 2026.08.04 |