본문으로 건너뛰기

LLM 예산 초과

quant-ai는 두 단계 예산 가드를 갖습니다.

위치트리거효과
클라이언트 (LLM_DAILY_BUDGET_USD)analysis_reports.cost_usd 24h 합분석 큐 적재 자체를 거부
서버 (LiteLLM max_budget)proxy 측 합산429 응답

거기에 Grafana quantai-llm-daily-cost 룰이 $10 초과 시 5분 sustained로 Telegram에 알림을 보냅니다.

사전 요구 사항

  • LiteLLM proxy가 떠 있고 quant-ai와 연결되어 있음 — 자세한 셋업은 LiteLLM 프록시 참조
  • analysis_reports 테이블이 존재 (07_analysis_reports 적용됨)

1. 알림 수신 시 첫 동작

# 1) 24h 사용 비용 합산 (Grafana 룰과 동일 쿼리)
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT SUM(cost_usd)::numeric(10,2) AS total_24h_usd,
COUNT(*) AS report_count,
MAX(cost_usd) AS max_single
FROM analysis_reports
WHERE requested_at >= NOW() - INTERVAL '1 day';
"

# 2) 사용자별 top-10
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT user_id, COUNT(*) AS reports,
SUM(cost_usd)::numeric(10,2) AS usd
FROM analysis_reports
WHERE requested_at >= NOW() - INTERVAL '1 day'
GROUP BY user_id ORDER BY usd DESC LIMIT 10;
"

# 3) 모델 분포
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT model_used, COUNT(*) AS calls,
SUM(cost_usd)::numeric(10,2) AS usd,
AVG(total_tokens) AS avg_tokens
FROM analysis_reports
WHERE requested_at >= NOW() - INTERVAL '1 day'
GROUP BY model_used ORDER BY usd DESC;
"

2. 원인 가설

원인빈도흔적
단일 사용자가 폭주 호출흔함top-10에서 한 사용자가 압도적
OPENAI_MODEL_DECISION (gpt-4o)가 너무 자주 호출흔함모델 분포에서 4o가 다수
분석 큐 retry loop (실패 시 무한 재시도)가끔같은 user_id가 같은 symbol 반복
프롬프트 길이 증가 (PR 후)가끔total_tokens 평균 급증
LiteLLM proxy의 모델 라우팅 오설정 (cheap → expensive)드묾모델 분포가 예상과 다름

3. 즉시 차단 방법

Option A: 분석 기능 일시 비활성

가장 빠른 광역 차단:

sed -i 's/^FEATURE_LLM_ANALYSIS=.*/FEATURE_LLM_ANALYSIS=false/' .env
docker compose restart api analysis-worker

/api/equity/analyze 가 503을 반환하고, UI는 "AI 분석 일시 비활성" 메시지를 표시합니다. 거래는 영향 없음.

Option B: 단일 사용자 차단

# 사용자별 분석 일일 limit이 있는 deployment 한정
docker compose exec timescaledb psql -U quant -d quantai -c "
UPDATE user_settings
SET analysis_daily_limit_override = 0
WHERE user_id = <USER_ID>;
"

또는 큐 leftover 정리:

docker compose exec timescaledb psql -U quant -d quantai -c "
UPDATE analysis_request_queue
SET status = 'cancelled'
WHERE user_id = <USER_ID> AND status IN ('queued','in_progress');
"

Option C: 한도 상향 (정상 폭주 시)

# .env
LLM_DAILY_BUDGET_USD=20.00
docker compose restart analysis-worker

# LiteLLM 측에도 max_budget 동시 상향 권장

4. retry loop 진단

# 같은 user_id × symbol이 반복 실패하는지
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT user_id, symbol, status, attempts, COUNT(*)
FROM analysis_request_queue
WHERE created_at > NOW() - INTERVAL '2 hours'
GROUP BY 1,2,3,4
HAVING COUNT(*) > 1 OR attempts > 1
ORDER BY attempts DESC LIMIT 20;
"

attempts >= ANALYSIS_WORKER_MAX_ATTEMPTS (기본 3)에 도달하면 worker가 자동 fail-final 처리합니다. 그 전에 비용이 누적될 수 있으므로, loop이 발견되면:

# 진행 중 작업을 취소
docker compose exec timescaledb psql -U quant -d quantai -c "
UPDATE analysis_request_queue
SET status = 'cancelled'
WHERE status = 'in_progress'
AND created_at < NOW() - INTERVAL '30 minutes';
"

5. 모델 라우팅 점검

OPENAI_MODEL_DEFAULT (싸고 빠른 모델, 1차 요약) vs OPENAI_MODEL_DECISION (큰 모델, 2차 의사결정) 분리가 의도대로 되는지.

docker compose exec api python -c "
import os
print('default:', os.environ.get('OPENAI_MODEL_DEFAULT'))
print('decision:', os.environ.get('OPENAI_MODEL_DECISION'))"

decision이 모든 호출에 쓰이고 있다면 분석 워커 코드 또는 LiteLLM 라우팅 오설정. 자세한 셋업은 LiteLLM 프록시 §3.

6. 검증

# 차단 후 한 시간 동안 누적 비용
docker compose exec timescaledb psql -U quant -d quantai -c "
SELECT date_trunc('minute', requested_at) AS t,
COUNT(*), SUM(cost_usd)::numeric(10,2) AS usd
FROM analysis_reports
WHERE requested_at >= NOW() - INTERVAL '1 hour'
GROUP BY 1 ORDER BY 1 DESC;
"
# 새 분석이 0이어야 함 (Option A) 또는 의도된 비율

7. 사후

  • 영향 사용자에게 Telegram + 이메일 안내 (분석 일시 비활성 / 한도 상향)
  • LiteLLM 측에서 사용자별 spend report 다운로드 후 PR / 디자인 결정
  • Grafana 룰 임계 ($10 → $20 등) 영구 변경 시 디자인 리뷰

트러블슈팅

증상원인 / 조치
차단 후에도 비용 증가analysis-worker에 진행 중 작업이 있음. docker compose stop analysis-worker -t 0 으로 강제 정지 후 재기동
LiteLLM 측에서 429서버 측 max_budget 도달. proxy admin에서 한도 상향
401인데 LiteLLM은 정상사용자별 LiteLLM key가 따로 있는 deployment에서 키 만료. master_key가 아닌 user key 확인
analysis_reports.cost_usd가 NULLLiteLLM이 cost meta를 안 반환. proxy 설정 track_cost: true 확인

관련 페이지