GPT-5.6와 Claude 5 시대의 Model Router: 모든 일을 상급 모델에게 시키지 않는 방법

이경규·2026년 7월 28일

GPT-5.6와 Claude 5 시대의 Model Router: 모든 일을 상급 모델에게 시키지 않는 방법

GPT-5.6과 Claude 5 세대가 나오면서 모델 선택이 오히려 더 복잡해졌다.

예전에는 대략 이런 식이었다.

빠른 모델
vs
똑똑한 모델

지금은 그렇지 않다.

OpenAI에는 GPT-5.6 Sol, Terra, Luna가 있고 Claude에는 Fable 5, Opus 5, Sonnet 5, Haiku 4.5가 있다.

여기에 reasoning effort까지 붙는다.

low
medium
high
xhigh
max

장시간 Agent인지, 실시간 응답인지, Tool을 얼마나 많이 호출하는지, Context가 얼마나 큰지도 모델 선택에 영향을 준다.

그래서 앞으로 Agent Runtime에서 모델을 이렇게 고정하는 방식은 좋지 않다.

const MODEL = "gpt-5.6-sol";

모든 작업을 가장 강한 모델에게 보내는 것도 답이 아니다.

간단한 JSON 정리까지 최고급 모델이 처리하면 비용과 지연 시간이 커진다.

반대로 대규모 리팩터링이나 장시간 Agent 작업을 지나치게 작은 모델에게 맡기면 재시도와 Tool 호출이 늘어 결국 전체 비용이 더 커질 수도 있다.

이제 필요한 것은 Model Router다.

Task
↓
Task 분석
↓
Complexity / Latency / Risk / Budget / Horizon
↓
Model Router
↓
적절한 모델 + Reasoning Effort
↓
Agent 실행

이번 글에서는 GPT-5.6과 Claude 5 세대를 기준으로 실제 Agent Runtime에서 사용할 수 있는 Model Router를 만들어본다.


1. 먼저 현재 모델 구조부터 정리한다

2026년 7월 기준 OpenAI의 GPT-5.6 계열은 세 단계로 나뉜다.

GPT-5.6 Sol
→ 복잡한 전문 작업과 고난도 추론

GPT-5.6 Terra
→ 성능과 비용의 균형

GPT-5.6 Luna
→ 저비용·대량 처리

API 모델 ID는 다음과 같다.

gpt-5.6-sol
gpt-5.6-terra
gpt-5.6-luna

gpt-5.6 alias는 현재 Sol을 가리킨다.

세 모델 모두 최대 약 105만 토큰 Context Window와 128K 출력 한도를 제공한다.

Claude도 역할이 나뉜다.

Claude Fable 5
→ 가장 어려운 장시간 Agent 작업

Claude Opus 5
→ 복잡한 Agent Coding과 Enterprise 작업

Claude Sonnet 5
→ 속도와 성능의 균형

Claude Haiku 4.5
→ 빠르고 대량 처리하기 좋은 경량 모델

API ID는 다음과 같다.

claude-fable-5
claude-opus-5
claude-sonnet-5
claude-haiku-4-5

Fable 5, Opus 5, Sonnet 5는 100만 토큰 Context Window와 최대 128K 출력을 지원한다.

이 구조만 봐도 한 가지가 보인다.

최고 모델 하나를 정해서 쓰는 시대
↓
작업별 모델을 선택하는 시대

2. 가격 차이도 상당하다

2026년 7월 현재 GPT-5.6 API 가격은 100만 토큰 기준 다음과 같다.

GPT-5.6 Sol

Input   $5
Output  $30
GPT-5.6 Terra

Input   $2.50
Output  $15
GPT-5.6 Luna

Input   $1
Output  $6

Sol과 Luna의 출력 가격은 5배 차이다.

Claude 역시 모델별 차이가 있다.

Claude Fable 5

Input   $10
Output  $50
Claude Opus 5

Input   $5
Output  $25
Claude Sonnet 5

Input   $2
Output  $10

Sonnet 5의 $2 / $10은 2026년 8월 31일까지 적용되는 출시 가격이고, 9월 1일부터는 $3 / $15가 예정되어 있다.

Haiku 4.5는

Input   $1
Output  $5

수준이다.

단순히 가격만 보면 작은 모델이 무조건 좋아 보인다.

하지만 Agent에서는 그렇게 계산하면 안 된다.


3. Agent 비용은 토큰 가격만 보면 틀린다

예를 들어 어려운 버그 수정 작업이 있다고 하자.

작은 모델을 사용했을 때 다음처럼 움직일 수 있다.

Repository 탐색

→ 잘못된 파일 수정

→ 테스트 실패

→ 다시 탐색

→ 수정

→ 테스트 실패

→ 다시 수정

→ Reviewer 재검토

큰 모델은 한 번에 다음처럼 끝낼 수도 있다.

Repository 탐색

→ 핵심 파일 판단

→ 수정

→ 테스트

→ 완료

