Usage, Quota & Spend Tracking (한국어)
OmniRoute를 통과하는 모든 요청은 다음 정보를 담은 사용량 레코드를 생성합니다.
- 식별 정보: API 키, 제공자, 모델, 콤보
- 토큰: 프롬프트 토큰, 완료 토큰, 캐시된 토큰, 총합
- 비용: USD 금액(가격 데이터를 기반으로 계산)
- 시간 정보: 지연 시간, 시작/종료 타임스탬프
- 상태: 성공, 오류, 속도 제한 등
이러한 레코드는 분석 데이터로 집계되고, 할당량 스냅샷으로 영구 저장되며, 키별 예산 한도를 적용하는 데 사용됩니다.
요청 ──▶ chatCore ──▶ usage.record() ──▶ SQLite │ ┌───────┼───────┐ ▼ ▼ ▼ 분석 할당량 청구 (대시보드) (적용) (내보내기)기록되는 항목
섹션 제목: “기록되는 항목”usage.ts 서비스는 모든 요청에 대해 사용량 이벤트를 기록합니다.
| 필드 | 유형 | 출처 |
|---|---|---|
id |
string | 기록 시 생성되는 UUID |
apiKeyId |
string | 요청을 시작한 API 키 |
provider |
string | 제공자 ID (openai, anthropic 등) |
model |
string | 모델 ID (gpt-5, claude-opus-4-6 등) |
comboId |
string? | 콤보를 통해 라우팅된 경우의 콤보 ID |
promptTokens |
number | 업스트림 응답에서 가져옴 |
completionTokens |
number | 업스트림 응답에서 가져옴 |
cachedTokens |
number | 캐시 적중 토큰(Anthropic 프롬프트 캐싱 등) |
totalTokens |
number | 프롬프트 + 완료 |
costUsd |
number | 가격 데이터를 기반으로 계산 |
latencyMs |
number | 엔드투엔드 요청 소요 시간 |
status |
enum | success, error, rate_limited, timeout, cancelled |
errorClass |
string? | status != success인 경우의 오류 클래스 |
timestamp |
string | ISO 8601 UTC |
metadata |
object | 사용자 정의 플러그인이 삽입한 데이터 |
토큰의 출처
섹션 제목: “토큰의 출처”토큰은 응답 핸들러에서 업스트림 제공자의 응답으로부터 추출됩니다.
// open-sse/handlers/chatCore.ts에서 가져옴const response = await providerExecutor.execute(provider, request);const usage = response.usage || { prompt_tokens: 0, completion_tokens: 0, cached_tokens: 0,};사용량을 반환하지 않는 제공자(일부 웹 쿠키 제공자)의 경우 OmniRoute는 토큰당 약 4자 휴리스틱을 사용하여 토큰 수를 추정합니다(open-sse/services/autoCombo/pipelineRouter.ts 참조).
캐시된 토큰
섹션 제목: “캐시된 토큰”OmniRoute는 다음과 같은 이유로 cached_tokens를 prompt_tokens와 별도로 추적합니다.
- Anthropic 프롬프트 캐싱에서는 캐시된 토큰에 대해 할인된 요금(정상 요금의 10%)을 부과합니다.
- 일부 제공자는 별도로 가격을 책정해야 하는
cache_read_input_tokens를 반환합니다. - 분석에서는 캐시 적중률 =
cached_tokens / prompt_tokens를 표시할 수 있습니다.
비용 계산
섹션 제목: “비용 계산”비용은 LiteLLM에서 동기화된 가격 데이터(src/lib/pricingSync.ts)를 사용하여 계산됩니다.
| 모델 | 입력 $/1M | 출력 $/1M | 캐시 $/1M |
|---|---|---|---|
| gpt-5 | $2.50 | $10.00 | — |
| claude-opus-4-6 | $15.00 | $75.00 | $1.50 |
| claude-sonnet-4-5 | $3.00 | $15.00 | $0.30 |
| gemini-2.5-pro | $1.25 | $10.00 | — |
비용 계산식(src/lib/usage/costCalculator.ts):
cost = (prompt_tokens - cached_tokens) * input_price + cached_tokens * cached_price + completion_tokens * output_price;캐시된 토큰을 프롬프트 토큰에서 빼는 이유는 무엇인가요? 캐시된 부분은 별도로 가격이 책정되므로, 전체 프롬프트에 입력 가격을 적용하면 비용이 중복 계산됩니다.
가격 동기화
섹션 제목: “가격 동기화”가격 데이터는 /api/pricing/sync 엔드포인트를 통해 LiteLLM에서 자동으로 동기화됩니다(사용자용 환경 변수가 아닌 내장 cron 작업에 의해 실행됨).
# 수동 실행curl -X POST http://localhost:20128/api/pricing/sync가격 데이터가 없는 모델의 경우 OmniRoute는 LiteLLM의 가격 데이터에서 가져온 내부 평균 요율을 사용하여 비용을 추정합니다.
날짜 범위 집계
섹션 제목: “날짜 범위 집계”usageAnalytics.ts 모듈은 원시 사용량 데이터로부터 대시보드 위젯을 계산합니다. 다음 7개의 시간 범위를 지원합니다.
| 범위 | 기간 | 사용 사례 |
|---|---|---|
1d |
최근 24시간 | 시간별 비용 급증 감지 |
7d |
최근 7일 | 주간 검토 |
30d |
최근 30일 | 월별 청구 |
90d |
최근 90일 | 분기별 분석 |
ytd |
현재 연도의 1월 1일부터 | 연간 예산 추적 |
all |
전체 기간 | 누적 통계 |
custom |
사용자가 정의한 시작/종료 기간 | 감사, 임시 쿼리 |
계산되는 대시보드 위젯
섹션 제목: “계산되는 대시보드 위젯”모든 날짜 범위에 대해 분석 계층은 다음을 계산합니다.
| 위젯 | 설명 |
|---|---|
| 요약 카드 | 총 요청 수, 총비용, 총 토큰 수, 성공률 |
| 일별 추세 차트 | 모델별로 누적 표시된 일별 비용 및 토큰 수 |
| 활동 히트맵 | 시간대 × 요일 그리드, 색상 = 요청 수 |
| 모델 분석 | 모델별 비용을 나타내는 원형 차트 |
| 제공자 분석 | 제공자별 요청 수를 나타내는 막대 차트 |
| 상위 API 키 | 비용 기준 상위 10개 키를 보여주는 표 |
| 오류 분석 | 시간 경과에 따른 오류율, 주요 오류 클래스 |
프로그래밍 방식으로 접근
섹션 제목: “프로그래밍 방식으로 접근”import { computeAnalytics } from "@/lib/usageAnalytics";
const analytics = await computeAnalytics( history, // 사용량 기록 "7d", // 시간 범위: "1d" | "7d" | "30d" | "90d" | "ytd" | "all" | "custom" connectionMap, // 제공자 연결 맵(connectionId → 계정 이름) { startDate: "2025-01-01", // 선택 사항: "custom" 범위에 사용 endDate: "2025-06-01", // 선택 사항: "custom" 범위에 사용 });
console.log(analytics.summary.totalCost); // 12.34(센트)console.log(analytics.byModel[0]); // { model, cost, requests, promptTokens, completionTokens }
---
## 할당량 적용
API 키별 할당량은 다음 두 지점에서 적용됩니다.
1. **소프트 제한** (`quotaWarnAt`): 사용량이 임계값을 초과하면 대시보드에 경고 표시2. **하드 제한** (`quotaLimit`): 사용량이 초과되면 HTTP 429로 요청 거부
### 구성
```ts// API 키별await updateApiKey(keyId, { quotaWarnAt: 5_00, // $5.00 — 경고 표시 quotaLimit: 10_00, // $10.00 — 하드 중단 quotaWindow: "month", // "day" | "week" | "month" | "all"});적용 흐름
섹션 제목: “적용 흐름”요청 ──▶ quotaCheck() │ ├── 제한 이내? ──▶ 허용 │ └── 제한 초과? ──▶ 429 Too Many Requests Retry-After 헤더 포함할당량 스냅샷
섹션 제목: “할당량 스냅샷”quotaSnapshots 테이블은 추세 분석을 위한 과거 할당량 상태를 저장합니다.
| 필드 | 설명 |
| ———– | –––––––––––––––– | —— | —–– |
| apiKeyId | 추적 중인 키 |
| window | “day” | “week” | “month” |
| used | 이 기간에 사용된 비용(센트) |
| limit | 제한(센트) |
| resetAt | 기간이 재설정되는 시점 |
| createdAt | 스냅샷이 생성된 시점 |
스냅샷은 비용이 0보다 큰 모든 요청에서 생성되며, 다음 용도로 사용됩니다.
- 대시보드에 할당량 진행률 표시줄 렌더링
- 30일 할당량 추세 차트 표시
- 사용량이 제한에 근접하면 알림 트리거
REST API
섹션 제목: “REST API”사용량 레코드 목록 조회
섹션 제목: “사용량 레코드 목록 조회”GET /api/usage?range=7d&limit=100GET /api/usage?apiKeyId=key-123&range=30dGET /api/usage?provider=openai&range=1d응답:
{ "records": [ { "id": "uuid", "apiKeyId": "key-123", "provider": "openai", "model": "gpt-5", "promptTokens": 1234, "completionTokens": 567, "totalTokens": 1801, "costUsd": 0.005, "latencyMs": 1234, "status": "success", "timestamp": "2026-06-08T12:00:00Z" } ], "total": 1234, "nextCursor": "..."}분석 요약 조회
섹션 제목: “분석 요약 조회”GET /api/usage/analytics?range=7d&groupBy=model응답:
{ "summary": { "totalCost": 12.34, "totalRequests": 5678, "totalTokens": 12345678, "successRate": 0.987, "avgLatencyMs": 1234 }, "models": [ { "model": "gpt-5", "cost": 8.5, "requests": 1234, "tokens": 4567890 }, { "model": "claude-opus-4-6", "cost": 3.84, "requests": 234, "tokens": 234567 } ], "daily": [ { "date": "2026-06-01", "cost": 1.5, "requests": 800 }, { "date": "2026-06-02", "cost": 2.0, "requests": 1000 } ]}사용량 분석 쿼리
섹션 제목: “사용량 분석 쿼리”사용량 데이터는 직접 REST 내보내기 엔드포인트가 아니라 대시보드 또는 MCP 도구를 통해 접근합니다. 사용 가능한 분석은 다음과 같습니다.
/api/usage/analytics— 집계된 사용량 지표(모델, 제공업체, 키별 그룹화)/api/usage/quota— API 키별 현재 할당량 상태/api/usage/history— 요청 기록 로그
MCP 도구
섹션 제목: “MCP 도구”두 개의 MCP 도구가 에이전트에 사용량 데이터를 제공합니다(open-sse/mcp-server/tools/ 참조).
| 도구 | 설명 |
|---|---|
omniroute_cost_report |
지정된 기간에 대한 키별 비용 보고서 생성 |
omniroute_check_quota |
API 키의 현재 할당량 상태 반환 |
에이전트 호출 예시:
{ "tool": "omniroute_cost_report", "args": { "period": "week" }}보존 및 정리
섹션 제목: “보존 및 정리”사용량 데이터는 요청당 약 1~10KB씩 증가합니다. 대규모 환경에서는 상당한 용량이 될 수 있습니다.
보존 설정
섹션 제목: “보존 설정”사용량 기록 보존 기간은 UI의 데이터베이스 설정 또는 /api/settings/database를 통해 구성합니다.
기본적으로 사용량 기록은 90일 동안 보존됩니다.
오래된 레코드는 src/lib/db/cleanup.ts에 의해 정리됩니다.
- 백그라운드 cron 프로세스에 의해 실행됨
- 구성된
usageHistory보존 설정보다 오래된usage_history레코드를 삭제함
저장 공간 추정
섹션 제목: “저장 공간 추정”| 요청 빈도 | 30일 저장 공간 | 90일 저장 공간 |
|---|---|---|
| 일 100회 요청 | ~3MB | ~9MB |
| 일 1,000회 요청 | ~30MB | ~90MB |
| 일 10,000회 요청 | ~300MB | ~900MB |
| 일 100,000회 요청 | ~3GB | ~9GB |
트래픽이 매우 많은 경우 다음을 고려하세요.
- 데이터베이스 설정에서 보존 기간 단축
- 원시 레코드 대신
aggregated_metrics사용(분석 전용)
비용 최적화 팁
섹션 제목: “비용 최적화 팁”1. 적절한 모델 사용
섹션 제목: “1. 적절한 모델 사용”# 빠른 답변 — 저렴하고 빠른 모델 사용curl -d '{"model":"auto/fast","messages":[...]}'
# 복잡한 작업 — 고품질 모델 사용curl -d '{"model":"auto/smart","messages":[...]}'2. 캐싱 활성화
섹션 제목: “2. 캐싱 활성화”Anthropic 프롬프트 캐싱은 반복되는 컨텍스트의 비용을 90% 절감합니다.
// 캐싱은 자동으로 수행됩니다. 동일한 대용량 시스템 프롬프트를 포함하기만 하면 됩니다.const response = await openai.chat({ model: "claude-sonnet-4-5", system: longSystemPrompt, // 자동으로 캐시됨 messages: [{ role: "user", content: "..." }],});3. 압축 사용
섹션 제목: “3. 압축 사용”RTK + Caveman 압축은 도구 사용이 많은 세션에서 15~95%를 절감합니다.
const config = { compression: { engine: "rtk", intensity: "aggressive", },};4. 키별 할당량 설정
섹션 제목: “4. 키별 할당량 설정”과도한 비용 발생을 방지하려면 항상 quotaLimit을 설정하세요.
await updateApiKey(keyId, { quotaLimit: 10_00 }); // 월 $10 한도5. 사용량 상위 소비자 감사
섹션 제목: “5. 사용량 상위 소비자 감사”대시보드 또는 **/api/usage/analytics**를 사용하여 API 키별로 그룹화하고 비용순으로 정렬하세요.
GET /api/usage/analytics?groupBy=apiKey문제 해결
섹션 제목: “문제 해결”“비용이 예상보다 높음”
섹션 제목: ““비용이 예상보다 높음””- **
/api/usage/analytics?groupBy=model**을 확인하여 비용이 많이 드는 모델을 찾습니다. - **
/api/usage/analytics?groupBy=apiKey**를 확인하여 사용량이 많은 소비자를 찾습니다. - 가격 데이터가 최신인지 확인합니다:
POST /api/pricing/sync
“레코드가 누락됨”
섹션 제목: ““레코드가 누락됨””- Dashboard → Database → Cleanup에서 DB 보존 설정을 확인하세요. 오래된 레코드는 주기적인 정리 작업(
src/lib/db/cleanup.ts)에 의해 삭제됩니다. src/lib/db/usage*.ts의 오류를 확인하세요. DB 쓰기 실패는 로그에 기록되지만 사용자에게 표시되지는 않습니다.- 요청이 실제로
chatCore에 도달했는지 확인하세요. 콤보 라우팅을 점검합니다.
“할당량이 적용되지 않음”
섹션 제목: ““할당량이 적용되지 않음””- 키의
quotaLimit설정을 확인하세요. quotaWindow가 올바르게 설정되어 있는지 확인하세요.quotaSnapshots레코드를 확인하세요. 모든 요청에서 생성되어야 합니다.
참고 자료
섹션 제목: “참고 자료”- DATABASE_GUIDE.md — 사용량 테이블 스키마
- ENVIRONMENT.md — 가격 동기화 환경 변수
- AUTO-COMBO.md —
auto/fast,auto/cheap이 비용을 절감하는 방법 - API_REFERENCE.md — 전체
/api/usage/*참조 문서 - 소스:
open-sse/services/usage.ts,src/lib/usageAnalytics.ts,src/lib/db/usage*.ts
HagiCode
HagiCode는 구조화된 워크플로, 다중 에이전트 실행, Hero Dungeon 뷰를 갖춘 에이전트 코딩 작업 공간입니다.
더 스마트하고 빠르며 즐거운 에이전트 워크플로로 유용한 소프트웨어를 만드세요.

- Smart구조화된 워크플로는 의도를 아이디어부터 배포까지 실행 가능한 경로로 바꿉니다.
- Efficient다중 에이전트 워크플로로 조사, 구현, 검토를 병렬로 진행합니다.
- FunHero Dungeon은 긴 코딩 세션을 시각적이고 협업적인 경험으로 만듭니다.