Skip to content

LOCAL_LLM_HYBRID_ROUTING

playground edited this page May 27, 2026 · 4 revisions

Mac Studio ๋กœ์ปฌ LLM + Claude Opus ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ผ์šฐํŒ… ์ „๋žต โ€” ๋…ผ์˜ ์ž๋ฃŒ

โš ๏ธ ์ด ๋ฌธ์„œ๋Š” ๋…ผ์˜ยท๊ฒ€ํ† ์šฉ ์ž๋ฃŒ์ž…๋‹ˆ๋‹ค. ํ˜„์žฌ ์„ค๊ณ„ ๊ฒฐ์ •์— ๋ฐ˜์˜๋œ ๋‚ด์šฉ์ด ์•„๋‹ˆ๋ฉฐ, 7๊ฐœ ์„ค๊ณ„ deliverable์˜ ๋ถˆ๋ณ€์‹์„ ๋ฐ”๊พธ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ชจ๋ธ ์„ ํƒ(claude-opus-4-7 vs claude-sonnet-4-6)์€ SYSTEM_DESIGN ยง15์—์„œ ๋ฏธ๊ฒฐ๋กœ ๋‚จ์•„ ์žˆ์œผ๋ฉฐ, ์ด ๋ฌธ์„œ๋Š” ๋กœ์ปฌ LLM์„ ์„ธ ๋ฒˆ์งธ ํ›„๋ณด๋กœ ์ถ”๊ฐ€ ๊ฒ€ํ† ํ•˜๋Š” ๋ฉ”๋ชจ์ž…๋‹ˆ๋‹ค.

์ž‘์„ฑ์ผ: 2026-05-27

ํ˜„์žฌ orchestrator๋Š” Anthropic Claude SDK๋ฅผ ํ†ตํ•ด claude-opus-4-7 ๋˜๋Š” claude-sonnet-4-6์„ ํ˜ธ์ถœํ•œ๋‹ค (SYSTEM_DESIGN ยง15, OSS_INTEGRATION ยง3.3). "Mac Studio ์žฅ๋น„๊ฐ€ ํ™•๋ณด๋˜์–ด ์žˆ๋‹ค๋ฉด ๋กœ์ปฌ LLM์„ ๋„์ž…ํ•ด ๋น„์šฉยท์ง€์—ฐยท์˜คํ”„๋ผ์ธ ๊ฐ€์šฉ์„ฑ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€"๋ฅผ ๊ฒ€ํ† ํ•œ ๋ฉ”๋ชจ.


1. Mac Studio ํ•˜๋“œ์›จ์–ด ์—ญ๋Ÿ‰

Apple Silicon์˜ ํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ(Unified Memory) ๋Š” CPU์™€ GPU/Neural Engine์ด ๋™์ผ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ณต์œ ํ•˜๋ฏ€๋กœ, LLM ์ถ”๋ก  ์‹œ VRAM ๋ณ‘๋ชฉ ์—†์ด ์ „์ฒด RAM์„ ๋ชจ๋ธ ๊ฐ€์ค‘์น˜์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๊ฒƒ์ด ๋™๊ธ‰ ๊ฐ€๊ฒฉ๋Œ€ Windows ์›Œํฌ์Šคํ…Œ์ด์…˜ ๋Œ€๋น„ ๋กœ์ปฌ LLM ์šด์˜์—์„œ ๊ฐ€์žฅ ํฐ ์ด์ ์ด๋‹ค.

์žฅ๋น„ ํ†ตํ•ฉ ๋ฉ”๋ชจ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋Œ€์—ญํญ ์‹ค์šฉ LLM ํฌ๊ธฐ ์ƒํ•œ
Mac Studio M4 Max (128 GB) 128 GB ~546 GB/s 70B Q4~Q6, 32B Q8
Mac Studio M4 Ultra (192 GB) 192 GB ~800 GB/s 70B Q8, ~120B Q4
Mac Studio M3 Ultra (192 GB) 192 GB 800 GB/s ๋™์ƒ
Mac Studio M2 Ultra (192 GB) 192 GB 800 GB/s ๋™์ƒ