그래서 Agent 비용은 이런 식으로 봐야 한다.

실제 작업 비용

=
모델 토큰 비용
+
Tool 호출 비용
+
재시도 비용
+
Subagent 비용
+
실행 시간
+
실패 후 복구 비용

Model Router가 필요한 이유가 바로 이것이다.

가장 싼 모델을 선택하는 것이 아니라

작업을 성공시키는 데 필요한 총비용이 가장 낮은 모델을 선택해야 한다.


4. 처음에는 네 가지 작업 등급이면 충분하다

복잡한 AI Router부터 만들 필요 없다.

Task를 네 단계 정도로 나누는 것으로 시작할 수 있다.

SIMPLE

STANDARD

COMPLEX

LONG_HORIZON

SIMPLE

파일 하나 확인
짧은 설명
형식 변환
간단한 코드 변경
문서 정리
반복 작업

STANDARD

일반 기능 구현
Bug Fix
테스트 추가
몇 개 파일 수정
일반적인 PR 리뷰

COMPLEX

여러 Module을 건드리는 작업
Architecture 변경
복잡한 Debugging
대규모 Refactoring
보안 검토
고난도 코드 분석

LONG_HORIZON

수십 분 이상 실행

큰 Repository 분석

대규모 Migration

여러 단계의 Research

다수 Tool 사용

Subagent 협업

장시간 Coding Agent

이것만 있어도 기본 Model Router를 만들 수 있다.


5. 첫 번째 Router는 아주 단순하게 만든다

OpenAI만 사용한다면 이렇게 시작할 수 있다.

type TaskComplexity =
  | "simple"
  | "standard"
  | "complex"
  | "long_horizon";

type OpenAIModel =
  | "gpt-5.6-luna"
  | "gpt-5.6-terra"
  | "gpt-5.6-sol";

function selectOpenAIModel(
  complexity: TaskComplexity
): OpenAIModel {
  switch (complexity) {
    case "simple":
      return "gpt-5.6-luna";

    case "standard":
      return "gpt-5.6-terra";

    case "complex":
    case "long_horizon":
      return "gpt-5.6-sol";
  }
}

Claude만 사용한다면 비슷하다.

type ClaudeModel =
  | "claude-haiku-4-5"
  | "claude-sonnet-5"
  | "claude-opus-5"
  | "claude-fable-5";

function selectClaudeModel(
  complexity: TaskComplexity
): ClaudeModel {
  switch (complexity) {
    case "simple":
      return "claude-haiku-4-5";

    case "standard":
      return "claude-sonnet-5";

    case "complex":
      return "claude-opus-5";

    case "long_horizon":
      return "claude-fable-5";
  }
}

실제 운영에서는 이것보다 조건이 더 필요하지만 출발점으로는 충분하다.


6. 하지만 Complexity만으로 고르면 금방 문제가 생긴다

다음 두 작업을 생각해보자.

작업 A

Swift 파일 100개를 읽고
deprecated API 사용 여부를 찾아 목록으로 만들어라.

파일은 많지만 판단 자체는 단순하다.

작업 B

AuthManager.swift에서 가끔 발생하는
Race Condition 원인을 찾아 수정해라.

파일은 몇 개 안 되지만 추론 난이도가 높다.

둘 다 단순히 파일 개수로 판단하면 안 된다.

그래서 Router 입력을 조금 더 구조화한다.

type TaskProfile = {
  complexity: number;
  latencySensitivity: number;
  risk: number;
  toolDepth: number;
  contextSize: number;
  expectedDuration: number;
  volume: number;
};

각 값은 1~5 정도로 두면 된다.


7. Task Profile을 만든다

예를 들어 간단한 반복 작업은 다음과 같다.

const simpleTask: TaskProfile = {
  complexity: 1,
  latencySensitivity: 5,
  risk: 1,
  toolDepth: 1,
  contextSize: 1,
  expectedDuration: 1,
  volume: 5
};

대규모 리팩터링은 다르다.

const refactoringTask: TaskProfile = {
  complexity: 5,
  latencySensitivity: 1,
  risk: 4,
  toolDepth: 5,
  contextSize: 5,
  expectedDuration: 5,
  volume: 1
};

Router가 이 정보를 기반으로 판단한다.


8. 실전에서는 모델과 Effort를 같이 고른다

GPT-5.6에서는 모델 선택만큼 reasoning.effort도 중요하다.

현재 GPT-5.6은 다음 수준을 지원한다.

none
low
medium
high
xhigh
max

그래서

Terra냐 Sol이냐

만 판단할 것이 아니라

Terra + low

Terra + medium

Sol + high

Sol + max

까지 같이 판단해야 한다.

예를 들어 일반적인 기능 구현이라면

GPT-5.6 Terra
+
medium

으로 시작할 수 있다.

복잡한 Architecture 문제라면

GPT-5.6 Sol
+
high

가 적합한 후보가 된다.

아주 어려운 분석이라면

GPT-5.6 Sol
+
max

