DEV Community

Cover image for 15분 만에 만든 챗봇 — Render를 버렸는데, 다시 썼다
Yoskee
Yoskee

Posted on • Originally published at moday.me

15분 만에 만든 챗봇 — Render를 버렸는데, 다시 썼다

Originally published at moday.me. Building MODAY in public.

15분 만에 만든 챗봇 — Render를 버렸는데, 다시 썼다

5/19의 기회손실에서, 15분 만에 굴러간 데까지

다른 글에서도 적었지만, 5/19에 첫 문의가 2건 들어왔다.
그날 안에는 답을 못 했고, 회신을 보낸 건 다음 날이었다.
이걸 기회손실이라고 보고, 그날 안에 챗봇을 박아넣었다.

스토어 오른쪽 아래에 띄우는, 흔히들 보는 그 위젯.
작업 시작에서 Shopify에 배포되어 돌아가기까지, 대략 15분.
내가 파악하고 있는 범위 안에서 내용을 적어둔다.

구성

대충 이렇게 되어 있다.

  • 프론트: Shopify 테마에 오른쪽 아래 위젯 (내가 어떻게 구현했는지는 파악 안 함)
  • 백엔드: Render.com에서 Claude API를 친다
  • 언어: Shopify 로케일에 연동, 9개 언어
  • 이력: 구글 스프레드시트에 저장
  • 에스컬레이션: 답할 수 없는 질문은 문의 폼으로 유도

설계 사상은 단순하다. 단순하게 끝낸다, 이게 전부.
개인 사업 단계에서, 뭘 하든 복잡한 걸 끌고 다니고 싶지 않다.

Render를 버렸는데, 다시 썼다

다른 글에서 "FastAPI / Render는 이미 떼냈다"라고 예고했었다.
모순처럼 들리지만, 떼낸 건 Webhook 용도 쪽 얘기.
Shopify 주문을 받아서 Gelato로 흘리는 처리가 Render 위의 FastAPI에서 돌고 있었다.
그건 다른 구성으로 갈아치웠다 (그 경위는 그것대로 한 편 쓸 만한 얘기라, 다음 기회에).

챗봇은, 그 Render를 다른 구성으로 부활시켰다.
Webhook 서버로 굴리던 인프라와, 챗봇 API로 굴리는 인프라.
역할은 별개고, 다른 서비스, 다른 프로세스.
같은 Render를 쓰고 있을 뿐이다.

"Render를 떼냈다"와 "Render를 쓰고 있다"는 모순되지 않는다.
용도별로, 그 시점에서 최적의 도구를 다시 고르는 것일 뿐.
과거의 판단에 묶여서 "이제 안 쓴다"라고 못 박으면 판단이 굳어진다.

판단 축은 내가 쥐고 있다. 구현은 Claude Code가 짠다.
다시 짤 때마다, 그 시점의 최적해를 가지러 간다.

이력을 구글 스프레드시트에 저장하고 있다

봇과 유저의 주고받음은, 전부 구글 스프레드시트에 기록된다.
일시, 로케일, 유저의 질문, 봇의 답변, 에스컬레이션 여부.

이건 Claude Code의 제안을 받아들였다.
나중에 따져보니, 3가지 이유로 딱 좋았다.

  1. DB를 세우고 싶지 않다: 스키마 설계가 필요하고, 운영비도 들고, 시각화도 따로 필요하다. 개인 사업 단계에는 무겁다
  2. 공짜로 끝난다: 구글 계정만 있으면 비용 0
  3. 나중에 분석시킬 때, 나도 Claude Code도 바로 읽을 수 있다: 컬럼만 훑으면 다 보인다

특히 3번째가 크다.
앞으로 Claude Code한테 "최근 문의 경향 정리해줘"라고 부탁할 때,
스프레드시트를 직접 읽으러 갈 수 있다.
DB였다면 추출 스크립트를 짜서, CSV로 떨궈서, 한 단계가 더 낀다.