ํ•ต์‹ฌ ์ œ์•ฝ โ€” Llama 3.1 405B ๋ถˆ๊ฐ€: 4-bit ์–‘์žํ™”(Q4_K_M) ๊ธฐ์ค€์œผ๋กœ๋„ 405B ๋ชจ๋ธ์€ ~230 GB๊ฐ€ ํ•„์š”ํ•˜๋‹ค. 192 GB ์žฅ๋น„์—์„œ ์™„์ „ ์ธ๋ฉ”๋ชจ๋ฆฌ ์‹คํ–‰์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ , ๋””์Šคํฌ ์˜คํ”„๋กœ๋“œ ์‹œ ์ถ”๋ก  ์†๋„๊ฐ€ 10โ€“50๋ฐฐ ์ €ํ•˜๋˜์–ด ์‹ค์‹œ๊ฐ„ ๋กœ๋ณดํ‹ฑ์Šค ์šฉ๋„์— ๋ถ€์ ํ•ฉํ•˜๋‹ค.


2. Mac Studio์—์„œ ์‹ค์šฉ์ ์ธ ๋กœ์ปฌ LLM ํ›„๋ณด

2.1 ๋ชจ๋ธ ๋น„๊ต

๋ชจ๋ธ ํŒŒ๋ผ๋ฏธํ„ฐ Q4_K_M ํŒŒ์ผ ํฌ๊ธฐ ๊ถŒ์žฅ ์žฅ๋น„ ์ฃผ์š” ํŠน์ง•
Qwen3 72B 72B ~45 GB M4 Max 128 GBโ†‘ 2025๋…„ ์ตœ์‹ , ์ถ”๋ก ยทํ•œ๊ตญ์–ด ์šฐ์ˆ˜, thinking mode ์ง€์›
Llama 3.3 70B 70B ~42 GB M4 Max 128 GBโ†‘ Meta ์ตœ์‹  70B, instruction following ์•ˆ์ •์ 
Qwen 2.5 72B 72B ~45 GB M4 Max 128 GBโ†‘ ๊ตฌ์กฐํ™” ์ถœ๋ ฅยท์ฝ”๋”ฉ ๊ฐ•์ , JSON ์Šคํ‚ค๋งˆ ์ค€์ˆ˜ ๋†’์Œ
DeepSeek R1 Distill 70B 70B ~42 GB M4 Max 128 GBโ†‘ Chain-of-Thought ์ถ”๋ก  ํŠนํ™”, ๋ณต์žกํ•œ ๊ณ„ํš ์ˆ˜๋ฆฝ
Mistral Large 2 (123B) 123B ~75 GB M4 Ultra 192 GBโ†‘ 70B๊ธ‰ ๋Œ€๋น„ ํ’ˆ์งˆ ํ–ฅ์ƒ, Ultra ์ „์šฉ

2.2 ์ถ”๋ก  ์†๋„ (์‹ค์‹œ๊ฐ„์„ฑ ํŒ๋‹จ ๊ธฐ์ค€)

๋ชจ๋ธ ์žฅ๋น„ ์ƒ์„ฑ ์†๋„ 100 ํ† ํฐ ์‘๋‹ต ์‹œ๊ฐ„
70B Q4_K_M M4 Ultra 192 GB ~40โ€“50 tok/s ~2โ€“2.5์ดˆ
70B Q4_K_M M4 Max 128 GB ~28โ€“38 tok/s ~3โ€“4์ดˆ
70B Q8 M4 Ultra 192 GB ~22โ€“30 tok/s ~4โ€“5์ดˆ
123B Q4_K_M M4 Ultra 192 GB ~18โ€“25 tok/s ~5โ€“6์ดˆ

ํ˜„์žฌ ์„ค๊ณ„์—์„œ vision/zone/enter โ†’ orchestrator ๊ฒฐ์ • โ†’ MCP tool dispatch ๋ฃจํ”„์˜ ํ—ˆ์šฉ ์ง€์—ฐ์€ ๋ช…์‹œ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋กœ๋ด‡ ๋ฌผ๋ฆฌ ๋™์ž‘ ๊ฐœ์‹œ ์ „๊นŒ์ง€ 3โ€“5์ดˆ๋Š” ๋Œ€๋ถ€๋ถ„์˜ ์ƒํ˜ธ์ž‘์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ์ˆ˜์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ”์œ„๋‹ค. ๊ธด๊ธ‰ ๊ฒฝ๋กœ(e-stop, ์ถฉ๋Œ ํšŒํ”ผ)๋Š” HA ๋ฃฐ ๊ธฐ๋ฐ˜ fallback์ด ์ปค๋ฒ„ํ•œ๋‹ค (OPERATIONS ยงํด๋ฐฑ/e-stop).

