ai-startup
CHAPTER 32 / 100
읽기 약 2분
FUNCTION
비용 관리: 토큰 사용량 추적 + 사용자별 제한
핵심 개념
usage tracking·rate limit·plan별 한도·실시간 알림.
본문
비용 폭주 위험
[흔한 시나리오]
- 사용자 1명이 10,000 메시지 보냄 (스크립트)
- 비용: 100만 토큰 × $15 = $15,000
- → 한 달 만에 파산
[방어]
1. Rate Limit (분당·일별)
2. Plan별 한도
3. 비용 알림
4. 자동 차단사용량 DB 스키마
CREATE TABLE usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
model TEXT NOT NULL,
input_tokens INT NOT NULL,
output_tokens INT NOT NULL,
cost_cents INT NOT NULL, -- 0.01센트 단위
endpoint TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX ON usage (user_id, created_at DESC);
CREATE TABLE user_plans (
user_id UUID PRIMARY KEY,
plan TEXT NOT NULL DEFAULT 'free', -- free, pro, business
monthly_token_limit INT NOT NULL,
daily_request_limit INT NOT NULL,
current_period_start TIMESTAMPTZ,
current_period_tokens INT DEFAULT 0
);사용량 기록 미들웨어
// lib/track-usage.ts
import { createClient } from '@/lib/supabase/server';
const PRICING = {
'gpt-4o-mini': { input: 0.015, output: 0.06 }, // per 1K tokens (cents)
'gpt-4o': { input: 0.25, output: 1 },
'claude-haiku-4-5': { input: 0.08, output: 0.4 },
'claude-sonnet-4-6': { input: 0.3, output: 1.5 },
'claude-opus-4-7': { input: 1.5, output: 7.5 },
};
export async function trackUsage({
userId,
model,
inputTokens,
outputTokens,
endpoint,
}: any) {
const pricing = PRICING[model];
const costCents = Math.round(
(inputTokens / 1000) * pricing.input * 100 +
(outputTokens / 1000) * pricing.output * 100,
);
const supabase = await createClient();
await supabase.from('usage').insert({
user_id: userId,
model,
input_tokens: inputTokens,
output_tokens: outputTokens,
cost_cents: costCents,
endpoint,
});
// Plan 사용량 누적
await supabase.rpc('increment_period_tokens', {
user_id: userId,
tokens: inputTokens + outputTokens,
});
}API 라우트에 통합
import { streamText } from 'ai';
import { trackUsage } from '@/lib/track-usage';
export async function POST(req: Request) {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
if (!user) return new Response('Unauthorized', { status: 401 });
// 한도 체크
const { canUse, reason } = await checkUsage(user.id);
if (!canUse) {
return new Response(reason, { status: 429 });
}
const result = streamText({
model: anthropic('claude-sonnet-4-6'),
messages: req.messages,
onFinish: async ({ usage }) => {
// 응답 완료 후 사용량 기록
await trackUsage({
userId: user.id,
model: 'claude-sonnet-4-6',
inputTokens: usage.promptTokens,
outputTokens: usage.completionTokens,
endpoint: '/api/chat',
});
},
});
return result.toDataStreamResponse();
}한도 체크
async function checkUsage(userId: string) {
const supabase = await createClient();
// 일별 요청 수
const today = new Date(); today.setHours(0,0,0,0);
const { count: todayCount } = await supabase
.from('usage')
.select('*', { count: 'exact', head: true })
.eq('user_id', userId)
.gte('created_at', today.toISOString());
// Plan 정보
const { data: plan } = await supabase
.from('user_plans')
.select()
.eq('user_id', userId)
.single();
// 일별 한도
if (todayCount! >= plan!.daily_request_limit) {
return { canUse: false, reason: 'Daily limit exceeded' };
}
// 월별 토큰 한도
if (plan!.current_period_tokens >= plan!.monthly_token_limit) {
return { canUse: false, reason: 'Monthly token limit exceeded' };
}
return { canUse: true };
}Plan 정의
const PLANS = {
free: {
monthly_tokens: 50_000, // 월 50K 토큰
daily_requests: 20,
models: ['gpt-4o-mini', 'gemini-flash'],
},
pro: {
monthly_tokens: 1_000_000, // 월 1M 토큰
daily_requests: 200,
models: ['gpt-4o', 'claude-sonnet-4-6', 'gemini-flash'],
},
business: {
monthly_tokens: 10_000_000,
daily_requests: 1000,
models: ['claude-opus-4-7', 'gpt-4o', 'claude-sonnet-4-6'],
},
};사용량 대시보드
// app/dashboard/usage/page.tsx
async function UsagePage() {
const supabase = await createClient();
const { data: usage } = await supabase
.from('usage')
.select('*')
.gte('created_at', startOfMonth())
.order('created_at', { ascending: false });
const totalCost = usage!.reduce((s, u) => s + u.cost_cents, 0) / 100;
const totalTokens = usage!.reduce((s, u) => s + u.input_tokens + u.output_tokens, 0);
return (
<div>
<Card>
<h2>이번 달 사용량</h2>
<p>{totalTokens.toLocaleString()} tokens</p>
<p>${totalCost.toFixed(2)}</p>
</Card>
<UsageChart data={usage} />
</div>
);
}비용 알림
// 일일 cron — 비정상 사용 검출
export async function checkAbnormalUsage() {
const supabase = await createClient();
const { data } = await supabase.rpc('get_top_users_today');
for (const user of data) {
if (user.cost_today > 5_00) { // $5 이상
await notifyOps({
userId: user.user_id,
cost: user.cost_today / 100,
message: 'Abnormal usage detected',
});
}
}
}다음 챕터
CH.33 "AI SaaS 종합".
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
무료
월 $0 — 검증·시작 단계
AI 비용 관리을 무료 도구만으로 시작하는 방법을 알려줘.
소자본
월 $20~50 — MVP·초기 운영
월 $20~50 예산으로 AI 비용 관리을 검증·MVP 단계까지 진행하는 전략은?
프로덕션
월 $200~500 — 성장 단계
AI 비용 관리을 프로덕션 단계로 확장할 때 필요한 도구·운영 체계는?
스택
풀스택 — 도구 조합 분석
2026년 AI 비용 관리 관련 도구 5개를 조합한 추천 스택을 알려줘.
⭐ 이것만 기억하세요
비용 관리: 토큰 사용량 추적 + 사용자별 제한은 이 3가지만 확실히 잡으세요
1.사용량 기록 (onFinish) + 한도 체크 = 비용 폭주 방어
2.Plan별 한도 (free/pro/business) = SaaS 표준
3.사용량 대시보드로 사용자 투명성
공유하기
진행도 32 / 100