전용 DB라면 깔끔하겠지만, 지금 규모에서는 SS로 충분하다.
개인 사업 단계에서, 이건 올바른 게으름이라고 본다.

9개 언어 대응은 어떻게 하고 있나

Shopify의 현재 로케일을 가져와서, 봇에 넘긴다.
봇은 "이 언어로 답해줘"라는 프롬프트로 Claude API를 친다.
중간에 번역 단계는 끼우지 않는다. Claude가 직접 그 언어로 쓴다.

다른 글에서 "번역이 아니라 로컬라이즈·리라이트"라고 적었는데, 이건 봇에도 그대로 들어맞는다.
일본어로 쓰고 영어로 번역하는 게 아니라, 처음부터 영어 네이티브가 쓰는 문체로 답한다.
독일어면 독일어 네이티브로서 답한다.
모델 안에서 닫혀 있으니까, 번역 레이턴시도, 오역 리스크도 구조적으로 줄어든다.

이것도 특별한 거 안 했다.
"Shopify 로케일을 받아서, 그 언어로 답하도록"이라고 한 줄 부탁했을 뿐이다.

프롬프트에는 "사이트 정보를 파악해라"라고 적었다

봇은 MODAY 사이트에 실린 정보와 Gelato의 상품 정보를 답할 수 있다.
배송 가부, 납기, 사이즈, 결제 방법, 반품 정책, 가격, 번들 구성.

이걸 "파악해라"라고 Claude Code한테 부탁했다.

솔직히 적어두면, 어떻게 파악시켰는지는 내가 파악하지 못한다.
프롬프트에 박혀 있는지, 사이트를 fetch하고 있는지,
둘 다 조합해서 쓰는지, 그건 Claude Code가 정하고 구현했다.

다른 글에서 쓴 대로, 지시는 냈고, 구현은 맡겼다.
굴러가고 있고, 제대로 된 답이 돌아오니까, 지금은 그걸로 충분.
망가지면 Claude Code한테 "고쳐줘"라고 한다.

답할 수 없는 건, 문의 폼으로 유도한다

모든 질문에 봇이 답해버리는 건 위험하다.

특정 사이즈의 개별 상담, 기프트 래핑, 법인 안건, 트러블 대응.
이 근방은 봇이 단언하게 두면 나중에 어긋난다.

봇이 "이건 답하지 않는 게 낫다"라고 판단하면, 문의 폼으로 유도한다.
가드레일 설계도 Claude Code에 맡겼다.
내가 한 건 "답할 수 없는 질문은 문의 폼으로 유도하는 사양으로 해줘"라고
한 줄 부탁한 것뿐.

어떤 질문을 봇이 답하고, 어떤 질문을 에스컬레이션할지.
그 경계선도 Claude Code가 그었다.
가끔 로그를 훑어보고 명백히 이상한 분배가 있으면 조정할 생각이지만,
지금까지 그런 건 안 왔다.

15분 만에 굴러간 건, 그 15분 안에서 생각할 게 적었기 때문이다.

"오른쪽 아래에 둔다" "Claude API 기반" "9개 언어" "Render 부활" "이력은 SS"
"에스컬레이션은 문의 폼".
이만큼 정해지면, 나머지는 Claude Code가 짠다.
나는 GO를 내고, 굴러갔는지 확인할 뿐이다.

스토어를 연 지 2일째에, 서포트 자동화 기반이 돌기 시작했다.
"하루에 하나는 개선", 그 첫 번째가 이거였다.

또 쓸게요.

— Yoskee

moday.me


오늘을 입다. — MODAY 티셔츠

세트 장수 가격
풀 위크 세트 → Mon–Sun (7) $159
워크위크 세트 → Mon–Fri (5) $119
스타터 팩 → Mon · Wed · Fri (3) $79
위켄드 세트 → Sat · Sun (2) $55

$99 이상 무료 배송 · 8색 × 6사이즈 · 9개 언어

Top comments (0)