본문으로 건너뛰기
AI NEWS JOURNAL
Hacker News Show HNAI NEWS / JOURNAL

Show HN: LLMBrake – OpenAI/Anthropic API 호출에 대한 고객별 달러 한도

기사 URL: https://github.com/llmbrake/llmbrake 댓글 URL: https://news.ycombinator.com/item?id=50386174 포인트: 2 # 댓글: 0

이 언어의 번역이 아직 없어 원문을 표시합니다.

AI 앱의 고객별 비용 상한: 모든 고객에게 월간 달러 예산을 설정하고, 한도에 가까워지면 더 저렴한 모델로 전환하며, 한도에 도달하면 요청을 차단합니다. llmbrake는 OpenAI 호환 chat.completions.create 호출을 래핑하는 작은 TypeScript 라이브러리입니다. 이 라이브러리는 제공자가 반환하는 토큰 사용량을 기준으로 각 호출을 USD로 요금 산정하고, 고객별 누적 월간 총액을 유지합니다. 고객의 예산에 근접하면 더 저렴한 모델로 교체하고, 예산에 도달하면 요청이 제공자에게 도달하기도 전에 유형화된 BudgetExceededError를 발생시킵니다. 프록시가 아닙니다. 앱 내부에서 실행되며 고객의 고유 키를 사용하여 직접 제공자를 호출합니다. 메타데이터만 처리합니다. 프롬프트나 완성 내용을 읽거나 저장하지 않으며, 고객 ID, 플랜, 기능 태그, 모델, 토큰 수, 비용 및 타임스탬프만 관리합니다. 런타임 종속성이 없습니다. ESM, Node 18+, MIT 라이선스 적용. 버전: 0.1.0, 초기 버전. 웹사이트: llmbrake.com npm install llmbrake npm에 llmbrake로 배포되었습니다. 대신 최신 main 브랜치를 사용하려면 npm install github:llmbrake/llmbrake을 실행하세요(설치 시 빌드됩니다). llmbrake는 ESM 전용입니다(import 사용, require 아님). 30초 간편 시작 import OpenAI from "openai"; import { createGuard, isBudgetExceededError } from "llmbrake"; const openai = new OpenAI(); const guard = createGuard({ budgetUsd: (ctx) => (ctx.plan === "pro" ? 20 : 2), // 고객당 월간(UTC) USD 예산 downgradeAt: 0.8, // 예산의 80%에 도달하면... downgradeMap: { "gpt-5.5": "gpt-5.4-mini" }, // ...gpt-5.5 요청을 gpt-5.4-mini로 보내기 }); const chat = openai.chat.completions; const create = guard.wrap(chat.create.bind(chat)); try { const res = await create( { model: "gpt-5.5", messages: [{ role: "user", content: "Hello" }] }, { customerId: user.id, plan: user.plan, feature: "chat" }, ); } catch (e) { if (isBudgetExceededError(e)) { // e.customerId, e.spentUsd, e.budgetUsd, e.period return showUpgradePrompt(); } throw e; } await guard.status({ customerId: user.id, plan: user.plan }); // → { period: "2026-10", spentUsd: …, budgetUsd: 20, remainingUsd: … } 작동 방식 각 래핑된 호출은 세 단계를 거칩니다: 확인 (호출 전). llmbrake는 고객의 예산(숫자 또는 ctx => number 함수, 예: plan에 따라)을 해결하고, 현재 기간(예: UTC 기준 2026-10과 같은 달력 월) 동안의 지출액을 읽습니다. 결정. 차단: 지출이 예산 이상인 경우 BudgetExceededError("LLMBRAKE_BUDGET_EXCEEDED" 코드)를 발생시키며, 제공자는 절대 호출되지 않습니다. 업그레이드 프롬프트를 표시하려면 이를 캡처하세요. 다운그레이드: 지출이 예산 × downgradeAt 이상이고 요청된 모델이 downgradeMap에 있는 경우, 대신 더 저렴한 모델로 요청이 전송됩니다. 사용 이벤트에는 downgraded: true 및 원래 requestedModel이 보고됩니다. 그렇지 않으면 요청은 변경 없이 진행됩니다. 기록 (호출 후). 비용은 응답의 사용량(캐시되지 않은 입력, 캐시된 입력 및 출력 토큰)과 가격표를 기반으로 계산된 다음 고객의 총액에 추가됩니다. onUsage 훅은 다음과 같은 사용 이벤트를 수신합니다: { customerId: "cus_123", plan: "pro", feature: "chat", period: "2026-10", requestedModel: "gpt-5.5", model: "gpt-5.4-mini", downgraded: true, promptTokens: 1102, completionTokens: 182, cachedTokens: 640, costUsd: 0.0012, spentUsd: 16.41, budgetUsd: 20, timestamp: "2026-10-11T20:00:00.000Z" } guard.check(ctx, model)는 호출 없이 1~2단계를 실행하므로, 사용자가 클릭하기 전에 버튼을 비활성화하는 데 유용합니다. 스트리밍 stream: true 설정 시 llmbrake는 stream_options.include_usage = true를 설정하고 스트림이 종료될 때 비용을 기록합니다. 여기에는 코드가 조기에 읽기를 중단하는 경우도 포함되며(그때까지 수신된 사용량이 모두 기록됨), 해당 상황에서도 비용이 기록됩니다. 다른 OpenAI 호환 엔드포인트 { model, ... }을 수락하고 { model, usage: { prompt_tokens, completion_tokens } }을 반환하는 모든 create(params) 함수는 작동합니다. 예를 들어 OpenRouter, Anthropic의 OpenAI 호환 엔드포인트 및 로컬 게이트웨이가 있습니다. 가격 테이블에 해당 모델 ID를 추가하세요. 예시: Vercel AI SDK, OpenRouter, LangChain 테스트된 통합은 examples/ 디렉터리에 실시간으로 포함되어 있습니다: Vercel AI SDK: generateText / streamText 전에 guard.check()을 호출한 다음 result.usage(캐시된 토큰 포함)에서 비용을 청구합니다. 또한 Next.js 라우트 핸들러 스케치도 제공합니다. OpenRouter: OpenRouter를 가리키는 OpenAI SDK에 guard.wrap()을 적용하고, 가격 테이블에 OpenRouter 모델 ID를 입력합니다. LangChain.js: invoke() 전에 guard.check()을 호출한 다음 AIMessage.usage_metadata에서 비용을 청구합니다. CI는 API 키 없이 모ック 제공자에 대해 이들을 실행합니다. 스토리지(Redis 예시) 기본 MemoryStore는 프로세스 메모리에 총액을 저장합니다. 단일 서버, 테스트 및 데모에는 적합하지만 재시작 시 손실되며 인스턴스 간에 공유되지 않습니다. 다중 인스턴스 또는 서버리스 환경에서는 두 가지 메서드로 구성된 UsageStore 인터페이스를 구현해야 합니다. ioredis를 사용할 경우: import Redis from "ioredis"; import { createGuard, type UsageStore } from "llmbrake"; const redis = new Redis(process.env.REDIS_URL!); const key = (customerId: string, period: string) => `llmbrake:${period}:${customerId}`; const redisStore: UsageStore = { async getSpend(customerId, period) { return Number((await redis.get(key(customerId, period))) ?? 0); }, async addSpend(customerId, period, usd) { const k = key(customerId, period); const res = await redis .multi() .incrbyfloat(k, usd) .expire(k, 60 * 60 * 24 * 40) // 약 40일간 유지 후 오래된 월 데이터 만료 .exec(); const [err, total] = res?.[0] ?? [new Error("Redis 트랜잭션 실패"), null]; if (err) throw err; return Number(total); }, }; const guard = createGuard({ budgetUsd: 5, store: redisStore }); INCRBYFLOAT는 원자적이므로 인스턴스 간에 합계가 정확하게 유지됩니다. 저장소에서 예외가 발생하거나(또는 비수치형 값을 반환하면) 기본적으로 호출이 열림 상태로 실패하므로 제품이 계속 작동합니다. 대신 failOpen: false를 설정하면 호출이 닫힌 상태로 실패합니다. 서버 간 공유 예산(HostedStore) HostedStore는 LLMBrake Cloud에 카운터를 저장하므로, 프로젝트의 API 키를 사용하는 모든 서버 및 서버리스 인스턴스는 고객당 하나의 카운터를 공유하며, 대시보드에서 편집한 예산은 다음 호출부터 적용되며 Redis를 실행할 필요가 없습니다. import { createGuard, HostedStore } from "llmbrake"; const guard = createGuard({ budgetUsd: 5, // 기본값; 고객을 위해 대시보드에 설정된 예산이 우선 적용됨 downgradeMap: { "gpt-5.5": "gpt-5.4-mini" }, store: new HostedStore({ apiKey: process.env.LLMBRAKE_API_KEY! }), }); 또한 동시 초과 호출 간격도 해소합니다. 각 호출 전에 가드는 호출 비용(프롬프트 크기와 max_tokens 합산 또는 estimateUsd)을 추정하여 예약하며, 이 예약은 서버의 단일 원자적 단계에서 지출액과 다른 처리 중인 예약 총합이 예산 범위 내에 있을 때만 성공합니다. 호출 후 실제 비용을 정산하고 보류를 해제합니다(프로바이더 호출 실패 시에는 $0으로 해제됨). 따라서 병렬 호출이 최대 한 번 정도의 호출 분량만 초과할 수 있으며, 처리 중인 모든 호출이 초과되는 상황은 방지됩니다. API에 접속할 수 없는 경우 가드는 failOpen 설정을 따릅니다(기본값: 호출 통과). 모든 저장소는 reserve 및 settle 메서드를 구현하여 이 기능을 선택적으로 활성화할 수 있습니다(ReservingStore 인터페이스). createGuard(options)은 { wrap, check, status } 객체를 반환합니다. 라핑된 함수의 두 번째 인수로 전달되는 호출 컨텍스트는 { customerId: string; plan?: string; feature?: string }입니다. 모델 가격: 신뢰하기 전에 확인하세요 DEFAULT_PRICES는 몇 가지 일반적인 OpenAI 및 Anthropic 모델을 USD 단위로 다룹니다 1M 토큰당(표준 등급), 2026-10-09 기준 읽기: OpenAI: https://developers.openai.com/api/docs/pricing Anthropic: https://docs.anthropic.com/en/docs/about-claude/pricing 공급업체의 가격은 자주 변경되며, 이 값들이 최신 정보임을 보장하지 않습니다. 청구 결정에 사용하기 전에 위의 페이지에서 해당 값을 확인하십시오. 각 항목에는 소스 필드가 있습니다. 표를 재정의하거나 확장하십시오: import { createGuard, DEFAULT_PRICES } from "llmbrake"; createGuard({ budgetUsd: 5, prices: { ...DEFAULT_PRICES, "my-model": { inputPerMTok: 1, outputPerMTok: 3 } }, }); gpt-5.4-mini-2026-03-17과 같은 날짜가 지정된 스냅샷 ID는 날짜가 지정되지 않은 항목으로 대체됩니다. 알려진 제한 사항 동시 초과 발생. MemoryStore 또는 일반 UsageStore를 사용할 경우, 예산은 호출 전에 확인되고 비용은 호출 후에 기록되므로 동일한 고객의 여러 실행 중인 호출이 각각 검사를 통과하여 합산된 비용만큼 한도를 초과할 수 있습니다. HostedStore(또는 모든 ReservingStore)는 각 호출 전에 예약을 수행하므로 초과분이 약 한 번의 호출로 제한됩니다. 가격 확인 필요. 위 참조. 장문 컨텍스트 등급, 배치 할인, 지역 또는 데이터 거주지 인상 및 우선 순위 등급은 모델링되지 않았으며, 기본 표의 Anthropic ID가 귀하의 엔드포인트에서 허용하는 값과 다를 수 있습니다. 채팅 완성만 지원. 채팅 완성 스타일의 토큰 사용량만 계측되며, 이미지, 오디오, 임베딩 또는 도구 수수료는 아직 지원되지 않습니다. 스트리밍에는 사용량이 필요합니다. 공급업체가 include_usage를 무시하거나 사용량 청크가 도착하기 전에 스트림이 중단되면 해당 호출은 비용이 제로로 기록됩니다. UTC 달력 월. 예산 기간은 매월 1일 00:00 UTC에 재설정됩니다. 동일한 동작을 하는 Python 포트는 python/ 디렉터리에 있으며, 동기 및 비동기 OpenAI 클라이언트, 스트리밍, 플러거블 스토어(메모리 내, Redis), 의존성 제로, Python 3.9 이상을 지원합니다. pip install llmbrake이 곧 PyPI에 출시될 예정입니다. 현재는 GitHub에서 설치하십시오: pip install "git+https://github.com/llmbrake/llmbrake#subdirectory=python" 빠른 시작 방법은 python/README.md를 참조하세요. 호스팅된 대시보드(LLMBrake Cloud) 이 라이브러리는 무료이며 MIT 라이선스를 유지합니다. LLMBrake Cloud는 추가 유료 계층으로, 공유 카운터(HostedStore), 고객별 지출, 예산 및 상태를 확인할 수 있는 대시보드(예산 실시간 편집 가능), 80% 및 100% 사용 시 Slack/webhook 알림, 그리고 고객별 AI 비용 대 Stripe 수익 분석 기능을 제공합니다. llmbrake.com을 방문해 보세요. 기여하기 문제 보고 및 풀 리퀘스트를 환영합니다. CONTRIBUTING.md를 참고하세요. 보안 문제에 대해서는 SECURITY.md를 확인해 주세요.

자료 출처

원문 읽기 ↗

관련 주제

← 전체 소식 이어 읽기