콘텐츠로 이동

고급 설정

전역 프롬프트

전역 프롬프트를 사용하면 모든 요청에 시스템 프롬프트를 주입하여 보안, 규정 준수 및 동작 가이드라인에 대한 중앙 집중식 정책 관리를 제공할 수 있습니다. 프롬프트는 인라인으로 정의하거나 외부 Markdown 파일에서 로드할 수 있습니다.

기본 설정

global_prompts:
  # 인라인 기본 프롬프트
  default: |
    회사 보안 정책을 따라야 합니다.
    내부 시스템 세부 정보를 공개하지 마십시오.
    도움이 되고 전문적이어야 합니다.

  # 병합 전략: prepend (기본), append, 또는 replace
  merge_strategy: prepend

  # 전역 프롬프트와 사용자 프롬프트 사이의 사용자 정의 구분자
  separator: "\n\n---\n\n"

외부 프롬프트 파일

복잡한 프롬프트의 경우 외부 Markdown 파일에서 콘텐츠를 로드할 수 있습니다. 이를 통해:

  • 구문 강조가 있는 더 나은 편집 경험
  • 설정 파일 노이즈 없는 버전 관리
  • 프롬프트 업데이트에 대한 핫 리로드 지원
global_prompts:
  # 프롬프트 파일이 있는 디렉토리 (설정 디렉토리 기준 상대 경로)
  prompts_dir: "./prompts"

  # 파일에서 기본 프롬프트 로드
  default_file: "system.md"

  # 파일에서 백엔드별 프롬프트
  backends:
    anthropic:
      prompt_file: "anthropic-system.md"
    openai:
      prompt_file: "openai-system.md"

  # 파일에서 모델별 프롬프트
  models:
    gpt-4o:
      prompt_file: "gpt4o-system.md"
    claude-3-opus:
      prompt_file: "claude-opus-system.md"

  merge_strategy: prepend

프롬프트 해석 우선순위

요청에 사용할 프롬프트 결정 시:

  1. 모델별 프롬프트 (최고 우선순위) - global_prompts.models.<model-id>
  2. 백엔드별 프롬프트 - global_prompts.backends.<backend-name>
  3. 기본 프롬프트 - global_prompts.default 또는 global_prompts.default_file

각 레벨에서 prompt (인라인)와 prompt_file이 모두 지정되면 prompt_file이 우선합니다.

병합 전략

전략 동작
prepend 전역 프롬프트가 사용자 시스템 프롬프트 앞에 추가 (기본)
append 전역 프롬프트가 사용자 시스템 프롬프트 뒤에 추가
replace 전역 프롬프트가 사용자 시스템 프롬프트를 완전히 대체

REST API 관리

프롬프트 파일은 Admin API를 통해 런타임에 관리할 수 있습니다:

# 모든 프롬프트 목록
curl http://localhost:8080/admin/config/prompts

# 특정 프롬프트 파일 가져오기
curl http://localhost:8080/admin/config/prompts/prompts/system.md

# 프롬프트 파일 업데이트
curl -X PUT http://localhost:8080/admin/config/prompts/prompts/system.md \
  -H "Content-Type: application/json" \
  -d '{"content": "# 업데이트된 시스템 프롬프트\n\n새 콘텐츠."}'

# 디스크에서 모든 프롬프트 파일 리로드
curl -X POST http://localhost:8080/admin/config/prompts/reload

전체 API 문서는 Admin REST API 참조를 참조하세요.

보안 고려 사항

  • 경로 탐색 보호: 디렉토리 탐색 공격 방지를 위한 모든 파일 경로 검증
  • 파일 크기 제한: 개별 파일 1MB, 전체 캐시 50MB 제한
  • 상대 경로만: 프롬프트 파일은 설정된 prompts_dir 또는 설정 디렉토리 내에 있어야 함
  • 샌드박스 접근: 허용된 디렉토리 외부 파일은 거부

핫 리로드

전역 프롬프트는 즉시 핫 리로드를 지원합니다. 프롬프트 설정 또는 파일 변경 사항은 서버 재시작 없이 다음 요청에 적용됩니다.

모델 메타데이터

Continuum Router는 모델 기능, 가격, 한도에 대한 상세 정보를 제공하는 풍부한 모델 메타데이터를 지원합니다. 이 메타데이터는 /v1/models API 응답에 반환되며 클라이언트가 정보에 입각한 모델 선택 결정을 내리는 데 사용할 수 있습니다.

