
게이트웨이 라우팅은 AI 앱에 도움이 되지만, 에이전트 런타임에는 여전히 호출 전 가드(Pre-Call Guards)가 필요합니다.
요약
Vercel의 AI Gateway 라우팅 기능이 모델 재작성 및 차단을 지원하지만, 에이전트의 안전한 실행을 위해서는 런타임 수준의 가드(Pre-Call Guards)가 필수적입니다. 게이트웨이는 모델 선택을 결정할 뿐, 예산 초과나 무한 루프 같은 에이전트 내부 컨텍스트를 제어할 수 없기 때문입니다.
핵심 포인트
- AI Gateway 라우팅은 모델 재작성 및 차단에 유용함
- 게이트웨이는 에이전트의 실행 단계, 예산, 루프 여부를 알 수 없음
- 안전한 에이전트 구축을 위해 런타임 내 '호출 전 가드' 패턴 권장
- 예산 확인, 최대 단계 제한, 재시도 폭풍 탐지 등의 제어 기능 필요
Vercel은 7월 2일에 AI Gateway에 라우팅 규칙(routing rules)을 추가했습니다.
라우팅 규칙을 통해 팀은 게이트웨이 수준에서 모델 요청을 재작성(rewrite)하거나 거부(deny)할 수 있습니다. 재작성 규칙은 하나의 모델에 대한 요청을 다른 모델을 사용하여 처리합니다. 거부 규칙은 특정 모델을 차단하고 403 에러를 반환합니다. Vercel은 모델이 다운되었거나 은퇴했을 때의 재라우팅(rerouting), 하나의 모델로 표준화, 비용이 많이 드는 모델을 더 저렴한 모델로 라우팅, 또는 승인되지 않은 모델의 사용을 팀에서 제한하는 것과 같은 사용 사례를 나열하고 있습니다.
이는 유용한 인프라입니다.
하지만 AI 에이전트(AI agents)를 구축하고 있다면, 이것이 안전 계층(safety layer)의 전부인 것은 아닙니다.
게이트웨이는 요청이 어디로 갈지를 결정할 수 있습니다.
하지만 여러분의 런타임(runtime)은 해당 요청이 실행되어야 하는지 여부를 여전히 결정해야 합니다.
차이점
게이트웨이 라우팅(Gateway routing)은 다음을 답변합니다:
"어떤 모델이 이 요청을 처리해야 하는가?"
런타임 가딩(Runtime guarding)은 다음을 답변합니다:
"이 요청이 아예 허용되어야 하는가?"
이것들은 서로 다른 문제입니다.
게이트웨이는 다음과 같이 재작성할 수 있습니다:
anthropic/claude-opus-4.8 -> anthropic/claude-haiku-4.5
이는 트래픽을 계속 흐르게 할 수 있습니다.
하지만 게이트웨이는 다음 사항들을 알지 못할 수 있습니다:
- 에이전트가 이미 12번이나 재시도했다는 사실
- 현재 프롬프트(prompt)가 이전의 실패한 프롬프트와 거의 동일하다는 사실
- 실행이 할당된 작업 예산(task budget)을 초과했다는 사실
- 에이전트가 최대 단계 제한(max-step limit)을 넘었다는 사실
- 진전 없이 도구 호출(tool calls)만 계속 발생하고 있다는 사실
- 폴백(fallback) 모델이 루프를 유지시키고는 있지만 작업을 개선하지 못하고 있다는 사실
그러한 컨텍스트(context)는 대개 에이전트 런타임(agent runtime) 내부에 존재합니다.
단순한 에이전트 루프(A naive agent loop)
많은 에이전트 루프는 다음과 같이 시작됩니다:
while (!task.done) {
const response = await provider.call({
model: task.model,
messages: task.messages,
});
task = await applyAgentStep(task, response);
}
이것은 단순합니다.
하지만 프로덕션(production) 환경에서 중요한 제어 기능들이 빠져 있습니다.
예산 확인(budget check)이 없습니다.
최대 단계 확인(max-step check)도 없습니다.
재시도 폭풍(retry-storm) 탐지도 없습니다.
프롬프트 루프(prompt-loop) 탐지도 없습니다.
알 수 없는 가격 책정(unknown-pricing) 차단도 없습니다.
진전 없음(no-progress) 중단 기능도 없습니다.
만약 게이트웨이가 모델을 재작성한다면, 이 루프는 계속 실행될 수 있습니다.
그것이 항상 여러분이 원하는 결과는 아닙니다.
호출 전 가드(pre-call guard) 추가하기
더 안전한 패턴은 제공자 호출(provider call) 전에 로컬 결정을 배치하는 것입니다:
const decision = guard.beforeCall({
runId: task.id,
model: task.model,
messages: task.messages,
stepCount: task.steps.length,
retryCount: task.retryCount,
previousPrompts: task.previousPrompts,
budgetRemaining: task.budgetRemaining,
progressState: task.progress,
});
if (!decision.allowed) {
return {
status: "stopped",
reason: decision.reason,
error: decision.error,
};
}
const response = await provider.call({
model: task.model,
messages: task.messages,
});
정확한 API는 중요하지 않습니다.
중요한 것은 위치입니다.
가드는 제공자 호출(provider call) 전에 실행됩니다.
런타임은 무엇을 확인해야 할까요?
- 알려진 모델 가격 책정 (Known model pricing)
런타임이 모델의 가격을 책정할 수 없다면, 신뢰할 수 있는 예산 제한을 적용할 수 없습니다.
if (!pricingCatalog.has(model)) {
return {
allowed: false,
reason: "unknown_model_pricing",
};
}
라우팅 및 폴백 규칙(fallback rules)이 존재하는 경우 이 점은 더욱 중요합니다.
재작성된 모델이라도 비용 프로필(cost profile)을 가집니다.
런타임은 이를 알아야 합니다.
- 남은 예산 (Budget remaining)
태스크 수준의 예산은 계정 수준의 제한과 다릅니다.
if (estimatedNextCallCost > budgetRemaining) {
return {
allowed: false,
reason: "budget_exceeded",
};
}
월별 대시보드에서는 나중에 지출을 확인할 수 있습니다.
런타임 예산은 지금 다음 호출을 중단할 수 있습니다.
- 최대 단계 (Max steps)
에이전트는 명시적인 중지 규칙을 가져야 합니다.
if (stepCount >= maxSteps) {
return {
allowed: false,
reason: "max_steps_exceeded",
};
}
모델 라우팅은 변경될 수 있습니다.
단계 제한은 여전히 적용되어야 합니다.
- 재시도 폭풍 (Retry storms)
재시도는 유용합니다.
맹목적인 재시도는 그렇지 않습니다.
if (retryCount > maxRetries && recentErrorsAreSimilar(errors)) {
return {
allowed: false,
reason: "retry_storm_detected",
};
}
폴백 모델은 실행을 유지함으로써 재시도 폭풍을 숨길 수 있습니다.
런타임은 이 패턴을 감지해야 합니다.
- 프롬프트 루프 (Prompt loops)
에이전트는 때때로 거의 같은 것을 반복적으로 요청합니다.
if (similarToRecentPrompt(currentPrompt, previousPrompts)) {
return {
allowed: false,
reason: "similar_prompt_loop",
};
}
만약 프롬프트가 의미 있게 변하지 않는다면, 모델 라우팅 (model route)이 주요 문제가 아닐 수 있습니다.
에이전트가 정체되었을 수 있습니다.
- 진전 없음 (No progress)
실행 (run)이 진행 중이더라도 개선이 없을 수 있습니다.
유용한 진전 신호 (progress signals)는 다음과 같습니다:
- 테스트 통과 (tests passing)
- 에러 감소 (errors decreasing)
- 파일의 의미 있는 변경 (files changing meaningfully)
- 작업 체크리스트 항목 완료 (task checklist items completing)
- 사용자 정의 성공 기준 개선 (user-defined success criteria improving)
에이전트가 진전 없이 단계 (steps)만 소비한다면, 중단하십시오.
제어 계층화 (Layer the controls)
훌륭한 AI 에이전트 아키텍처 (AI-agent architecture)는 게이트웨이 정책 (gateway policy)과 런타임 가드 (runtime guards)를 모두 사용할 수 있습니다.
가능한 흐름 중 하나는 다음과 같습니다:
에이전트가 다음 호출을 요청함
↓
로컬 런타임 가드가 실행 상태 (run state)를 확인함
↓
게이트웨이가 모델 라우팅 (model routing) 또는 거부 규칙 (deny rules)을 적용함
↓
프로바이더 (provider)가 요청을 실행함
↓
로그와 대시보드가 결과를 기록함
순서가 중요합니다.
런타임은 실행 컨텍스트 (run context)를 가지고 있습니다.
게이트웨이는 팀 수준의 모델 정책 (team-level model policy)을 가지고 있습니다.
프로바이더는 실행합니다.
대시보드는 설명합니다.
하나의 계층에 이 네 가지 작업을 모두 수행하도록 요구하지 마십시오.
AI CostGuard의 역할
AI CostGuard는 바로 이러한 종류의 문제를 해결하기 위해 제가 구축하고 있는 로컬 우선 (local-first) TypeScript / Node.js 런타임 안전 계층 (runtime safety layer)입니다.
이는 AI 에이전트 프로젝트를 위한 호출 전 점검 (pre-call checks)에 집중합니다:
- 재시도 폭풍 (retry storms)
- 프롬프트 루프 (prompt loops)
- 최대 단계 폭발 (max-step explosions)
- 폭주하는 에이전트 실행 (runaway agent execution)
- 알 수 없는 모델 가격 (unknown model pricing)
- 예산 초과 (budget overruns)
- 통제되지 않는 프로바이더 호출 (uncontrolled provider calls)
이것은 과금 원장 (billing ledger)이 아닙니다.
이것은 엄격한 보안 경계 (hard security boundary)가 아닙니다.
프로바이더 대시보드나 게이트웨이 라우팅을 대체하지도 않습니다.
목표는 더 구체적입니다:
에이전트 런타임이 다음 프로바이더 호출을 실행할지 여부를 결정하도록 돕는 것입니다.
요점 (Takeaway)
게이트웨이 라우팅은 유용합니다.
모델 정책을 중앙 집중화합니다.
모델이 다운되었거나, 은퇴했거나, 너무 비싸거나, 승인되지 않았을 때 팀이 트래픽을 이동시키는 데 도움을 줍니다.
하지만 라우팅이 런타임 안전성 (runtime safety)을 대체할 수는 없습니다.
더 저렴한 폴백 (fallback) 모델이라도 여전히 돈을 낭비할 수 있습니다.
정책 승인을 받은 모델이라도 여전히 프롬프트 루프의 일부가 될 수 있습니다.
유효한 요청이라도 여전히 작업 예산을 초과할 수 있습니다.
AI 에이전트의 경우, 중요한 질문은 호출(call) 이전에 발생합니다:
이 요청이 존재해야 할까요?
[https://github.com/salimassili62-afk/ai-costguard]
[

AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기