Split View: 코딩 에이전트 비용은 한도로 잡는 게 아니라 마찰로 잡습니다
코딩 에이전트 비용은 한도로 잡는 게 아니라 마찰로 잡습니다
- 청구서는 왔는데 누가 얼마를 썼는지 모르는 상태
- 하드 예산이 마지막 수단인 이유
- 폭주 방지와 거버넌스를 분리하는 2단 구조
- 증분 하나의 크기가 설계의 거의 전부입니다
- 라우팅은 가장 싼 모델이 아니라 해낼 수 있는 가장 싼 모델로
- 실제로 비용을 지배하는 것은 모델 단가가 아니라 컨텍스트
- 캐시는 공짜가 아닙니다
- 우리 조직에 옮길 때의 최소 구성
- 참고 자료
청구서는 왔는데 누가 얼마를 썼는지 모르는 상태
코딩 에이전트를 팀에 풀고 두 달쯤 지나면 대개 같은 대화가 시작됩니다. 지난달 대비 청구액이 세 배가 됐고, 그게 어디서 왔는지 아무도 설명하지 못합니다. 도구가 세 종류이고, 각자 다른 계정으로 다른 모델을 부르고 있으며, 사용량은 벤더 콘솔에 흩어져 있습니다.
이 상태에서 가장 흔한 대응은 인당 한도를 거는 것입니다. 그리고 대체로 실패합니다. 한도에 걸린 사람은 작업 도중에 막히고, 티켓을 열고, 누군가 승인해 줄 때까지 기다립니다. 절약된 금액보다 끊긴 작업 시간이 더 비쌉니다.
하드 예산이 마지막 수단인 이유
Databricks가 2026년 8월 7일에 공개한 Managing AI Coding Costs at Scale은 여러 회사를 인터뷰한 뒤 이렇게 적습니다. 하드 예산은 그들이 이야기해 본 모든 회사에서 마지막 수단으로만 쓰이고 있었다는 것입니다.
이유는 비용 구조에 있습니다. 코딩 에이전트 지출은 정규분포가 아니라 롱테일입니다. 대부분의 엔지니어는 평범하게 쓰고, 소수가 큰 작업을 돌립니다. 그리고 그 소수의 큰 작업이 대체로 가장 가치 있는 작업입니다. 대규모 리팩터링, 오래된 서비스의 마이그레이션, 장애 원인 추적처럼 사람이 하면 며칠이 걸리는 일들입니다. 평균에 맞춰 한도를 그으면 정확히 그 작업들이 잘립니다.
한도의 두 번째 문제는 학습 효과가 없다는 것입니다. 막힌 사람은 자기가 왜 많이 썼는지 알게 되는 게 아니라 그냥 막혔다는 사실만 알게 됩니다. 다음 달에도 같은 방식으로 쓰다가 같은 자리에서 막힙니다.
그래서 방향이 바뀝니다. 못 쓰게 막는 대신 얼마 쓰고 있는지 보이게 하고, 계속 쓰려면 한 번 확인하게 만듭니다.
폭주 방지와 거버넌스를 분리하는 2단 구조
같은 회사가 2026년 7월 28일에 낸 How Databricks manages its own coding agent spend에는 그 설계가 구체적으로 나옵니다. 예산이 두 층으로 분리되어 있습니다.
일일 예산은 낮게 잡힌 폭주 방지선입니다. 목적은 절약이 아니라 사고 감지입니다. 무한 루프에 빠진 에이전트, 잘못 설정된 배치 작업 같은 것을 하루 안에 잡습니다. 사용량의 90퍼센트 근처에 닿으면 Slack으로 알림이 가고, 버튼 하나로 본인이 한도를 한 단계 올릴 수 있습니다. 이 자가 승인에는 횟수 제한이 없습니다.
월간 예산은 성격이 다릅니다. 대부분의 엔지니어는 평생 닿지 않을 만큼 높게 잡히고, 올리려면 관리자 승인이 필요하며, 상향은 1개월, 3개월, 6개월처럼 기한이 붙어 자동으로 원복됩니다. 단계도 촘촘하지 않고 대략 2배, 5배, 사실상 무제한 정도로 거칩니다. 거칠게 만든 것이 의도인데, 그래야 승인 대화가 형식적인 확인이 아니라 실제 논의가 됩니다.
증분 하나의 크기가 설계의 거의 전부입니다
이 구조에서 가장 신경 써서 정해야 하는 값은 한도가 아니라 증분입니다. 원문의 표현대로, 월간 예산에 맞춰 고르게 쓰는 엔지니어는 알림을 한 번도 보지 않도록 증분 크기를 잡았습니다.
그리고 관리자가 월간 한도를 올려 주면 일일 한도와 증분이 비례해서 함께 커집니다. 이걸 안 하면 큰 프로젝트를 승인받은 사람이 하루 종일 자가 승인 버튼만 누르게 되고, 폭주 방지선이 의미를 잃습니다.
"""게이트웨이 예산 판정: 한도는 두 개, 실효 한도는 하나."""
from dataclasses import dataclass
@dataclass
class BudgetPolicy:
monthly_max: float # 관리자 승인으로만 오르는 상한
runaway_increment: float # 자가 승인 1회로 열리는 폭
def effective_limit(self, month_to_date: float) -> float:
"""월 누적 + 증분 1회, 단 월 상한을 넘지 않는다."""
return min(month_to_date + self.runaway_increment, self.monthly_max)
def decide(self, month_to_date: float, today: float, today_limit: float):
limit = self.effective_limit(month_to_date)
if month_to_date + today >= self.monthly_max:
return "block", "월 상한 도달 — 관리자 승인 필요"
if today >= today_limit:
return "self_ack", "확인 버튼 1회로 계속 진행 가능"
if today >= today_limit * 0.9:
return "notify", f"오늘 잔여 {round(today_limit - today, 2)} 단위"
return "allow", ""
# 월 상한을 넉넉히 두고, 하루 증분은 작게 잡는 조합
policy = BudgetPolicy(monthly_max=1000.0, runaway_increment=40.0)
for mtd, today, day_limit in [(120, 10, 40), (120, 37, 40), (120, 41, 40), (990, 15, 40)]:
print(mtd, today, policy.decide(mtd, today, day_limit))
이 코드가 하는 일은 단순하지만, 여기에 조직 정책이 전부 들어 있습니다. 무엇이 차단이고 무엇이 확인이며 무엇이 침묵인지가 네 줄로 정해집니다. 흩어진 대시보드 대신 이 함수 하나를 리뷰하면 됩니다.
라우팅은 가장 싼 모델이 아니라 해낼 수 있는 가장 싼 모델로
두 번째 축은 라우팅입니다. Databricks는 사내 게이트웨이의 스마트 라우터가 최고 품질 모델과 대체로 비슷한 결과를 유지하면서 평균 작업 비용을 30퍼센트 넘게 줄인다고 밝히고 있습니다.
주의할 점은 이게 "싼 모델을 쓰자"와 다르다는 것입니다. 요청마다 그 일을 해낼 수 있는 가장 저렴한 모델을 고르는 판정이고, 판정을 잘못하면 재시도가 붙어서 오히려 비싸집니다. 그래서 라우터는 도입 전후로 반드시 품질 지표와 재시도율을 함께 봐야 합니다. 비용만 보면 항상 개선된 것처럼 보입니다.
같은 글에는 상위 모델을 사내에 열지 않기로 한 판단도 나옵니다. 이전 버전 대비 품질 향상이 확인되지 않았다는 이유였습니다. 최신 모델을 쓰지 않는 것도 선택지라는 점이 여기서 중요합니다.
실제로 비용을 지배하는 것은 모델 단가가 아니라 컨텍스트
세 번째 축이 가장 큽니다. 원문의 표현을 옮기면, 값비싼 추론이 실행되는 시점에는 사용자가 처음 친 문장이 시스템에 들어가는 데이터 중 무시할 만한 비율에 불과하고 비용은 컨텍스트가 지배합니다.
에이전트 한 번의 호출에 실리는 것은 시스템 프롬프트, 도구 정의, 파일 스니펫, 검색 결과, 그리고 이전 턴의 이력 전부입니다. 사용자가 친 한 줄은 여기에 비하면 반올림 오차입니다. 그래서 단가가 절반인 모델로 옮기는 것보다 컨텍스트를 절반으로 줄이는 쪽이 대체로 더 큰 효과를 냅니다.
Databricks는 하네스 튜닝과 캐시 설정 조정으로 생성 토큰 수를 거의 50퍼센트 줄였다고 적고 있습니다. 모델을 바꾸지 않고 얻은 숫자라는 점이 핵심입니다.
캐시는 공짜가 아닙니다
캐시에 대해서는 한 문장이 정확합니다. 캐시 쓰기에는 비용이 들고, 캐시 읽기는 추론당 비용을 크게 낮춘다는 것입니다.
이 둘이 같이 있다는 사실이 실무에서 자주 잊힙니다. 프리픽스가 자주 바뀌는 구성에서 캐시를 켜면 쓰기 비용만 계속 내고 히트는 나지 않습니다. 그래서 캐시를 켜기 전에 확인해야 하는 것은 히트율이 아니라 프리픽스의 안정성입니다. 시스템 프롬프트와 도구 정의가 요청마다 순서가 달라지거나 타임스탬프가 섞여 들어가면 히트율은 구조적으로 오르지 않습니다.
점검은 어렵지 않습니다. 실제 트래픽에서 요청 100건을 뽑아 캐시 대상 프리픽스를 해시로 찍어 보면 됩니다. 서로 다른 해시가 90개 나온다면 그 구성에서는 캐시가 비용만 늘립니다. 도구 목록의 정렬 순서를 고정하고, 동적으로 끼워 넣던 현재 시각과 세션 식별자를 프리픽스 뒤로 옮기는 것만으로 해시 종류가 한 자릿수로 떨어지는 경우가 흔합니다.
우리 조직에 옮길 때의 최소 구성
이 설계를 그대로 복제할 필요는 없지만, 순서는 지킬 만합니다.
| 순서 | 할 일 | 이걸 안 하면 |
|---|---|---|
| 1 | 모든 에이전트 트래픽을 게이트웨이 한 곳으로 모은다 | 이후 모든 숫자가 부분 집계가 된다 |
| 2 | 사용량을 사람과 작업 단위로 귀속한다 | 누가 무엇에 썼는지 영원히 모른다 |
| 3 | 낮은 일일 폭주 방지선과 자가 승인 버튼을 붙인다 | 사고를 하루 안에 못 잡는다 |
| 4 | 프리픽스를 고정해 캐시 히트율을 먼저 올린다 | 모델을 바꿔도 오버헤드가 그대로 남는다 |
| 5 | 그다음에 라우팅과 모델 교체를 검토한다 | 품질 하락을 비용 개선으로 오독한다 |
Databricks 글은 사내에서 예산 구조를 바꾸기 전에 매달 500명에서 1,000명 사이의 엔지니어가 한도에 걸리고 있었다고 밝힙니다. 수백 건의 티켓과 그만큼의 끊긴 작업 세션입니다. 비용 관리의 성패는 청구서가 얼마나 줄었느냐만이 아니라, 줄이는 과정에서 몇 번이나 사람 손이 필요했느냐로도 봐야 한다는 뜻입니다.
참고 자료
- Managing AI Coding Costs at Scale — Databricks, 2026-08-07 — 네 가지 기법, 라우팅 30퍼센트 이상 절감, 생성 토큰 50퍼센트 감소, 캐시 쓰기 비용 언급이 이 글의 내용입니다.
- How Databricks manages its own coding agent spend with Unity AI Gateway Budgets — Databricks, 2026-07-28 — 2단 예산, 자가 승인, 증분 비례 확대, 월 500~1,000명이 한도에 걸리던 상황이 여기 나옵니다.
- 일부 매체 요약에는 이 기법들로 최대 90퍼센트를 절감했다는 표현이 돌지만, Databricks 원문에서 제가 확인할 수 있었던 수치는 위에 적은 것들이며 표로 정리된 절감폭은 비공식 설문에 기반한 방향성 수치라고 원문이 직접 밝히고 있습니다. 90퍼센트라는 숫자는 원문에서 확인되지 않습니다.
- 본문의 예산 판정 코드는 원문에 서술된 규칙을 제가 옮겨 구현한 것이며, 숫자는 예시입니다.
Coding Agent Spend Is Controlled by Friction, Not by Caps
- The bill arrived and nobody knows who spent what
- Why a hard budget is the last resort
- The two-tier structure that separates runaway protection from governance
- The size of one increment is nearly the whole design
- Route to the cheapest model that can do the job, not to the cheapest model
- What actually dominates cost is context, not model pricing
- The cache is not free
- A minimum configuration for bringing this into your own organization
- References
The bill arrived and nobody knows who spent what
About two months after coding agents are turned loose on a team, the same conversation usually starts. The bill has tripled against last month, and nobody can explain where it came from. There are three kinds of tools, each calling different models under different accounts, and usage is scattered across vendor consoles.
The most common response in this state is a per-person cap. And it mostly fails. The person who hits the cap is blocked mid-task, opens a ticket, and waits for someone to approve it. The interrupted working time costs more than the money saved.
Why a hard budget is the last resort
Managing AI Coding Costs at Scale, published by Databricks on 7 August 2026, interviews a number of companies and then writes this: hard budgets were used only as a last resort at every company they talked to.
The reason lies in the cost structure. Coding agent spend is not a normal distribution, it is a long tail. Most engineers use an ordinary amount, and a small number run large jobs. And those few large jobs are generally the most valuable work — big refactors, migrations of aging services, tracing the cause of an outage, the kind of thing that takes a human days. Draw the cap at the average and you cut exactly those jobs.
The second problem with caps is that they produce no learning. The person who gets blocked does not come to understand why they spent so much; they only learn that they were blocked. Next month they work the same way and get blocked in the same place.
So the direction changes. Instead of blocking use, make the amount being spent visible, and require one confirmation to keep going.
The two-tier structure that separates runaway protection from governance
How Databricks manages its own coding agent spend, from the same company on 28 July 2026, lays out that design concretely. The budget is separated into two layers.
The daily budget is a low runaway-protection line. Its purpose is not saving but accident detection. It catches things like an agent stuck in an infinite loop or a misconfigured batch job within a day. When usage gets near ninety percent, a Slack notification goes out, and with a single button the person can raise their own limit by one step. There is no cap on how many times this self-approval can be used.
The monthly budget has a different character. It is set high enough that most engineers will never reach it in their working lives, raising it requires manager approval, and the increase carries an expiry — one month, three months, six months — after which it reverts automatically. The steps are not fine-grained either: roughly two times, five times, effectively unlimited. The coarseness is intentional, because that is what turns the approval conversation into a real discussion rather than a formality.
The size of one increment is nearly the whole design
In this structure, the value that needs the most care is not the limit but the increment. As the original puts it, the increment size was chosen so that an engineer spending evenly against the monthly budget would never see a notification at all.
And when a manager raises the monthly budget, the daily limit and the increment grow proportionally with it. Skip that, and someone approved for a big project spends the whole day pressing the self-approval button, and the runaway-protection line loses its meaning.
"""Gateway budget decision: two limits, one effective limit."""
from dataclasses import dataclass
@dataclass
class BudgetPolicy:
monthly_max: float # ceiling that only manager approval can raise
runaway_increment: float # the width one self-approval opens up
def effective_limit(self, month_to_date: float) -> float:
"""Month to date plus one increment, but never above the monthly ceiling."""
return min(month_to_date + self.runaway_increment, self.monthly_max)
def decide(self, month_to_date: float, today: float, today_limit: float):
limit = self.effective_limit(month_to_date)
if month_to_date + today >= self.monthly_max:
return "block", "monthly ceiling reached - manager approval required"
if today >= today_limit:
return "self_ack", "one confirmation button and you may continue"
if today >= today_limit * 0.9:
return "notify", f"remaining today: {round(today_limit - today, 2)} units"
return "allow", ""
# a generous monthly ceiling combined with a small daily increment
policy = BudgetPolicy(monthly_max=1000.0, runaway_increment=40.0)
for mtd, today, day_limit in [(120, 10, 40), (120, 37, 40), (120, 41, 40), (990, 15, 40)]:
print(mtd, today, policy.decide(mtd, today, day_limit))
What this code does is simple, but the whole of the organizational policy lives in it. What counts as a block, what counts as a confirmation, and what counts as silence are settled in four lines. Instead of scattered dashboards, you review this one function.
Route to the cheapest model that can do the job, not to the cheapest model
The second axis is routing. Databricks states that the smart router in its internal gateway cuts the average cost per task by more than thirty percent while keeping results broadly comparable to the highest-quality model.
The thing to watch is that this is not the same as "let us use cheap models." It is a decision, made per request, about the cheapest model that can actually do that job, and a bad decision brings retries that make it more expensive instead. So a router must always be evaluated with quality metrics and retry rate alongside cost, before and after adoption. Look at cost alone and it always looks like an improvement.
The same post also describes a decision not to open a top-tier model internally, on the grounds that a quality improvement over the previous version had not been confirmed. What matters here is that not using the newest model is also an option.
What actually dominates cost is context, not model pricing
The third axis is the biggest. To carry over the original wording: by the time the expensive inference runs, the sentence the user first typed is a negligible fraction of the data entering the system, and cost is dominated by context.
What rides along on a single agent call is the system prompt, the tool definitions, file snippets, retrieval results, and the entire history of previous turns. The one line the user typed is a rounding error next to that. So halving the context generally produces a larger effect than moving to a model that costs half as much per token.
Databricks writes that harness tuning and cache configuration changes cut the number of generated tokens by nearly fifty percent. The key point is that this number was obtained without changing the model.
The cache is not free
One sentence about caching is exactly right: writing to the cache costs money, and reading from the cache greatly lowers the cost per inference.
The fact that these two live together is frequently forgotten in practice. Turn on the cache in a configuration whose prefix changes often, and you keep paying the write cost while the hits never come. So the thing to check before enabling a cache is not the hit rate but the stability of the prefix. If the system prompt and the tool definitions come out in a different order every request, or a timestamp gets mixed in, the hit rate structurally cannot rise.
Checking is not hard. Pull a hundred requests from real traffic and print a hash of the prefix that would be cached. If ninety distinct hashes come out, then in that configuration the cache only adds cost. It is common for the number of distinct hashes to drop into single digits merely by fixing the sort order of the tool list and moving the dynamically injected current time and session identifier behind the prefix.
A minimum configuration for bringing this into your own organization
You do not need to clone this design exactly, but the order is worth keeping.
| Order | What to do | If you skip it |
|---|---|---|
| 1 | Funnel all agent traffic through a single gateway | Every number after this is a partial aggregate |
| 2 | Attribute usage to a person and a task | You never learn who spent what on what |
| 3 | Attach a low daily runaway line and a self-approval button | You cannot catch accidents within a day |
| 4 | Fix the prefix and raise the cache hit rate first | Change the model and the overhead stays exactly where it was |
| 5 | Only then review routing and model swaps | You misread a quality drop as a cost improvement |
The Databricks post states that before the budget structure was changed internally, somewhere between 500 and 1,000 engineers were hitting limits every month. That is hundreds of tickets and the same number of interrupted working sessions. Which means the success or failure of cost management should be judged not only by how much the bill fell, but also by how many times a human hand was required in the process of lowering it.
References
- Managing AI Coding Costs at Scale — Databricks, 2026-08-07 — the four techniques, routing savings above 30 percent, the 50 percent reduction in generated tokens, and the mention of cache write cost all come from this post.
- How Databricks manages its own coding agent spend with Unity AI Gateway Budgets — Databricks, 2026-07-28 — the two-tier budget, self-approval, proportional scaling of the increment, and the situation of 500 to 1,000 people a month hitting limits appear here.
- Some media summaries circulate a claim that these techniques delivered savings of up to 90 percent, but the figures I could confirm in the Databricks originals are the ones written above, and the original itself states that the savings ranges collected in its table are directional numbers based on an informal survey. The 90 percent figure is not confirmed in the original.
- The budget decision code in this post is my own implementation of the rules described in the original, and the numbers are examples.