에이전트의 모델 호출 중 프론티어 모델이 정말 필요한 건 얼마나 될까?
TMThttps://www.langchain.com/blog/switchyard-agent-routing-benchmark
에이전트는 LLM 호출을 아주 많이 만들어내는데, 대부분의 팀은 그 호출을 전부 같은 모델로 보냅니다. NVIDIA NeMo Switchyard는 에이전트 워크플로 단계별로 모델 선택을 자동화하는 오픈소스 모델 라우팅 라이브러리로, 프론티어 모델이 필요 없는 작업은 프론티어 모델로 가지 않게 해줍니다.
저희는 Deep Agents 평가 스위트를 Switchyard에 통과시켜, 라우터가 턴을 몇 개나 프론티어 모델로 보내는지 측정했습니다. 답은 7%였습니다. 나머지 93%는 300억 파라미터 모델이 처리했습니다. NVIDIA Nemotron 3.5 Lightning과 Claude Opus 4.8 사이를 라우팅하자 Opus 단독 실행 대비 총비용이 74% 줄었고, 같은 호출에 대한 정확도는 93% 수준으로 유지됐습니다.
아래에 측정 내용과 함께, 같은 전략을 자기 워크로드에 검토할 만한 시점을 알려주는 공식을 정리했습니다.
모델 하나만 고르는 방식의 문제
모든 호출을 한 모델로 보내는 것은 모델이 더 싸고 능력 차이도 크지 않던 시절에는 합리적인 기본값이었습니다. 이제는 상황이 달라졌습니다. 프론티어 모델은 더 비싸지고 더 유능해졌고, 오픈 웨이트 모델은 전부는 아니어도 에이전트가 하는 일의 상당 부분을 감당할 만큼 빠르고 저렴해졌습니다. 그런데도 "이 파일을 읽어라" 턴과 "이 테스트가 왜 실패하는지 알아내라" 턴은 여전히 같은 모델에 같은 토큰 단가로 갑니다. 하나는 사소한 일이고 다른 하나는 그렇지 않은데도 말입니다.
라우팅이 수지가 맞는지는 실제로 비싼 모델이 필요한 턴이 얼마나 되느냐에 달려 있습니다. 저희는 이미 Deep Agents 대상 벤치마크 스위트를 운영하고 있으므로, 그중 하나를 모델 대신 라우터에 겨눴습니다.
Switchyard가 하는 일
Switchyard는 NVIDIA의 오픈소스 라우팅 라이브러리입니다. 단계별로 설정한 전략에 따라 각 에이전트 쿼리를 폐쇄형 모델과 오픈 모델의 어떤 조합으로든 자동으로 라우팅합니다. 에이전트가 바라보는 프록시로 띄울 수도 있고, 에이전트 프로세스 안의 미들웨어로 돌릴 수도 있습니다.
라우팅 방식은 두 가지가 기본 제공되고 세 번째는 연구 단계에 있는데, 각각 지연 시간과 정확도를 서로 다르게 맞바꿉니다:
- LLM 분류기. 작은 심판(judge) 모델이 라우팅 결정에 참여합니다. 세 가지 모드 중 하나로 동작합니다. capability 모드는 호출마다 대상 모델을 고르고, escalation(에스컬레이션) 모드는 모든 작업을 저렴하게 시작했다가 나쁜 턴이 반복되면 세션을 더 큰 모델로 승격시키며, custom 모드는 직접 정의할 수 있습니다. 작은 모델 호출이 한 번 더 드는 대신 정확도의 상한이 높아집니다.
- 스테이지 라우터(휴리스틱). NVIDIA는 이를 워크플로 단계 기반 라우팅이라고 설명하는데, 오류 패턴·추론 패턴·토큰 수를 읽어 판단합니다. 추가 모델 호출이 없고 지연 비용도 거의 들지 않습니다. 다만 에이전트 트래픽이 이 라우터가 찾는 신호를 만들어낼 때만 작동하며, 이번 벤치마크에서는 다루지 않았습니다.
- 프리필 활성값 MLP. 모델 내부 신호로 라우팅합니다. 프리필 시점의 활성값 패턴을 읽습니다. 프로덕션에 쓸 단계라기보다 연구 단계이지만, NVIDIA가 탐색 중인 방향입니다.
저희가 벤치마크한 것은 에스컬레이션 모드의 LLM 분류기로, 아래 설정의 type = "llm_classifier"에 해당합니다. 에스컬레이션은 모든 작업을 저렴한 모델에서 시작합니다. 작은 심판 모델이 완료된 턴을 하나씩 읽고 에이전트가 제대로 가고 있는지 판정합니다. 부정 판정이 두 번 연속 나오면 그 작업은 이후 계속 비싼 모델로 라우팅됩니다. 한 번 넘어가면 되돌아오지 않는 구조라, 작업이 에스컬레이션된 뒤에는 심판 모델이 매 턴 돌지 않게 되어 라우팅 비용이 줄어듭니다.
에스컬레이션 라우팅: 스트라이크 두 번이면 그 작업은 세션이 끝날 때까지 비싼 모델로 넘어갑니다.
측정 내용
저희 Deep Agents 평가 스위트는 145개의 다단계 에이전트 과제로 이루어져 있고, 과제당 평균 6.3회의 모델 호출이 발생하며, 도구 작업은 실제 프로덕션 워크로드와 대응됩니다:
- 정책 제약 아래의 고객 지원 대화.
- 온콜 장애 조사.
- 메시징·이슈 트래킹·이메일을 넘나드는 다단계 워크플로 자동화.
평가는 도구 사용, 다단계 검색, 파일시스템 작업, 롱컨텍스트 요약을 아우르고, 시나리오는 τ²-bench의 항공(airline) 시나리오, Berkeley Function Calling Leaderboard, FRAMES, Nexus에서 가져왔습니다. 평가 자체는 여기에서 확인할 수 있습니다.
결과를 공유하기 전에 범위에 관해 한 가지 짚어둘 점이 있습니다. 이 평가들은 통제된 시나리오에서 실행됩니다. 그 덕에 실패의 원인을 곧바로 짚어낼 수 있다는 장점이 있지만, 그 통제의 대가로 스위트가 포화 상태이기도 합니다. 세 가지 워크로드 유형 모두에서 정확도가 높았고, 300억 파라미터 모델과 프론티어 모델의 차이는 8점에 불과했습니다. 그만큼 더 어려운 워크로드에 비해 라우팅이 가치를 증명할 여지가 적습니다. 아래 내용은 각자의 워크로드에 대한 예측이 아니라 하나의 워크로드에 대한 측정으로 받아들이기 바랍니다. 모든 비용은 캐시된 입력을 캐시 요금으로 계산했는데, 청구서에 찍히는 값이 바로 그것이기 때문입니다.
| 구성 | 정확도 | 실행당 비용 | 완료 과제당 비용 |
|---|---|---|---|
| Opus 4.8 단독 | 86.0% | $11.45 | $0.092 |
| Opus + Nemotron 3.5 Lightning (라우팅) | 80.0% | $3.00 | $0.026 |
| Nemotron 3.5 Lightning 단독 | 77.7% | $0.72 | $0.006 |
핵심 발견은 호출이 간 곳과 돈이 간 곳이 갈렸다는 점입니다. Nemotron 3.5 Lightning은 모델 호출의 93%를 처리하면서 지출의 10.4%만 썼고, Opus는 호출의 7%를 처리하면서 지출의 68.4%를 가져갔습니다. 프론티어 모델은 단일 모델 구성이 가정하는 것보다 훨씬 드물게 쓰였고, 마지막 6점의 정확도를 얻는 데는 완료 과제당 3.5배의 비용이 들었습니다.
라우팅 구성에서 모델 호출 점유율과 지출 점유율의 대비. 호출 수에는 심판이 빠져 있는데, 심판은 저렴한 등급의 턴마다 한 번씩 돕니다.
나머지 지출 21.2%는 심판 몫이었습니다. 심판은 작업이 에스컬레이션되기 전까지 매 턴 돌고, 프론티어 모델과 달리 프롬프트 캐싱의 혜택도 받지 못하기 때문에 라우팅 구성에서 두 번째로 큰 비용 항목이 됩니다. Opus 비용의 약 3분의 1 규모입니다. 그러니 라우팅 비용을 줄이고 싶다면 에스컬레이션 비율만이 아니라 심판 모델도 최적화할 가치가 있습니다.
- 정확도 손실은 실재합니다. 라우팅은 74% 저렴했고 정확도는 6점 낮았습니다. 개별 실행 간 편차가 약 2.7점이므로, 6점 차이는 그 잡음 범위를 훌쩍 벗어납니다.
- 가치는 트래픽을 프론티어 모델 쪽으로 보내는 데서가 아니라, 그쪽에서 빼내는 데서 나왔습니다. 절감은 쉬운 일을 저렴한 모델로 보낸 데서 나왔습니다. 저렴한 모델이 고전할 때 작업을 Opus로 옮기는 방식은 저렴한 모델로 전부 돌리는 것보다 2.3점 높았는데, 이는 실행 간 자연 편차보다 작아서 여기서 라우팅이 저렴한 모델을 이겼다고 말할 수는 없습니다.
- 비용은 실행 간에 안정적이었습니다. Opus 비용은 세 번의 실행에서 1.5%만 변동했으므로 74%라는 수치는 안정된 기준선 위에 서 있습니다. 실행별 절감률은 68.5%에서 81.1% 사이였는데, 그 이유는 다음 섹션에서 다룹니다.
숫자 하나가 아니라 범위로 예산을 잡으세요
다섯 번의 실행에서 프론티어 트래픽은 4.1%에서 9.1% 사이, 평균 6.9%였고, 에스컬레이션이 가장 잦았던 실행은 가장 적었던 실행보다 두 배 넘게 자주 에스컬레이션했습니다. Opus 호출 한 번은 $0.0324, Nemotron 3.5 Lightning은 $0.00037로 약 87배 차이가 나기 때문에, 이 변동이 $2.16에서 $3.61에 이르는 비용 범위를 만들었습니다. 실행 사이에 바뀐 것은 라우터가 어떤 턴을 에스컬레이션하기로 했는지뿐인데도 청구액은 67%나 움직였습니다.
라우터를 도입하면 감수하게 되는 거래가 바로 이것입니다. 평균 지출은 낮아지지만 그 주변의 변동 폭은 넓어집니다. 계획은 그 범위의 상단에 맞춰 세우세요. 범위를 좁히고 싶다면 스트라이크 횟수가 가장 지렛대 효과가 큰 설정입니다. 아래 설정의 confirmations가 그것으로, 작업을 프론티어 모델로 옮기기 전에 심판이 나쁜 턴을 몇 번 봐야 하는지를 정합니다. 이 값을 낮추면 에스컬레이션이 잦아지고, 그 호출들이 바로 비싼 호출입니다. 심판 자체가 또 하나의 지렛대입니다. 라우팅 지출의 21.2%를 차지했으므로, 더 저렴한 심판 모델을 쓰거나 명백히 잘 가고 있는 턴은 건너뛰는 심판을 쓰면 그만큼이 청구서에서 바로 빠집니다.
당연히 나올 반론
Nemotron 3.5 Lightning 단독은 실행당 $0.72에 77.7%를 기록했습니다. Opus 단독은 $11.45에 86.0%, 라우팅은 $3.00에 80.0%였습니다. 그렇다면 모델 라우터를 대체 왜 쓰는 걸까요?
라우팅은 저렴한 모델보다 2.3점 높았고 비용은 4.2배였습니다. 그 격차는 실행 간 자연 편차인 2.7점보다 작으므로, 여기서 라우팅이 저렴한 모델을 이겼다고 말할 수는 없습니다. 저렴한 모델이 선전했다는 점은 분명히 말해둘 만합니다. 이 스위트에서 Nemotron 3.5 Lightning과 프론티어 모델의 차이는 8점뿐입니다. 다만 이것은 하나의 워크로드일 뿐이니, 행동에 옮기기 전에 각자의 워크로드로 확인하세요.
이 비교에는 사후 확신도 섞여 있습니다. 저희는 이 145개 과제가 어떻게 끝났는지 이미 알고 있습니다. 프로덕션에서는 방금 도착한 요청이 쉬운지 어려운지 알 수 없고, 저렴한 모델로 전부 돌린다는 것은 어려운 요청에 대해서도 그 모델의 답을 받아들인다는 뜻입니다. 라우팅은 추측하지 않아도 되는 대가이며, 비용의 상한도 낮춰줍니다. 최악의 라우팅 실행이 $3.61로, Opus 단독의 약 3분의 1이었습니다.
그러니 최소 비용이 최우선이고 트래픽이 이 워크로드와 비슷하다면 Nemotron 3.5 Lightning 단독이 더 나은 선택입니다. 라우팅은 어려운 요청에는 프론티어 능력이 필요하지만 어떤 요청이 어려운지 미리 알 수 없는 팀을 위한 것입니다.
이 거래가 자기 워크로드에서 해볼 만한지
라우터가 프론티어 모델 단독 대비 총비용을 줄여주는 것은, 작은 모델로 넘기는 턴의 비율이 다음 기준선을 넘을 때뿐입니다:
최소 오프로드 비율 = 심판 비용 / (비싼 모델 비용 - 저렴한 모델 비용)
심판은 모든 실행에 붙는 고정 세금입니다. 결국 에스컬레이션이 일어나든 아니든, 작업이 에스컬레이션되기 전까지 매 턴 돕니다. 그래서 질문은 "내 저렴한 모델이 충분히 좋은가?"가 아닙니다. "두 모델의 가격 차이가 심판 비용을 감당할 만큼 넓은가?"입니다.
저희 조합에서는 심판 모델이 실행당 $0.64, 가격 차이가 $10.73이라 턴의 5.9%만 넘기면 됐습니다. 실제로는 93%를 넘겨 기준선을 16배 차이로 통과했습니다. 아슬아슬한 승부가 아니었으니, 이렇게 격차가 큰 조합에서는 공식이 형식적인 절차에 가깝습니다. 공식이 더 쓸모 있는 것은 답이 덜 자명한, 가격 차이가 좁은 조합에서입니다.
공식은 라우팅을 배제하는 데도 쓸 수 있습니다. 두 모델의 가격이 비슷하면 턴 하나를 넘길 때의 절감이 작아서, 공식이 턴의 100%가 넘는 비율을 저렴한 모델로 보내라고 요구하게 되는데, 이는 불가능합니다. 어떤 심판 설정으로도 해결되지 않습니다. 예외는 로컬에서 직접 호스팅하는 저렴한 모델입니다. NVIDIA DGX Spark 같은 장비에서 직접 돌리면 추론 비용이 0에 가까워져, 격차가 다시 라우팅이 남는 수준으로 벌어집니다.
공식은 이 라우터가 실제 트래픽에서 좋은 선택을 내릴지는 말해주지 못합니다. 좋은 선택에 돈을 낼 가치가 있는지만 말해줍니다. 비용 관점에서 라우팅을 배제하는 데 공식을 쓰고, 라우팅을 채택하는 판단은 자기 워크로드를 직접 돌려서 하세요.
이 방식을 쓰지 말아야 할 때
- 지연 시간에 민감한 경우. 심판은 턴마다 붙는 두 번째 모델 호출로, 스테이지 라우터가 사실상 0인 데 비해 약 700ms가 듭니다
- 워크로드가 짧은 경우. 에스컬레이션이 읽을 만한 근거를 얻으려면 여러 턴의 궤적이 필요합니다
시작하기
Switchyard를 Deep Agents와 함께 돌리는 방법은 두 가지이고, 목적에 따라 맞는 쪽이 다릅니다.
측정 결과 재현하기
저희 수치는 에스컬레이션 모드에서 나왔는데, 이는 Switchyard 서버의 라우트 설정입니다. NVIDIA-NeMo/Switchyard에서 서버를 띄우고, 에이전트의 base_url이 서버를 향하게 한 뒤, 설정 파일에 모델들을 기술하세요.
schema_version = 1
[llm_clients.nvidia]
format = "openai_chat"
base_url = "https://integrate.api.nvidia.com/v1"
api_key_env = "NVIDIA_API_KEY"
[llm_clients.anthropic]
format = "anthropic_messages"
base_url = "https://api.anthropic.com"
api_key_env = "ANTHROPIC_API_KEY"
[llm_clients.gemini]
format = "openai_chat"
base_url = "https://generativelanguage.googleapis.com/v1beta/openai"
api_key_env = "GOOGLE_API_KEY"
[targets.weak]
id = "nvidia/nemotron-3.5-lightning-30b-a3b"
llm_client = "nvidia"
[targets.strong]
id = "claude-opus-4-8"
llm_client = "anthropic"
[targets.judge]
id = "gemini-3.1-flash-lite"
llm_client = "gemini"
[routes.switchyard]
id = "switchyard"
type = "llm_classifier"
mode = "escalation"
weak_target = "weak"
strong_target = "strong"
classifier_target = "judge"
[routes.switchyard.escalation]
confirmations = 2 # 강한 모델로 전환하기 전까지의 스트라이크 횟수Switchyard가 형식 간 변환을 맡기 때문에, 위의 세 모델이 각각 OpenAI Chat, Anthropic Messages, OpenAI Chat 형식을 쓰더라도 에이전트는 OpenAI Chat 하나만 쓰면 됩니다.
에이전트 안에서 라우팅하기
이제 Deep Agents용 Switchyard 미들웨어도 있습니다. 라우팅이 프로세스 안에서 일어나므로 따로 띄울 서비스가 없고, 어떤 LangChain 챗 모델이든 라우팅 대상이 될 수 있습니다. 도구 바인딩, 콜백, 트레이싱, 구조화 출력이 모두 그대로 동작하고, 모든 응답의 response_metadata["switchyard"]에 라우팅 트레이스가 실립니다. 최종 선택은 selected_model에 담기고, 알고리즘이 여러 번 결정한 경우에는 순서가 보존된 트레이스가 decisions에 담깁니다.
from deepagents import create_deep_agent
from langchain_openrouter import ChatOpenRouter
from switchyard.libsy import LlmTarget, algorithms
from langchain_nvidia_switchyard import LangChainLlmClient, SwitchyardRoutingMiddleware
# 라우팅할 모델 쌍은 원하는 대로 바꿔 넣으세요.
efficient_model = ChatOpenRouter(model="nvidia/nemotron-3.5-lightning-30b-a3b")
capable_model = ChatOpenRouter(model="anthropic/claude-opus-4.8")
# 인자 순서가 중요합니다: 유능한(capable) 대상이 먼저, 효율적인(efficient) 대상이 그다음입니다.
router = algorithms.stage_router(
LlmTarget("capable", LangChainLlmClient(capable_model)),
LlmTarget("efficient", LangChainLlmClient(efficient_model)),
picker="efficient_first",
confidence_threshold=0.5,
recent_window=3,
)
# Deep Agents에는 여전히 기본 모델이 필요합니다. 미들웨어가 호출마다 자체 선택으로
# 대체하므로, 설정해둔 대상을 재사용하면 쓰이지 않는 세 번째 모델이 생기지 않습니다.
agent = create_deep_agent(
model=efficient_model,
middleware=[SwitchyardRoutingMiddleware(router)],
)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Summarize the important files in this project."}]}
)이 미들웨어는 실험 단계이며 아직 패키지로 배포되지 않았습니다. Switchyard와 langchain-nvidia를 둘 다 클론해서 로컬에 설치해야 하고, Python 3.12 이상과 deepagents 0.7.4 이상이 필요합니다. 제공되는 알고리즘은 스테이지 라우팅, LLM 작업 분류기, 랜덤, 무동작(noop)입니다. 저희 수치는 서버의 LLM 분류기 라우트를 에스컬레이션 모드로 돌려 얻은 것인데, 이는 미들웨어 알고리즘이 아니라 라우트 설정이므로 위 예제로는 그대로 재현되지 않습니다. 스테이지 라우팅은 도구 호출과 도구 결과 신호를 단서로 삼기 때문에, 코딩 에이전트처럼 도구 트래픽이 밀집된 에이전트에 잘 맞습니다.
다음으로 실험해볼 것들
- 더 저렴하거나 로컬에서 호스팅하는 심판. 라우팅 지출의 21.2%를 차지하는 만큼, 이 구성에서 가장 개선 여지가 뚜렷한 부분입니다.
- 더 어려운 워크로드. 이 스위트는 포화 상태이고, 라우팅은 모델 간 격차가 더 벌어진 곳에서 증명할 것이 더 많습니다.
- confirmations = 1. 여기서는 모든 구성이 스트라이크 2회로 돌았기 때문에, 이 설정이 중요하다는 것까지는 말할 수 있어도 얼마나 중요한지는 말할 수 없습니다.
자기 작업으로 직접 돌려보세요. 공식은 일반적이지만, 거기에 넣을 숫자는 각자의 것입니다.