를 검토한다.

중요한 것은 처음부터 무조건 max를 사용하지 않는 것이다.


9. Claude Opus 5도 Effort를 조절할 수 있다

Claude Opus 5 역시 최신 API에서 effort를 주요 제어 수단으로 사용한다.

지원 단계는 다음과 같다.

low
medium
high
xhigh
max

Anthropic은 기본적으로 high에서 시작하고, 실제 Eval 결과에 따라 낮추거나 높이는 방식을 권장한다.

예를 들어

일반 코드 분석
→ Sonnet 5

복잡한 Agent Coding
→ Opus 5 high

매우 어려운 추론
→ Opus 5 xhigh / max

장시간 고난도 Agent
→ Fable 5

같은 식으로 나눌 수 있다.


10. Model Router가 선택해야 하는 것은 사실 두 개다

이제 Router 결과를 다음처럼 만든다.

type ModelSelection = {
  provider: "openai" | "anthropic";
  model: string;
  effort:
    | "none"
    | "low"
    | "medium"
    | "high"
    | "xhigh"
    | "max";
};

예를 들어

{
  "provider": "openai",
  "model": "gpt-5.6-terra",
  "effort": "medium"
}

또는

{
  "provider": "anthropic",
  "model": "claude-opus-5",
  "effort": "high"
}

처럼 반환한다.

Router가 모델 이름만 선택하는 구조보다 훨씬 유연하다.


11. 가장 먼저 Latency를 본다

사용자가 기다리고 있는 작업과 백그라운드 Agent 작업은 요구사항이 다르다.

예를 들어 IDE 안에서 코드 한 줄을 설명하는 기능은 빠른 응답이 중요하다.

사용자 요청

→ 1~2초 내 반응 기대

이런 작업에서 최고급 long-horizon 모델을 사용할 이유는 적다.

후보는 다음처럼 잡을 수 있다.

GPT-5.6 Luna

Claude Haiku 4.5

조금 더 판단이 필요하다면

GPT-5.6 Terra

Claude Sonnet 5

정도가 된다.

반대로 사용자가

이 Repository 전체를 분석해서
Concurrency 구조를 개선하고
테스트까지 수정해줘.

라고 했다면 latency보다 성공률이 중요하다.

이때는

GPT-5.6 Sol

Claude Opus 5

Claude Fable 5

같은 모델이 후보가 된다.


12. 다음은 Risk다

같은 난이도의 작업이라도 위험도가 다르다.

예를 들어

README 수정

결제 로직 수정

은 Complexity가 비슷할 수 있다.

하지만 Risk는 전혀 다르다.

그래서 Router에 Risk를 넣는다.

type RiskLevel =
  | "low"
  | "medium"
  | "high"
  | "critical";

높은 Risk에서는 모델을 한 단계 올릴 수 있다.

Standard + Low Risk

→ Terra
Standard + High Risk

→ Sol

또는

Sonnet 5
→ Opus 5

로 승격한다.

하지만 여기서 중요한 것이 하나 있다.

고위험 작업을 강한 모델에게 보낸다고 안전해지는 것은 아니다.

사람 승인과 테스트가 별도로 필요하다.

High Risk

→ Strong Model
→ Test
→ Review
→ Human Approval

모델 선택은 안전 정책을 대체하지 않는다.


13. Long-Horizon 여부는 별도로 판단한다

Task Complexity와 Task Duration은 다르다.

예를 들어

1만 개 파일에서 특정 패턴을 찾아라.

는 판단은 단순하지만 오래 걸릴 수 있다.

반대로

작은 Race Condition 하나를 분석해라.

는 짧지만 매우 어려울 수 있다.

그래서 Router에는 horizon을 별도로 둔다.

type TaskHorizon =
  | "short"
  | "medium"
  | "long";

장시간 Agent라면 단순 모델 성능뿐 아니라 다음 항목도 본다.

Tool 사용 안정성

Context 유지

Checkpoint

Recovery

Subagent

Budget

Timeout

Artifact 관리

Claude Fable 5가 공식적으로 long-running agent를 주요 용도로 두는 이유도 여기 있다.

GPT-5.6 Sol 역시 long-horizon 전문 작업과 Agent workflow를 중요한 사용처로 두고 있다.


14. Tool Depth도 중요한 Router 신호다

Tool 호출이 한두 번인 작업과 수십 번인 작업은 다르다.

Task A

read_file
→ answer
Task B

read_file
→ git_diff
→ test
→ read_log
→ edit_file
→ test
→ shell
→ git_diff
→ reviewer
→ fix
→ test

두 번째 작업에서는 모델의 Tool 사용 능력이 전체 성공률에 큰 영향을 준다.

그래서 다음 값을 둔다.

type ToolDepth =
  | "shallow"
  | "medium"
  | "deep";

deep이면 한 단계 높은 모델로 올릴 수 있다.


15. Context가 크다고 무조건 최고 모델이 필요한 것은 아니다

