모든 요청에 가장 비싼 모델을 쓰는 팀이 있습니다. 돈이 줄줄 샙니다.

반대로 전부 싼 모델에 넣는 팀도 있습니다. 실패와 재시도로 시간을 잃습니다.

정답은 중간입니다. 쉬운 일은 싼 모델, 어려운 일은 비싼 모델. 이걸 자동으로 나누는 게 모델 라우팅입니다. Luna·Sol·Astra 글의 이론을 이번에는 코드로 옮겨봅니다.

왜 지금 라우팅인가: 중간 자리가 채워졌다

9월 말에 라우팅의 재료가 좋아졌습니다.

고지능 자리: Opus 5.5 max 58점, Astra max 53점, Argon 53점
중간 자리:   GPT-6.1 Sol 52점 (Astra 대비 4분의 1 이하 비용, 9/29 투입)
             Sonnet 5.5 max 56점 (Opus xhigh와 동점)
가벼운 자리: Luna급 소형 + 캐시 + 빠른 응답

→ "위임할 중간"이 생겼으니 라우터가 값을 한다

GPT-6.1 Sol이 GPT-6 Sol을 7일 만에 교체하면서 Astra보다 1점 낮은 지능을 훨씬 싼 비용에 내놓은 게 대표적입니다. 라우터의 중간 단계로 딱 맞는 자리입니다.

라우터 구조: 4단계면 된다

요청 ──→ [1. 분류] ──→ 싼 모델 시도 ──→ [2. 자신감·검증]
                                          ├─ 통과 → 반환 + 기록
                                          └─ 실패 → [3. 승격] 비싼 모델
                                                      └─ [4. 기록] 비용·성공사례 저장

각 단계의 일을 정리하면 이렇습니다.

단계 하는 일 실패하면
1. 분류 난이도·유형 추정 (길이, 전문성, 도구 필요 여부) 기본값은 중간 등급으로
2. 시도+검증 싼 모델로 실행, 테스트·형식·근거 검사 기준 미달이면 승격
3. 승격+폴백 강한 모델로 재실행, 그래도 안 되면 사람에게 무한 재시도 금지 (상한 2회)
4. 기록 모델·effort·비용·성공 여부 로그 주 1회 보고 승격률 조정

최소 구현 예제

개념을 보여주는 작은 파이썬 스케치입니다. 그대로 운영에 쓰기보다 구조 참고용으로 보세요.

# router.py — 개념 스케치
MAX_ESCALATIONS = 2

def classify(task):
    """난이도 추정: 길고 전문적이고 도구가 필요하면 어렵다고 본다."""
    score = 0
    if len(task.instructions) > 800:
        score += 1
    if task.needs_tools or task.needs_long_context:
        score += 1
    if task.domain in ("legal", "finance", "medical", "security"):
        score += 1
    if score >= 2:
        return "strong"     # Opus급 / Astra급
    if score == 1:
        return "middle"     # GPT-6.1 Sol급 / Sonnet급
    return "light"          # Luna급 소형

def verify(result, task):
    """검증 게이트: 테스트·형식·근거 중 task에 맞는 것만."""
    checks = []
    if task.tests:
        checks.append(run_tests(result.patch))
    if task.schema:
        checks.append(matches_schema(result.output, task.schema))
    if task.requires_citation:
        checks.append(has_citation(result.output))
    return all(checks)

def route(task, call_model, log):
    tier = classify(task)
    attempts = 0
    for candidate in expand(tier):  # 예: light → middle → strong
        attempts += 1
        result = call_model(candidate, task)
        log.record(model=candidate, cost=result.cost,
                   ok=verify(result, task))
        if verify(result, task):
            return result
        if attempts > MAX_ESCALATIONS:
            break
    return escalate_to_human(task)

포인트는 세 개입니다. 분류는 단순하게, 검증은 task마다 다르게, 재시도는 상한을 둡니다. 라우터가 똑똑해질 필요는 없습니다. 검증이 엄격하면 라우터는 단순해도 됩니다.

캐싱: 라우터의 단짝

라우팅과 같이 붙이면 좋은 게 프롬프트 캐싱입니다. 반복되는 시스템 지시·문서를 캐시에 올려 입력 처리를 아낍니다.

캐시 친화적 프롬프트 구조:
[앞부분 고정: 역할·규칙·자주 쓰는 문서] → 캐시 적중
[뒷부분 가변: 이번 요청·이번 입력] → 매번 새로

효과 (10월 기준 각사 발표):
- Opus 5.5 캐시 읽기 $0.20 (95% 할인 수준)
- Gemini 4 Argon 캐시 95% 할인
- GPT-6 Astra 캐시 읽기 90% 할인

프롬프트 캐싱 글의 계산법을 라우터 로그에 붙이세요. 등급별 비용과 캐시 적중률을 같이 보면 어디가 새는지 보입니다.

CodeBridge Mini Lab: 승격률 20%를 목표로

① 2등급으로 시작 (light + strong):
   - 분류는 길이·도구 여부 2개 규칙만
   - 검증은 테스트 통과 1개만

② 2주간 로그 후 판정:
   - 승격률 50% 이상 → 분류가 너무 낙천적, 기준 강화
   - 승격률 5% 이하 → strong을 너무 안 씀, 어려운 일 샘플 확인
   - 목표: 승격률 10~20% + 성공률 유지

③ 그다음 3등급 (middle 추가):
   - GPT-6.1 Sol급 중간 모델을 승격 1단계에 배치
   - 성공 1건당 비용이 줄었는지 확인

GPT-5.6 Sol 글과 GPT-6 Sol vs Luna 글에서 말한 것처럼, 강한 모델을 모든 작업에 쓰는 게 비효율인 이유는 승격 구조로 해결됩니다.

결론: 라우터는 평가 + 예산 + 폴백이다

마지막으로 오해를 하나 풉니다. 라우터가 분류를 기가 막히게 해서 돈을 버는 게 아닙니다. 검증이 실패를 잡아내고, 상한이 폭주를 막고, 로그가 다음 주 결정을 바꾸는 구조가 돈을 법니다.

오늘 할 일은 작습니다. 등급 2개, 검증 1개, 재시도 상한 2회로 시작하세요. 2주 뒤 로그를 보면 다음에 살 중간 모델이 보입니다.

함께 읽으면 좋은 글

참고 자료

이 주제를 직접 따라가며 배우고 싶다면

분류·위임·검증을 구조로 설계하는 연습이 필요하다면, 하네스·루프·그래프를 순서대로 쌓는 과정이 이 글의 4단계 라우터와 바로 이어집니다.