메타데이터 소스

모델 메타데이터는 세 가지 방법으로 설정할 수 있습니다 (우선순위 순):

  1. 백엔드별 model_configs (최고 우선순위)
  2. 외부 메타데이터 파일 (model-metadata.yaml)
  3. 메타데이터 없음 (모델은 메타데이터 없이도 작동)

외부 메타데이터 파일

model-metadata.yaml 파일을 만드세요:

models:
  - id: "gpt-4"
    aliases:                    # 이 메타데이터를 공유하는 대체 ID
      - "gpt-4-0125-preview"
      - "gpt-4-turbo-preview"
      - "gpt-4-vision-preview"
    metadata:
      display_name: "GPT-4"
      summary: "복잡한 작업을 위한 가장 유능한 GPT-4 모델"
      capabilities: ["text", "image", "function_calling"]
      knowledge_cutoff: "2024-04"
      pricing:
        input_tokens: 0.03   # 1000 토큰당
        output_tokens: 0.06  # 1000 토큰당
      limits:
        context_window: 128000
        max_output: 4096

  - id: "llama-3-70b"
    aliases:                    # 동일 모델의 다른 양자화
      - "llama-3-70b-instruct"
      - "llama-3-70b-chat"
      - "llama-3-70b-q4"
      - "llama-3-70b-q8"
    metadata:
      display_name: "Llama 3 70B"
      summary: "강력한 성능의 오픈 소스 모델"
      capabilities: ["text", "code"]
      knowledge_cutoff: "2023-12"
      pricing:
        input_tokens: 0.001
        output_tokens: 0.002
      limits:
        context_window: 8192
        max_output: 2048

설정에서 참조하세요:

model_metadata_file: "model-metadata.yaml"

Thinking 패턴 설정

일부 모델은 추론/사고 콘텐츠를 비표준 방식으로 출력합니다. 라우터는 스트리밍 응답을 적절히 변환하기 위해 모델별 thinking 패턴 설정을 지원합니다.

패턴 유형:

패턴 설명 예시 모델
none thinking 패턴 없음 (기본값) 대부분의 모델
standard 명시적 시작/종료 태그 (<think>...</think>) 커스텀 추론 모델
unterminated_start 시작 태그 없이 종료 태그만 있음 nemotron-3-nano

설정 예시:

models:
    - id: nemotron-3-nano
      metadata:
        display_name: "Nemotron 3 Nano"
        capabilities: ["chat", "reasoning"]
        # Thinking 패턴 설정
        thinking:
          pattern: unterminated_start
          end_marker: "</think>"
          assume_reasoning_first: true

Thinking 패턴 필드:

필드 타입 설명
pattern string 패턴 유형: none, standard, 또는 unterminated_start
start_marker string standard 패턴용 시작 마커 (예: <think>)
end_marker string 종료 마커 (예: </think>)
assume_reasoning_first boolean true인 경우, 종료 마커까지 첫 토큰들을 추론으로 처리

작동 방식:

모델에 thinking 패턴이 설정되면:

  1. 스트리밍 응답이 가로채져 변환됨
  2. end_marker 이전 콘텐츠는 reasoning_content 필드로 전송
  3. end_marker 이후 콘텐츠는 content 필드로 전송
  4. 출력은 호환성을 위해 OpenAI의 reasoning_content 형식을 따름

출력 예시:

// 추론 콘텐츠 (종료 마커 이전)
{"choices": [{"delta": {"reasoning_content": "분석해 보겠습니다..."}}]}

// 일반 콘텐츠 (종료 마커 이후)
{"choices": [{"delta": {"content": "답은 42입니다."}}]}

네임스페이스 인식 매칭

라우터는 네임스페이스 접두사가 있는 모델 ID를 지능적으로 처리합니다. 예:

  • 백엔드 반환: "custom/gpt-4", "openai/gpt-4", "optimized/gpt-4"
  • 메타데이터 정의: "gpt-4"
  • 결과: 모든 변형이 일치하고 동일한 메타데이터 수신

따라서 다른 백엔드가 공통 메타데이터 정의를 공유하면서 자체 명명 규칙을 사용할 수 있습니다.

