이코에코(Eco²) Knowledge Base/Applied

LLM Gateway & Unified Interface Pattern

mango_fr 2026. 1. 5. 06:16

https://www.taboola.com/engineering/llm-gateway/

AI 에이전트 시스템에서 LLM 모델 선택을 에이전트 로직과 분리하는 아키텍처 패턴

용어 정의

⚠️ Note: 이 문서에서 다루는 개념들은 업계에서 다양한 명칭으로 불립니다.
공식적으로 통일된 명칭은 없으며, 아래와 같은 용어들이 실제로 사용됩니다.

실제 사용 용어 사용처 설명
LLM Gateway / AI Gateway Cloudflare, Kong, AWS LLM 요청을 중앙에서 관리하는 게이트웨이
LLM Router 당근, Martian 모델별로 요청을 라우팅하는 컴포넌트
Unified LLM Interface LiteLLM, OpenRouter 여러 Provider를 하나의 API로 통합
Multi-Provider Support LangChain, LiteLLM 다중 LLM Provider 지원
Model Abstraction Layer 일반 아키텍처 용어 모델 구현을 추상화하는 계층

관련 오픈소스 프로젝트

개요

Model-Agnostic Agent Architecture는 AI 에이전트 시스템에서 LLM 모델 선택에이전트 실행 로직(Agent Loop)을 분리하는 설계 패턴이다. 이 패턴을 통해 에이전트는 특정 LLM에 종속되지 않고, 런타임 또는 설계 시점에 유연하게 모델을 교체할 수 있다.

핵심 개념

1. 전통적 AI 에이전트 구조의 문제점 (이코에코 LLM 파이프라인)

[사용자 요청] → [에이전트 로직 + GPT-4 직접 호출] → [결과]

문제점:

  • 특정 모델에 하드코딩된 의존성
  • 모델 교체 시 전체 코드 수정 필요
  • 비용 최적화 어려움
  • 모델 장애 시 전체 서비스 중단

2. Model-Agnostic 구조

[사용자 요청]
      ↓
[Model Selector] → "claude-4-sonnet" or "gpt-5" or "auto"
      ↓
[Agent Loop (ReAct)]
   ├─ Think (LLM 호출)
   ├─ Act (Tool 실행)
   └─ Observe (결과 분석)
      ↓
[결과]

장점:

  • 모델 독립적인 에이전트 로직
  • 런타임 모델 교체 가능
  • 작업 유형별 최적 모델 선택
  • Fallback 메커니즘 구현 용이

아키텍처 패턴

패턴 1: Frontend Model Selection (Cursor 방식)

사용자가 프론트엔드 UI에서 직접 모델을 선택하는 패턴.

┌─────────────────────────────────────────────────────────┐
│                   Frontend (IDE/UI)                      │
│  ┌───────────────────────────────────────────────────┐ │
│  │  Model Selector: [Claude ▼] [GPT ▼] [Gemini ▼]   │ │
│  └───────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────┘
                         │ model: "claude-4-sonnet"
                         ▼
┌─────────────────────────────────────────────────────────┐
│                     Agent Loop                           │
│  ┌─────────┐    ┌─────────┐    ┌─────────┐             │
│  │ Think   │ →  │ Act     │ →  │ Observe │ → [Loop]    │
│  │ (LLM)   │    │ (Tool)  │    │ (Read)  │             │
│  └─────────┘    └─────────┘    └─────────┘             │
└─────────────────────────────────────────────────────────┘

구현 예시 (Cursor Cloud Agents API):

# Agent 실행 시 model 파라미터로 전달
POST /v0/agents
{
    "prompt": {
        "text": "Add README.md with installation instructions"
    },
    "model": "claude-4-sonnet",  # 프론트엔드에서 선택한 모델
    "source": {
        "repository": "https://github.com/org/repo"
    }
}

적용 사례:

  • Cursor IDE
  • GitHub Copilot Chat (부분적)
  • OpenAI ChatGPT (모델 선택 드롭다운)

패턴 2: Gateway Model Routing (당근 방식)

중앙 집중식 Gateway가 모델 라우팅을 담당하는 패턴.