GPT-5.6 계열은 약 105만 토큰, Claude 5 주요 모델들은 100만 토큰 Context를 지원한다.

그렇다고 Repository 전체를 항상 Context에 넣는 것은 좋은 설계가 아니다.

예를 들어

800K Context
+
간단한 파일 분류

라면 가장 강한 모델이 필요한 것은 아니다.

Model Router와 Context Router를 분리해야 한다.

Task Router
→ 어떤 모델?

Context Router
→ 어떤 정보를 넣을까?

큰 Context Window는

다 넣어도 된다.

는 뜻이 아니라

필요할 때 더 많이 넣을 수 있다.

는 의미로 보는 편이 좋다.


16. 실제 Router 점수를 만들어보자

간단한 점수 기반 Router를 만들 수 있다.

function calculateTaskScore(
  task: TaskProfile
): number {
  return (
    task.complexity * 3 +
    task.risk * 2 +
    task.toolDepth * 2 +
    task.contextSize +
    task.expectedDuration * 2 -
    task.latencySensitivity
  );
}

점수에 따라 모델을 선택한다.

function routeOpenAI(
  task: TaskProfile
): ModelSelection {
  const score = calculateTaskScore(task);

  if (score <= 10) {
    return {
      provider: "openai",
      model: "gpt-5.6-luna",
      effort: "low"
    };
  }

  if (score <= 24) {
    return {
      provider: "openai",
      model: "gpt-5.6-terra",
      effort: "medium"
    };
  }

  if (score <= 34) {
    return {
      provider: "openai",
      model: "gpt-5.6-sol",
      effort: "high"
    };
  }

  return {
    provider: "openai",
    model: "gpt-5.6-sol",
    effort: "max"
  };
}

이 숫자가 정답이라는 뜻은 아니다.

실제 프로젝트에서는 Eval 결과로 조정해야 한다.


17. Claude Router도 같은 방식으로 만든다

function routeClaude(
  task: TaskProfile
): ModelSelection {
  const score = calculateTaskScore(task);

  if (score <= 10) {
    return {
      provider: "anthropic",
      model: "claude-haiku-4-5",
      effort: "low"
    };
  }

  if (score <= 24) {
    return {
      provider: "anthropic",
      model: "claude-sonnet-5",
      effort: "medium"
    };
  }

  if (score <= 34) {
    return {
      provider: "anthropic",
      model: "claude-opus-5",
      effort: "high"
    };
  }

  return {
    provider: "anthropic",
    model: "claude-fable-5",
    effort: "max"
  };
}

실제 Claude API에서 모델별 effort 지원 방식이 다르므로 Adapter에서 최종 요청 파라미터를 변환하는 편이 좋다.

Router가 Provider API 세부 구현까지 알게 만들 필요는 없다.


18. Router와 Provider Adapter를 분리한다

구조는 이렇게 만든다.

Task

↓️

Task Classifier

↓️

Model Router

↓️

ModelSelection

↓️

Provider Adapter

├── OpenAI Adapter
└── Anthropic Adapter

폴더 구조도 분리한다.

src/
├── routing/
│   ├── TaskClassifier.ts
│   ├── ModelRouter.ts
│   ├── RoutingPolicy.ts
│   └── ModelCatalog.ts
│
├── providers/
│   ├── openai/
│   │   └── OpenAIAdapter.ts
│   │
│   └── anthropic/
│       └── AnthropicAdapter.ts
│
└── runtime/
    └── AgentRuntime.ts

이렇게 해야 나중에 모델이 바뀌어도 Runtime 전체를 수정하지 않는다.


19. 모델 정보는 코드에 흩어놓지 않는다

Model Catalog를 따로 관리한다.

type ModelCapability = {
  provider: "openai" | "anthropic";
  model: string;

  tier:
    | "fast"
    | "balanced"
    | "advanced"
    | "frontier";

  longHorizon: boolean;
  toolUse: boolean;
  maxContextTokens: number;
  maxOutputTokens: number;

  inputCostPerMTok: number;
  outputCostPerMTok: number;
};

예를 들어

const models: ModelCapability[] = [
  {
    provider: "openai",
    model: "gpt-5.6-luna",
    tier: "fast",
    longHorizon: false,
    toolUse: true,
    maxContextTokens: 1_050_000,
    maxOutputTokens: 128_000,
    inputCostPerMTok: 1,
    outputCostPerMTok: 6
  },

  {
    provider: "openai",
    model: "gpt-5.6-terra",
    tier: "balanced",
    longHorizon: true,
    toolUse: true,
    maxContextTokens: 1_050_000,
    maxOutputTokens: 128_000,
    inputCostPerMTok: 2.5,
    outputCostPerMTok: 15
  },

  {
    provider: "openai",
    model: "gpt-5.6-sol",
    tier: "frontier",
    longHorizon: true,
    toolUse: true,
    maxContextTokens: 1_050_000,
    maxOutputTokens: 128_000,
    inputCostPerMTok: 5,
    outputCostPerMTok: 30
  }
];