메타데이터 우선순위 및 별칭 해석

모델의 메타데이터를 조회할 때, 라우터는 다음 우선순위 체인을 사용합니다:

  1. 정확한 모델 ID 매칭
  2. 정확한 별칭 매칭
  3. 날짜 접미사 정규화 (자동, 설정 불필요)
  4. 와일드카드 패턴 별칭 매칭
  5. 기본 모델 이름 폴백 (네임스페이스 제거)

각 소스 (백엔드 설정, 메타데이터 파일, 내장) 내에서 동일한 우선순위가 적용됩니다:

  1. 백엔드별 model_configs (최고 우선순위)

    backends:
      - name: "my-backend"
        model_configs:
          - id: "gpt-4"
            aliases: ["gpt-4-turbo", "gpt-4-vision"]
            metadata: {...}  # 이것이 우선
    

  2. 외부 메타데이터 파일 (두 번째 우선순위)

    model_metadata_file: "model-metadata.yaml"
    

  3. 내장 메타데이터 (OpenAI 및 Gemini 백엔드용)

자동 날짜 접미사 처리

LLM 프로바이더는 날짜 접미사가 있는 모델 버전을 자주 릴리스합니다. 라우터는 설정 없이 자동으로 날짜 접미사를 감지하고 정규화합니다:

지원되는 날짜 패턴:

  • -YYYYMMDD (예: claude-opus-4-5-20251130)
  • -YYYY-MM-DD (예: gpt-4o-2024-08-06)
  • -YYMM (예: o1-mini-2409)
  • @YYYYMMDD (예: model@20251130)

작동 방식:

요청: claude-opus-4-5-20251215
      ↓ (날짜 접미사 감지됨)
조회: claude-opus-4-5-20251101  (기존 메타데이터 항목)
      ↓ (기본 이름 일치)
결과: claude-opus-4-5-20251101 메타데이터 사용

이는 모델 패밀리당 메타데이터를 한 번만 설정하면 되고, 새로운 날짜 버전이 자동으로 메타데이터를 상속한다는 것을 의미합니다.

와일드카드 패턴 매칭

별칭은 * 문자를 사용한 glob 스타일 와일드카드 패턴을 지원합니다:

  • 접두사 매칭: claude-*claude-opus, claude-sonnet 등과 매칭
  • 접미사 매칭: *-previewgpt-4o-preview, o1-preview 등과 매칭
  • 중위 매칭: gpt-*-turbogpt-4-turbo, gpt-3.5-turbo 등과 매칭

와일드카드 패턴이 있는 설정 예:

models:
    - id: "claude-opus-4-5-20251101"
    aliases:
        - "claude-opus-4-5"     # 기본 이름의 정확한 매칭
        - "claude-opus-*"       # 모든 claude-opus 변형에 대한 와일드카드
    metadata:
        display_name: "Claude Opus 4.5"
        # 자동 매칭: claude-opus-4-5-20251130, claude-opus-test 등

    - id: "gpt-4o"
    aliases:
        - "gpt-4o-*-preview"    # 프리뷰 버전 매칭
        - "*-4o-turbo"          # 접미사 매칭
    metadata:
        display_name: "GPT-4o"

우선순위 참고: 정확한 별칭은 항상 와일드카드 패턴보다 먼저 매칭되어 둘 다 매칭될 수 있는 경우에도 예측 가능한 동작을 보장합니다.

모델 변형에 별칭 사용

별칭은 특히 다음에 유용합니다:

  • 다른 양자화: qwen3-32b-i1, qwen3-23b-i4 → 모두 qwen3 메타데이터 사용
  • 버전 변형: gpt-4-0125-preview, gpt-4-turbogpt-4 메타데이터 공유
  • 배포 변형: llama-3-70b-instruct, llama-3-70b-chat → 동일 기본 모델
  • 날짜 버전: claude-3-5-sonnet-20241022, claude-3-5-sonnet-20241201 → 메타데이터 공유 (날짜 접미사 처리로 자동)

별칭이 있는 설정 예:

