
AI를 사용하는 측과, 탑재하는 측. 개인 개발자의 관점에서 본 토큰 경제
요약
AI 제품 개발 시 발생하는 토큰 비용 구조와 사용자 이탈 문제를 분석합니다. 월정액 방식에서 종량제(Pay-as-you-go)로 변화하는 AI 경제 모델과 개발자 및 이용자의 비용 부담 주체에 따른 비즈니스적 시사점을 다룹니다.
핵심 포인트
- API 키 설정 및 과금 단계에서의 높은 사용자 이탈 발생
- AI 에이전트 확산으로 인한 계산 비용 증가와 요금 체계 변화
- 월정액 모델에서 토큰 기반 종량제 모델로의 전환 추세
- 사용자와 개발자 간의 토큰 비용 부담 주체 설계의 중요성
AI 채팅 봇 플러그인을 만들어 공개했을 때, 가장 많은 이탈이 어디에서 발생했는지 아십니까? 기능 설명도, 설정 화면도 아니었습니다. "API 키를 취득하고, 프로바이더(Provider)에 과금을 설정해 주세요"라는 그 한 문장 앞이었습니다.
설치는 해준다. 활성화도 한다. 하지만 그 다음 단계에서 멈춘다. 생각해보면 당연한 일입니다. 이용자 입장에서는, 단순히 설치해 본 플러그인을 위해 모르는 회사에 신용카드를 등록하고, 비용이 얼마나 들지도 모르는 수도꼭지를 자신 쪽으로 여는 이야기이기 때문입니다. 기능이 좋고 나쁨을 떠나기 전의 벽이었습니다. 설치 수와 실제로 채팅이 작동한 수의 차이를 보고 그 골짜기의 깊이를 깨달았을 때, 솔직히 소름이 돋았습니다. 좋은 것을 만들면 사용해 줄 것이라 생각했는데, 기능에 도달하기도 전에 사람들이 사라지고 있었습니다.
토큰 비용이라는 보이지 않는 수도꼭지가 제작자가 아닌 이용자 쪽에 열립니다. 게다가 그 수도꼭지는 사용하면 할수록 계속 나옵니다. 구매 방식(Buy-out)도, 월정액(Subscription)도 아닌, 비틀 때마다 조금씩 흘러나오는 종류의 지출입니다. AI를 제품에 탑재하고 나서야 비로소 그것을 깨달았습니다.
이 기사는 토큰 비용을 두 개의 지갑으로 나누어 생각한 이야기입니다. AI를 사용하는 측의 지갑과, AI를 탑재하는 측의 지갑. 전자는 자신이 지불하고, 후자는 이용자가 지불합니다. 둘 다 토큰 경제(Token Economy)이지만, 영향을 미치는 지점이 완전히 달랐습니다. 후반부에는 탑재하는 측의 지갑 이야기를 비중 있게 다루겠습니다. 그쪽은 제가 지불하는 입장에 있는 한 보이지 않던 풍경이었기 때문입니다.
검증 환경
가격이나 플랜은 변화가 빠른 영역입니다. 아래 내용은 확인한 시점의 것을 기준으로 읽어주시기 바랍니다.
- AI 에이전트 측: Claude의 구독 플랜 (실기 및 공식 현재 가격 확인, 플레이스홀더), Codex CLI
- 플러그인이 이용자에게 사용되는 루트: OpenRouter, 각 사의 API
- 대상은 직접 제작한 WordPress 플러그인 (AI 채팅 봇)
요금 체계는 몇 개월 단위로 변합니다. 여기에 적는 금액이나 구조는 집필 시점의 이해입니다. 최신 정보는 각 사의 공식 요금 페이지에서 확인해 주세요. 또한, 아래 내용은 개인 개발자로서 자신의 지갑과 플러그인 이용자의 지갑을 지켜봐 온 범위 내의 이야기이며, 만능 정답은 아닙니다. 오히려 자신이 지불하는 쪽의 감각 그대로 제품을 설계했다가 한 번 실패했던 인간의 반성으로서 읽어주신다면 거리감이 맞을 것이라 생각합니다.
비용은 어딘가의 지갑에 착지한다
얼마 전까지만 해도 AI 도구의 요금은 월정액 고정이 당연했습니다. 매달 얼마인지 정해져 있고, 사용하든 사용하지 않든 동일합니다. 그 안도감이 좋았습니다. 헬스장 회비처럼, 결제해 두면 나머지는 신경 쓰지 않고 다닐 수 있습니다.
그 전제가 지금 무너지기 시작하고 있습니다. 2026년 6월 1일, GitHub Copilot이 월정액 고정에서 종량제(Pay-as-you-go)로 전환되었습니다. 월간 요청 수를 세는 방식을 버리고, 입력·출력·캐시의 토큰량에 따라 크레딧을 소비하는 형태가 되었습니다. 배경으로서 GitHub는 에이전트화로 인해 계산 비용(Computing Cost)이 불어나 기존의 판매 방식으로는 지속 가능하지 않다는 취지의 설명을 했습니다. 짧은 코드 보완으로 끝났던 시대와 달리, 지금은 에이전트가 몇 시간 동안 리포지토리를 헤집고 다닙니다. 그 비용을 월정액 고정으로는 감당할 수 없게 되었다는 이야기입니다. 이용자들로부터는 같은 가격으로 받을 수 있는 것이 줄어든다, 매달 얼마가 될지 예측할 수 없어 불안하다는 반발도 나왔습니다.
이 움직임의 시비(是非)는 여기서 제쳐두겠습니다. 중요한 것은 여기서 보이는 일반적인 사실입니다. AI의 계산에는 실비가 들며, 그 실비는 반드시 어딘가의 지갑에 착지합니다. 월정액 고정은 제공자 측이 그 착지점을 일단 떠안아서 평평하게 보여준 것에 불과했습니다. 종량제는 그 수도꼭지를 이용자의 손으로 되돌려 놓았다고도 할 수 있습니다. 어느 쪽이 좋고 나쁨의 문제가 아니라, 수도꼭지가 어느 쪽 손에 있느냐의 차이입니다.
개인 개발에서도 구도는 같았습니다. 토큰 비용은 내가 지불할 것인가, 이용자가 지불할 것인가, 둘 중 하나에 착지합니다. 공중에 띄워둔 채로 둘 수는 없습니다. 그래서 지갑을 두 개로 나누어 생각하기로 했습니다. 사용하는 쪽의 지갑과, 탑재하는 쪽의 지갑입니다. 순서대로 적겠습니다.
사용하는 쪽의 지갑
먼저, 자신이 지불하는 쪽입니다. AI 에이전트로 개발하는 데 비용이 얼마나 드는지에 대한 이야기입니다.
체감상 가장 크게 와닿는 것은, 에이전트 (Agent)를 길게 자율 주행 (Self-running) 시켰을 때입니다. 지시를 내리고 자리를 비웠다가 돌아오면, 기분 좋게 작업이 진행되어 있습니다. 하지만 그동안 토큰 (Token)은 계속해서 타들어 가고 있습니다. 인간이 쉬는 동안에도 에이전트는 입력과 출력을 계속 쌓아갑니다. 편리함과 비용이 같은 수도꼭지에서 흘러나오는 셈입니다. 커피를 내려서 돌아오니 작업이 진행되어 있었지만, 그 이면에서는 꽤 많은 양의 토큰이 흘러나가고 있었던 적이 여러 번 있었습니다. 한 번은 테스트가 통과되지 않아 끝없이 수정을 시키고 있었더니, 같은 부분을 계속 맴돌며 어느샌가 상당한 양의 토큰을 태워버린 적도 있습니다. 결과물은 단 몇 줄의 수정인데, 그곳에 도달하기까지의 시행착오만큼 토큰은 쌓여갑니다. 결과물의 크기와 소비량은 반드시 비례하지 않았습니다.
제가 정신줄을 놓지 않기 위해 실천하고 있는 몇 가지 방법이 있습니다.
첫 번째는 플랜 (Plan)을 선택하는 방법입니다. 매일 뭉쳐서 사용한다면, 구독형 정액제가 결국 계산해 보면 더 저렴합니다. 사용하든 안 하든 같은 금액이므로 마음 편히 돌릴 수 있습니다. 반대로, 가끔밖에 쓰지 않는 용도를 정액제로 늘리면 사용하지 않는 시간만큼 낭비가 됩니다. 그런 보조적인 용도는 종량제 API (Pay-as-you-go API)로 그때마다 지불하는 편이 대기 비용이 없습니다. 저는 상용하는 에이전트는 정액제로, 보조적으로 쓰는 것은 종량제로 나누어 사용합니다. 제 방식으로는, 본격적으로 집중해서 쓰는 작업은 정액제 플랜으로 돌리고, 별도의 계통의 에이전트는 세컨드 오피니언 (Second opinion)이나 가벼운 검증용으로 필요할 때만 호출합니다. 매일 많이 돌리는 것을 정액제에 두면, 사용할수록 1회당 비용이 실질적으로 희석되는 느낌이 듭니다. 반대로 한 달에 몇 번밖에 쓰지 않는 것을 정액제로 안고 있으면, 그 고정비가 통째로 놀게 됩니다. 한 달 운영 측면에서는, 본격적인 개발은 정액제 플랜으로 다 해치우고, 외부의 살아있는 데이터를 가져오는 것과 같은 종량제 방식은 필요한 태스크 (Task) 때만 수도꼭지를 엽니다. 월말에 "이번 달은 정액제 본전을 뽑았나", "종량제는 얼마가 나갔나"를 대략적으로 되돌아보며 다음 달의 배분을 미세 조정합니다. 가계부만큼 엄격하지는 않지만, 한 달에 한 번 검토하는 것만으로도 지갑의 감각을 어느 정도 유지할 수 있습니다. 월초에 "이것은 정액제로 돌린다, 이것은 그때그때 지불한다"라고 정해두면 지갑의 전망이 보입니다. 그리고 종량제로 사용 중인 부분은 제공사의 사용량 대시보드 (Usage Dashboard)를 가끔 들여다보도록 하고 있습니다. 월말에 한꺼번에 놀라기보다, 중간에 한 번 확인해 두는 편이 페이스를 조절할 수 있습니다. 보지 않고 있으면 수도꼭지는 조용히 계속 흐릅니다.
또 다른 하나는 태스크를 끊어주는 것입니다. 끝도 없이 자율 주행을 시키면 토큰도 끝도 없이 쌓입니다. 한 구간에서 멈추고, 거기까지의 결과를 확인한 뒤에 다음으로 넘깁니다. 도중에 방향이 어긋났다면 그 시점에서 알아챌 수 있으므로, 잘못된 방향으로 수만 토큰을 달리는 사고를 줄일 수 있습니다. 이는 비용 때문만이 아니라, 폭주를 조기에 막는다는 의미에서도 하고 있습니다. 비용과 안전은 여기서 같은 방향을 향하고 있었습니다.
그리고 항상 안고 있는 것들을 늘리지 않는 것입니다. 대화할 때마다 매번 읽어 들여야 하는 것, 예를 들어 상시 연결된 외부 접속이나 비대해진 지시 파일 (Instruction file)은 사용하지 않는 날에도 매번 입력에 포함됩니다. 단 한 번의 대화라면 작은 차이겠지만, 수십 번 이어지는 주고받음에서는 그 서문을 매번 운반하게 됩니다. 이 부분은 다른 기사에 썼으므로 깊게 다루지는 않겠지만, 안고 있는 짐을 가볍게 할수록 매번의 입력이 가벼워지고 비용도 가벼워집니다. 반대로 과거의 대화 내용을 전부 안은 채 긴 대화를 이어가면, 매번 그 전부를 운반하게 됩니다. 적절한 지점에서 대화를 한 번 접고, 요점만 챙겨서 새로 시작하면 운반하는 짐이 가벼워져 비용도 안정되었습니다.
사용하는 쪽의 지갑은 궁극적으로 "자신의 고삐에 관한 이야기"입니다. 자신의 사용 방식에 따라 증감합니다. 플랜을 선택하는 것도, 태스크를 끊는 것도, 짐을 가볍게 하는 것도 모두 자신의 손안에 있습니다. 그래서 아직은 다루기 쉽습니다. 무서운 것은 고삐가 자신의 손에 있지 않은 쪽의 지갑이었습니다.
탑재하는 쪽의 지갑
AI 기능을 제품에 탑재하면, 토큰 값을 지불하는 것은 만든 자신이 아닙니다. 사용하는 사람입니다. 이 부분이 제가 지불하는 쪽만 보고 있을 때는 전혀 보이지 않았던 풍경이었습니다.
서두에 쓴 이탈이 그 상징입니다. 직접 만든 Rapls AI Chatbot이라는, WordPress 사이트에 AI 채팅을 배치하는 플러그인을 공개했습니다. 설치는 됩니다. 활성화도 됩니다. 하지만 API 키를 취득하고 결제 설정을 하는 단계에서 사람들이 슥 빠져나갑니다. 제작자인 저는 1원도 내지 않는데, 설계를 잘못하면 이용자의 지갑이 먼저 아파집니다. 이 비대칭성이 제품에 AI를 탑재하는 것의 가장 어려운 부분이었습니다.
게다가 이용자는 자신이 얼마를 지불하게 될지, 사용하기 전에는 알 수 없습니다. 채팅 1회당 비용이 얼마인지 전혀 가늠할 수 없는 수도꼭지를, 갑자기 자기 쪽으로 틀라고 요구받는 격입니다. 아주 강력한 동기가 있지 않는 한, 거기서 손이 멈춥니다. 기능이 아무리 좋아도 그 직전에서 이탈합니다. '좋은 것을 만들면 사용해 줄 것이다'라는 소박한 믿음이 여기서 한 번 무너졌습니다. 좋고 나쁨을 판단받을 수 있는 토대조차 올라서지 못했던 것입니다.
내가 지불하는 입장일 때, 비용은 '내가 주의하면 되는 문제'였습니다. 탑재하는 입장이 된 순간, 비용은 '타인이 지불하는데, 설계는 내가 하는' 뒤틀린 문제가 되었습니다. 이용자가 플러그인을 설치하고 나서 사용하기 시작할 때까지의 과정을 순서대로 나열해 보면, 골짜기가 어디에 있는지 보입니다. 설치한다. 활성화한다. 설정 화면을 연다. 여기까지는 비교적 잘 진행됩니다. 그다음 'API 키를 취득해 주세요'가 나옵니다. 여기서 AI 프로바이더 (AI Provider) 사이트에 가서 계정을 만들고 키를 발행하는 등, 별개의 세계와 같은 절차가 끼어듭니다. 게다가 '결제를 설정해 주세요'라며 카드 등록이 이어집니다. 그러고 나서야 겨우 한 번 채팅을 돌려볼 수 있습니다. 이 턱이 많은 계단 중 어느 한 단계에서 발이 멈추면, 기능에는 영원히 도달할 수 없습니다. 나중에 기술할 설계의 노하우는, 요컨대 이 계단의 턱을 어떻게 깎아낼 것인가에 대한 이야기였습니다.
내 지갑이라면 '비싸면 쓰지 않는다'라는 자연스러운 브레이크가 작동합니다. 이용자의 지갑에는 나의 브레이크가 작동하지 않습니다. 이용자가 어디에서 '비싸다'고 느껴 손을 뗄지를 상상으로 앞질러 예측하고, 설계로 방어할 수밖에 없습니다. 이 상상력의 싸움이 바로 탑재하는 측의 지갑 그 자체였습니다. 특히 악의적인 사용이나 단순한 설정 실수로 인해, 예상치의 수십 배가 호출되는 경로가 없는지는 설계 단계에서 미리 차단해 두고 싶습니다. 이는 이용자를 믿느냐 마느냐의 문제가 아니라, 사고는 선의로도 발생하기 때문입니다.
그리고 간과하고 있었던 지갑이 하나 더 있었습니다. 바로 서포트 (Support)의 수고입니다. 결제 관련 내용이 이해하기 어려우면 그 질문이 제작자에게 날아옵니다. '키를 어떻게 가져오는지 모르겠다', '결제는 됐는데 어디에 쓰였는지 모르겠다', '생각보다 비싸다'. 토큰 (Token) 비용 자체는 이용자가 지불하고 있더라도, 그 불안과 혼란에 응답하는 시간은 제작자 측에 쌓여갑니다. 비용 설계를 허술하게 하면 이용자의 지갑뿐만 아니라, 자신의 시간이라는 지갑도 깎여 나간다는 것을 나중에 깨달았습니다. 이해하기 쉬운 설계는 서포트를 줄이는 설계이기도 합니다.
이용자는 플러그인이 무료라고 생각한다
또 하나, WordPress 플러그인이라는 맥락에 고유한, 뿌리 깊은 전제가 있었습니다. 많은 이용자는 플러그인이 무료로 작동하는 것이라고 생각합니다.
WordPress의 플러그인은 오랫동안 '설치하면 바로 작동하는 것'이었습니다. 무료인 것이 대량으로 존재하고, 유료라 하더라도 한 번 사면 계속 쓸 수 있다는 감각이 배어 있습니다. 그곳에 '사용할 때마다 외부 AI에 따라 종량제로 과금됩니다'라는 제품을 내놓으면, 그 전제와 정면으로 충돌합니다. 플러그인 자체는 무료로 배포하더라도, 구동할 때마다 돈이 듭니다. 이 구도는 지금까지의 플러그인에는 없던 것이었습니다.
그 때문에 이용자가 경계하는 것은 가격이 비싸서라기보다, 예상하지 못했던 종류의 지출이기 때문이라는 측면이 큽니다. 월정액 구독 (Subscription)에는 익숙해도, 자신이 사용한 횟수만큼 미지의 금액이 청구되는 방식에는 익숙하지 않습니다. 서두에 언급한 이탈의 정체에는 이 '예상 밖'이라는 요소도 있었다고 생각합니다.
여기서 만드는 쪽이 할 수 있는 것은, 그 지출의 성격을 처음에 솔직하게 전달하는 것이었습니다. 'AI를 사용하므로 이용 시 토큰 비용이 발생합니다'라고 숨기지 않고 적습니다. 그러면서도 우선 무료로 체험할 수 있는 입구를 마련하여, 갑작스럽게 미지의 지출에 직면하게 하지 않습니다. 놀라게 하지 않는 것이, 이 전제와 충돌하는 제품에서는 꽤 중요한 일이었습니다.
누구의 지갑에 맞출 것인가
여기서 설계의 가장 상류 단계에 하나의 갈림길이 있습니다. 토큰 비용을 이용자에게 부담하게 할 것인가, 아니면 제작자인 내가 떠안을 것인가.
이용자에게 부담하게 하는 방식은 각자가 자신의 API 키를 가져오는 방식입니다. 제작자는 토큰 비용을 부담하지 않습니다. 서버 비용도 최소화할 수 있습니다. 대신, 서두에 말한 장벽이 생깁니다. 이용자가 키를 가져오고 결제를 설정하는 번거로움이 첫 번째 관문이 됩니다.
개발자가 부담하는 형태는, 개발자가 한꺼번에 프로바이더 (Provider)에게 지불하고 이용자에게는 정액제 구독(Subscription) 등으로 제공하는 방식입니다. 이용자 입장에서 보면 키(Key)도 필요 없고 결제 설정도 필요 없이, 넣기만 하면 바로 작동합니다. 경험이 매우 매끄럽습니다. 대신, 토큰 비용과 폭주(Runaway) 리스크를 개발자가 전부 떠안아야 합니다. 이용자가 예상치 못하게 과도하게 사용한다면, 그 차액은 개발자의 지갑에서 나갑니다. 요금 설계(Pricing design)를 잘못하면, 사용하면 할수록 적자가 나는 상황이 발생할 수도 있습니다. 월 1,000엔에 팔았는데 헤비 유저가 한 달에 몇 천 엔어치를 사용한다면, 그 차액은 개발자의 손실입니다. 정액으로 받는 금액은 정해져 있는데, 나가는 토큰 비용에는 상한이 없습니다. 열심히 사용해 주는 사람일수록 적자가 불어나는, 참으로 뒤틀린 구조가 될 수 있습니다. 이를 유지하기 위해서는 상한선이나 단계별 요금제를 상당히 세밀하게 설계해야 하는데, 개인이 감당하기에는 짐이 무겁다고 느꼈습니다.
어느 쪽이 정답이라는 이야기는 아닙니다. 매끄러운 경험을 강점으로 내세워 개발자가 리스크를 감수하는 것도 하나의 길입니다. 하지만 개인 개발로서, 게다가 혼자서 관리해야 하는 규모라면, 개발자가 타인의 토큰 비용과 폭주 리스크를 무제한으로 떠안는 것은 무섭습니다. 그래서 저는 이용자가 키를 직접 가져오는 형태를 기본으로 삼았습니다. 그 위에서, 키를 가져오는 첫 번째 번거로움을 최대한 가볍게 만드는 방향으로 설계합니다. 다음 장은 그 "가볍게 만드는" 내용입니다.
어느 쪽으로 기울일지를 처음에 결정해 두지 않으면 나중에 타격을 입습니다. 이용자가 지불하는 것을 전제로 한다면, 온보딩 (Onboarding)의 마찰을 어떻게 낮추느냐가 승부처가 됩니다. 개발자가 부담하는 것을 전제로 한다면, 상한선과 요금 설계를 틀리지 않는 것이 생사가 걸린 문제입니다. 어느 쪽의 지갑에 무게를 두느냐에 따라 집중해야 할 곳이 달라지기 때문입니다.
한 가지 머릿속에 두고 있는 전망도 있습니다. 모델의 가격은 긴 안목으로 보면 내려왔습니다. 비슷한 수준의 지능이 시간이 흐름에 따라 저렴해집니다. 따라서 지금은 높아서 넘기 힘든 지갑의 벽도, 내년에는 조금 낮아져 있을지도 모릅니다. 그렇다고 해도 설계는 지금 해야 합니다. 나중에 저렴해질 것이라는 이유로 지금의 벽을 방치하면, 그 미래가 오기 전에 이용자는 떠나버립니다. 가격 하락을 기대하면서도, 오늘의 벽은 오늘의 손으로 낮춘다. 저는 이 이중 구조로 생각하려고 노력하고 있습니다.
이용자의 지갑에 친화적인 코스트 설계
이용자가 키를 가져오는 것을 전제로, 그 지갑이 망가지지 않도록 설계에서 할 수 있는 것들을 나열합니다. 제가 실제로 적용한 것과 앞으로 적용하고 싶은 것들이 섞여 있습니다.
먼저, 요청(Request) 1회를 처리하는 전체 흐름을 골격으로 잡겠습니다. 어떤 가드 (Guard)를 호출하기 전에 둘지, 호출한 후에 둘지가 핵심이므로 우선 전체상을 먼저 보겠습니다.
function rapls_chat_handle( $user_id, $message ) {
// 1. 호출 전의 제동 장치: 횟수·간격의 상한을 초과하지 않았는가
$gate = rapls_chat_check_limits( $user_id );
...
순서에 의미가 있습니다. 상한 체크는 반드시 호출 전에 합니다. 모델 선택과 출력 상한은 그다음입니다. 사용량 기록은 호출한 후에 합니다. 이 4가지 위치만 지킨다면, 나머지는 각 가드의 내용을 조금씩 키워나갈 수 있습니다. 이하, 하나씩 살펴보겠습니다.
우선, 무료로 한 번 작동해 볼 수 있는 입구를 만드는 것. 이것이 가장 효과적이었습니다. 신용카드를 등록하지 않아도 일단 한 번은 채팅이 작동하는 상태를 준비합니다. 구체적으로는, OpenRouter의 무료 체험 범위를 활용한 온보딩을 넣었습니다. 첫 단계에서 카드를 꺼내지 않아도 된다면, "얼마나 들지 모른다"는 불안감을 일단 접어두고 기능 그 자체를 시험해 볼 수 있습니다. 이탈이 발생했던 그 문장의 벽을 낮추는 장치입니다. 한 번 작동하는 것을 보고 나서 결제를 생각하는 것과, 작동시키기 전에 결제를 요구받는 것은 넘기 쉬운 정도가 완전히 달랐습니다. 하고 있는 일은 무료 체험 루트를 사용하여, 키 발급과 카드 등록이라는 단계를 처음에는 건너뛸 수 있도록 하는 것입니다. 우선 한 번, 자신의 사이트에서 채팅이 답변을 보내는 것을 보게 합니다. 작동한다는 것을 알고 나서, 본격적으로 사용할 만큼의 키나 결제를 생각하게 하면 됩니다. 첫 번째 계단을 몇 개를 한꺼번에 깎아낸 형태입니다.
그렇다고 해서 무료 입구가 만능은 아닙니다. 무료 범위에는 횟수나 속도 제한이 있고, 사양도 제공 측의 사정에 따라 변합니다. 따라서 무료 동선은 어디까지나 "한 번 작동시켜 시험해 보는" 입구로 한정하고, 본격적으로 사용하려면 자신의 키로 전환하도록 하는 경로를 처음부터 보여줍니다. 무료 범위에만 의존하는 설계로 만들면, 그 범위가 바뀌는 날 제품 전체가 멈춥니다. 시험하기 위한 입구와 계속 사용하기 위한 발판은 나누어 준비해 두는 것이 안전했습니다.
다음으로, 프로바이더(Provider)나 모델을 이용자가 선택할 수 있도록 하는 것입니다. 특정 업체 한 곳에 고정하면, 그 회사의 가격에 이용자의 지갑이 묶이게 됩니다. 교체할 수 있도록 준비해 두면, 예산이 적은 사람은 저렴한 모델을, 품질이 필요한 사람은 높은 모델을, 자신의 지갑 사정에 맞춰 선택할 수 있습니다. 제작자가 "이것이 베스트"라고 단정 짓지 않는 것이 결과적으로 이용자의 지갑을 지키는 길입니다. 가격을 느끼는 방식은 사람마다 다르기 때문에, 선택지를 남겨두는 편이 진입 장벽을 낮추는 데 도움이 되었습니다.
그다음은 모델의 단계별 활용(段使い)입니다. 간단한 용건에까지 높은 모델을 사용할 필요는 없습니다. 자주 묻는 질문에 대한 답변 같은 가벼운 용건은 저렴한 모델로 처리하고, 복잡한 상담일 때만 높은 모델로 넘깁니다. 이는 다른 기사에서 썼던 "가벼운 순서대로 적용한다"라는 생각의 유료 버전이라고 생각합니다. 가장 강력한 모델을 기본값으로 설정해 두는 것은, 이용자의 지갑 관점에서 보면 가장 비싼 수도꼭지를 완전히 틀어놓고 기다리는 것과 같았습니다. 용건의 무게에 모델의 가격을 맞추는 것입니다. 챗봇(Chatbot)의 경우, "영업시간은?"과 같은 정형화된 문의가 실제로는 매우 많은데, 거기에 최상위 모델을 사용하는 것은 아깝다기보다 과잉이었습니다. 가벼운 용건을 저렴하게 처리할 수 있으면, 이용자 1인당 평균 결제 금액이 낮아져서 계속 사용하기가 더 쉬워집니다.
분류 방식도 처음에는 단순한 규칙만으로 충분했습니다. 짧은 정형 질문은 저렴한 모델, 장문이나 문맥이 필요한 상담은 상위 모델로 나누는 정도의 배분이었습니다.
// 이용자의 명시적 지정 우선, 없으면 용건의 무게에 따라 자동 분류
function rapls_chat_pick_model( $user_id, $message ) {
// 1. 이용자가 설정에서 선택했다면 그것을 존중한다
...
처음부터 똑똑한 분류기(Classifier)를 만들 필요는 없었고, 글자 수와 복잡한 상담을 나타내는 단어가 포함되어 있는지 정도의 판정부터 시작했습니다. 중요한 것은 이용자가 직접 모델을 선택했다면, 그것을 자동 분류보다 우선하는 것입니다. 지갑의 주도권은 이용자에게 있다는 원칙을 코드에서도 깨뜨리지 않도록 하고 있습니다.
자동 분류에서 벗어나더라도 피해는 작게 설계할 수 있습니다. 저렴한 모델로 받은 답변이 부족하다면, 이용자가 "더 자세히"라고 이어서 말했을 때 상위 모델로 다시 올리는 에스컬레이션(Escalation) 방식을 취하면, 처음부터 상위 모델을 전개하지 않아도 됩니다. 저렴하게 받고, 필요할 때만 올린다. 이것이 단계별 활용 구현의 핵심이었습니다.
코드로 구현하면 다음과 같은 형태입니다. 명확한 "상향 요청"은 처음부터 상위 모델로, 그 외에는 우선 저렴한 모델로 받은 뒤 답변이 부족할 때만 딱 한 번 다시 올립니다.
function rapls_chat_answer( $user_id, $message, $context ) {
// "더 자세히" 등 명확한 상향 요청은 처음부터 상위 모델로
if ( preg_match( '/もっと詳しく|詳細に|長めに|きちんと/u', $message ) ) {
...
한 가지 솔직한 주의사항이 있습니다. 모델을 다시 올리게 되면, 해당 용건은 저렴한 모델과 상위 모델을 총 2번 호출하게 됩니다. 즉, 에스컬레이션은 잘못하면 1회분 비용을 두 배로 만들 수 있습니다. 따라서 모델 상향은 단 한 번으로 제한합니다. 그리고 이 2회분 호출도 앞서 설정한 횟수 제한(Ceiling) 범위 내에서 계산합니다. 저렴하게 처리하려는 노력이 상향 과정에서의 손실로 인해 상쇄되지 않도록, 상향 조건을 다소 까다롭게 설정하는 것이 저의 타협점이었습니다.
폭주에 대한 상한선을 두는 것도 필요합니다. 1회 요청당, 또는 하루당 토큰(Token) 사용량에 상한을 둡니다. 루프(Loop)에 빠져 끝없이 토큰을 태우는 사고를 설계 단계에서 막아야 합니다. 이용자의 청구 금액이 어느 날 아침 말도 안 되는 액수가 되어 있는 사태는 어떻게 해서든 피하고 싶습니다. 특히 API 키를 직접 가져와 사용하는 방식이라면, 폭주로 인한 청구액은 그대로 이용자에게 전달됩니다. 구체적으로는 1회 응답에서 사용하는 토큰의 상한을 정해두고, 하루 호출 횟수에 천장을 만들며, 비슷한 대화가 짧은 시간 내에 반복되면 중단하는 등의 안전장치입니다. 특히 에러나 예상치 못한 입력으로 루프에 빠지면, 사람이 보고 있지 않는 사이에 끊임없이 호출이 이어질 수 있습니다. 그 부분을 설계로 막아두지 않으면 이용자의 청구 금액이 하룻밤 사이에 치솟을 수 있습니다.
구현 측면에서는, 요청당 상한은 API 호출의 max_tokens로 억제하고, 횟수 제한은 WordPress의 트랜지언트(Transient)를 사용하여 일일 카운터를 갖는 정도의 소박한 구조만으로도 효과가 있습니다.
// 횟수 상한과 최소 간격(연타·루프 방지)을 한꺼번에 확인
function rapls_chat_check_limits( $user_id, $daily = 100, $min_interval = 2 ) {
$today = 'rapls_chat_count_' . $user_id . '_' . gmdate( 'Ymd' );
...
목표는 두 가지입니다. 일일 상한(Ceiling)을 통해 하루에 다 써버릴 총량에 뚜껑을 씌우는 것. 그리고 최소 간격(Minimum Interval)을 통해 연타나, 에러로 인해 동일한 호출이 고속으로 루프되는 경로를 차단하는 것입니다. 특히 후자가 중요한데, 사람이 보고 있지 않은 시간에 호출이 무한히 이어지는 사고는 이 간격 가드(Guard) 하나만으로도 상당히 방지할 수 있습니다. WP_Error로 이유를 반환해 두면, 프론트엔드 측에서 "한도에 도달했습니다"라고 이용자에게 그대로 보여줄 수 있습니다. 이용자마다 상한을 다르게 설정하고 싶다면, $daily를 플랜별 값으로 바꾸기만 하면 됩니다.
상한은 이용자의 지갑을 지키는 안전밸브인 동시에, 제작자의 신용을 지키는 안전밸브이기도 했습니다.
불필요한 토큰을 줄이는 것도 은근히 효과가 있습니다. 매번 질문할 때마다 필요 없는 긴 서문을 싣고 있지는 않은지, 동일한 문맥을 몇 번이고 다시 보내고 있지는 않은지 확인해야 합니다. 대응이 가능하다면 프롬프트 캐시 (Prompt Cache)를 사용하세요. 보내는 토큰이 줄어들면 그만큼 이용자의 비용 부담도 줄어듭니다. 이용자의 지갑을 위한 튜닝은 돌고 돌아 제품이 "저렴하게 쓸 수 있다"라는 평판으로 이어집니다. 이 부분은 메커니즘이 바뀌기 쉬우므로, 집필 시점에서 대응 상황을 확인한 후 사용하시기 바랍니다.
챗봇의 경우, 매번 질문할 때마다 동일한 인격 설정이나 전제 조건(시스템 프롬프트 (System Prompt))을 붙여서 보내는 경우가 많습니다. 이 부분은 내용이 변하지 않기 때문에, 대응이 가능하다면 캐시가 잘 작동하는 영역입니다. 고정된 서문을 캐시에 올리고, 이용자마다 달라지는 질문만 매번 보내는 방식으로 나눌 수 있다면 반복되는 입력 비용을 낮출 수 있습니다. 변하지 않는 것은 재사용하고, 변하는 것만 새로 보낸다. 보내는 토큰을 줄이는 발상은 대개 이 형태에 도달했습니다.
플로우(Flow)에서 호출하던 rapls_chat_call_api 내부에서는 이러한 프로바이더 (Provider)별 차이를 흡수합니다. 이용자가 프로바이더를 선택할 수 있는 설계로 만들었기 때문에, 보내는 방식의 차이를 이곳 한 곳에 가두어 두면 이후 작업이 편했습니다.
function rapls_chat_call_api( $model, $message, $options = array() ) {
$provider = rapls_chat_provider_of( $model ); // 'openrouter' / 'anthropic' 등
$system = rapls_chat_system_prompt(); // 고정된 인격 설정 (매번 동일)
...
캐시 지시 방식(cache_control을 붙이는 법)도, 엔드포인트 (Endpoint)도, 인증 헤더 (Authentication Header)도 프로바이더마다 다릅니다. 위 예시는 특정 회사의 작성 방식에 맞춘 것이므로, 실제로는 대응 프로바이더마다 분기 처리가 필요하며 사양도 달라집니다. 집필 시점에 각사의 문서를 확인하십시오. 여기서 말하고자 하는 핵심은, 그 차이를 rapls_chat_call_api 내부에 가두어 두면 플로우의 상류(상한 설정·모델 선택·기록)는 프로바이더를 신경 쓰지 않고 작성할 수 있다는 것입니다. OpenRouter처럼 여러 프로바이더를 통합해서 호출할 수 있는 인터페이스를 사용하면 이 분기 자체를 얇게 만들 수 있어, 무료 유도 경로와도 궁합이 좋았습니다.
입력뿐만 아니라 출력의 길이도 중요합니다. 많은 모델에서 출력 토큰은 입력보다 단가가 높습니다. 묻지도 않은 내용을 장황하게 설명하면 그만큼 이용자의 비용이 늘어납니다. 응답의 최대 토큰(Max Tokens) 제한을 두면서, 시스템 프롬프트로 "간결하게 답할 것"이라고 방향을 잡아두면 불필요하게 긴 답변이 줄어들어 오히려 사용자 경험도 좋아졌습니다. 짧고 정확한 것이 채팅으로서도 기분이 좋습니다. 지갑에 친화적인 설계와 사용감이 좋은 설계가 여기서는 같은 방향을 향하고 있었습니다.
마지막으로 투명성입니다. "이 작업은 대략 이 정도 비용이 듭니다"라고 이용자에게 보여주는 것입니다. 보이지 않는 수도꼭지는 무섭습니다. 보이는 수도꼭지라면 이용자가 스스로 조절할 수 있습니다. 얼마나 썼는지, 이번 달에는 어느 정도인지 보여주는 것만으로도 불안감은 상당히 줄어들 것입니다. 금액 그 자체보다 '모른다는 사실'이 불안의 정체였기에, 보여주는 것 자체에 의미가 있습니다. 예를 들어, 설정 화면에서 모델을 선택하는 곳에 단가 기준을 한 줄 덧붙이는 것만으로도 막연함은 줄어듭니다.
$models = array(
'cheap-model' => '저렴함·일상적인 질문용 (기준: 저단가)',
'strong-model' => '고품질·복잡한 상담용 (기준: 고단가)',
...
정확한 금액은 단가표와 토큰 수에 따라 달라지므로 단정 지을 수는 없지만, "저렴함" 혹은 "비쌈"과 같은 체감 수치를 선택하는 순간에 보여주는 것만으로도 사용자는 자신의 예산에 맞춰 선택할 수 있습니다.
한 걸음 더 나아간다면, 플로우 (Flow)의 마지막 단계에서 기록된 사용량을 단가표와 곱하여 개략적인 금액으로 변환합니다. 프로바이더 (Provider)로부터 사용 토큰 수가 반환되므로, 이를 모델별 단가와 곱하기만 하면 됩니다.
// 모델별 단가 (100만 토큰당, 집필 시점의 단가표로 채움)
const RAPLS_CHAT_PRICE = array(
'cheap-model' => array( 'in' => 0.0, 'out' => 0.0 ),
...
단가 숫자는 휘발성이 있습니다. 여기서는 0을 넣어두고, 공개 시점에 자신이 대응하는 모델의 단가표로 채운다는 전제로 합니다. 플로우의 마지막에서 호출했던 rapls_chat_record_usage의 내용은 이 개략적인 금액을 월간 합계에 더하는 것뿐입니다.
// 플로우 마지막에서 호출. 월간 합계에 횟수·토큰·개략 금액을 더함
function rapls_chat_record_usage( $user_id, $model, $usage ) {
$cost = rapls_chat_estimate_cost( $model, $usage );
...
그다음은 이것을 읽어서 "이번 달은 대략 이 정도"라고 보여주기만 하면 됩니다.
function rapls_chat_usage_summary( $user_id ) {
$stats = get_user_meta( $user_id, 'rapls_chat_usage_' . gmdate( 'Ym' ), true );
if ( ! is_array( $stats ) ) {
...
개략적인 금액이므로 실제 청구 금액과는 일치하지 않습니다. 그 부분은 "기준치입니다"라는 설명을 덧붙여 보여줍니다. 그럼에도 불구하고 횟수와 대략적인 금액이 보이는 것만으로도, 보이지 않던 수도꼭지가 꽤 잘 보이는 수도꼭지가 됩니다.
보여주는 장소로는 우선 사용자의 프로필 화면이 간편했습니다. 앞서 언급한 모델 선택(pick_model이 존중하는 rapls_chat_model)과 이번 달 이용 기준치를 같은 화면에 나란히 배치합니다.
add_action( 'show_user_profile', 'rapls_chat_profile_fields' );
add_action( 'edit_user_profile', 'rapls_chat_profile_fields' );
function rapls_chat_profile_fields( $user ) {
...
저장 측면에서는 권한 체크와 예상 범위 내의 값만 허용하는 새니타이즈 (Sanitize)를 잊지 말아야 합니다 (본래는 nonce 검증도 포함해야 합니다).
AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기