← 목록으로

OpenAI 비용, 대체 어디서 샌다고? 직접 만든 대시보드로 100배 지출 갭 발견!

2026. 5. 1.

OpenAI 비용, 대체 어디서 샌다고? 직접 만든 대시보드로 100배 지출 갭 발견!

OpenAI 과금 페이지, 총 사용 금액은 분명하게 보여줍니다. 하지만 어떤 기능 때문에, 어떤 테넌트가, 어떤 대화에서 그 비용이 발생했는지는 전혀 알려주지 않죠. 멀티테넌트 AI 제품을 운영하는 입장에서는 그야말로 '눈 감고 운전하는 꼴'이었습니다. 그래서 직접 나섰습니다. 래퍼, DB 테이블, 대시보드, 이렇게 딱 3개의 파일로 이루어진 모니터링 시스템을 만들었고, 덕분에 API 호출 한 건당 8자리 소수점까지 비용을 추적할 수 있게 됐습니다. 놀랍게도, 대시보드를 처음 열어본 날, 저는 비슷하다고 생각했던 두 기능 간에 무려 100배에 달하는 비용 차이를 발견하고 말았죠.


OpenAI 대시보드의 불편한 진실

지금 바로 platform.openai.com/usage에 접속해보세요. 아마 이런 정보들을 보실 수 있을 겁니다.

  • 일일 총 지출
  • 모델별 사용량 (gpt-4o, gpt-4o-mini 등)
  • 총 토큰 사용량

네, 이게 전부입니다.

반면, 다음 정보들은 전혀 알 수 없습니다.

  • 내 앱의 어떤 기능이 이 토큰들을 발생시켰는지
  • 어떤 사용자테넌트가 해당 호출을 유발했는지
  • 어떤 특정 대화가 예산을 초과했는지
  • 실패한 호출이 여전히 비용을 발생시키고 있는지
  • 지연 시간(latency)이 비용과 어떻게 연관되는지

개인 사이드 프로젝트라면 괜찮을 수 있습니다. 하지만 프로덕션 환경의 AI 제품이라면, 그저 추측만 할 뿐이죠. 제가 10년 넘게 IT 현장에서 다양한 서비스를 만들면서 느낀 건데, 결국 '측정할 수 없는 것은 개선할 수 없다'는 불변의 진리더라고요. 특히 AI 시대에는 이 말이 더욱 와닿습니다.

저는 아랍어권 이커머스 상점을 위한 AI 판매 챗봇인 Provia를 개발하고 있습니다. 이 서비스는 멀티테넌트(각 상점이 개별 고객)이며, 챗 완성, 임베딩, 이미지 분석, 프로필 추출 등 여러 기능을 제공합니다. 고객 메시지 하나가 1~3번의 OpenAI API 호출을 유발할 수 있죠.

처음 서비스를 배포했을 때, OpenAI는 어제 제가 $4.27을 썼다고 알려줬습니다.

이 숫자는 정말이지 아무런 쓸모가 없었습니다. 혹시 값비싼 이미지 분석 한 건 때문이었을까? 메시지 수천 개를 보낸 특정 상점 때문인가? 같은 호출이 반복적으로 발생하는 무한 루프였을까? 전혀 알 길이 없었죠.

그래서 저는 저만의 관측 시스템을 만들었습니다. 딱 세 개의 파일, 그리고 단 한 번의 오후 시간 투자로 말이죠.


파일 1: 래퍼 (openai-logger.ts)

핵심 아이디어는 간단합니다. OpenAI API를 직접 호출하지 않고, 모든 것을 측정하고 비동기적으로 로깅하는 래퍼를 거쳐 호출하는 겁니다.

가격표 테이블

OpenAI API는 토큰 개수는 반환하지만, 실제 비용은 반환하지 않습니다. 따라서 하드코딩된 가격표를 통해 직접 계산해야 합니다.

// 최종 확인일: 2026-04-15 — https://openai.com/pricing
const PRICING: Record<string, { input: number; output: number }> = {
  "gpt-4o":      { input: 2.50,  output: 10.00 },   // 토큰 100만 개당
  "gpt-4o-mini": { input: 0.15,  output: 0.60  },   // 토큰 100만 개당
};

