
OwlAI의 관리자는 사용자마다 사용 한도를 걸 수 있고, OwlAI SaaS는 호출마다 구성원의 크레딧을 줄입니다. 둘 다 제품이 스스로 기록한 LLM 비용을 읽습니다. 이 기록이 프로바이더 청구서보다 적으면 한도는 실제 지출을 넘긴 뒤에야 멈추고, 크레딧은 쓴 만큼 줄지 않습니다. 기록이 더 많으면 사용자는 아직 쓸 수 있는 예산을 앞에 두고 막힙니다. 기록이 어긋나는 자리는 대개 셋입니다. 프롬프트 캐시를 쓰면 응답의 토큰 칸이 프로바이더마다 다른 뜻을 갖고, 요청한 처리 등급과 실제로 청구된 등급이 다를 수 있으며, 단가표 자체가 실제 청구 단가와 다를 수 있습니다.
이 글은 그 셋을 다루는 설계를 설명합니다. 과금되는 호출은 모두 사용량 원장(호출 한 번마다 토큰과 금액을 한 행으로 적는 테이블)에 남기고, 금액은 기록할 때 확정합니다. 토큰은 함수 하나가 응답의 형식을 보고 세고, 금액은 응답이 알려 준 처리 등급의 단가로 매깁니다. 원장이 맞는지는 원장 안의 숫자끼리가 아니라 프로바이더의 청구 금액과 맞춰 보고 확인합니다.
과금되는 호출은 모두 원장의 한 행이 된다
원장은 두 개입니다. LLM 호출은 LLM 사용량 원장에, 임베딩·리랭크·음성 인식·웹 검색처럼 따로 과금되는 도구 호출은 도구 사용량 원장에 호출마다 한 행씩 들어갑니다. 금액은 USD로 적습니다. 사용자별 한도 판정, 관리자의 한도 화면, 구성원의 내 사용량 게이지, 사용자별 조직 비용은 모두 두 원장을 합치는 집계 하나를 읽습니다. 이 집계에는 공용 키로 부른 호출만 들어갑니다. 관리 화면 「시스템 현황」의 「전체 비용」 탭도 같은 두 원장에서 설치 전체의 금액을 모델과 도구로 나눠 보여 줍니다.
채팅·플레이북·회의처럼 기능마다 비용 집계 테이블을 따로 두면 화면 하나는 빨리 만들 수 있습니다. 대신 기능마다 세는 규칙이 조금씩 달라지고, 한 곳에만 필터가 붙으면 한도 판정과 화면이 다른 숫자를 봅니다. 그래서 공용 키만 세는 조건과 기간 조건은 집계 한 곳에만 적었습니다.
LLM 원장의 한 행에는 시각, 모델, 프로바이더, 사용자, 대화, 입력·출력 토큰, 캐시 읽기·쓰기 토큰, 금액, 공용 키와 개인 키 가운데 무엇으로 불렀는지가 남습니다. 요청한 처리 등급과 응답이 알려 준 처리 등급도 함께 남습니다. 어느 에이전트가 어느 작업 단위 안에서 몇 단계 아래에서 부른 호출인지도 적혀서, 딥 리서치처럼 총괄과 조사원이 함께 도는 작업의 비용을 에이전트별로 나눠 볼 수 있습니다.
원장 기록은 다음 규칙을 따릅니다.
- 실패하거나 중단한 호출도 남깁니다. 프로바이더는 호출이 도중에 실패해도 처리한 만큼 청구합니다. 답을 받는 도중에 사용자가 멈춘 호출의 토큰을 어떻게 채우는지는 「한 턴의 입력 토큰은 라운드 수의 제곱으로 늘어난다」에서 다룹니다.
- 임베딩·리랭크 어댑터는 반환 형식을 바꾸지 않고, 호출이 끝나면 사용량만 따로 넘깁니다. 제품 코드에서 이 사용량을 받을 곳을 빠뜨린 호출 경로는 타입 검사에서 걸립니다. 빠뜨린 경로의 호출은 원장에 실리지 않아 한도가 모르는 비용이 되기 때문입니다.
- 원장 기록이 실패해도 호출은 그대로 끝납니다. 실패는 로그로 남깁니다. 이 실패를 호출 실패로 올리면 잡이 재시도되고, 재시도는 같은 호출을 프로바이더에 한 번 더 청구합니다.
- 도구 사용량 원장은 프로바이더가 보고한 사용량을 그대로 적고, 예산은 요청에서 직접 계산한 몫으로 줄입니다. 여러 호출에 걸쳐 쌓인 양으로 청구 단위를 채우는 도구에서는, 단위를 넘긴 호출이 앞선 호출들의 몫까지 한꺼번에 보고받기 때문입니다.
캐시 토큰은 프로바이더 이름 대신 응답 형식을 보고 센다
프롬프트 캐싱을 쓰면 응답 하나에 입력 토큰, 캐시에서 읽은 토큰, 캐시에 새로 쓴 토큰 칸이 함께 옵니다. 이 칸들이 겹치는 방식이 프로바이더마다 다릅니다. 캐시가 무엇을 아끼는지는 「시스템 프롬프트 한 줄에 캐시 읽기가 0이 된다, 바뀌는 블록은 뒤로 보낸다」에서 다루고, 여기서는 그 토큰을 원장에 세는 방법만 다룹니다.
| 「입력 토큰」 칸의 뜻 | 캐시 읽기·쓰기 칸 | |
|---|---|---|
| OpenAI | 총 입력 | 입력 토큰 안에 포함됩니다. 캐시 읽기 + 캐시 쓰기 + 캐시에 걸리지 않은 입력 = 입력 토큰 |
| Anthropic | 캐시에 걸리지 않은 입력만 | 응답 최상위에 따로 옵니다. 세 칸이 서로 겹치지 않아 더해야 총 입력이 됩니다 |
두 형식을 한 규칙으로 세면 오차가 자릿수 단위로 납니다. 포함 형식을 가정해 「캐시 읽기는 입력 토큰을 넘을 수 없다」며 잘라 내면, 따로 오는 형식의 응답에서는 캐시 읽기 대부분이 사라집니다. 캐시를 잘 쓰는 긴 대화일수록 새 입력은 작고 캐시 읽기는 커서, 원장 금액이 실제 청구의 몇 분의 일로 줄어듭니다.
그래서 토큰 정규화는 함수 하나에서만 합니다. 이 함수는 응답 최상위에 캐시 읽기·쓰기 칸이 따로 있으면 세 칸을 더해 「캐시 읽기와 쓰기를 포함한 총 입력」으로 바꾸고, 없으면 입력 토큰을 그대로 총 입력으로 씁니다. 판정에 프로바이더 이름은 쓰지 않습니다. 원장의 프로바이더 칸에는 관리자가 설치에서 붙인 이름이 들어가서, 그 이름으로는 응답 형식을 알 수 없기 때문입니다.
원장, 라운드마다 남기는 구조화 로그(「구축형 제품은 JSON 로그 하나로 관측하고, 요청 ID로 워커까지 잇는다」), 턴의 토큰 합계, 중단한 호출의 토큰 추정이 모두 이 함수를 거칩니다. 로그와 원장이 서로 다른 규칙으로 세면 두 숫자가 갈리고, 둘 가운데 무엇이 맞는지 가릴 근거가 없어집니다.
금액은 네 단가와 응답이 알려 준 처리 등급으로 매긴다
단가는 설치 설정의 모델 행마다 pricing 으로 적습니다. 채팅 모델의 단가는 캐시에 걸리지 않은 입력(input), 캐시 읽기(cachedInput), 캐시 쓰기(cacheWrite), 출력(output)의 네 칸이고, 프로바이더 청구서의 항목과 하나씩 맞습니다. 캐시 쓰기를 따로 두는 이유는 캐시에 새로 적재하는 토큰을 입력 정가보다 비싸게 청구하는 모델이 있기 때문입니다. 캐시 읽기나 쓰기 단가를 비워 두면 입력 정가로 계산합니다. 모르는 값을 싸게 잡으면 원장이 실제 청구보다 적어지고, 그 차이만큼 한도가 늦게 멈춥니다.
금액을 바꾸는 조건이 두 가지 더 있습니다.
- 긴 컨텍스트 요금은 요청 단위로 겁니다. 긴 컨텍스트 구간(
longContext)이 있는 모델은 요청 하나의 총 입력이 기준을 넘으면 그 요청 전체를 상위 단가로 계산합니다. 넘은 부분만 비싸지는 방식이 아닙니다. - 처리 등급은 응답에서 읽습니다. 빠른 처리 등급으로 요청해도 프로바이더가 트래픽에 따라 일반 등급으로 처리하고 일반 등급으로 청구할 수 있습니다. 그래서 금액은 응답이 알려 준 등급의 단가로 매기고, 요청한 등급과 다르면 로그를 남깁니다. 응답의 등급에 맞는 단가가 설정에 없으면 배수로 짐작하지 않고 그 모델 행의 단가로 적은 뒤 오류 로그를 남깁니다. 금액이 청구와 어긋나고 있다는 신호입니다.
단가가 없는 모델에서 원장이 조용히 0원을 적지 않게, 설정을 읽을 때 막습니다. 외부 프로바이더의 모델 행에 단가가 없으면 설정 검사가 거절합니다. 자체 호스팅 모델은 단가를 비우면 0원으로 기록되고, 운영자가 GPU 원가를 단가로 적으면 그때부터 예산을 씁니다(「vLLM 동시성 상한은 짧은 프롬프트가 아니라 운영 입력 길이로 잰다」). 크레딧으로 과금하는 OwlAI SaaS는 자체 호스팅 모델까지 포함해 단가가 없는 모델이 하나라도 있으면 기동하지 않습니다. 「이 모델은 예산을 쓰지 않는다」는 판정은 선언된 단가가 0일 때만 내리고, 단가 조회가 실패하면 예산을 쓰는 모델로 봅니다.
개인 키로 부른 호출은 토큰과 호출 수만 남기고 금액은 0으로 적습니다. 그 호출은 키 소유자에게 청구되고, 그 계정의 할인이나 요금 등급은 제품이 알 수 없습니다. 관리 화면에는 개인 키 토큰과 개인 키 호출 수가 따로 보입니다.
금액은 기록할 때 확정합니다. 단가를 바꾸면 바뀐 설정으로 뜬 서버의 호출부터 새 단가로 적히고, 이미 적힌 행은 다시 계산하지 않습니다. 그 시점의 청구와 맞았던 행은 그대로 맞는 값입니다.
원장이 맞는지는 프로바이더의 청구 금액으로 확인한다
원장 안의 숫자끼리 맞춰 보는 시험은 세는 규칙이 틀려도 통과합니다. 캐시 읽기를 잘라 내는 규칙으로 세면 원장과 화면과 한도가 함께 틀리고, 셋은 서로 일치합니다. 틀렸다는 사실은 프로바이더가 실제로 청구한 금액과 맞춰 볼 때만 드러납니다.
주요 프로바이더는 조직 관리자 키로 부르는 사용량 API와 비용 API를 엽니다. 사용량 API는 모델별·일별 토큰과 요청 수를, 비용 API는 일별 금액을 입력·캐시 입력·캐시 쓰기·출력 같은 항목으로 나눠 주고 긴 컨텍스트 요금도 따로 보여 줍니다. 이 두 API로 운영 절차에서 두 가지를 맞춰 봅니다.
- 금액 대조: 원장의 일별·모델별 합계를 비용 API의 같은 칸과 비교합니다.
- 실단가 역산: 비용 API의 항목별 금액을 사용량 API의 같은 항목 토큰 수로 나눠 그날의 실제 단가를 구하고, 설정의 단가와 비교합니다.
역산에서는 캐시 입력 항목이 가장 잘 갈립니다. 같은 키를 원장 밖에서 쓴 사용분이 섞여도 금액과 토큰이 함께 늘어서 나눈 값은 그대로이고, 단가가 바뀐 날은 그 값이 뚜렷하게 끊깁니다. 입력과 출력 항목은 원장 밖 사용분이 섞이면 몇 퍼센트씩 어긋납니다.
대조할 때 걸리는 조건은 다음과 같습니다.
- 같은 조직에 프로젝트가 여럿이면 프로젝트로 걸러야 합니다.
- 같은 키를 여러 설치가 함께 쓰면 금액 대신 요청 수와 토큰으로 대조합니다. 다른 설치의 사용분이 금액에 섞이기 때문입니다.
- 비용은 UTC 하루 단위로 묶이고, 그날 비용은 늦게 붙습니다. 경계일에 단가가 바뀌면 그날의 역산 값은 두 단가가 섞여 나옵니다.
사내 업무 환경에서 2026년 9~10월 약 40일 동안 긴 컨텍스트 요금이 섞인 한 프로바이더의 사용분을 대조했을 때, 일별·모델별 41칸 가운데 39칸이 소수점 넷째 자리까지 일치했고 기간 합계의 차이는 0.05% 안이었습니다.
단가를 고칠 때도 가격 문서보다 역산 값을 먼저 봅니다. 가격 문서의 각주나 단가 표기가 실제 청구 단가와 다른 경우가 있고, 단가 인하를 발표한 날과 청구에 새 단가가 붙은 날이 며칠씩 다를 때도 있습니다. 설정에 적는 단가는 역산으로 확인한 값이고, 근거로 남기는 것은 가격 문서의 주소와 조회일입니다.
설계에서 고른 것
- 제품 안의 자동 대조 대신 운영 절차를 골랐습니다. 비용 API를 제품이 직접 부르면 운영자 손이 덜 갑니다. 하지만 그 API를 여는 관리자 키는 조직 전체의 사용량과 비용을 읽는 자격이라, 제품에 보관하지 않고 대조할 때만 씁니다. 구축형 고객도 「전체 비용」 탭의 합계를 자기 프로바이더 콘솔의 청구와 같은 방식으로 맞춰 볼 수 있습니다.
- 현재 단가로 다시 계산하는 대신 기록 시점에 금액을 확정했습니다. 소급 계산은 단가표 한 곳만 고치면 되어 단순합니다. 대신 이미 걸린 한도와 지난달 화면의 숫자가 그때의 실제 청구와 어긋납니다.
- 개인 키 사용분에는 추정 금액 대신 토큰과 호출 수만 남겼습니다. 제품 단가를 곱하면 사람마다 쓴 양을 금액 하나로 비교할 수 있습니다. 그런데 그 금액은 키 소유자가 받는 청구와 맞지 않아, 금액은 각 프로바이더 콘솔에서 보게 했습니다.
- 모델 단가는 화면에 보이지 않고 설정과 원장에만 둡니다. 같은 모델도 응답마다 처리 등급과 긴 컨텍스트 요금이 달라 호출 하나의 원가가 바뀌므로, 고정된 단가 표시는 실제 금액과 맞지 않습니다. 화면은 원장에 확정된 금액의 합계를 보여 줍니다.
여러 프로바이더의 모델을 섞어 쓰고 사람마다 비용 한도를 거는 시스템이라면, 토큰을 세는 함수가 하나인지부터 확인해 볼 만합니다. 그다음 프로바이더의 비용 API로 캐시 입력 항목의 실단가를 하루치만 역산해 보면, 원장이 캐시 토큰을 제대로 세고 있는지 바로 드러납니다.
설치·운영과 품질의 다른 글

엔지니어링 노트 · 설치·운영과 품질
설치 전 점검은 호스트를 읽기만 하고, 고칠 명령은 사람에게 넘긴다
구축형 OwlAI는 고객이 고른 호스트 한 대에 Docker Compose로 올라갑니다. 배포판과 커널, 도커 판, 보안 모듈, 인증서는 고객마다 다릅니다.

엔지니어링 노트 · 설치·운영과 품질
도커 주소 풀은 설치하는 사람이 정하고, 점검은 사내 대역과 대조한다
구축형 OwlAI를 기업망 호스트에 설치하고 몇 주 뒤, 어제까지 붙던 사내 DB나 추론 서버에 컨테이너에서 닿지 않는 날이 올 수 있습니다. 같은 호스트의 셸에서도 닿지 않습니다.

엔지니어링 노트 · 설치·운영과 품질
사내 프록시 뒤에서는 NO_PROXY를 대역 대신 이름과 IP로 적는다
사내 프록시로만 밖에 나갈 수 있는 기업망에 구축형 OwlAI를 설치하면, 클라우드 LLM으로 가는 호출은 HTTPSPROXY를 따라 프록시로 나가야 합니다.