model_configs:
  - id: "qwen3"
    aliases:
      - "qwen3-32b-i1"     # 1비트 양자화된 32B
      - "qwen3-23b-i4"     # 4비트 양자화된 23B
      - "qwen3-16b-q8"     # 8비트 양자화된 16B
      - "qwen3-*"          # 다른 모든 qwen3 변형에 대한 와일드카드
    metadata:
      display_name: "Qwen 3"
      summary: "Alibaba의 Qwen 모델 계열"
      # ... 나머지 메타데이터

API 응답

/v1/models 엔드포인트는 풍부한 모델 정보를 반환합니다:

{
  "object": "list",
  "data": [
    {
      "id": "gpt-4",
      "object": "model",
      "created": 1234567890,
      "owned_by": "openai",
      "backends": ["openai-proxy"],
      "metadata": {
        "display_name": "GPT-4",
        "summary": "복잡한 작업을 위한 가장 유능한 GPT-4 모델",
        "capabilities": ["text", "image", "function_calling"],
        "knowledge_cutoff": "2024-04",
        "pricing": {
          "input_tokens": 0.03,
          "output_tokens": 0.06
        },
        "limits": {
          "context_window": 128000,
          "max_output": 4096
        }
      }
    }
  ]
}

핫 리로드

Continuum Router는 서버 재시작 없이 런타임 설정 업데이트를 위한 핫 리로드를 지원합니다. 설정 변경은 자동으로 감지되어 분류에 따라 적용됩니다.

설정 항목 분류

설정 항목은 핫 리로드 기능에 따라 세 가지 범주로 분류됩니다:

즉시 업데이트 (서비스 중단 없음)

이 설정들은 서비스 중단 없이 즉시 업데이트됩니다:

# 로깅 설정
logging:
  level: "info"                  # ✅ 즉시: 로그 레벨 변경이 즉시 적용
  format: "json"                 # ✅ 즉시: 로그 형식 변경이 즉시 적용

# 속도 제한 설정
rate_limiting:
  enabled: true                  # ✅ 즉시: 속도 제한 활성화/비활성화
  limits:
    per_client:
      requests_per_second: 10    # ✅ 즉시: 새 제한이 즉시 적용
      burst_capacity: 20         # ✅ 즉시: 버스트 설정이 즉시 업데이트

# 서킷 브레이커 설정
circuit_breaker:
  enabled: true                  # ✅ 즉시: 서킷 브레이커 활성화/비활성화
  failure_threshold: 5           # ✅ 즉시: 임계값 업데이트가 즉시 적용
  timeout_seconds: 60            # ✅ 즉시: 타임아웃 변경이 즉시

# 재시도 설정
retry:
  max_attempts: 3                # ✅ 즉시: 재시도 정책이 즉시 업데이트
  base_delay: "100ms"            # ✅ 즉시: 백오프 설정이 즉시 적용
  exponential_backoff: true      # ✅ 즉시: 전략 변경이 즉시

# 전역 프롬프트
global_prompts:
  default: "당신은 도움이 됩니다"     # ✅ 즉시: 프롬프트 변경이 새 요청에 적용
  default_file: "prompts/system.md"  # ✅ 즉시: 파일 기반 프롬프트도 핫 리로드

# Admin 통계
admin:
  stats:
    retention_window: "24h"        # ✅ 즉시: 보존 기간 즉시 업데이트
    token_tracking: true           # ✅ 즉시: 토큰 추적 토글 즉시 적용

점진적 업데이트 (기존 연결 유지)

이 설정들은 기존 연결을 유지하면서 새 연결에 적용됩니다:

# 백엔드 설정
backends:
  - name: "ollama"               # ✅ 점진적: 새 요청이 업데이트된 백엔드 풀 사용
    url: "http://localhost:11434"
    weight: 2                    # ✅ 점진적: 새 요청에 로드 밸런싱 업데이트
    models: ["llama3.2"]         # ✅ 점진적: 모델 라우팅이 점진적으로 업데이트

# 헬스 체크 설정
health_checks:
  interval: "30s"                # ✅ 점진적: 다음 헬스 체크 주기가 새 간격 사용
  timeout: "10s"                 # ✅ 점진적: 새 체크가 업데이트된 타임아웃 사용
  unhealthy_threshold: 3         # ✅ 점진적: 임계값이 새 평가에 적용
  healthy_threshold: 2           # ✅ 점진적: 복구 임계값이 점진적으로 업데이트