여기서 주목할 만한 비용 비율을 살펴보세요.

모델Input (1M당)Output (1M당)비용 비율
gpt-4o$2.50$10.001배
gpt-4o-mini$0.15$0.60약 16배 저렴

gpt-4o는 동일한 토큰 수에 대해 gpt-4o-mini보다 약 16배 더 비쌉니다. gpt-4o-mini로 처리할 수 있는 작업에 gpt-4o를 사용하고 있다면, 그야말로 돈을 태우고 있는 셈이죠. 대시보드를 통해 이를 호출 건별로 명확하게 볼 수 있다면, 어떤 모델을 어디에 사용할지 결정하는 데 큰 도움이 됩니다.

래퍼 코드

import OpenAI from "openai";
import { createAdminClient } from "@/lib/supabase/admin";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

const PRICING: Record<string, { input: number; output: number }> = {
  "gpt-4o":      { input: 2.50,  output: 10.00 },
  "gpt-4o-mini": { input: 0.15,  output: 0.60  },
};

interface LogMeta {
  storeId: string;
  conversationId?: string;
  leadId?: string;
  endpoint: string;
  functionCalled?: string;
  searchQuery?: string;
  productsFound?: number;
}

export async function loggedChatCompletion(
  params: OpenAI.Chat.Completions.ChatCompletionCreateParams,
  meta: LogMeta
) {
  const start = Date.now();
  const result = await openai.chat.completions.create(params);
  const duration = Date.now() - start;

  const tokens = result.usage;
  const rates = PRICING[params.model as string] || PRICING["gpt-4o-mini"];
  const cost = tokens
    ? (tokens.prompt_tokens * rates.input +
       tokens.completion_tokens * rates.output) / 1_000_000
    : 0;

  // Fire-and-forget 로깅 — 응답을 절대 블로킹하지 않습니다.
  const supabase = createAdminClient();
  supabase
    .from("api_logs")
    .insert({
      store_id: meta.storeId,
      conversation_id: meta.conversationId,
      lead_id: meta.leadId,
      endpoint: meta.endpoint,
      model: params.model,
      prompt_tokens: tokens?.prompt_tokens,
      completion_tokens: tokens?.completion_tokens,
      total_tokens: tokens?.total_tokens,
      cost,
      duration_ms: duration,
      function_called: meta.functionCalled,
      search_query: meta.searchQuery,
      products_found: meta.productsFound,
      status: "success",
    })
    .then(() => {})
    .catch(() => {}); // 조용히 실패 (Silent fail) — 모니터링이 앱을 망가뜨려서는 안 됩니다.

  return { result, cost, duration };
}

가장 중요한 패턴: Fire-and-Forget

이 코드를 안전하게 배포할 수 있게 해주는 핵심 라인은 바로 이것입니다.

.then(() => {}).catch(() => {}); // 조용히 실패

로그 삽입은 await 하지 않습니다. 데이터베이스가 다운되거나, 네트워크 문제가 발생하거나, 테이블이 아직 존재하지 않더라도 사용자에게 응답하는 데 아무런 지장을 주지 않습니다.

제가 테스트해본 결과, 로그 삽입은 1540ms 정도 걸렸고, 챗 완성(chat completion)은 8002500ms가 소요됐습니다. 만약 로그 삽입을 await했다면, 사용자에게는 아무런 이득 없이 모든 요청에 2~5%의 지연 시간이 추가되었을 겁니다. 제가 실무에서 여러 모니터링 시스템을 구축하면서 얻은 가장 큰 교훈 중 하나가 바로 이 부분입니다. 모니터링은 절대 모니터링 대상의 성능을 저하시켜서는 안 됩니다. 이것이 여기서 가장 중요한 유일한 규칙입니다.

이 패턴을 몇 주 동안 운영하면서 수천 개의 로그 항목 중 2~3개 정도만 유실되었는데, 이 정도는 충분히 허용 가능한 트레이드오프라고 생각합니다.