2.3 Claude Opus์™€์˜ ์„ฑ๋Šฅ ๊ฒฉ์ฐจ

Claude Opus 4.7   โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ  ๊ธฐ์ค€์„  (์ถ”์ • 1T+ ํŒŒ๋ผ๋ฏธํ„ฐ)
Qwen3 72B         โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  ๊ตฌ์กฐํ™” ํƒœ์Šคํฌยท์ถ”๋ก  ~70%
Llama 3.3 70B     โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘  instruction following ~65%
Claude Sonnet 4.6 โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘  ~80% (API ๋น„์šฉ ์ ˆ๊ฐ ๊ฒฝ๋กœ)

์†”์งํ•œ ํ‰๊ฐ€: 70B ๋กœ์ปฌ ๋ชจ๋ธ์€ Opus์˜ ๋ฉ€ํ‹ฐ์Šคํ… ์ถ”๋ก ยท์•ˆ์ „ critical ํŒ๋‹จ ์ˆ˜์ค€์— ๋„๋‹ฌํ•˜์ง€ ๋ชปํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋„๋ฉ”์ธ์ด ์ข๊ณ  ๊ฐ€๋“œ๋ ˆ์ผ์ด ์ด๋ฏธ MCP ์„œ๋ฒ„ ์ธก์— ๊ฐ•์ œ๋˜์–ด ์žˆ๋Š” ์ด ํ”„๋กœ์ ํŠธ์—์„œ๋Š”, JSON schema โ†’ capability whitelist โ†’ zone polygon clamp โ†’ velocity clamp 4๋‹จ๊ณ„๊ฐ€ ๋ชจ๋ธ ์ถœ๋ ฅ์„ ๊ฒ€์ฆํ•˜๋ฏ€๋กœ ๋‹จ์ˆœยท๋ฃจํ‹ด ๊ฒฐ์ •์—๋Š” 70B๊ฐ€ ์‹ค์šฉ์ ์ด๋‹ค.


3. ์‹คํ–‰ ํ”„๋ ˆ์ž„์›Œํฌ

ํ”„๋ ˆ์ž„์›Œํฌ ํŠน์ง• ์ด ํ”„๋กœ์ ํŠธ ์ ํ•ฉ๋„
Ollama OpenAI ํ˜ธํ™˜ API, Metal ๊ฐ€์†, ๋ชจ๋ธ ๋ฒ„์ „ ๊ด€๋ฆฌ ์šฉ์ด โ˜…โ˜…โ˜…โ˜…โ˜…
llama.cpp server ์ €์ˆ˜์ค€, ์ตœ๊ณ  ์„ฑ๋Šฅ, ์„ค์ • ๋ณต์žก โ˜…โ˜…โ˜…โ˜…โ˜†
MLX-LM Apple Silicon ์ตœ์ ํ™”, Python native, Apple ๊ณต์‹ ์ง€์› โ˜…โ˜…โ˜…โ˜…โ˜†
LM Studio GUI, ํƒ์ƒ‰ยทํ”„๋กœํ† ํƒ€์ดํ•‘ ์ „์šฉ โ˜…โ˜…โ˜…โ˜†โ˜†

๊ถŒ์žฅ: Ollama. /v1/chat/completions OpenAI ํ˜ธํ™˜ ์—”๋“œํฌ์ธํŠธ๋ฅผ ๊ทธ๋Œ€๋กœ ๋…ธ์ถœํ•˜๋ฏ€๋กœ orchestrator ์ฝ”๋“œ๋ฅผ ๊ฑฐ์˜ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ  ์—ฐ๋™ ๊ฐ€๋Šฅํ•˜๋‹ค. Metal ๊ฐ€์†์ด ์ž๋™์œผ๋กœ ์ ์šฉ๋˜๋ฉฐ, ollama pull qwen3:72b ํ•œ ์ค„๋กœ ๋ชจ๋ธ์„ ๋‚ด๋ ค๋ฐ›์•„ ์ฆ‰์‹œ ์„œ๋น™ํ•  ์ˆ˜ ์žˆ๋‹ค.


4. ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ผ์šฐํŒ… ์ „๋žต

Claude Opus API์™€ ๋กœ์ปฌ LLM์„ ํƒœ์Šคํฌ ํŠน์„ฑ์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์„ ํƒํ•œ๋‹ค. ๋‹จ์ผ ๋ชจ๋ธ ๊ณ ์ • ๋Œ€๋น„ ์žฅ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋น„์šฉ: ๋ฃจํ‹ด ๊ฒฐ์ •์˜ 80%๋ฅผ ๋กœ์ปฌ๋กœ ์ฒ˜๋ฆฌ โ†’ API ํ˜ธ์ถœ ๋น„์šฉ ๋Œ€ํญ ์ ˆ๊ฐ
  • ์ง€์—ฐ: ๋กœ์ปฌ 70B๋Š” ์ฒซ ํ† ํฐ๊นŒ์ง€ 0.3โ€“0.5์ดˆ๋กœ Claude API(1โ€“3์ดˆ)๋ณด๋‹ค ๋น ๋ฆ„
  • ์˜คํ”„๋ผ์ธ ๊ฐ€์šฉ์„ฑ: ๋„คํŠธ์›Œํฌ ์žฅ์•  ์‹œ ๋กœ์ปฌ LLM์œผ๋กœ graceful degradation

4.1 ๋ผ์šฐํŒ… ๊ฒฐ์ • ๊ธฐ์ค€

์•„๋ž˜ ์„ธ ์ถ•์˜ ์กฐํ•ฉ์œผ๋กœ ๋ชจ๋ธ์„ ์„ ํƒํ•œ๋‹ค.

์ถ• ๋กœ์ปฌ LLM ์„ ํƒ Claude Opus ์„ ํƒ
๋ณต์žก๋„ ๋‹จ์ผ zone ์ง„์ž… โ†’ ๋‹จ์ˆœ ๋™์ž‘ 1๊ฐœ ๋‹ค์ค‘ ์กฐ๊ฑด, ๋ณตํ•ฉ ๊ณ„ํš, ๋ฉ€ํ‹ฐ tool chain
์•ˆ์ „ ๋“ฑ๊ธ‰ safety_level: low โ€” ์ „์‹œ ์˜์—ญ ์ด๋™ ๋“ฑ safety_level: high โ€” ๊ตฐ์ค‘ ์ ‘๊ทผ, e-stop ํŒ๋‹จ
๋„คํŠธ์›Œํฌ ์˜คํ”„๋ผ์ธ / API ์‘๋‹ต ์ง€์—ฐ โ‰ฅ 2s ์ •์ƒ ์—ฐ๊ฒฐ

4.2 ๋ชจ๋ธ ์„ ํƒ ๋กœ์ง (์˜์‚ฌ ์ฝ”๋“œ)

# orchestrator/router.py  (illustrative spec)
from enum import Enum

class ModelTier(Enum):
    LOCAL   = "local"    # Ollama ๋กœ์ปฌ LLM
    SONNET  = "sonnet"   # claude-sonnet-4-6 (์ค‘๊ฐ„ ๋น„์šฉ)
    OPUS    = "opus"     # claude-opus-4-7   (์ตœ๊ณ  ํ’ˆ์งˆ)

def select_model(event: ZoneEvent, ctx: SessionContext) -> ModelTier:
    # 1์ˆœ์œ„: ๋„คํŠธ์›Œํฌ ์ƒํƒœ (์˜คํ”„๋ผ์ธ ๊ฐ•์ œ ๋กœ์ปฌ)
    if not ctx.api_reachable:
        return ModelTier.LOCAL

    # 2์ˆœ์œ„: ์•ˆ์ „ ๋“ฑ๊ธ‰ (safety_level์€ zones.yaml์— ์ •์˜)
    zone = ctx.zone_registry[event.zone_id]
    if zone.safety_level == "high":
        return ModelTier.OPUS        # ๊ตฐ์ค‘ ์ ‘๊ทผ, ํ˜‘์†Œ ๊ตฌ์—ญ ๋“ฑ

    # 3์ˆœ์œ„: ๋ณต์žก๋„ ์ ์ˆ˜
    complexity = estimate_complexity(event, ctx)
    # complexity: ๊ด€๋ จ zone ์ˆ˜, ํ™œ์„ฑ ์„ธ์…˜ ์ˆ˜, ๋ณด๋ฅ˜ ์ค‘ tool ์ˆ˜ ํ•ฉ์‚ฐ
    if complexity >= COMPLEXITY_THRESHOLD:   # ์„ค์ •๊ฐ’, ์ดˆ๊ธฐ๊ฐ’ 3
        return ModelTier.OPUS
    elif complexity >= SIMPLE_THRESHOLD:     # ์„ค์ •๊ฐ’, ์ดˆ๊ธฐ๊ฐ’ 1
        return ModelTier.SONNET
    else:
        return ModelTier.LOCAL