┌──────────────────────────────────────────────────────────┐
│                   Product Services                        │
│   Service A          Service B          Service C         │
└─────────┬───────────────┬───────────────┬────────────────┘
          │               │               │
          ▼               ▼               ▼
┌──────────────────────────────────────────────────────────┐
│                      LLM Router                           │
│  ┌────────────────────────────────────────────────────┐ │
│  │  • 통합 인터페이스 (OpenAI SDK 표준)                │ │
│  │  • model="claude-4.5-sonnet" → 자동 라우팅          │ │
│  │  • Retry, Fallback, Circuit Breaker                 │ │
│  │  • 비용/사용량 중앙 관리                            │ │
│  └────────────────────────────────────────────────────┘ │
└───────────────────────────┬──────────────────────────────┘
                            │
          ┌─────────────────┼─────────────────┐
          ▼                 ▼                 ▼
    ┌──────────┐      ┌──────────┐      ┌──────────┐
    │ OpenAI   │      │ Anthropic│      │ Google   │
    └──────────┘      └──────────┘      └──────────┘

구현 예시:

from openai import OpenAI

# base_url만 변경하면 모든 모델 사용 가능
client = OpenAI(base_url="https://llm-router.internal")

# 모델만 바꾸면 자동으로 해당 Provider로 라우팅
response = client.chat.completions.create(
    model="claude-4.5-sonnet",  # 또는 "gpt-5.2", "gemini-3-pro"
    messages=[{"role": "user", "content": "Hello!"}]
)

적용 사례:

  • 당근마켓 LLM Router
  • AWS Bedrock
  • Azure OpenAI Service

패턴 3: Agent-Level Model Configuration (CrewAI 방식)

각 에이전트에 개별적으로 모델을 할당하는 멀티에이전트 패턴.

┌────────────────────────────────────────────────────────┐
│                    Multi-Agent System                   │
│                                                         │
│  ┌─────────────────┐    ┌─────────────────┐           │
│  │ Researcher Agent│    │ Writer Agent    │           │
│  │ llm: GPT-4      │    │ llm: Claude-3   │           │
│  │ tools: [search] │    │ tools: [write]  │           │
│  └────────┬────────┘    └────────┬────────┘           │
│           │                      │                     │
│           └──────────┬───────────┘                     │
│                      │                                 │
│              ┌───────▼───────┐                         │
│              │  Orchestrator │                         │
│              │  (Task Flow)  │                         │
│              └───────────────┘                         │
└────────────────────────────────────────────────────────┘

구현 예시 (CrewAI):

from crewai import Agent, Task, Crew
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

# 각 에이전트에 다른 모델 할당
researcher = Agent(
    role="Researcher",
    goal="Research the topic thoroughly",
    llm=ChatOpenAI(model="gpt-4"),
    tools=[search_tool]
)

writer = Agent(
    role="Writer",
    goal="Write compelling content",
    llm=ChatAnthropic(model="claude-3-opus"),
    tools=[write_tool]
)

# Crew로 에이전트들 조합
crew = Crew(agents=[researcher, writer], tasks=[...])

적용 사례:

  • CrewAI
  • AutoGen (Microsoft)
  • OpenAI Swarm

패턴 4: Dynamic Model Selection (LangGraph 방식)

런타임에 작업 특성에 따라 동적으로 모델을 선택하는 패턴.

┌────────────────────────────────────────────────────────┐
│                   Request Handler                       │
│                         │                               │
│                         ▼                               │
│              ┌─────────────────────┐                   │
│              │   Model Router      │                   │
│              │  (Dynamic Selection)│                   │
│              └──────────┬──────────┘                   │
│                         │                               │
│    ┌────────────────────┼────────────────────┐         │
│    │                    │                    │         │
│    ▼                    ▼                    ▼         │
│ [Simple]            [Complex]           [Creative]     │
│ GPT-3.5             Claude-4            GPT-4          │
│ (저비용)            (고성능)            (창의성)       │
└────────────────────────────────────────────────────────┘

구현 예시 (LangGraph):

from langgraph.prebuilt import create_react_agent