Claude 모델도 같은 Catalog에 추가한다.


20. 가격은 Config로 빼는 게 좋다

가격은 바뀐다.

특히 현재 Claude Sonnet 5처럼 기간 한정 가격이 적용되는 경우가 있다.

그래서 Application 코드 안에 가격을 박아두지 않는다.

{
  "pricingVersion": "2026-07-28",
  "models": {
    "gpt-5.6-sol": {
      "input": 5,
      "output": 30
    },
    "gpt-5.6-terra": {
      "input": 2.5,
      "output": 15
    },
    "gpt-5.6-luna": {
      "input": 1,
      "output": 6
    },
    "claude-fable-5": {
      "input": 10,
      "output": 50
    },
    "claude-opus-5": {
      "input": 5,
      "output": 25
    },
    "claude-sonnet-5": {
      "input": 2,
      "output": 10
    }
  }
}

파일 이름도 날짜를 포함할 수 있다.

model-pricing-2026-07-28.json

가격 변경 시 Router 코드를 수정할 필요가 없다.


21. 비용 상한도 Router에 넣는다

사용자가 다음 작업을 요청했다고 하자.

Repository 전체를 분석해서
Architecture 개선안을 만들어줘.

Router는 Sol 또는 Fable을 선택할 수 있다.

하지만 Task Budget이 아주 낮다면 문제가 된다.

type TaskBudget = {
  maxCostUsd: number;
  maxDurationSeconds: number;
};

예를 들어

{
  "maxCostUsd": 0.5,
  "maxDurationSeconds": 120
}

이라면 Router는 모델을 낮추거나 작업을 분할해야 한다.

Requested

Sol + max

Budget Check

↓️

Budget 초과 예상

↓️

Terra + medium

또는

Task 분할

Model Routing과 Budget Engineering이 연결되는 지점이다.


22. Router가 무조건 작은 모델부터 시작하게 만들 필요는 없다

많이 사용하는 방식 중 하나가

작은 모델
→ 실패
→ 큰 모델

이다.

항상 좋은 것은 아니다.

복잡한 작업인데 처음부터 Luna를 보내면

Luna 실패

→ Terra 재시도

→ Sol 재시도

로 Context와 Tool 비용을 세 번 쓸 수 있다.

Task Classifier가 복잡한 작업이라고 확신한다면 처음부터 적절한 모델로 보내는 것이 낫다.

High Confidence Complex

→ Sol

또는

→ Opus

Escalation은 불확실한 작업에서만 사용한다.


23. 반대로 결과가 쉬우면 Downshift한다

Model Router는 위로만 올라갈 필요가 없다.

예를 들어 Sol에게 작업 계획을 맡겼다고 하자.

Sol

→ Task 분석

→ 47개의 단순 파일 수정으로 분해

실제 Subtask는 Terra나 Luna가 수행할 수 있다.

Sol

Planner
│
├── Luna
├── Luna
├── Terra
└── Luna

Claude에서도 같은 구조가 가능하다.

Opus / Fable

Planner
│
├── Sonnet
├── Sonnet
└── Haiku

큰 모델은 어려운 판단에 쓰고 반복 실행은 작은 모델에게 맡긴다.

이게 Multi-Agent에서 Model Router가 특히 중요한 이유다.


24. Planner와 Worker의 모델을 다르게 둔다

다음 구조를 생각해보자.

Planner

→ 작업 분석

→ Subtask 생성

Worker

→ 실제 실행

Planner는 높은 reasoning이 필요할 수 있다.

Sol high

또는

Opus high

Worker는 단순할 수 있다.

Terra medium

Sonnet 5

대량 Worker라면

Luna

Haiku

까지 내려갈 수 있다.

예를 들어

Architecture Migration

Sol
↓
50개 파일 작업 계획

Terra Worker × 5
↓
수정

Sol Reviewer
↓
최종 검증

처럼 구성할 수 있다.


25. Reviewer 역시 무조건 최고 모델일 필요는 없다

Review 유형도 나눈다.

Style Review
→ 작은 모델

Scope Review
→ Balanced 모델

Architecture Review
→ Advanced 모델

Security Critical Review
→ Frontier 모델 + 사람

예를 들어

Formatting
→ Luna

일반 PR Review
→ Terra / Sonnet

대규모 Architecture 변경
→ Sol / Opus

장시간 전체 Repository Review
→ Fable

정도로 시작할 수 있다.


26. Provider까지 자동으로 고르는 Router

OpenAI와 Claude를 모두 사용한다면 Router가 Provider까지 고를 수도 있다.

다만

GPT가 더 좋다.

Claude가 더 좋다.

같은 고정 규칙을 만들면 안 된다.

자신의 실제 작업 Eval을 사용한다.

예를 들어 내부 결과가 이런 식이라고 해보자.

