AI 해석 기능 붙이기 — 서버리스 API 아키텍처
타로 카드를 뒤집었을 때 매번 똑같은 해석이 나온다면, 두 번째 리딩부터는 흥미가 사라진다. AI 실시간 해석은 선택이 아니라 필수였다. 문제는 비용이었다.
처음에는 고정 텍스트였다
프로젝트 초기에는 78장 각각에 대해 미리 작성된 해석 텍스트를 보여줬다. 정방향과 역방향까지 합하면 156개의 해석문이 필요했고, 이걸 JSON 파일에 담아서 카드가 뒤집어질 때 매칭해서 보여주는 방식이었다.
이 방식의 장점은 명확하다. API 호출이 없으니 비용이 제로이고, 지연 시간도 없다. 카드를 뒤집는 순간 해석이 바로 나타난다. 하지만 치명적인 단점이 있었다. 한 번 본 해석은 다음에도 똑같다. 타로 리딩의 핵심은 "같은 카드라도 맥락에 따라 다른 메시지를 전달한다"는 것인데, 이걸 구현할 수 없었다.
AI 해석으로 확장하기로 한 순간
결정적 계기는 쓰리카드 리딩이었다. 과거-현재-미래 세 장의 카드가 나왔을 때, 각각의 고정 해석을 나열하는 건 의미가 있지만, 세 장의 관계를 엮어서 해석하는 건 불가능했다. "과거에 이런 카드가 나왔기 때문에 현재의 이 카드는 이런 의미를 가진다"는 맥락적 해석은 AI만이 할 수 있었다.
문제는 비용이었다. OpenAI GPT-4 기준으로 한 번 해석에 수백 토큰이 들고, 하루 수백 건의 리딩이 발생하면 비용이 급격히 올라간다. 사이드 프로젝트에 월 수십 달러를 쓸 수는 없었다.
Groq API라는 발견
Groq는 자체 LPU 칩을 사용해서 LLM 추론 속도가 극도로 빠른 서비스다. 중요한 건 무료 티어가 있다는 점이었다. 하루 14,400건의 요청이 가능하고, LLaMA 3.3 70B 모델을 사용할 수 있다.
LLaMA 3.3 70B는 오픈소스 모델치고 성능이 상당히 좋다. 타로 해석 같은 창작적 텍스트 생성에서 GPT-4에 비해 크게 뒤지지 않았다. 무엇보다 Groq의 추론 속도가 압도적이었다. 일반적인 LLM API가 응답에 2~5초 걸리는 데 비해, Groq는 대부분 1초 이내에 응답했다. 사용자 경험 측면에서 큰 차이다.
하루 14,400건이면 충분할까? 사이드 프로젝트 기준으로는 넉넉하다. 분당 10건씩 24시간 쉬지 않고 요청해야 14,400건이다. 초기 트래픽으로는 절대 도달할 수 없는 수치였다.
API 키 은닉이라는 과제
프론트엔드만으로 구성된 앱에서 LLM API를 호출하려면 API 키가 필요하다. 문제는 프론트엔드 코드는 브라우저에서 실행되므로, 코드에 포함된 모든 정보가 사용자에게 노출된다는 것이다.
환경 변수에 넣어도 소용없다. 빌드 시점에 코드에 포함되기 때문이다. 브라우저 개발자 도구를 열면 네트워크 탭에서 API 키가 그대로 보인다. 누군가 이 키를 가져다가 악용하면 내 무료 할당량이 순식간에 소진될 수 있다.
결론은 하나다. 중간에 서버가 필요하다. 프론트엔드는 내 서버에 요청하고, 내 서버가 API 키를 붙여서 Groq에 요청하는 프록시 구조다.
Cloudflare Workers: 무료 서버리스의 답
"서버가 필요하다"는 결론에 도달하면, 보통 AWS Lambda나 Vercel Serverless Functions를 떠올린다. 하지만 Cloudflare Workers에는 결정적 장점이 있다. 하루 100,000건의 무료 요청, 그리고 전 세계 엣지에서 실행되는 빠른 응답 속도.
Workers의 코드는 간단하다. 프론트엔드에서 요청이 오면, 요청 본문을 그대로 Groq API로 전달하되 API 키를 헤더에 추가한다. 응답을 받아서 프론트엔드로 돌려준다. 이게 전부다.
CORS 설정도 필요했다. 내 도메인에서 오는 요청만 허용하고 나머지는 차단하는 것이다. 이렇게 하면 다른 사이트에서 내 Workers URL을 몰래 사용하는 것도 방지할 수 있다.
프롬프트 엔지니어링: 타로 해석의 톤
기술 아키텍처만큼 중요했던 것이 프롬프트 설계다. LLM에게 "타로 카드를 해석해달라"고만 하면 위키피디아 같은 건조한 설명이 나온다. 타로 리딩의 매력은 신비로우면서도 따뜻한 어조에 있다.
프롬프트에 포함한 핵심 지시사항은 다음과 같았다. "당신은 경험 많은 타로 리더입니다. 신비롭고 따뜻한 어조로 해석해주세요. 카드의 상징과 이미지를 활용하되, 질문자에게 용기를 주는 방향으로 해석하세요. 부정적인 카드도 성장의 기회로 재해석해주세요."
여기서 "용기를 주는 방향"이 중요했다. 타로 리딩을 찾는 사람들은 대부분 고민이 있거나 불안한 상태다. 죽음 카드가 나왔을 때 "끝과 새로운 시작을 의미합니다"라고 해석하는 것과 "무언가가 끝납니다"라고만 말하는 것은 천지 차이다.
쓰리카드나 켈틱 크로스 같은 스프레드에서는 카드 간의 관계를 해석하라는 지시도 추가했다. "세 장의 카드를 전체적으로 연결하여, 하나의 이야기로 풀어주세요." 이 한 줄의 지시가 AI 해석의 품질을 극적으로 높였다.
Cloudflare Workers AI로의 전환
Groq API로 잘 운영하고 있었는데, 왜 Cloudflare Workers AI로 전환했을까? 두 가지 이유가 있었다.
첫째, 아키텍처 단순화다. Groq를 쓰면 Cloudflare Workers(프록시)와 Groq API(추론) 두 개의 외부 서비스에 의존하게 된다. Cloudflare Workers AI를 쓰면 프록시와 추론이 하나의 플랫폼에서 해결된다. 장애 포인트가 하나 줄어든다.
둘째, Workers AI의 무료 티어가 충분했다. 하루 10,000 뉴런 단위의 무료 할당이 제공되고, 가벼운 모델을 사용하면 사이드 프로젝트 수준의 트래픽은 충분히 감당할 수 있었다. 모델 성능은 LLaMA 3.3 70B에 비해 다소 떨어지지만, 타로 해석이라는 특정 용도에서는 체감 차이가 크지 않았다.
전환 과정은 의외로 간단했다. Workers 코드에서 Groq API를 호출하는 부분을 Workers AI의 AI 바인딩으로 교체하면 끝이었다. 프론트엔드 코드는 한 줄도 바꿀 필요가 없었다. 프록시 서버가 있으니, 뒤에서 어떤 LLM을 쓰든 프론트엔드는 모른다. 이것이 프록시 아키텍처의 장점이다.
무료 인프라로 프로덕션을 운영한다는 것
정리하면, 이 프로젝트의 AI 해석 인프라는 완전 무료다. Groq API는 하루 14,400건, Cloudflare Workers는 하루 100,000건, Workers AI도 일정 수준까지 무료. GitHub Pages도 무료. 서버 비용 제로.
물론 한계는 있다. 무료 티어의 할당량을 초과하면 서비스가 중단된다. 하지만 사이드 프로젝트의 현실적인 트래픽을 생각하면, 이 한계에 도달하는 것 자체가 성공의 신호다. 그때가 되면 유료 전환이나 다른 아키텍처를 고민해도 늦지 않다.
"일단 무료로 시작하고, 문제가 생기면 그때 해결한다." 사이드 프로젝트에서 이보다 합리적인 전략은 없다고 생각한다.
다음 편 예고
AI 해석이 붙으니 프로젝트가 한층 완성도 있어 보였다. 하지만 아무도 찾아오지 않는 앱은 존재하지 않는 것과 같다. Part 13에서는 SPA의 태생적 SEO 한계를 뒤늦게 깨닫고, 프리렌더링과 메타 태그로 분투한 이야기를 다룬다.
댓글
댓글 쓰기