드롭인 방식으로 사용

이전 코드:

const response = await openai.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: customerMessage }],
});

래퍼 적용 후:

const { result, cost, duration } = await loggedChatCompletion(
  {
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: customerMessage }],
  },
  {
    storeId: store.id,
    conversationId: conversation.id,
    leadId: lead.id,
    endpoint: "chat",
  }
);

인터페이스는 동일하고, 매개변수 하나만 추가되었습니다. 코드베이스 전체를 찾아서 바꾸는 데 10분 정도 걸렸죠.


파일 2: 테이블 (api_logs)

CREATE TABLE api_logs (
  id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
  store_id UUID REFERENCES stores(id),
  conversation_id UUID,
  lead_id UUID,
  endpoint TEXT NOT NULL,
  model TEXT,
  prompt_tokens INT,
  completion_tokens INT,
  total_tokens INT,
  cost DECIMAL(10,8),
  duration_ms INT,
  function_called TEXT,
  search_query TEXT,
  products_found INT,
  status TEXT DEFAULT 'success',
  error TEXT,
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_api_logs_store ON api_logs(store_id);
CREATE INDEX idx_api_logs_created ON api_logs(created_at);
CREATE INDEX idx_api_logs_endpoint ON api_logs(endpoint);

이 컬럼들은 데이터를 '슬라이스'할 수 있는 차원(dimension)들입니다. 각 컬럼은 OpenAI 대시보드가 답할 수 없는 질문에 답해줍니다.

  • store_id → "어떤 테넌트가 가장 비싼가?" 멀티테넌트 SaaS에서는 한 상점이 다른 상점보다 10배 더 많은 비용을 발생시킬 수 있습니다. 이 컬럼이 없으면 절대 알 수 없죠.
  • endpoint → "챗 기능이 비싼 부분인가, 아니면 이미지 분석이 비싼 부분인가?"
  • conversation_id + lead_id → "이 대화는 얼마의 비용이 들었지? 이 고객은?"
  • function_called + search_query + products_found → 디버깅용 컬럼들입니다. 고객이 "빨간 드레스 보여줘"라고 했는데 봇이 아무것도 반환하지 않을 때, 검색 함수를 호출했는지? 어떤 쿼리로 호출했는지? 몇 개의 제품이 반환되었는지 확인할 수 있습니다. 덕분에 디버깅 시간을 몇 시간이나 절약했습니다.
  • duration_ms → 지연 시간(Latency). 대시보드에서는 색상으로 구분됩니다. 녹색 <1.5초, 노란색 1.5~3초, 빨간색 >3초.
  • error → 실패한 호출도 프롬프트 토큰을 소모합니다. OpenAI는 이에 대해 과금하죠. 이를 추적해야 합니다.

한 가지 놓치기 쉬운 세부 사항은 바로 cost DECIMAL(10,8) 입니다. 소수점 이하 8자리.

gpt-4o-mini의 챗 완성 호출 한 건은 대략 $0.00013 정도입니다. 만약 DECIMAL(10,2)로 저장한다면, 모든 호출이 $0.00으로 반올림되어 총액이 무의미해집니다. 규모가 커질수록 100분의 1센트 단위까지도 중요해집니다.


파일 3: 대시보드

API 라우트 (/api/admin/logs/route.ts)는 필터 (startDate, endDate, endpoint, storeId)를 받아 다음과 같이 집계된 데이터를 반환합니다.

{
  summary: {
    totalRequests, totalTokens, avgTokensPerRequest, avgLatency, totalCost
  },
  dailyTokens:       [{ date, prompt, completion, total }, ...],
  hourlyActivity:    [{ hour, count }, ...],
  endpointBreakdown: [{ endpoint, count, cost, percentage }, ...],
  modelBreakdown:    [{ model, count, cost, percentage }, ...],
  storeBreakdown:    [{ storeId, storeName, count, cost }, ...],
}

UI는 의도적으로 단조롭게 만들었습니다.

  • 상단에 5개의 통계 카드 — 총 요청 수, 총 토큰 수, 요청당 평균 토큰 수, 평균 지연 시간(색상 구분), 총 비용
  • 날짜 필터 — 오늘, 7일, 30일, 전체 기간, 사용자 지정 범위
  • 드롭다운 — 엔드포인트, 상점
  • 실시간 모드 토글 — 5초마다 자동 새로 고침
  • 두 개의 차트 — 일일 토큰 사용량(프롬프트 vs 완성), 시간별 활동
  • 확장 가능한 로그 행 — 클릭 시 전체 상세 정보(모델, 토큰, 비용, 지연 시간, 검색 쿼리, 발견된 제품) 확인

API가 무거운 작업을 처리하고, UI는 미리 집계된 데이터를 그저 렌더링할 뿐입니다. 클라이언트 측 계산도, 예상치 못한 동작도 없습니다.


무엇을 찾아냈을까?

Provia의 실제 운영 데이터를 통해 하루 동안 발견한 숫자들입니다.

지표
처리된 고객 메시지 수42
OpenAI API 호출 수약 85
총 토큰 수약 31,000
총 비용약 $0.005
메시지당 평균 비용약 $0.00013

기능별 비용 분할:

엔드포인트모델호출 수비용 점유율
gpt-4o-mini42약 85%
임베딩text-embedding-3-small42약 2%
프로필 추출gpt-4o-mini약 12약 3%
이미지 분석gpt-4o1약 10%

이 대시보드 뷰를 보자마자 두 가지가 눈에 확 들어왔습니다.

첫째. gpt-4o를 이용한 이미지 분석은 gpt-4o-mini를 이용한 챗 기능보다 호출당 비용이 대략 100배 더 높았습니다. 전체 호출의 약 1%만이 이미지 분석이었음에도 불구하고, 예산의 약 10%를 차지하고 있었던 거죠. 이 사실은 어떤 기능에 gpt-4o를 사용하고 어떤 기능에 gpt-4o-mini를 사용할지에 대한 제 생각을 완전히 바꿔놓았습니다.

둘째. 챗 엔드포인트가 제가 예상했던 것보다 훨씬 더 많은 프롬프트 토큰을 호출당 사용하고 있었습니다. 대시보드는 이 문제를 보여주었고, 조사 결과 모든 응답마다 전체 대화 이력을 컨텍스트로 보내고 있다는 것을 알게 됐습니다. 이는 제가 여기에 작성한 별도의 아키텍처 수정 사항이지만, 이 글의 핵심은 대시보드가 문제를 보여주지 않았다면 저는 그 버그를 찾으려 하지도 않았을 거라는 점입니다.

이것이 바로 선순환입니다. 측정할 수 없는 것은 최적화할 수 없습니다. 계측하지 않으면 측정할 수 없습니다. 그리고 일반적인 청구 대시보드는 당신의 애플리케이션을 계측하지 않습니다.


구축하면서 배운 5가지 교훈

1. OpenAI 대시보드는 청구 도구이지, 관측 도구가 아니다

재무 부서에 청구할 금액을 알려주는 용도일 뿐입니다. 엔지니어링 팀에 무엇을 고쳐야 할지 알려주지 않죠. 역할이 다릅니다.

2. Fire-and-forget은 절대적이다

모니터링이 요청 경로를 블로킹한다면, 당신은 제품을 더 나쁘게 만든 것입니다. 관측 가능성(observability)의 요점은 '쳐다보지 않을 때는 보이지 않는 것'입니다. 항상 await 없는 삽입, 로그 오류 발생 시 조용한 실패를 추구해야 합니다.

3. 소수점 이하 8자리, 2자리가 아니다

비용을 DECIMAL(10,2)로 저장하면 모든 호출이 0으로 반올림됩니다. AI 비용은 호출당 100분의 1센트 단위입니다. 그 미세한 단위까지 다루어야 합니다.

4. 차원(Dimensions)이 곧 제품이다

총 비용은 숫자일 뿐입니다. 테넌트당 비용, 기능당 비용, 대화당 비용은 인사이트입니다. 당신이 로그에 기록하는 컬럼이 답할 수 있는 질문을 결정합니다. 문제가 생긴 후에 추가하지 말고, 기능을 개발할 때부터 컬럼을 추가하세요.

5. 가격은 하드코딩하고 수동으로 업데이트한다

OpenAI 가격 정보를 쿼리할 수 있는 API는 존재하지 않습니다. 마지막으로 확인한 날짜를 주석으로 달아 가격표를 하드코딩하고, OpenAI가 가격을 변경할 때 수동으로 업데이트하세요. 두 줄의 코드, 한 달에 3분이면 충분합니다.

// 최종 확인일: 2026-04-15 — https://openai.com/pricing
const PRICING = {
  "gpt-4o":      { input: 2.50,  output: 10.00 },
  "gpt-4o-mini": { input: 0.15,  output: 0.60  },
};

다음 단계: 무엇을 추가할 것인가

기본 버전이 잘 작동한다면, 다음 업그레이드 경로를 고려해 보세요.

지연 시간 백분위수 (Latency percentiles). 평균 지연 시간은 종종 착각을 불러일으킵니다. p50, p95, p99를 추적하세요. 평균이 1.2초여도 p99가 8초라면, 100명 중 한 명은 끔찍한 경험을 하고 있다는 뜻입니다.

테넌트별 예산 알림. 상점당 일일 $1와 같은 임계치를 설정하고, 초과 시 Slack/이메일로 알림을 보냅니다. 이는 무한 루프, 엄청난 출력을 생성하는 프롬프트 인젝션, 또는 예상치 못한 사용량 급증을 겪는 상점을 조기에 파악하는 데 도움이 됩니다.

엔드포인트별 오류율. 전체 오류율은 실제 분포를 숨깁니다. 챗 기능에서 2% 오류, 이미지 분석에서 15% 오류는 둘 다 8% 오류인 경우와는 전혀 다른 문제입니다.

전환당 비용 (Cost per conversion). AI가 비즈니스 성과(판매, 가입, 완료)를 유도하기 위해 존재한다면, 로그를 해당 성과 테이블에 연결하세요. 그러면 단순히 대화당 지출이 아니라 대화당 ROI를 얻을 수 있습니다.

모델 마이그레이션 추적. 기능을 gpt-4o에서 gpt-4o-mini로 전환할 때, 비용 절감 효과가 명확하게 보여야 합니다. model 컬럼 덕분에 전환 전후 비교가 아주 쉬워집니다.


결론: 이 '렌즈'가 모든 것을 바꿨습니다

세 개의 파일. 단 한 번의 오후 시간. 총 400라인 정도의 코드.

모든 API 호출을 가로채는 래퍼. 데이터를 슬라이스할 수 있는 충분한 차원을 가진 테이블. 그리고 이를 실행 가능한 정보로 집계하는 페이지.

LangSmith나 Helicone, Datadog 같은 훌륭한 도구들이 있지만, 반드시 필요한 것은 아닙니다. "어떤 기능이, 어떤 테넌트가, 어떤 대화가" 비용을 발생시켰는지 답할 수 있는 최소한의 도구가 필요한 거죠. 왜냐하면 바로 그 질문에 당신의 청구 대시보드는 답할 수 없기 때문입니다.

제가 직접 만든 대시보드를 처음 열었을 때, 저는 비슷하게 생각했던 두 기능 간의 100배에 달하는 비용 차이를 발견했습니다. 그 차이를 볼 수 있는 '렌즈'를 만들었기에 가능한 일이었죠.

배포하기 전에 이 렌즈를 만드세요. 아니, 더 솔직히 말하자면, 배포하는 날, 잊어버리기 전에 바로 만드세요.


저는 아랍어권 이커머스 상점을 위한 AI 판매 챗봇인 Provia를 가자 지구에서 한정된 예산으로 개발하고 있습니다. AI 제품 개발에 대한 더 많은 이야기를 듣고 싶다면 팔로우해주세요.


원문: https://dev.to/alimafana/openai-tells-you-what-you-spent-not-where-so-i-built-a-dashboard-b6 수집일: 2026-05-01 01:48:40