{
  "ios_bug_fix": {
    "openai_success_rate": 0.93,
    "anthropic_success_rate": 0.91
  },

  "architecture_review": {
    "openai_success_rate": 0.88,
    "anthropic_success_rate": 0.95
  }
}

Router는 이 데이터를 사용할 수 있다.


27. Task Type도 중요한 Feature다

type TaskType =
  | "coding"
  | "debugging"
  | "review"
  | "planning"
  | "documentation"
  | "data"
  | "computer_use";

그리고 Routing Policy를 만든다.

routing:

  coding:
    default:
      provider: openai
      model: gpt-5.6-terra

  debugging:
    complex:
      provider: openai
      model: gpt-5.6-sol

  review:
    default:
      provider: anthropic
      model: claude-sonnet-5

  planning:
    complex:
      provider: anthropic
      model: claude-opus-5

  long_horizon:
    provider: anthropic
    model: claude-fable-5

이건 어디까지나 예시다.

실제 정책은 팀의 Eval 결과에 맞춰야 한다.


28. Model Router가 스스로 모델을 선택하게 하지 않는다

여기서 흔히 생기는 설계가 있다.

LLM에게 물어본다.

"어떤 모델을 사용할까요?"

그리고 LLM이

이건 어려우니까 최고 모델을 사용하겠습니다.

라고 판단한다.

문제가 있다.

모델은 비용 정책을 정확히 알지 못할 수 있고 자기 자신을 과도하게 선택할 수 있다.

Model Routing의 핵심 정책은 Runtime이 가져야 한다.

Agent
→ Task Metadata 생성

Runtime
→ Router Policy 평가

Runtime
→ 모델 선택

모델은 신호를 제공할 수 있지만 최종 선택은 Runtime이 한다.


29. Router 결과에 이유를 남긴다

왜 해당 모델을 선택했는지 기록한다.

{
  "taskId": "PAP-142",
  "selection": {
    "provider": "openai",
    "model": "gpt-5.6-sol",
    "effort": "high"
  },
  "reason": {
    "complexity": 5,
    "risk": 4,
    "toolDepth": 4,
    "longHorizon": false
  }
}

나중에 분석할 수 있다.

왜 Sol이 선택됐는가?

Terra로도 가능했는가?

비용 대비 성공률은 어땠는가?

Model Router도 Observability가 필요하다.


30. 결과도 기록한다

실행이 끝난 뒤 결과를 저장한다.

{
  "taskId": "PAP-142",

  "route": {
    "model": "gpt-5.6-sol",
    "effort": "high"
  },

  "result": {
    "status": "completed",
    "durationMs": 48121,
    "toolCalls": 12,
    "retries": 0,
    "testsPassed": true
  },

  "usage": {
    "inputTokens": 42000,
    "outputTokens": 8100
  }
}

이 데이터가 쌓이면 Router를 개선할 수 있다.


31. Routing은 결국 Eval 문제다

처음에는 사람이 규칙을 만든다.

Simple
→ Luna

Standard
→ Terra

Complex
→ Sol

하지만 운영 데이터가 쌓이면 더 정확해진다.

예를 들어 1,000개 Task를 분석했더니

일반 Bug Fix

Sol
성공률 96%
평균 비용 $1.10

Terra
성공률 94%
평균 비용 $0.31

이라면 대부분의 Bug Fix는 Terra로 보내는 것이 합리적이다.

반면

Concurrency Bug

Sol
성공률 91%

Terra
성공률 63%

라면 Sol로 보내는 편이 낫다.

Router는 벤치마크보다 우리 Repository에서의 실제 성공률을 봐야 한다.


32. Task Fixture를 만든다

Router 평가용 작업을 저장한다.

.ai/
└── routing-evals/
    ├── simple/
    │   ├── rename-property.json
    │   └── document-update.json
    │
    ├── standard/
    │   ├── login-error-fix.json
    │   └── add-unit-test.json
    │
    ├── complex/
    │   ├── concurrency-bug.json
    │   └── architecture-refactor.json
    │
    └── long-horizon/
        └── repository-migration.json

각 Task에 기대 결과를 둔다.

{
  "id": "concurrency-bug",

  "expected": {
    "testsMustPass": true,
    "maxUnexpectedFiles": 0,
    "requiredFiles": [
      "FramePublisher.swift"
    ]
  }
}

모델을 바꿀 때 같은 Fixture를 실행한다.


33. Router Eval 결과

결과는 이런 형태로 저장할 수 있다.

{
  "task": "concurrency-bug",

  "results": [
    {
      "model": "gpt-5.6-terra",
      "success": false,
      "durationMs": 82103,
      "retries": 2
    },
    {
      "model": "gpt-5.6-sol",
      "success": true,
      "durationMs": 51442,
      "retries": 0
    },
    {
      "model": "claude-opus-5",
      "success": true,
      "durationMs": 59304,
      "retries": 0
    }
  ]
}

이런 데이터가 Model Router의 실제 근거가 된다.


34. Fallback도 설계해야 한다