# 타임아웃 설정
timeouts:
  connection: "10s"              # ✅ 점진적: 새 요청이 업데이트된 타임아웃 사용
  request:
    standard:
      first_byte: "30s"          # ✅ 점진적: 새 요청에 적용
      total: "180s"              # ✅ 점진적: 새 요청이 새 타임아웃 사용
    streaming:
      chunk_interval: "30s"      # ✅ 점진적: 새 스트림이 업데이트된 설정 사용

재시작 필요 (핫 리로드 불가)

이 설정들은 적용을 위해 서버 재시작이 필요합니다. 변경 사항은 경고로 기록됩니다:

server:
  bind_address: "0.0.0.0:8080"   # ❌ 재시작 필요: TCP/Unix 소켓 바인딩
  #   - "0.0.0.0:8080"
  #   - "unix:/var/run/router.sock"
  socket_mode: 0o660              # ❌ 재시작 필요: 소켓 권한
  workers: 4                      # ❌ 재시작 필요: 워커 스레드 풀 크기

이 설정들이 변경되면 라우터는 다음과 같은 경고를 기록합니다:

WARN server.bind_address가 '0.0.0.0:8080'에서 '0.0.0.0:9000'으로 변경됨 - 적용하려면 재시작 필요

핫 리로드 프로세스

  1. 파일 시스템 감시자 - 설정 파일 변경 자동 감지
  2. 설정 로딩 - 새 설정 로드 및 파싱
  3. 유효성 검사 - 스키마에 대해 새 설정 검증
  4. 변경 감지 - ConfigDiff 계산으로 변경 사항 식별
  5. 분류 - 변경 사항 분류 (즉시/점진적/재시작)
  6. 원자적 업데이트 - 유효한 설정이 원자적으로 적용
  7. 컴포넌트 전파 - 영향받는 컴포넌트에 업데이트 전파:
  8. HealthChecker가 체크 간격 및 임계값 업데이트
  9. RateLimitStore가 속도 제한 규칙 업데이트
  10. CircuitBreaker가 실패 임계값 및 타임아웃 업데이트
  11. BackendPool이 백엔드 설정 업데이트
  12. 즉시 헬스 체크 - 백엔드가 추가되면 즉시 헬스 체크가 실행되어 새 백엔드가 다음 주기적 체크를 기다리지 않고 1-2초 내에 사용 가능해짐
  13. 오류 처리 - 잘못된 경우 오류 기록 및 이전 설정 유지

핫 리로드 상태 확인

admin API를 사용하여 핫 리로드 상태 및 기능을 확인하세요:

# 핫 리로드가 활성화되었는지 확인
curl http://localhost:8080/admin/config/hot-reload-status

# 현재 설정 보기
curl http://localhost:8080/admin/config

핫 리로드 동작 예제

예제 1: 로그 레벨 변경 (즉시)

# 이전
logging:
  level: "info"

# 이후
logging:
  level: "debug"
결과: 로그 레벨이 즉시 변경됩니다. 재시작 불필요. 진행 중인 요청은 계속되고 새 로그는 debug 레벨 사용.

예제 2: 백엔드 추가 (즉시 헬스 체크와 함께 점진적)

# 이전
backends:
  - name: "ollama"
    url: "http://localhost:11434"

# 이후
backends:
  - name: "ollama"
    url: "http://localhost:11434"
  - name: "lmstudio"
    url: "http://localhost:1234"
결과: 새 백엔드가 풀에 추가되고 즉시 헬스 체크가 실행됩니다. 새 백엔드는 1-2초 내에 사용 가능해집니다(다음 주기적 헬스 체크까지 최대 30초를 기다리는 대신). 기존 요청은 현재 백엔드로 계속됩니다. 헬스 체크 통과 후 새 요청은 lmstudio로 라우팅 가능.

예제 2b: 백엔드 제거 (우아한 드레이닝)

# 이전
backends:
  - name: "ollama"
    url: "http://localhost:11434"
  - name: "lmstudio"
    url: "http://localhost:1234"

# 이후
backends:
  - name: "ollama"
    url: "http://localhost:11434"
결과: "lmstudio" 백엔드가 드레이닝 상태로 전환됩니다. 새 요청은 해당 백엔드로 라우팅되지 않지만, 기존 진행 중인 요청(스트리밍 포함)은 완료될 때까지 계속됩니다. 모든 참조가 해제되거나 5분 타임아웃 후에 백엔드가 메모리에서 완전히 제거됩니다.