def estimate_complexity(event: ZoneEvent, ctx: SessionContext) -> int:
    score = 0
    score += len(event.overlapping_zones)    # ๊ต์ฐจ zone ์ˆ˜
    score += len(ctx.pending_tool_calls)     # ๋ฏธ์™„๋ฃŒ tool call ์ˆ˜
    score += (1 if ctx.active_sessions > 3 else 0)  # ๋™์‹œ ์„ธ์…˜ ๊ณผ๋ถ€ํ•˜
    return score

4.3 ๋ผ์šฐํŒ… ํ๋ฆ„๋„

MQTT vision/zone/enter
        โ”‚
        โ–ผ
  [Router.select_model()]
        โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚                         โ”‚
API ๋ถˆ๊ฐ€?                API ๊ฐ€๋Šฅ?
   โ”‚                         โ”‚
   โ–ผ                    zone.safety_level?
LOCAL LLM               โ”‚           โ”‚
(Ollama)               HIGH        LOW/MED
                        โ”‚           โ”‚
                     OPUS      complexity score
                             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”
                            โ‰ฅ3    1โ€“2      0
                             โ”‚      โ”‚      โ”‚
                           OPUS  SONNET  LOCAL
                                          โ”‚
                                     (Ollama)
        โ”‚
        โ–ผ
  [๊ฐ€๋“œ๋ ˆ์ผ ๊ณตํ†ต ๊ฒฝ๋กœ]
  JSON schema ๊ฒ€์ฆ โ†’ capability whitelist
  โ†’ zone polygon clamp โ†’ velocity clamp
        โ”‚
        โ–ผ
  MCP tool dispatch (robot-adapter / ha-bridge / tablet-gateway)

โš ๏ธ ๊ฐ€๋“œ๋ ˆ์ผ 4๋‹จ๊ณ„๋Š” ๋ชจ๋ธ ํ‹ฐ์–ด์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ํ•ญ์ƒ ์‹คํ–‰๋œ๋‹ค. LOCAL ๋ชจ๋ธ ์ถœ๋ ฅ์ด ๊ฐ€๋“œ๋ ˆ์ผ์„ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•˜๋ฉด ๋ช…๋ น์€ ํ๊ธฐ๋˜๊ณ  Prometheus ์นด์šดํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค. ์ด ๊ฒฝ์šฐ HA ๋ฃฐ ๊ธฐ๋ฐ˜ fallback์ด ํ™œ์„ฑํ™”๋œ๋‹ค.

4.4 ๋ผ์šฐํŒ… ๊ฒฐ๊ณผ ์ถ”์ 

๋ผ์šฐํŒ… ๊ฒฐ์ • ์ž์ฒด๋ฅผ ๊ฐ€์‹œํ™”ํ•˜์—ฌ ๋ชจ๋ธ ์„ ํƒ ๋น„์œจ, ๋กœ์ปฌ LLM ๊ฐ€๋“œ๋ ˆ์ผ ๊ฑฐ๋ถ€์œจ์„ ์ง€์† ๋ชจ๋‹ˆํ„ฐ๋งํ•œ๋‹ค.

# illustrative: ๋ผ์šฐํŒ… ๊ฒฐ๊ณผ ๋ฉ”ํŠธ๋ฆญ ๊ธฐ๋ก
router_decision_counter.labels(
    tier=selected_tier.value,
    zone_safety=zone.safety_level,
    complexity_band=complexity_band,   # "low" / "medium" / "high"
    offline=str(not ctx.api_reachable),
).inc()