모델 호출은 실패할 수 있다.

Rate Limit

Provider 장애

Timeout

Refusal

Context 초과

Tool 오류

그래서 Fallback Chain을 만든다.

fallbacks:

  gpt-5.6-sol:
    - claude-opus-5
    - gpt-5.6-terra

  claude-opus-5:
    - gpt-5.6-sol
    - claude-sonnet-5

  gpt-5.6-terra:
    - claude-sonnet-5

  claude-sonnet-5:
    - gpt-5.6-terra

하지만 모든 오류에서 Fallback하면 안 된다.


35. Retry와 Fallback을 구분한다

예를 들어

503 Provider Error

라면 다른 Provider로 Fallback할 수 있다.

하지만

Policy Violation

은 모델을 바꿔 우회해서는 안 된다.

function canFallback(
  errorCode: string
): boolean {
  return [
    "PROVIDER_UNAVAILABLE",
    "RATE_LIMITED",
    "TIMEOUT"
  ].includes(errorCode);
}

보안·정책 오류는 중단한다.

POLICY_DENIED

→ stop

36. GPT-5.6의 ultra는 일반 모델 이름으로 보면 안 된다

GPT-5.6에는 ultra라는 높은 Capability 설정도 등장했다.

하지만 이것을

model = "gpt-5.6-ultra"

같은 일반 API 모델로 생각하면 안 된다.

현재 OpenAI는 ChatGPT Work와 Codex의 ultra를 복잡한 작업을 여러 Agent가 병렬로 처리하는 최고 Capability 설정으로 설명하고 있다.

API에서는 Multi-Agent 기능이 별도의 beta 기능으로 제공된다.

따라서 Runtime Model Catalog에서는

Sol
Terra
Luna

를 모델 Tier로 보고,

effort
multi-agent

같은 실행 전략을 별도로 관리하는 편이 좋다.


37. Claude Fable도 항상 쓸 필요는 없다

Fable 5는 Anthropic이 가장 강한 공개 모델이자 장시간 Agent 작업을 주요 용도로 설명하는 모델이다.

그러나 일반 기능 개발까지 모두 Fable로 보내는 것은 비효율적이다.

UI 텍스트 수정

→ Fable

간단한 Unit Test

→ Fable

README 수정

→ Fable

같은 구조는 좋지 않다.

Sonnet이나 Haiku로 충분한 작업은 작은 모델로 보낸다.

Fable은

대규모 Repository 작업

오래 실행되는 Agent

복잡한 연구

중요한 장기 Planning

여러 단계의 자율 작업

같은 곳에 남겨두는 편이 낫다.


38. 처음 운영할 때 추천하는 현실적인 Router

처음부터 8개 모델을 모두 사용하면 관리하기 어렵다.

OpenAI 중심 팀이라면 세 개면 충분하다.

Luna
→ Fast

Terra
→ Default

Sol
→ Escalation

Claude 중심 팀이라면

Haiku
→ Fast

Sonnet
→ Default

Opus
→ Complex

Fable
→ Long Horizon

정도로 시작한다.

두 Provider를 모두 쓰더라도 처음에는 네 개 정도면 충분하다.

Fast
→ Luna

Default
→ Terra

Complex
→ Opus 5

Long Horizon
→ Fable 5

또는 팀 Eval 결과가 다르면 당연히 다른 조합을 선택하면 된다.


39. 제가 Agent Runtime을 만든다면

처음 버전은 다음 구조로 시작할 것 같다.

Task

↓️

Task Profiler

complexity
risk
latency
toolDepth
horizon

↓️

Policy Router

↓️

Fast
Balanced
Advanced
Frontier

↓️

Model Catalog

↓️

Provider Adapter

↓️

Agent Run

↓️

Execution Result

↓️

Routing Eval Store

폴더 구조는 다음 정도다.

src/
├── routing/
│   ├── TaskProfiler.ts
│   ├── ModelRouter.ts
│   ├── RoutingPolicy.ts
│   ├── ModelCatalog.ts
│   └── BudgetGuard.ts
│
├── providers/
│   ├── OpenAIAdapter.ts
│   └── AnthropicAdapter.ts
│
├── eval/
│   ├── RoutingEval.ts
│   └── TaskFixtures.ts
│
└── runtime/
    └── AgentRuntime.ts

Router는 Agent Prompt와 분리한다.

이게 중요하다.


40. 가장 중요한 원칙

Model Router를 만들 때 처음부터 AI가 알아서 완벽한 모델을 선택하게 만들 필요는 없다.

오히려 작은 규칙부터 시작한다.

1.

Default 모델을 정한다.

2.

빠른 작업은 아래 모델로 내린다.

3.

어려운 작업만 위 모델로 올린다.

4.

장시간 작업은 별도로 분류한다.

5.

실제 성공률과 비용을 기록한다.

6.

Eval 데이터를 기준으로 Router를 수정한다.

예를 들어 처음에는

OpenAI

Default
→ Terra