def model_router(state):
    """작업 복잡도에 따라 모델 선택"""
    task_complexity = analyze_complexity(state["messages"])

    if task_complexity == "simple":
        return ChatOpenAI(model="gpt-3.5-turbo")
    elif task_complexity == "complex":
        return ChatAnthropic(model="claude-3-opus")
    else:
        return ChatOpenAI(model="gpt-4")

# 미들웨어로 동적 모델 선택
@wrap_model_call
def select_model(config):
    return model_router(config["state"])

적용 사례:

  • LangGraph (LangChain v1.0+)
  • Cursor Auto Mode
  • 당근 Prompt Studio (Model Fallback)

구현 가이드

1. 인터페이스 정의

from abc import ABC, abstractmethod
from typing import List, Dict, Any

class LLMInterface(ABC):
    """Model-Agnostic LLM 인터페이스"""

    @abstractmethod
    async def chat_completion(
        self,
        messages: List[Dict[str, str]],
        model: str,
        **kwargs
    ) -> str:
        pass

    @abstractmethod
    async def function_call(
        self,
        messages: List[Dict[str, str]],
        tools: List[Dict[str, Any]],
        model: str,
        **kwargs
    ) -> Dict[str, Any]:
        pass

2. 모델 라우터 구현

class ModelRouter:
    """다양한 LLM Provider를 통합 관리하는 라우터"""

    def __init__(self):
        self.providers = {
            "openai": OpenAIProvider(),
            "anthropic": AnthropicProvider(),
            "google": GoogleProvider(),
        }
        self.model_mapping = {
            "gpt-4": "openai",
            "gpt-3.5-turbo": "openai",
            "claude-3-opus": "anthropic",
            "claude-3-sonnet": "anthropic",
            "gemini-pro": "google",
        }

    def get_provider(self, model: str) -> LLMInterface:
        provider_name = self.model_mapping.get(model)
        if not provider_name:
            raise ValueError(f"Unknown model: {model}")
        return self.providers[provider_name]

    async def route(
        self,
        messages: List[Dict],
        model: str,
        **kwargs
    ) -> str:
        provider = self.get_provider(model)
        return await provider.chat_completion(messages, model, **kwargs)

3. Agent Loop 구현

class ModelAgnosticAgent:
    """Model-Agnostic ReAct Agent"""

    def __init__(self, model_router: ModelRouter):
        self.router = model_router
        self.tools = {}

    async def run(
        self,
        prompt: str,
        model: str,  # 외부에서 모델 주입
        max_iterations: int = 10
    ) -> str:
        messages = [{"role": "user", "content": prompt}]

        for _ in range(max_iterations):
            # Think: LLM에게 다음 행동 결정 요청
            response = await self.router.route(
                messages=messages,
                model=model,  # 주입된 모델 사용
                tools=list(self.tools.values())
            )

            if response.get("tool_calls"):
                # Act: 도구 실행
                tool_results = await self._execute_tools(response["tool_calls"])

                # Observe: 결과를 컨텍스트에 추가
                messages.append({"role": "tool", "content": tool_results})
            else:
                # 완료
                return response["content"]

        return "Max iterations reached"

비교 분석

패턴 모델 선택 시점 적합한 사용 사례 복잡도
Frontend Selection 런타임 (사용자) 개발자 도구, IDE 낮음
Gateway Routing 요청 시점 엔터프라이즈, B2B 중간
Agent-Level Config 설계 시점 멀티에이전트 시스템 중간
Dynamic Selection 런타임 (자동) 비용 최적화, Auto Mode 높음

모범 사례

1. 통합 인터페이스 사용

OpenAI SDK를 표준으로 채택하여 모든 모델을 동일한 방식으로 호출.

2. Fallback 메커니즘 구현

async def call_with_fallback(messages, primary_model, fallback_models):
    for model in [primary_model] + fallback_models:
        try:
            return await router.route(messages, model)
        except RateLimitError:
            continue
    raise AllModelsFailedError()

3. 비용/성능 모니터링

모델별 사용량, 비용, 응답 시간을 추적하여 최적화.

4. Circuit Breaker 패턴

특정 모델의 연속 실패 시 자동으로 차단하고 대체 모델로 전환.

References