5. Claude SDK ์—ฐ๋™ ๋ฐฉ์‹

ํ˜„์žฌ orchestrator๋Š” anthropic SDK๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•œ๋‹ค. ๋กœ์ปฌ LLM ์—ฐ๋™ ์‹œ ๋‘ ๊ฐ€์ง€ ๊ฒฝ๋กœ๊ฐ€ ์žˆ๋‹ค.

๊ฒฝ๋กœ A: OpenAI ํ˜ธํ™˜ ๋ž˜ํผ (๊ถŒ์žฅ)

Ollama๊ฐ€ /v1/chat/completions๋ฅผ ๋…ธ์ถœํ•˜๋ฏ€๋กœ openai SDK๋กœ ๋™์ผํ•˜๊ฒŒ ํ˜ธ์ถœํ•œ๋‹ค. LangGraph ๊ทธ๋ž˜ํ”„ ๋…ธ๋“œ์—์„œ provider๋ฅผ ์ถ”์ƒํ™”ํ•˜๋ฉด ์„ค์ •๊ฐ’ ๋ณ€๊ฒฝ๋งŒ์œผ๋กœ Claude API โ†” ๋กœ์ปฌ LLM์„ ์ „ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

# illustrative: provider ์ถ”์ƒํ™” (LangGraph ๋…ธ๋“œ)
def make_llm_client(tier: ModelTier):
    if tier == ModelTier.LOCAL:
        from openai import AsyncOpenAI
        return AsyncOpenAI(
            base_url="http://localhost:11434/v1",
            api_key="ollama",              # Ollama๋Š” ์ธ์ฆ ๋ถˆํ•„์š”
        ), "qwen3:72b"
    elif tier == ModelTier.SONNET:
        import anthropic
        return anthropic.AsyncAnthropic(), "claude-sonnet-4-6"
    else:
        import anthropic
        return anthropic.AsyncAnthropic(), "claude-opus-4-7"

๊ฒฝ๋กœ B: LiteLLM ํ†ตํ•ฉ ๋ ˆ์ด์–ด

litellm.completion("ollama/qwen3:72b", ...) ํ˜•ํƒœ๋กœ ๋‹จ์ผ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์œ ์ง€. ํ”„๋ ˆ์ž„์›Œํฌ ์ข…์†์„ฑ์ด ๋Š˜์–ด๋‚˜๋Š” ๋‹จ์ ์ด ์žˆ์œผ๋‚˜, ๋กœ๊น…ยท๋น„์šฉ ์ถ”์ ยทfallback ๋กœ์ง์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.


6. ํ”„๋กฌํ”„ํŠธ ์บ์‹ฑ ๊ณ ๋ ค์‚ฌํ•ญ

ํ˜„์žฌ ์„ค๊ณ„๋Š” ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ + zone ํ”Œ๋ ˆ์ด๋ถ์ด ์•ˆ์ •์ ์ด๋ฏ€๋กœ Anthropic ํ”„๋กฌํ”„ํŠธ ์บ์‹ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค (SYSTEM_DESIGN ยง15). ๋กœ์ปฌ LLM ๋ผ์šฐํŒ… ์‹œ ์ฃผ์˜ํ•  ์ :

  • ๋กœ์ปฌ LLM์—๋Š” ํ”„๋กฌํ”„ํŠธ ์บ์‹ฑ์ด ์—†๋‹ค. ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ํ† ํฐ์ด ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ, ํ”„๋กฌํ”„ํŠธ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๋กœ์ปฌ ๊ฒฝ๋กœ์—์„œ ์ค‘์š”ํ•˜๋‹ค.
  • Ollama๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ๋ณด์กดํ•˜๋Š” keep_alive ์˜ต์…˜์„ ์ง€์›ํ•œ๋‹ค. ์—ฐ์† ํ˜ธ์ถœ ์‹œ KV cache ์žฌ์‚ฌ์šฉ ํšจ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
  • Claude API ๊ฒฝ๋กœ์—์„œ๋Š” ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ cache_control: ephemeral ๋ธ”๋ก์„ ์‹œ์Šคํ…œ ํ”„๋กฌํ”„ํŠธ ๋์— ๋ถ™์ธ๋‹ค.