Fast
→ Luna

Complex
→ Sol

만으로 충분하다.

Claude라면

Default
→ Sonnet

Fast
→ Haiku

Complex
→ Opus

Long Horizon
→ Fable

정도로 시작한다.


41. 개발자가 왜 Model Router를 알아야 할까

앞으로 모델 성능은 계속 올라갈 것이다.

동시에 모델 종류도 계속 늘어난다.

Fast Model

Balanced Model

Reasoning Model

Long-Horizon Model

Computer Use Model

Multi-Agent Mode

개발자가 매번 직접 모델 이름을 선택하는 방식은 오래가기 어렵다.

애플리케이션은 사용자의 요청을 알아야 하고,

Agent Runtime은 그 작업을 수행하기에 적절한 계산량을 선택해야 한다.

결국 구조는 다음처럼 바뀐다.

사용자

"이 작업을 해줘"

↓

Agent Runtime

"이 작업은 어느 정도 어려운가?"

↓

Model Router

"이 정도 모델과 Effort면 충분하다."

↓

Model

작업 실행

Cloud에서 모든 요청을 가장 큰 서버에 보내지 않는 것과 비슷하다.

AI Agent에서도 작업에 필요한 만큼의 계산 자원을 배정해야 한다.


42. 마무리

GPT-5.6과 Claude 5 세대에서 중요한 변화는 단순히 모델이 더 똑똑해졌다는 것이 아니다.

모델 제품군 자체가 작업 성격에 따라 나뉘고 있다.

빠른 작업

균형 잡힌 일반 작업

복잡한 추론

장시간 Agent

최대 Capability

그래서 Agent Runtime도 바뀌어야 한다.

Task

→ Task Profile

→ Model Router

→ Model + Effort

→ Agent Execution

→ Result

→ Eval

→ Router 개선

모든 작업을 최고 모델에 보내는 것은 가장 쉬운 구현이지만 좋은 운영 방식은 아니다.

반대로 모든 작업을 작은 모델에 보내고 실패할 때마다 올리는 것도 비용 효율적이지 않을 수 있다.

좋은 Router는

난이도

위험도

지연 시간

Tool 깊이

Context 크기

장시간 실행 여부

Budget

실제 성공률

을 함께 본다.

그리고 가장 중요한 데이터는 제조사의 Benchmark가 아니다.

우리 서비스의 실제 Task를 어떤 모델이 얼마의 비용과 시간으로 성공시켰는가다.

한 줄로 정리하면 이렇다.

GPT-5.6와 Claude 5 시대에는
최고 모델을 고르는 능력보다
작업마다 충분한 모델을 자동으로 고르는 능력이 더 중요하다.

모델은 계속 바뀐다.

Sol 다음 버전이 나오고, Terra가 업데이트되고, Claude의 새로운 모델이 추가돼도 Router 구조가 잘 만들어져 있다면 Agent Runtime 전체를 다시 설계할 필요가 없다.

앞으로 중요한 것은 특정 모델 하나에 애플리케이션을 묶는 것이 아니라,

Task와 Model 사이에 교체 가능한 Routing Layer를 만드는 것이다.


참고 자료

  • OpenAI — GPT-5.6: Frontier intelligence that scales with your ambition
    GPT-5.6 Sol, Terra, Luna의 역할과 가격, reasoning effort, Multi-Agent 및 Agent workflow 관련 변화가 정리된 공식 발표 자료.

  • OpenAI API — Model guidance / Models
    GPT-5.6 Sol·Terra·Luna의 API Model ID, Context Window, 최대 출력, 가격과 모델 선택 가이드를 확인할 수 있는 공식 개발 문서.

  • Anthropic — Claude Models Overview
    Claude Fable 5, Opus 5, Sonnet 5, Haiku 4.5의 용도와 Context Window, 지연 특성, 가격을 비교할 수 있는 공식 문서.

  • Anthropic — What's new in Claude Opus 5
    Claude Opus 5의 effort 조절, 장시간 Agent 작업, Adaptive Thinking, Fast Mode 등 최신 Agent Runtime 관련 변경을 확인할 수 있는 자료.

핵심 참고 포인트

GPT-5.6은 Sol·Terra·Luna 세 Tier를 통해 고난도 작업부터 대량 저비용 작업까지 명확하게 역할을 나누고 있으며, reasoning effort를 none부터 max까지 별도로 조절할 수 있다.

Claude 역시 Fable·Opus·Sonnet·Haiku를 작업 특성에 따라 구분하고 있다. 특히 Fable 5는 long-running agent, Opus 5는 복잡한 agentic coding, Sonnet 5는 대부분의 production workload에서 속도와 지능의 균형을 목표로 한다.

따라서 최신 Agent Runtime에서는 Model ID 하나를 고정하기보다 Task Complexity + Effort + Budget + Horizon을 함께 판단하는 Routing Layer를 두는 것이 현실적인 방향이다.

profile
iOS 앱 개발자

0개의 댓글