VPS AI agent 비용 폭증 방지 및 제어 방법
항상 실행되는 VPS 환경에서 AI agent의 무한 루프와 토큰 과금을 막는 구체적인 방법을 설명합니다. Hard caps 설정, prompt caching 활용, 그리고 사용량 로그 확인법을 통해 예상치 못한 API 비용 발생을 방지하십시오.
항상 실행되는 AI agent의 비용 폭증을 방지하는 방법
VPS(virtual private server)에서 AI agent의 비용을 제어하려면 agent가 실행되기 전에 상한선을 설정해야 합니다. 실행 중에는 사용량을 실시간으로 감시할 수 없기 때문입니다. 모든 응답에 max_tokens를 적용하여 제한을 두고, 코드 내에서 루프 반복 횟수를 제한하십시오. 변경되지 않는 프롬프트 부분은 캐시를 사용하고, 각 응답의 사용량을 로그로 기록하여 어떤 작업에서 비용이 발생하는지 확인하십시오. 서버 대여료는 매달 고정된 가격입니다. 반면 model API는 토큰 단위로 과금되며, 방치된 루프는 조용히 토큰을 소모하기에 매우 적합합니다.
이 내용은 이미 존재하며 소유한 서버에서 Messages API를 호출하는 agent를 전제로 합니다. VPS에서 Claude로 AI agent 구축하기에서 관련 메커니즘을 다룹니다.
Unattended agent의 비용 구조가 다른 이유
Interactive session에는 사람이 개입합니다. 모델이 잘못된 경로로 진행하거나 40,000줄의 log를 읽을 때, 관찰자가 이를 중단할 수 있습니다. Unattended agent는 이러한 제어 장치가 없습니다. 루프가 종료될 때까지 실행되며, 타이머가 작동하면 다시 실행됩니다.
사람들이 간과하는 요소는 빈도(Frequency)입니다. 5분 간격으로 실행되는 job은 하루에 288번, 한 달에 약 8,640번 실행됩니다. 1회 실행 비용에 이 횟수를 곱하면 총비용이 됩니다. 많은 "always-on" agent가 항상 켜져 있을 필요는 없습니다. 특정 시간 내에 응답하면 되므로, 이는 곧 스케줄링의 문제입니다.
또한 agent는 chat window에서는 발생하지 않는 비용을 발생시킵니다.
- Tool definitions가 모든 request에 포함됩니다. Tool-use system prompt 비용은 Claude Opus 4.8 기준
tool_choiceofauto또는none일 때 290 tokens이며,any또는tool일 때 410 tokens입니다. bash tool은 325 tokens를 추가합니다. 연결된 모든 MCP server는 해당 스키마를 추가하며, MCP는 model context protocol을 의미합니다. - Tool results는 input tokens로 계산됩니다. 8,000줄을 출력하는 command는 다음 request와 해당 turn의 이후 모든 request에 8,000줄을 포함합니다.
- Fetched pages는 input tokens로 계산됩니다. 평균 10 kB 웹 페이지는 약 2,500 tokens이며, 500 kB 연구용 PDF는 약 125,000 tokens입니다.
max_content_tokens는 텍스트 콘텐츠에만 적용되고 "PDF와 같은 binary content에는 적용되지 않으므로" 텍스트만 절삭(truncate)합니다. PDF는max_uses및allowed_domains를 사용하여 제한하십시오. - Web search는 검색 횟수당 과금됩니다. 결과 수와 관계없이 1,000회 검색당 $10입니다. 오류가 발생한 검색은 과금되지 않습니다.
이 비용들은 단일 실행 시에는 저렴합니다. 하지만 8,640번 반복되면 매우 비싸집니다.
Hard ceilings and soft ceilings solve different problems
max_tokens가 적용됩니다. 이는 사고(thinking)와 응답 텍스트를 포함한 한 번의 요청에 대한 총 출력량의 하드 캡(hard cap)입니다. Claude는 이 한도를 초과하여 생성하지 않으며, 모델은 이 수치를 볼 수 없습니다. 한도에 도달하면 stop_reason: "max_tokens"이 발생하며 응답이 잘립니다. 에이전트 사용 시 주의사항: tool-use 루프 내의 모든 요청은 각각 고유한 max_tokens를 가집니다. 따라서 이는 전체 작업이 아닌 단일 응답에만 제한을 둡니다. 4,000 토큰인 tool call을 10번 수행하면 해당 턴의 한도는 40,000 토큰이 됩니다.
Task budget은 권장 사항입니다. task_budget는 output_config 내부에 위치하며, 사고, tool calls, tool results, output을 모두 포함하여 에이전트 루프 전체에 사용할 수 있는 토큰 수를 모델에 알려줍니다.
resp = client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=4096,
betas=["task-budgets-2026-03-13"],
output_config={"task_budget": {"type": "tokens", "total": 64000}},
messages=messages,
)"Task budgets는 하드 캡이 아닌 소프트 힌트(soft hint)입니다." Claude는 작업 중간에 한도를 초과할 수 있으며, 출력에 적용되는 강제 제한은 여전히 max_tokens입니다. "카운트다운은 모델에게만 보이며", 응답에는 남은 예산(remaining-budget) 필드가 포함되지 않습니다. 허용되는 최소 task_budget.total은 20,000 토큰이며, 이보다 작으면 400 error가 반환됩니다. 작업량에 비해 예산이 너무 적으면 모델이 작업을 축소하거나 조기에 중단하는 거절(refusal) 유사 동작이 발생합니다.
비용과 관련된 세부 사항이 있습니다. 클라이언트가 후속 요청마다 task_budget.remaining을 차감하면, 변경된 값으로 인해 해당 값을 포함하는 모든 캐시된 prefix가 무효화됩니다. 첫 번째 요청 시 한 번만 설정하십시오.
Task budgets는 Claude Fable 5, Claude Opus 4.8, Claude Opus 4.7에서 베타 버전으로 제공됩니다. Claude Sonnet 5와 Claude Haiku 4.5는 Not supported으로 분류되며, task budgets는 Claude Code에 적용되지 않습니다. 따라서 tmux에서 분리된 Claude Code 세션은 세션 관리(hygiene)에 의존해야 합니다.
세 번째 한도는 Claude Console에 있습니다. 에이전트에 전용 workspace를 할당한 다음, 월간 지출 한도(monthly spend limit)와 분당 속도 제한(per-minute rate limits)을 설정하십시오. "Default Workspace에는 한도를 설정할 수 없으며", "조직 전체 한도(Organization-wide limits)는 workspace 한도의 합계보다 크더라도 항상 적용됩니다." 한도에 도달하기 전에 알림을 받을 수 있도록 지출 알림(spend notifications)을 추가하십시오.
작업별 모델 선택 및 실제 비용 변화 요소
모델 선택은 작업 단위로 결정합니다. 2026년 7월 기준, 100만 토큰당 비용(입력/출력)은 다음과 같습니다. Claude Fable 5는 $10/$50, Claude Opus 4.8 및 Opus 4.7은 $5/$25, Claude Sonnet 5는 $3/$15, Claude Haiku 4.5는 $1/$5입니다. Sonnet 5는 현재 표시 가격보다 저렴합니다. "2026년 8월 31일까지 입력/출력 100만 토큰당 $2/$10의 도입 가격이 적용됩니다"라는 규정 때문입니다. 로그 라인을 분류하는 단순 작업에는 Opus가 필요하지 않습니다.
Effort는 두 번째 조절 요소입니다. output_config.effort은 low, medium, high, xhigh 및 max을 지원하며, 기본값은 high입니다. 따라서 high을 명시적으로 설정하는 것은 생략하는 것과 결과가 같습니다. Effort를 낮추면 추론 길이 외의 비용도 절감됩니다. 문서에 따르면, 낮은 Effort는 Claude의 tool call 횟수를 줄이고 여러 작업을 하나로 결합합니다. 에이전트 환경에서는 이것이 더 큰 비용 절감 효과를 줍니다. tool call을 피하면 요청 자체가 발생하지 않기 때문입니다.
주의할 점은 Effort가 cache와 충돌한다는 것입니다. 요청 사이에 이 값을 변경하면 prompt caching이 무효화됩니다. 문서의 예시에서 request 2는 cache_read_input_tokens: 3546을 기록했습니다. request 3은 effort를 high에서 medium으로 변경했으며, cache_creation_input_tokens은 3546, cache_read_input_tokens은 0을 기록했습니다. 따라서 workload에 따라 effort를 변경해야 하며, 하나의 cached conversation 내부에서 변경해서는 안 됩니다. cache를 깨뜨리지 않고 깊이를 조절하려면 prompt를 사용하십시오. 최신 user message에 "Answer directly without deliberating."과 같은 문구를 넣으면 이전 breakpoint를 유지할 수 있습니다.
Thinking tokens는 output 요율로 과금되며 max_tokens에 포함됩니다. 답변이 잘리는 현상은 대개 thinking이 예산을 모두 소모했음을 의미합니다. 정확한 수치는 usage.output_tokens_details.thinking_tokens을 참조하십시오. Claude 비용 청구의 실제 구성 요소에서 상세 내용을 확인할 수 있습니다.
Stable prefix를 캐싱하여 실수로 캐시가 깨지는 것을 방지하십시오
5-minute cache의 경우 캐시 쓰기 비용은 기본 입력 가격의 1.25배이며, 1-hour cache는 2배입니다. 캐시 읽기 비용은 0.1배입니다. 따라서 "5-minute duration의 경우 단 한 번의 캐시 읽기만으로도 이득이며(1.25x write), 1-hour duration의 경우 두 번의 캐시 읽기 이후부터 이득이 발생합니다(2x write)."
이 방식이 상시 가동되는 agent에 적합한 이유는 다음과 같습니다: "캐싱된 콘텐츠를 사용할 때마다 추가 비용 없이 캐시가 갱신됩니다." 5-minute cache를 대상으로 2분마다 실행되는 job은 단 한 번의 쓰기만으로 하루 종일 prefix를 warm 상태로 유지할 수 있습니다.
인지하지 못한 채 캐시를 잃게 되는 세 가지 방법.
변경되는 prefix. "Cache prefixes는 다음 순서로 생성됩니다: tools, system, 그 다음 messages." 해당 순서에서 앞선 바이트가 변경되면 이후의 모든 데이터가 무효화됩니다. 또한 editing tool definitions를 수행하면 전체 캐시가 무효화됩니다. 흔히 발생하는 실수 중 하나는 system prompt에 timestamp나 run id를 포함하는 것입니다. 이 경우 모든 request가 서로 다른 prefix를 가지게 되어, 1.25x 비용으로 매번 새로운 항목을 쓰기만 하고 캐시를 읽어오지 못합니다. 동일해 보이는 호출에서 usage.cache_read_input_tokens 값이 0이라면 이것이 원인입니다. 변동성이 있는 텍스트는 가장 최근의 user message로 이동하십시오.
너무 짧은 prefix. 각 model에는 최소 캐싱 가능 길이가 있으며, 이보다 짧으면 캐싱 없이 request가 처리되고 "no error is returned"됩니다. Claude Opus 4.8 및 Claude Sonnet 5의 기준 수치는 1,024 tokens이며, Claude Haiku 4.5는 4,096 tokens입니다. 따라서 job을 Sonnet에서 Haiku로 변경하면 캐싱이 조용히 비활성화될 수 있습니다.
lookback 범위를 초과하는 대화. "Lookback window는 20 blocks입니다." 시스템은 breakpoint당 최대 20개의 위치를 확인한 후 중단합니다. 문서화된 예시에서, block 35에 breakpoint가 있는 35 blocks 분량의 turn은 block 35부터 16까지를 확인합니다. 따라서 block 15에 있는 이전 turn의 항목은 window 범위를 벗어나므로 cache hit이 발생하지 않습니다. 매 turn마다 여러 개의 tool-use 및 tool-result blocks를 추가하는 agent는 두세 번의 turn 만에 20 blocks를 초과하게 됩니다. request당 4개의 breakpoints를 사용할 수 있으므로, 하나는 최근 메시지에 할당하십시오.
대기 가능한 작업은 Batches API로 전송하십시오
입력과 출력 모두 "표준 API 가격의 50%가 적용"됩니다. Batch 처리는 비동기 방식으로 작동하며, "대부분의 batch는 1시간 이내에 완료"됩니다. 결과는 모든 요청이 완료되거나 24시간이 경과하면 제공됩니다. 이는 일반적인 사례이며 보장되는 시간은 아닙니다.
processing_status 값이 ended가 될 때까지 폴링하십시오. errored, canceled 또는 expired를 반환하는 요청은 비용이 청구되지 않습니다. 지출 한도(spend cap)를 사용하는 경우 주의사항이 있습니다. "batch 작업이 Workspace에 설정된 지출 한도를 약간 초과할 수 있습니다."
할인은 중복 적용됩니다. batch 작업은 5분 이상 소요될 수 있으므로, 문서는 동일한 context를 공유하는 batch에 대해 1시간 캐시 사용을 권장합니다. 따라서 작업을 분리하십시오. 사람이나 webhook이 대기해야 하는 작업은 실시간 경로를 유지하고, 야간 요약이나 어제의 로그 분류 작업은 batch를 사용하여 절반 가격으로 처리하십시오.
모든 응답의 usage 필드를 자체 저장소에 기록하십시오
기록되지 않은 지출은 산출할 수 없습니다. 모든 응답에는 비용 정보가 포함되어 있습니다.
u = resp.usage
row = {
"job": job_name,
"model": resp.model,
"uncached_input": u.input_tokens,
"cache_write": u.cache_creation_input_tokens,
"cache_read": u.cache_read_input_tokens,
"output": u.output_tokens,
"stop_reason": resp.stop_reason,
}API 호출당 한 행을 JSON-lines 파일에 추가하고, job name 태그를 지정하십시오. 일주일 후 어떤 job이 비용을 발생시키고 어떤 job이 단순히 작업량만 많았는지 확인할 수 있습니다. cache_read을 주의하십시오. 0으로만 채워진 열은 self-hosted agent에서 가장 흔히 발생하는 비용 관련 버그입니다.
오독하기 쉬운 필드가 하나 있습니다. input_tokens는 마지막 cache breakpoint 이후의 token만 계산하므로, 실제 prompt 크기는 total_input_tokens = cache_read_input_tokens + cache_creation_input_tokens + input_tokens입니다. 대규모 prompt에 대해 input_tokens: 400을 보고하는 agent는 저렴한 것이 아닙니다. 나머지 부분은 cache에서 발생했기 때문입니다.
전송하기 전에 개수를 세십시오. Token counting은 무료이며 rate limit도 message creation과 별도로 적용됩니다. 따라서 oversized attachment를 발견하고 비용을 지불하는 대신, count_tokens을 사용하여 전송을 거부하십시오. 결과값은 추정치이므로 모델별로 다시 측정해야 하며, 다른 vendor의 tokenizer를 사용한 count를 재사용하지 마십시오. Claude Opus 4.7 및 이후의 Opus 모델, Claude Fable 5 및 Claude Sonnet 5는 "동일한 텍스트에 대해 약 30% 더 많은 token을 생성하는" 새로운 tokenizer를 사용합니다. Claude Sonnet 4.6 및 이전 버전, Claude Haiku 4.5 등이 이전 tokenizer를 사용합니다.
정확한 데이터를 확인하려면, Admin API가 https://api.anthropic.com/v1/organizations/usage_report/messages에서 usage를, https://api.anthropic.com/v1/organizations/cost_report에서 cost를 보고합니다. 두 항목 모두 admin key (sk-ant-admin01-...)를 x-api-key: $ANTHROPIC_ADMIN_KEY으로 사용하며 anthropic-version: 2023-06-01와 함께 bucket_width=1d, group_by[]=model, api_key_ids[]=를 허용합니다. 한 가지 제한 사항이 있습니다: "The Admin API is unavailable for individual accounts."
마지막 파라미터는 효율적인 attribution 기법입니다. 각 job에 고유한 API key를 부여하고, api_key_ids[]으로 필터링한 뒤, group_by[]=api_key_id을 사용하여 key별로 보고서를 분리하십시오. 필터는 복수형이며, grouping dimension은 단수형입니다. a first Claude API app on a VPS에서 처리하는 방식과 같이, key를 코드 내부가 아닌 environment에 보관하십시오.
Bound the loop, because nothing else will
A bounded iteration count is not optional here. The loop is yours, so the counter is yours:
for step in range(MAX_STEPS): # MAX_STEPS = 12, never "while True"
resp = client.messages.create(...)
if resp.stop_reason != "tool_use":
break
else:
log.warning("job %s hit MAX_STEPS=%d, giving up", job_name, MAX_STEPS)Neither ceiling above does it for you: max_tokens caps one response, and the model is only advised of a task budget.
Put a second brake outside the process. Run the job from a systemd timer instead of a permanent process, and set RuntimeMaxSec= on its service unit. With RuntimeMaxSec=600, a hung run is killed after ten minutes instead of spinning until you notice. Running a program as a systemd service and timer covers the unit files themselves. Read what a run did with journalctl -u triage-agent.service --since "1 hour ago".
Cap retries as well, because a handler that retries forever bills every attempt. A 429 or a 500 deserves a few tries with backoff. A 400 deserves none, since the same request fails the same way.
AI agent 비용 관리는 데이터 분석에서 시작됩니다
항상 실행 중인 agent의 정확한 비용은 아무도 알 수 없습니다. 비용은 '실행당 토큰 수'에 '일일 실행 횟수'를 곱하여 결정되며, 두 요소 모두 사용자가 관리하기 때문입니다. agent를 한 번 실행한 후, 로그에 기록된 사용량 행을 확인하고 실행 일정에 맞춰 곱해 보십시오. 이틀 뒤에 해당 계산 결과와 실제 비용 보고서를 비교하십시오. 두 수치가 일치하지 않는다면, 대부분 캐시 오류이거나 예상보다 길게 실행된 루프 때문입니다.
이 계산은 API key 사용을 전제로 합니다. agent는 Messages API를 호출하는 사용자 프로그램이기 때문입니다. 대화형 작업에 적합한 요금제를 확인하려면 사용자 작업 방식에 맞는 Claude 요금제를 참조하십시오. 여기에 기재된 모든 가격과 제한 사항은 2026년 7월 Anthropic 문서를 기준으로 검증되었습니다. 예산을 세우기 전에 가격 페이지를 다시 확인하십시오.
FAQ
VPS에서 상시 가동되는 AI agent를 운영하는 비용은 얼마입니까?
청구 항목은 두 가지이며, 그중 하나만 예측 가능합니다. 서버 비용은 매달 고정된 가격입니다. Model API는 token 단위로 과금되므로, 비용은 1회 실행 시 소비되는 양에 실행 빈도를 곱한 값입니다. Anthropic은 self-hosted 방식의 상시 가동 agent에 대한 수치를 공개하지 않으므로, 인용된 모든 수치는 추정치로 간주하십시오. 실제 실행에서 usage 로그를 추출하여 실행 일정에 따라 곱하십시오.
max_tokens와 task budget의 차이점은 무엇입니까?
max_tokens는 강제 적용되며 model에게는 보이지 않습니다. 이는 thinking을 포함한 1회 요청의 output을 제한하며, 이 한도에 도달하면 stop_reason: "max_tokens"가 발생합니다. Task budget은 반대입니다. model에게 해당 수치를 알려주어 agentic loop를 조절하게 하지만, "Task budgets are a soft hint, not a hard cap"이며 강제되는 한도는 여전히 max_tokens입니다.
왜 제 agent의 cache_read_input_tokens 값이 항상 0입니까?
Call 사이에 prefix가 변경되었거나, prefix가 너무 짧아 cache할 수 없기 때문입니다. 일반적인 원인은 system prompt에 삽입된 timestamp 또는 run id입니다. cache는 prefix를 기준으로 키를 생성하므로, 단 1 byte라도 변경되면 그 이후의 모든 내용이 무효화됩니다. tool definition을 변경하거나 effort 값을 변경하는 것도 동일한 결과를 초래합니다. 그 외에는 프롬프트 크기 문제입니다. 짧은 프롬프트는 cache되지 않으며 별도의 에러도 반환되지 않습니다.
AI agent가 무한 루프에 빠지는 것을 어떻게 방지합니까?
loop code에서 iteration 횟수를 계산하여 고정된 최대치에서 중단하십시오. max_tokens는 단일 response를 제한하지만, agent는 여러 번의 response를 생성하기 때문입니다. 프로세스 외부에서 wall-clock 제한을 추가하십시오. RuntimeMaxSec=가 설정된 systemd timer로 작업을 시작하면, 멈춘 작업이 예정된 시간에 종료됩니다. retry loop는 매 시도마다 비용이 발생하므로 retry 횟수도 제한하십시오.
단일 Claude API key에 지출 한도를 설정할 수 있습니까?
문서에 명시된 지출 한도는 key 단위가 아닌 workspace 단위입니다. 따라서 agent에게 전용 workspace를 할당하고 해당 workspace에서 월간 지출을 제한하십시오. "You cannot set limits on the Default Workspace". 임계값 도달 시 알림을 받을 수 있도록 지출 알림(spend notifications)을 추가하십시오. 비용 추적을 위해 각 작업에 개별 key를 발급한 후, group_by[]=api_key_id를 사용하여 사용량 보고서를 그룹화하십시오.