7. ๋ฏธ๊ฒฐ ์ด์Šˆ์™€์˜ ์—ฐ๊ด€

SYSTEM_DESIGN ยง15์—์„œ Opus vs Sonnet ๊ฒฐ์ •์ด ๋ฏธ๊ฒฐ๋กœ ๋‚จ์•„ ์žˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ ์ œ์•ˆํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ผ์šฐํŒ…์€ ๊ทธ ๊ฒฐ์ •์„ "๋‘˜ ๋‹ค, ํƒœ์Šคํฌ์— ๋”ฐ๋ผ" ๋กœ ์žฌํ”„๋ ˆ์ด๋ฐํ•œ๋‹ค. ์„ธ ๋ฒˆ์งธ ํ›„๋ณด(๋กœ์ปฌ LLM)๋ฅผ ์ถ”๊ฐ€ํ•  ๊ฒฝ์šฐ ยง15์— ๋‹ค์Œ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค:

  • ๋กœ์ปฌ LLM ๊ฐ€๋“œ๋ ˆ์ผ ๊ฑฐ๋ถ€์œจ ํ—ˆ์šฉ ์ž„๊ณ„๊ฐ’ ํ•ฉ์˜ (์ดˆ๊ธฐ๊ฐ’ ์ œ์•ˆ: 5% ์ด์ƒ ์‹œ tier ์ƒํ–ฅ)
  • COMPLEXITY_THRESHOLD / SIMPLE_THRESHOLD ์ดˆ๊ธฐ๊ฐ’ ํ™•์ • (ํ˜„์žฌ: 3 / 1)
  • ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ชจ๋“œ ํ™œ์„ฑํ™” ์กฐ๊ฑด (ํ•ญ์ƒ on vs. ์˜คํ”„๋ผ์ธ fallback ์ „์šฉ)
  • Mac Studio ์žฅ๋น„ ์šด์˜ ์ฃผ์ฒด ๋ฐ ๋„คํŠธ์›Œํฌ ๋ฐฐ์น˜ (์˜จ์‚ฌ์ดํŠธ ์ƒ์‹œ ๊ฐ€๋™ ์ „์ œ)

8. ๊ฒฐ๋ก  ๋ฐ ๊ถŒ๊ณ 

ํ•ญ๋ชฉ ๊ถŒ๊ณ 
ํ•˜๋“œ์›จ์–ด Mac Studio M4 Ultra (192 GB) โ€” 70B Q8 ๋˜๋Š” Mistral Large 2 Q4 ์‹ค์šฉ ๋ฒ”์œ„
1์ˆœ์œ„ ๋ชจ๋ธ Qwen3 72B Q4_K_M โ€” ์ถ”๋ก ยทํ•œ๊ตญ์–ดยท๊ตฌ์กฐํ™” ์ถœ๋ ฅ ๊ท ํ˜• ์ตœ์ƒ
2์ˆœ์œ„ ๋ชจ๋ธ Llama 3.3 70B Q4_K_M โ€” instruction following ์•ˆ์ •์„ฑ
์‹คํ–‰ ํ”„๋ ˆ์ž„์›Œํฌ Ollama (Metal ๊ฐ€์†, OpenAI ํ˜ธํ™˜ API)
ํ†ตํ•ฉ ์ „๋žต ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ผ์šฐํŒ… โ€” ์•ˆ์ „๋“ฑ๊ธ‰ยท๋ณต์žก๋„ยท๋„คํŠธ์›Œํฌ 3์ถ• ๊ธฐ์ค€
Opus ๋™๋“ฑ์„ฑ ๋ถˆ๊ฐ€ โ€” 70B ๋กœ์ปฌ ๋ชจ๋ธ์€ ๋ณตํ•ฉ ์ถ”๋ก ์—์„œ ์˜๋ฏธ ์žˆ๋Š” ๊ฒฉ์ฐจ ์กด์žฌ; ๊ฐ€๋“œ๋ ˆ์ผ ๋ณด๊ฐ•์œผ๋กœ ๋ณด์™„
์ฆ‰์‹œ ์ ์šฉ ์—ฌ๋ถ€ ๋ฏธ๊ฒฐ โ€” ยง15 ๊ฒฐ์ • ํ›„ propagation ํ•„์š”

Clone this wiki locally