백엔드 상태 생명주기

백엔드가 설정에서 제거되면 우아한 종료 프로세스를 거칩니다:

  1. Active → Draining: 백엔드가 드레이닝으로 표시됩니다. 새 요청은 이 백엔드를 건너뜁니다.
  2. 진행 중인 요청 완료: 기존 요청/스트림은 중단 없이 계속됩니다.
  3. 정리: 모든 참조가 해제되거나 5분 타임아웃 후에 백엔드가 제거됩니다.

설정 변경 중에도 진행 중인 연결에 영향을 주지 않습니다.

예제 3: 바인드 주소 변경 (재시작 필요)

# 이전
server:
  bind_address: "0.0.0.0:8080"

# 이후
server:
  bind_address: "0.0.0.0:9000"
결과: 경고 기록됨. 변경이 적용되지 않음. 새 포트에 바인드하려면 재시작 필요.

분산 추적

Continuum Router는 백엔드 서비스 간 요청 상관관계를 위한 분산 추적을 지원합니다. 이 기능은 여러 서비스를 통과하는 요청의 디버깅 및 모니터링에 도움을 줍니다.

설정

tracing:
  enabled: true                         # 분산 추적 활성화/비활성화 (기본값: true)
  w3c_trace_context: true               # W3C Trace Context 헤더 지원 (기본값: true)
  headers:
    trace_id: "X-Trace-ID"              # 추적 ID 헤더 이름 (기본값)
    request_id: "X-Request-ID"          # 요청 ID 헤더 이름 (기본값)
    correlation_id: "X-Correlation-ID"  # 상관 ID 헤더 이름 (기본값)

동작 방식

  1. 추적 ID 추출: 요청이 도착하면 라우터는 다음 우선순위로 헤더에서 추적 ID를 추출합니다:

    • W3C traceparent 헤더 (W3C 지원 활성화 시)
    • 설정된 trace_id 헤더 (X-Trace-ID)
    • 설정된 request_id 헤더 (X-Request-ID)
    • 설정된 correlation_id 헤더 (X-Correlation-ID)
  2. 추적 ID 생성: 헤더에서 추적 ID가 발견되지 않으면 새 UUID가 생성됩니다.

  3. 헤더 전파: 추적 ID는 여러 헤더를 통해 백엔드 서비스로 전파됩니다:

    • X-Request-ID: 광범위한 호환성을 위함
    • X-Trace-ID: 주요 추적 식별자
    • X-Correlation-ID: 상관관계 추적용
    • traceparent: W3C Trace Context (활성화 시)
    • tracestate: W3C Trace State (원본 요청에 존재 시)
  4. 재시도 시 보존: 동일한 추적 ID가 모든 재시도 시도에서 보존되어, 단일 클라이언트 요청에 대한 여러 백엔드 요청의 상관관계를 쉽게 파악할 수 있습니다.

구조화된 로깅

추적이 활성화되면 모든 로그 메시지에 trace_id 필드가 포함됩니다:

{
  "timestamp": "2024-01-15T10:30:00Z",
  "level": "info",
  "trace_id": "0af7651916cd43dd8448eb211c80319c",
  "message": "Processing chat completions request",
  "backend": "openai",
  "model": "gpt-4o"
}

W3C Trace Context

w3c_trace_context가 활성화되면 라우터는 W3C Trace Context 표준을 지원합니다:

  • 수신: traceparent 헤더 파싱 (형식: 00-{trace_id}-{span_id}-{flags})
  • 송신: 보존된 추적 ID와 새 span ID로 traceparent 헤더 생성
  • 상태: 원본 요청에 있는 경우 tracestate 헤더 전달

traceparent 예시: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

추적 비활성화

분산 추적을 비활성화하려면:

tracing:
  enabled: false

로드 밸런싱 전략

load_balancer:
  strategy: "round_robin"         # round_robin, weighted, random
  health_aware: true              # 정상 백엔드만 사용

전략:

  • round_robin: 백엔드 간 균등 분배
  • weighted: 백엔드 가중치에 기반한 분배
  • random: 무작위 선택 (패턴 방지에 좋음)

백엔드별 재시도 설정

backends:
  - name: "slow-backend"
    url: "http://slow.example.com"
    retry_override:               # 전역 재시도 설정 오버라이드
      max_attempts: 5             # 느린 백엔드에 더 많은 시도
      base_delay: "500ms"         # 더 긴 지연
      max_delay: "60s"

모델 폴백

Continuum Router는 기본 모델을 사용할 수 없을 때 자동 모델 폴백을 지원합니다. 이 기능은 계층화된 장애 조치 보호를 위해 서킷 브레이커와 통합됩니다.

설정

fallback:
  enabled: true

  # 각 기본 모델에 대한 폴백 체인 정의
  fallback_chains:
    # 동일 프로바이더 폴백
    "gpt-4o":
      - "gpt-4-turbo"
      - "gpt-3.5-turbo"

    "claude-opus-4-5-20251101":
      - "claude-sonnet-4-5"
      - "claude-haiku-4-5"

    # 크로스 프로바이더 폴백
    "gemini-2.5-pro":
      - "gemini-2.5-flash"
      - "gpt-4o"  # Gemini를 사용할 수 없으면 OpenAI로 폴백

  fallback_policy:
    trigger_conditions:
      error_codes: [429, 500, 502, 503, 504]
      timeout: true
      connection_error: true
      model_not_found: true
      circuit_breaker_open: true

    max_fallback_attempts: 3
    fallback_timeout_multiplier: 1.5
    preserve_parameters: true

  model_settings:
    "gpt-4o":
      fallback_enabled: true
      notify_on_fallback: true

트리거 조건

조건 설명
error_codes 폴백을 트리거하는 HTTP 상태 코드 (예: 429, 500, 502, 503, 504)
timeout 요청 타임아웃
connection_error TCP 연결 실패
model_not_found 백엔드에서 모델을 사용할 수 없음
circuit_breaker_open 백엔드 서킷 브레이커가 열림

응답 헤더

폴백이 사용되면 다음 헤더가 응답에 추가됩니다:

헤더 설명 예제
X-Fallback-Used 폴백이 사용되었음을 나타냄 true
X-Original-Model 원래 요청된 모델 gpt-4o
X-Fallback-Model 요청을 처리한 모델 gpt-4-turbo
X-Fallback-Reason 폴백이 트리거된 이유 error_code_429
X-Fallback-Attempts 폴백 시도 횟수 2

크로스 프로바이더 매개변수 변환

프로바이더 간 폴백 시 (예: OpenAI → Anthropic) 라우터가 요청 매개변수를 자동으로 변환합니다:

OpenAI 매개변수 Anthropic 매개변수 비고
max_tokens max_tokens 누락 시 자동 채움 (Anthropic 필수)
temperature temperature 직접 매핑
top_p top_p 직접 매핑
stop stop_sequences 배열 변환

프로바이더별 매개변수는 크로스 프로바이더 폴백 중에 자동으로 제거되거나 변환됩니다.

서킷 브레이커와의 통합

폴백 시스템은 서킷 브레이커와 함께 작동합니다:

  1. 서킷 브레이커가 실패 감지하고 임계값 초과 시 열림
  2. 폴백 체인 활성화 서킷 브레이커가 열렸을 때
  3. 요청이 폴백 모델로 라우팅 설정된 체인에 따라
  4. 서킷 브레이커가 복구 테스트하고 백엔드 복구 시 닫힘
# 예제: 서킷 브레이커와 폴백 결합 설정
circuit_breaker:
  enabled: true
  failure_threshold: 5
  timeout: 60s

fallback:
  enabled: true
  fallback_policy:
    trigger_conditions:
      circuit_breaker_open: true  # 서킷 브레이커에 연결

속도 제한

Continuum Router는 남용을 방지하고 공정한 리소스 할당을 보장하기 위해 /v1/models 엔드포인트에 대한 내장 속도 제한을 포함합니다.

현재 설정

속도 제한은 현재 다음 기본값으로 설정되어 있습니다:

# 참고: 이 값들은 현재 하드코딩되어 있지만 향후 버전에서 설정 가능해질 수 있습니다
rate_limiting:
  models_endpoint:
    # 클라이언트별 제한 (API 키 또는 IP 주소로 식별)
    sustained_limit: 100          # 분당 최대 요청 수
    burst_limit: 20               # 5초 윈도우에서 최대 요청 수

    # 시간 윈도우
    window_duration: 60s          # 지속 제한을 위한 슬라이딩 윈도우
    burst_window: 5s              # 버스트 감지를 위한 윈도우

    # 클라이언트 식별 우선순위
    identification:
      - api_key                   # Bearer 토큰 (처음 16자가 ID로 사용)
      - x_forwarded_for           # 프록시/로드 밸런서 헤더
      - x_real_ip                 # 대체 IP 헤더
      - fallback: "unknown"       # 식별자가 없을 때

작동 방식

  1. 클라이언트 식별: 각 요청은 다음을 사용하여 클라이언트와 연결:
  2. Authorization: Bearer <token> 헤더의 API 키 (선호)
  3. 프록시 헤더의 IP 주소 (폴백)

  4. 이중 윈도우 접근 방식:

  5. 지속 제한: 시간 경과에 따른 과도한 사용 방지
  6. 버스트 보호: 연속적인 빠른 요청 포착

  7. 독립적인 할당량: 각 클라이언트는 별도의 속도 제한:

  8. API 키 abc123...을 가진 클라이언트 A: 100 req/min
  9. API 키 def456...을 가진 클라이언트 B: 100 req/min
  10. IP 192.168.1.1의 클라이언트 C: 100 req/min

응답 헤더

속도 제한 시 응답 포함:

  • 상태 코드: 429 Too Many Requests
  • 오류 메시지: 버스트 또는 지속 제한 초과 여부 표시

캐시 TTL 최적화

캐시 오염 공격 방지를 위해:

  • 빈 모델 목록: 5초만 캐시
  • 일반 응답: 60초 캐시

이렇게 하면 공격자가 백엔드 장애 중에 빈 응답을 캐시하도록 강제하는 것을 방지합니다.

모니터링

속도 제한 위반은 메트릭에서 추적:

  • rate_limit_violations: 거부된 총 요청
  • empty_responses_returned: 제공된 빈 모델 목록
  • 문제가 있는 클라이언트 식별을 위한 클라이언트별 위반 추적

향후 개선 사항

향후 버전에서 지원될 수 있는 기능:

  • YAML/환경 변수를 통한 설정 가능한 속도 제한
  • 엔드포인트별 속도 제한
  • API 키별 사용자 정의 속도 제한
  • Redis 기반 분산 속도 제한

환경별 설정

개발 설정

# config/development.yaml
server:
  bind_address: "127.0.0.1:8080"

backends:
  - name: "local-ollama"
    url: "http://localhost:11434"

health_checks:
  interval: "10s"                 # 더 빈번한 확인
  timeout: "5s"

logging:
  level: "debug"                  # 상세 로깅
  format: "pretty"                # 사람이 읽기 쉬운
  enable_colors: true

프로덕션 설정

# config/production.yaml
server:
  bind_address: "0.0.0.0:8080"
  workers: 8                      # 프로덕션용 더 많은 워커
  connection_pool_size: 300       # 더 큰 연결 풀

backends:
  - name: "primary-openai"
    url: "https://api.openai.com"
    weight: 3
  - name: "secondary-azure"
    url: "https://azure-openai.example.com"
    weight: 2
  - name: "fallback-local"
    url: "http://internal-llm:11434"
    weight: 1

health_checks:
  interval: "60s"                 # 덜 빈번한 확인
  timeout: "15s"                  # 네트워크 지연을 위한 더 긴 타임아웃
  unhealthy_threshold: 5          # 더 많은 허용
  healthy_threshold: 3

request:
  timeout: "120s"                 # 프로덕션용 짧은 타임아웃
  max_retries: 5                  # 더 많은 재시도

logging:
  level: "warn"                   # 덜 상세한 로깅
  format: "json"                  # 구조화된 로깅

컨테이너 설정

# config/container.yaml - 컨테이너에 최적화
server:
  bind_address: "0.0.0.0:8080"
  workers: 0                      # 컨테이너 제한에 따라 자동 감지

backends:
  - name: "backend-1"
    url: "${BACKEND_1_URL}"       # 환경 변수 치환
  - name: "backend-2"
    url: "${BACKEND_2_URL}"

logging:
  level: "${LOG_LEVEL}"           # 환경을 통해 설정 가능
  format: "json"                  # 컨테이너에서 항상 JSON