설정 가이드¶
이 가이드는 Continuum Router 설정 방법을 설명합니다. 라우터는 다양한 배포 시나리오에 맞춰 명확한 우선순위 시스템과 함께 여러 설정 방법을 지원합니다.
설정 섹션:
- 서버 & 백엔드 — 서버 설정, 백엔드 프로바이더, 연결 옵션
- 헬스 & 캐싱 — 헬스 체크, 요청 설정, 재시도, 캐싱, 로깅
- 보안 & 관리 — API 키, 인증, WebUI, 관리 엔드포인트, ACP
- 고급 설정 — 글로벌 프롬프트, 모델 메타데이터, 핫 리로드, 트레이싱, 로드 밸런싱, 속도 제한
- 예제 — 설정 예제와 Rust Builder API
설정 방법¶
Continuum Router는 네 가지 설정 방법을 지원합니다:
- 설정 파일 (YAML) - 프로덕션 환경에 권장
- 환경 변수 - 컨테이너화된 배포에 적합
- 명령줄 인수 - 테스트 및 오버라이드에 유용
- Rust Builder API - 라이브러리 사용을 위한 타입 안전 프로그래밍 방식 설정
설정 파일 검색¶
라우터는 다음 위치에서 설정 파일을 순서대로 검색합니다. 각 위치에서 .yaml 확장자를 먼저, 그다음 .toml을 시도합니다:
--config플래그로 지정된 경로./config.yaml또는./config.toml(현재 디렉토리)~/.config/continuum-router/config.yaml또는config.toml(사용자 설정 디렉토리)/etc/continuum-router/config.yaml또는config.toml(시스템 설정 디렉토리)
설정 우선순위¶
설정은 다음 우선순위로 적용됩니다 (높은 것부터 낮은 순):
- 명령줄 인수 (최고 우선순위)
- 환경 변수
- 설정 파일
- 기본값 (최저 우선순위)
이렇게 하면 파일에 기본 설정을 두고, 컨테이너에서는 환경 변수로 특정 설정을 오버라이드하며, 명령줄 인수로 임시 조정을 할 수 있습니다.
설정 파일 형식¶
전체 설정 예제¶
# Continuum Router 설정
# 전체 주석이 달린 샘플은 continuum-router --generate-config로 생성하세요
# 서버 설정
server:
# bind_address는 단일 문자열 또는 주소 배열을 허용합니다
# TCP 형식: "host:port", Unix 소켓 형식: "unix:/path/to/socket"
bind_address: "0.0.0.0:8080" # 단일 주소
# bind_address: # 또는 다중 주소:
# - "0.0.0.0:8080" # 모든 인터페이스의 TCP
# - "unix:/var/run/router.sock" # Unix 소켓 (Linux/macOS, Windows 10 1809+)
# socket_mode: 0o660 # 선택 사항: Unix 소켓 파일 권한
workers: 4 # 워커 스레드 수 (0 = 자동 감지)
connection_pool_size: 100 # 백엔드당 최대 유휴 연결 수
# 모델 메타데이터 설정 (선택 사항)
model_metadata_file: "model-metadata.yaml" # 기본(0층) 메타데이터 파일 경로
model_metadata_dirs: # 추가 model-metadata.d 드롭인 디렉터리
- "/etc/router/metadata" # 관례 위치 다음에, 적은 순서대로 적용
# 로드 밸런싱 전략: RoundRobin (기본값), WeightedRoundRobin,
# LeastLatency, Random, ConsistentHash, PrefixAwareHash
selection_strategy: RoundRobin
# 백엔드 설정
backends:
# 내장 설정이 있는 네이티브 OpenAI API
- name: "openai"
type: openai # 네이티브 OpenAI 백엔드 사용
api_key: "${CONTINUUM_OPENAI_API_KEY}" # 환경 변수에서 로드
org_id: "${CONTINUUM_OPENAI_ORG_ID}" # 선택적 조직 ID
weight: 3
models: # 사용할 모델 지정
- gpt-4o
- gpt-4o-mini
- o3-mini
- text-embedding-3-large
retry_override: # 백엔드별 재시도 설정 (선택 사항)
max_attempts: 5
initial_delay: "200ms"
max_delay: "30s"
backoff_multiplier: 2.0
jitter: true
retryable_status_codes: [429, 502, 503, 504]
retryable_errors: [ConnectionError, TimeoutError]
timeout: "60s"
# 사용자 정의 메타데이터가 있는 일반 OpenAI 호환 백엔드
- name: "openai-compatible"
url: "https://custom-llm.example.com"
weight: 1
models:
- "gpt-4"
- "gpt-3.5-turbo"
model_configs: # 메타데이터가 포함된 향상된 모델 설정
- id: "gpt-4"
aliases: # 이 메타데이터를 공유하는 대체 ID (선택 사항)
- "gpt-4-0125-preview"
- "gpt-4-turbo-preview"
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
# 자동 URL 감지가 있는 Ollama 로컬 서버
- name: "local-ollama"
type: ollama # 기본값 http://localhost:11434
weight: 2
models:
- "llama2"
- "mistral"
- "codellama"
# vLLM 서버
- name: "vllm-server"
type: vllm
url: "http://localhost:8000"
weight: 1
# 지정하지 않으면 모델이 자동으로 검색됩니다
# 네임스페이스 접두사가 있는 모델 (예: "custom/gpt-4")은
# 자동으로 기본 이름의 메타데이터와 일치합니다 (예: "gpt-4")
# Google Gemini API (네이티브 백엔드)
- name: "gemini"
type: gemini # 네이티브 Gemini 백엔드 사용
api_key: "${CONTINUUM_GEMINI_API_KEY}" # 환경 변수에서 로드
weight: 2
models:
- gemini-3.1-pro-preview
- gemini-3-flash-preview
- gemini-2.5-pro
- gemini-2.5-flash
# 헬스 모니터링 설정
health_checks:
interval: "30s" # 백엔드 상태 확인 주기
timeout: "5s" # 헬스 체크 요청 타임아웃
unhealthy_threshold: 3 # 비정상으로 표시되기 전 실패 횟수
healthy_threshold: 2 # 정상으로 표시되기 전 성공 횟수
endpoint: "/health" # 헬스 체크에 사용되는 엔드포인트
warmup_check_interval: "1s" # 백엔드 워밍업(HTTP 503) 중 가속 체크 간격
max_warmup_duration: "300s" # 가속 워밍업 모드 최대 지속 시간
block_startup: true # 프리워밍과 첫 헬스 체크가 끝날 때까지 리스너 바인딩을 대기
# 요청 처리 및 타임아웃 설정
timeouts:
connection: "10s" # TCP 연결 설정 타임아웃
request:
standard: # 비스트리밍 요청
first_byte: "30s" # 첫 바이트 수신까지의 시간
total: "180s" # 전체 요청 타임아웃 (3분)
streaming: # 스트리밍 (SSE) 요청
first_byte: "60s" # 첫 SSE 청크까지의 시간
chunk_interval: "30s" # 청크 간 최대 시간
total: "600s" # 전체 스트리밍 타임아웃 (10분)
image_generation: # 이미지 생성 요청 (DALL-E 등)
first_byte: "60s" # 첫 바이트 수신까지의 시간
total: "180s" # 전체 타임아웃 (기본 3분)
model_overrides: # 모델별 타임아웃 오버라이드
gpt-5-latest:
streaming:
total: "1200s" # GPT-5용 20분
gpt-4o:
streaming:
total: "900s" # GPT-4o용 15분
health_check:
timeout: "5s" # 헬스 체크 타임아웃
interval: "30s" # 헬스 체크 간격
# 전역 재시도 및 복원력 설정
retry:
max_attempts: 3 # 최대 재시도 횟수
initial_delay: "100ms" # 재시도 간 초기 지연
max_delay: "10s" # 재시도 간 최대 지연
backoff_multiplier: 2.0 # 지수 백오프 배수
jitter: true # 지연에 무작위 지터 추가
retryable_status_codes: [429, 502, 503, 504]
retryable_errors: [ConnectionError, TimeoutError]
timeout: "30s" # 전체 재시도 예산
# 로깅 설정
logging:
level: "info" # 로그 레벨: trace, debug, info, warn, error
format: "json" # 로그 형식: json, pretty
# Files API 설정
files:
enabled: true # Files API 엔드포인트 활성화/비활성화
max_file_size: 536870912 # 최대 파일 크기 (바이트, 기본: 512MB)
storage_path: "./data/files" # 업로드된 파일 저장 경로 (~지원)
retention_days: 0 # 시작 시 보존 기간 초과 파일 정리 (일, 0 = 영구 보존)
metadata_storage: persistent # 메타데이터 백엔드: "memory" 또는 "persistent" (기본)
cleanup_orphans_on_startup: false # 시작 시 고아 파일 자동 정리
# 인증 및 권한
auth:
method: api_key # "none" 또는 "api_key" (기본)
required_scope: files # 접근에 필요한 API 키 스코프
enforce_ownership: true # 사용자가 자신의 파일만 접근 가능
admin_can_access_all: true # admin 스코프는 모든 파일 접근 가능
# 분산 추적 설정
tracing:
enabled: true # 분산 추적 활성화/비활성화
w3c_trace_context: true # W3C Trace Context 지원 (traceparent 헤더)
headers:
trace_id: "X-Trace-ID" # 추적 ID 헤더 이름
request_id: "X-Request-ID" # 요청 ID 헤더 이름
correlation_id: "X-Correlation-ID" # 상관 ID 헤더 이름
# 서킷 브레이커 설정
circuit_breaker:
enabled: true # 프록시 데이터 경로 상태 머신/Admin 제어 활성화
failure_threshold: 5 # 회로 개방까지의 연속 실패 횟수
failure_rate_threshold: 0.5 # 회로 개방 실패율 (0.0-1.0)
minimum_requests: 10 # 실패율 평가 전 최소 요청 수
timeout: "60s" # 복구 시도(반개방)까지의 시간
half_open_max_requests: 3 # 반개방 상태에서 허용되는 시험 요청 수
half_open_success_threshold: 2 # 회로를 닫는 데 필요한 성공 횟수
# 일반 LLM 프록시 경로가 이 상태를 기록하고 조회합니다. 열린 서킷은 선택에서
# 제외되며, 상태 확인·재시도·폴백과 함께 추론 라우팅을 보호합니다.
# 속도 제한 설정
rate_limiting:
enabled: true # 속도 제한 활성화
storage: memory # "memory" 또는 "redis"
limits:
per_client:
requests_per_second: 10
burst_capacity: 20
global:
requests_per_second: 1000
burst_capacity: 2000
# Admin API 설정
admin:
auth:
method: bearer # 인증 방법: none, bearer, basic, ip_whitelist, api_key
bearer_token: "${ADMIN_TOKEN}" # Admin 인증 토큰
stats:
enabled: true # 통계 수집 활성화/비활성화
retention_window: 24h # 윈도우 쿼리용 링 버퍼 보존 기간
token_tracking: true # 응답 본문에서 토큰 사용량 파싱
persistence:
enabled: true # 재시작 시 통계 영속 활성화
path: ./data/stats.json # 스냅샷 파일 경로
snapshot_interval: 5m # 주기적 스냅샷 간격
max_age: 7d # 시작 시 이보다 오래된 스냅샷은 폐기
# 메트릭 및 모니터링 설정
metrics:
enabled: true # Prometheus 메트릭 수집 활성화
path: "/metrics" # 메트릭 엔드포인트 경로
최소 설정¶
# 최소 설정 - 나머지 설정은 기본값 사용
server:
bind_address: "0.0.0.0:8080"
backends:
- name: "ollama"
url: "http://localhost:11434"
- name: "lm-studio"
url: "http://localhost:1234"
health_checks:
interval: "30s"
timeout: "5s"
unhealthy_threshold: 3
healthy_threshold: 2
endpoint: "/health"
logging:
level: "info"
format: "json"
환경 변수¶
환경 변수는 다음 두 가지 방식으로 설정에 반영됩니다.
- 직접 오버라이드: 시작 시 설정 파일의 해당 값을 덮어쓰는 소수의
CONTINUUM_*변수. -
일반
${VAR}보간: 시크릿뿐 아니라 모든 문자열 값 YAML/TOML 필드가 파일 로드 시 보간됩니다.logging.level: "${LOG_LEVEL}",files.storage_path: "/data/${TENANT}", 타임아웃 문자열, URL, 경로가 모두 동작합니다.${VAR}:VAR의 값으로 확장됩니다.${VAR:-default}:VAR가 설정되어 있으면 그 값, 없으면 리터럴default(빈 문자열도 가능)로 확장됩니다.$$: 리터럴$로 이스케이프됩니다. 따라서$${VAR}는 리터럴 텍스트${VAR}가 됩니다.- 변수 이름은
[A-Za-z_][A-Za-z0-9_]*와 일치해야 하며, 이름이 유효하지 않은${...}는 리터럴로 남습니다. 문자열 스칼라만 보간되므로, 숫자나 불리언이 필요한 자리의${VAR}는 타입 파싱에 실패합니다.
시작 및 핫 리로드 시 기본값 없는 미설정
${VAR}는 설정 경로를 명시하는 오류로 로드를 중단시킵니다. 반면continuum-router config validate는 미설정 참조를 경고로 보고하고 플레이스홀더를 유지하므로, 프로덕션 시크릿 없이도 템플릿을 검증할 수 있습니다.
직접 오버라이드¶
| 변수 | 타입 | 설명 |
|---|---|---|
CONTINUUM_BIND_ADDRESS |
string | server.bind_address 오버라이드 |
CONTINUUM_BACKEND_URLS |
string | 쉼표로 구분된 백엔드 URL. backends 목록을 오버라이드 |
CONTINUUM_LOG_LEVEL |
string | logging.level 오버라이드 (trace, debug, info, warn, error) |
CONTINUUM_SELECTION_STRATEGY |
string | selection_strategy 오버라이드. RoundRobin, WeightedRoundRobin, LeastLatency, Random, ConsistentHash, PrefixAwareHash를 허용합니다. 인식할 수 없는 값은 조용히 대체되지 않고 시작이 실패합니다. 우선순위: --selection-strategy > 이 변수 > 파일 값 > 기본값 RoundRobin |
CONTINUUM_FILES_AUTH_METHOD |
string | files.auth.method 오버라이드. none 또는 api_key를 허용합니다. 파일에 files: 섹션이 없어도 적용됩니다. 인식할 수 없는 값은 조용히 대체되지 않고 시작이 실패합니다 |
CONTINUUM_FILES_AUTH_SCOPE |
string | files.auth.required_scope 오버라이드 |
CONTINUUM_FILES_ENFORCE_OWNERSHIP |
boolean | files.auth.enforce_ownership 오버라이드. 정확히 true 또는 false(소문자)만 허용하며, 다른 값은 시작이 실패합니다 |
CONTINUUM_FILES_ADMIN_ACCESS_ALL |
boolean | files.auth.admin_can_access_all 오버라이드. CONTINUUM_FILES_ENFORCE_OWNERSHIP과 동일한 엄격한 true/false 문법을 사용합니다 |
RUST_LOG |
string | Rust 전용 로깅 필터 설정 |
네이티브 백엔드 API 키¶
네이티브 백엔드는 설정에 api_key가 없을 때 다음 변수로 폴백합니다:
| 변수 | 사용처 |
|---|---|
CONTINUUM_OPENAI_API_KEY |
type: openai 백엔드 |
CONTINUUM_OPENAI_ORG_ID |
type: openai 백엔드 (선택적 조직 ID) |
CONTINUUM_ANTHROPIC_API_KEY |
type: anthropic 백엔드 |
CONTINUUM_GEMINI_API_KEY |
type: gemini 백엔드 |
API 키 관리¶
| 변수 | 타입 | 기본값 | 설명 |
|---|---|---|---|
CONTINUUM_API_KEY |
string | - | 간단한 배포용 단일 API 키 |
CONTINUUM_API_KEY_SCOPES |
string | "read,write" |
API 키의 쉼표로 구분된 스코프 |
CONTINUUM_API_KEY_USER_ID |
string | "admin" |
API 키와 연결된 사용자 ID |
CONTINUUM_API_KEY_ORG_ID |
string | "default" |
API 키와 연결된 조직 ID |
CONTINUUM_DEV_MODE |
boolean | false |
개발용 API 키 활성화 (프로덕션에서 사용 금지) |
모델 메타데이터 내려받기 토큰¶
continuum-router metadata download는 아래 변수를 순서대로 확인해 비어 있지 않은 첫 값을 GitHub 토큰으로 씁니다. 전체 규칙은 모델 메타데이터 내려받기를 참조하세요.
| 변수 | 타입 | 설명 |
|---|---|---|
CONTINUUM_GITHUB_TOKEN |
string | 권장. continuum-router 저장소 읽기 권한이 있는 GitHub 토큰 |
GITHUB_TOKEN |
string | 대체. CI 러너가 이미 내보내는 이름 |
GH_TOKEN |
string | 대체. GitHub CLI가 이미 내보내는 이름 |
저장소가 비공개인 동안에는 토큰이 필수이며, 토큰은 raw.githubusercontent.com과 api.github.com에만 전송되고 로그나 출력에는 남지 않습니다.
환경 설정 예제¶
# 직접 오버라이드
export CONTINUUM_BIND_ADDRESS="0.0.0.0:9000"
export CONTINUUM_BACKEND_URLS="http://localhost:11434,http://localhost:1234"
export CONTINUUM_LOG_LEVEL="debug"
# config.yaml의 ${...} 치환에서 참조
export CONTINUUM_OPENAI_API_KEY="sk-..."
export ADMIN_TOKEN="my-admin-token"
# 라우터 시작
continuum-router
그 밖의 설정(헬스 체크, 타임아웃, 재시도, 캐싱, files.auth를 제외한 나머지 Files API 설정 등)은 모두 설정 파일로 지정합니다.
명령줄 인수¶
명령줄 인수는 최고 우선순위의 설정 방법으로 테스트와 임시 오버라이드에 유용합니다.
핵심 옵션¶
| 인수 | 타입 | 설명 |
|---|---|---|
--mode <MODE> |
enum | 서버 모드: http (기본값) 또는 stdio (ACP JSON-RPC 2.0 전송) |
-c, --config <FILE> |
path | 설정 파일 경로 |
--generate-config |
flag | YAML 샘플 설정을 생성하고 종료 |
--generate-example-config |
flag | 예제 설정 문서(환경 변수, 라우팅, 검증 규칙, 우선순위)를 생성하고 종료 |
--generate-toml-config |
flag | TOML 형식 샘플 설정을 생성하고 종료 |
--model-metadata <FILE> |
path | 모델 메타데이터 YAML 파일 경로 (설정 파일보다 우선) |
백엔드 설정¶
| 인수 | 타입 | 설명 |
|---|---|---|
--backends <URLs> |
string | 쉼표로 구분된 백엔드 URL |
--backend-url <URL> |
string | 단일 백엔드 URL (지원 중단) |
서버 설정¶
| 인수 | 타입 | 설명 |
|---|---|---|
--bind <ADDRESS> |
string | 서버 바인드 주소 |
--connection-pool-size <SIZE> |
integer | HTTP 연결 풀 크기 |
로드 밸런싱¶
| 인수 | 타입 | 설명 |
|---|---|---|
--selection-strategy <STRATEGY> |
string | 로드 밸런싱 전략: RoundRobin (기본값), WeightedRoundRobin, LeastLatency, Random, ConsistentHash, PrefixAwareHash |
헬스 체크 설정¶
| 인수 | 타입 | 설명 |
|---|---|---|
--disable-health-checks |
flag | 헬스 모니터링 비활성화 |
--health-check-interval <SECONDS> |
integer | 헬스 체크 간격 |
--health-check-timeout <SECONDS> |
integer | 헬스 체크 타임아웃 |
--unhealthy-threshold <COUNT> |
integer | 비정상 판정까지의 실패 횟수 |
--healthy-threshold <COUNT> |
integer | 정상 판정까지의 성공 횟수 |
설정 유틸리티¶
| 인수 | 타입 | 설명 |
|---|---|---|
--migrate-config-file <FILE> |
path | 라우터를 시작하지 않고 설정 파일 문제를 마이그레이션/수정. 백업을 만들고 모든 변경 사항을 보고 (YAML, TOML 지원) |
--dry-run |
flag | --migrate-config-file과 함께 사용해 변경 사항을 적용 없이 미리보기 |
컨테이너 헬스 체크¶
| 인수 | 타입 | 설명 |
|---|---|---|
--health-check |
flag | 실행 중인 서버의 상태를 확인하고 종료 (0 = 정상, 1 = 비정상). Docker HEALTHCHECK 용도 |
--health-check-url <URL> |
string | 확인할 헬스 엔드포인트 (기본값: http://localhost:8080/health) |
서브커맨드¶
| 명령 | 설명 |
|---|---|
auth login --backend <NAME> |
지정한 백엔드(auth.type이 oauth여야 함)에 대해 OAuth 디바이스 인가 플로를 실행하고 토큰을 auth.oauth.token_store에 저장. OAuth 백엔드 설정은 서버 & 백엔드를 참조하세요. |
config validate <FILE> |
YAML/TOML을 검증하고 구조화된 JSON 보고서를 출력. 유효하지 않으면 0이 아닌 코드로 종료 |
config generate --template <NAME> [--output <FILE>] |
내장 템플릿 9개 중 하나를 생성: minimal, development, multi-provider, production-ha, api-gateway, kv-cache-optimized, smart-routing, disaggregated, cost-optimized |
config diff <A> <B> |
두 설정의 유효 값을 비교. 비밀 값으로 추정되는 값은 마스킹 |
config show [--resolved] <FILE> |
정규화된 설정을 출력. --resolved는 공급자 기본값과 지원되는 필드별 환경 변수 확장을 적용하므로 평문 자격 증명이 출력될 수 있음 |
metadata download (별칭 metadata update) |
continuum-router 저장소에서 model-metadata.yaml을 내려받아 라우터가 읽는 경로에 설치. 아래 모델 메타데이터 내려받기 참조 |
metadata show [--resolved] [--json] |
기본 파일과 모든 model-metadata.d/ 드롭인을 합친 메타데이터를 적용된 레이어·건너뛴 파일과 함께 출력. --resolved는 원본 병합 대신 라우터가 실제로 쓰는 타입 문서를 출력. 아래 계층형 모델 메타데이터 참조 |
mcp-serve |
stdio에서 설정 도우미 MCP 서버 실행. 기본 빌드와 공식 릴리스에 포함된 mcp Cargo 기능 필요 |
모델 메타데이터 내려받기¶
model-metadata.yaml에는 라우터 전체가 참조하는 가격, 컨텍스트 윈도, 기능, thinking 패턴, /v1/models 응답 기본값이 담겨 있습니다. 라우터 바이너리보다 훨씬 자주 바뀌는데 릴리스 아카이브·Debian 패키지·컨테이너에는 이 파일이 들어 있지 않으므로, metadata download가 정식 사본을 받아 라우터가 읽는 위치에 설치합니다.
export CONTINUUM_GITHUB_TOKEN="$(gh auth token)" # 저장소가 비공개인 동안 필수
continuum-router metadata download # main을 받아 해석된 경로에 설치
continuum-router metadata download --check # 최신 여부만 확인하고 쓰지 않음
continuum-router metadata download --ref v1.15.5 # 릴리스 태그로 고정
continuum-router metadata download --output ./model-metadata.yaml
인증¶
continuum-router 저장소는 비공개라서 기본 소스에 인증 없이 요청하면 실제로 존재하는 ref까지 포함해 모든 ref가 404로 돌아옵니다. 읽기 권한이 있는 GitHub 토큰을 아래 변수 중 하나로 넘기세요. 순서대로 확인해서 비어 있지 않은 첫 값을 씁니다.
| 변수 | 설명 |
|---|---|
CONTINUUM_GITHUB_TOKEN |
권장. 라우터 자체의 CONTINUUM_* 환경 변수 체계와 맞으므로, 호스트의 모든 도구와 토큰을 공유하지 않고 라우터에만 한정할 수 있음 |
GITHUB_TOKEN |
CI 러너가 이미 내보내는 이름 |
GH_TOKEN |
GitHub CLI가 이미 내보내는 이름 |
앞뒤 공백은 잘라내고 공백만 있는 값은 설정되지 않은 것으로 취급하므로, 실수로 남은 export GITHUB_TOKEN=이 실제 GH_TOKEN을 가리지 않습니다.
--token 플래그는 일부러 두지 않았습니다. 명령줄 인수로 넘긴 비밀은 셸 히스토리에 남고 같은 머신의 모든 사용자에게 ps 출력으로 보입니다.
토큰은 요청 호스트가 정확히 raw.githubusercontent.com 또는 api.github.com일 때만 붙습니다. 미러를 가리키는 --url이나 raw.githubusercontent.com.evil.test 같은 유사 호스트에는 절대 전달되지 않습니다. 토큰은 로그에도 출력에도 남지 않으며, 보고서에는 값이 아니라 토큰을 읽어온 변수 이름만 나옵니다.
404가 나면 어느 쪽인지 메시지로 구분됩니다. 토큰이 없으면 세 변수 이름과 함께 저장소가 비공개일 수 있다고 알리고, 토큰이 있으면 ref나 경로가 없거나 토큰에 접근 권한이 없을 수 있다고 알립니다.
--url에는 비공개 미러용 basic 인증 정보를 담을 수 있습니다(https://ci:token@mirror.internal/model-metadata.yaml). 이 값은 Authorization: Basic 헤더로 전송되고, 명령이 소스를 출력하는 모든 지점(사람이 읽는 보고서, --json의 source_url 필드, 오류 메시지)에서는 userinfo를 먼저 제거하므로 비밀번호가 CI 로그나 보관된 보고서에 남지 않습니다.
플래그¶
| 플래그 | 기본값 | 동작 |
|---|---|---|
--ref <GIT_REF> |
main |
내려받을 브랜치 또는 태그. --url과 함께 쓸 수 없음 |
--url <URL> |
--ref에서 유도 |
미러나 폐쇄망 설치를 위한 전체 HTTPS 소스 오버라이드 |
--output <FILE> |
아래 규칙으로 해석 | 명시적 대상 경로 |
--check |
꺼짐 | 내려받아 비교만 하고 쓰지 않음 |
--force |
꺼짐 | 콘텐츠 해시가 같아도 다시 씀 |
--no-backup |
꺼짐 | 교체 대상 파일의 <file>.bak 사본을 만들지 않음 |
--timeout <SECONDS> |
30 |
요청 전체 제한 시간 |
--json |
꺼짐 | 사람이 읽는 보고서 대신 기계가 읽는 보고서 출력 |
대상 경로 해석에는 전역 -c/--config와 --model-metadata를 그대로 씁니다.
대상 경로 해석¶
대상은 다음 순서로 정해지며 성공하든 실패하든 언제나 출력됩니다.
--output <FILE>- 전역
--model-metadata <FILE>(틸드 확장 적용) - 불러온 설정의
model_metadata_file(틸드 확장 적용) - 발견한 설정 파일 옆의
model-metadata.yaml ~/.config/continuum-router/model-metadata.yaml
--model-metadata가 설정 필드보다 위에 있는 이유는 라우터 본체에서 하는 일이 바로 그것이기 때문입니다. 이 플래그는 model_metadata_file을 오버라이드합니다. 따라서 continuum-router --model-metadata /etc/cr/meta.yaml metadata download는 해당 라우터 인스턴스가 실제로 읽을 경로에 파일을 설치합니다.
상위 디렉터리가 없으면 만듭니다.
안전 동작¶
- 내려받은 내용은 디스크를 건드리기 전에 메타데이터 스키마로 파싱·검증합니다. 형식이 깨졌거나 스키마에 맞지 않으면 0이 아닌 코드로 종료하고 기존 파일은 바이트 단위로 그대로 둡니다.
- 교체는 대상 디렉터리 안의 임시 파일을 거쳐 원자적으로 이뤄지며, 기존 파일의 권한 모드를 유지합니다(새 파일은
0644). --no-backup을 주지 않으면 이전 파일을<file>.bak으로 남깁니다.- SHA-256으로 내용을 비교하므로 바뀐 것이 없으면
--force없이는 쓰지 않고 건너뜁니다. - HTTPS 소스만 받아들이며, HTTPS를 벗어나는 리다이렉트는 거부합니다.
- 8 MiB를 넘는 응답은 거부합니다.
종료 코드¶
| 코드 | 의미 |
|---|---|
0 |
정상적으로 썼거나 이미 최신 |
1 |
내려받기·검증·쓰기 실패 |
2 |
--check 전용: 업데이트가 있음 |
2가 따로 있어서 cron이나 CI가 오래된 사본을 오류로 취급하지 않고 분기할 수 있습니다.
실행 중인 라우터에 미치는 영향¶
파일을 갱신해도 실행 중인 라우터가 핫 리로드하지는 않습니다. 설정 감시기는 설정 파일 경로만 감시하고 model_metadata_file과 model_metadata_dirs 모두 admin 설정 스키마에서 requires_restart로 표시되어 있으므로, 새 메타데이터를 적용하려면 라우터를 재시작하거나 설정 리로드를 걸어야 합니다. 명령은 실행할 때마다 이 안내를 출력합니다.
계층형 모델 메타데이터¶
model_metadata_file은 0층일 뿐 전부가 아닙니다. 메타데이터는 계층형 탐색 경로에서 조립되므로, 이 프로젝트가 배포하고 metadata download가 덮어쓰는 벤더 기준 파일과 운영자가 직접 관리하는 파일이 서로 섞이지 않습니다.
탐색 경로¶
우선순위가 낮은 것부터 나열하며, 더 구체적인 위치가 나중에 적용되어 이깁니다.
model_metadata_file(기본 파일, 틸드 확장 적용)/etc/continuum-router/model-metadata.d/~/.config/continuum-router/model-metadata.d/./model-metadata.d/model_metadata_dirs에 적은 디렉터리 전부, 적은 순서대로
model_metadata_dirs는 관례 위치를 대체하지 않고 보강합니다. 또한 항목을 그대로 쓰기 때문에 뒤에 model-metadata.d를 붙이지 않습니다. 쿠버네티스 ConfigMap을 /etc/router/metadata/에 마운트했다면 그 경로를 그대로 적으면 됩니다. 전역 --model-metadata 플래그의 의미도 그대로입니다. 이 플래그는 기본 파일을 지정할 뿐 드롭인을 끄지 않습니다.
전형적인 배치는 다음과 같습니다.
/etc/continuum-router/model-metadata.yaml # 벤더 기준 파일, 덮어써도 안전
/etc/continuum-router/model-metadata.d/
10-private-models.yaml # 우리가 직접 호스팅하는 모델
50-negotiated-pricing.yaml # gpt-5 계약 단가
90-local-overrides.yaml
파일 선택 규칙¶
한 디렉터리 안에서는 이렇게 동작합니다.
- 확장자가
.yaml또는.yml인 일반 파일만 읽으며, 확장자는 대소문자를 구분하지 않습니다 - 파일 이름의 사전순으로 적용합니다.
10-/50-/90-숫자 접두사 관례가 동작하는 이유입니다 - 하위 디렉터리로는 재귀하지 않습니다
- 점으로 시작하는 파일,
*~,*.swp는 건너뜁니다. 편집기 백업과 vim 스왑 파일이 여기에 해당합니다 - 심볼릭 링크는 따라가되 최종 대상이 일반 파일이어야 합니다
- 디렉터리가 없어도 오류가 아닙니다
병합 규칙¶
레이어는 역직렬화 이전 단계인 파싱된 YAML에서 병합합니다.
- 매핑 대 매핑: 키 단위 재귀 병합. 상위 레이어가 적지 않은 키는 하위 레이어에서 물려받습니다
- 시퀀스: 통째로 교체하며, 합집합을 만들지 않습니다
- 스칼라(명시적
null포함): 교체합니다 models항목은id를 키로 씁니다. 이미 있는id는 기존 항목에 병합하고, 새id는 뒤에 덧붙입니다response_defaults는 매핑이므로 필드 단위로 병합됩니다
역직렬화 전에 병합하기 때문에 좁은 범위의 오버라이드가 가능합니다. responses_only를 언급하지 않은 오버라이드 파일이 물려받은 true를 지워버릴 수 없고, 나중에 메타데이터 스키마에 필드가 추가되어도 병합 코드를 손대지 않아도 됩니다.
시퀀스를 합집합이 아니라 교체로 정한 것은 의도적입니다. aliases와 capabilities가 시퀀스인데, 합집합이라면 물려받은 항목을 지울 방법이 없습니다.
벤더 기준 파일이 이렇고
models:
- id: gpt-5
aliases: [gpt-5-latest]
metadata:
display_name: GPT-5
capabilities: [chat, reasoning, vision]
pricing: { input_tokens: 1.25, output_tokens: 10.0 }
model-metadata.d/50-negotiated-pricing.yaml이 이렇다면
결과는 display_name, capabilities, aliases가 계속 업스트림을 따라가면서 pricing만 계약 단가로 바뀝니다. 운영자는 전체 사본을 떠안고 낡아가는 대신 네 줄만 관리하면 됩니다.
메타데이터 계층 바깥의 우선순위¶
바뀌지 않습니다. 백엔드 model_configs가 여전히 병합된 메타데이터보다 우선하고, 병합된 메타데이터가 내장 OpenAI 레지스트리보다 우선합니다. 이번 변경은 메타데이터 계층을 조립하는 방식만 바꿉니다.
실패 처리와 한도¶
읽기·파싱·검증에 실패한 드롭인은 경고와 함께 건너뛰고 나머지 탐색 경로는 그대로 적용됩니다. 잘못된 운영자 파일 하나가 실행 중인 라우터를 내려앉히지 못하도록 하기 위해서입니다. 기본 model_metadata_file이 잘못된 경우는 종전과 똑같이 치명적 오류입니다. 책임은 한 번만 묻습니다. 어떤 레이어를 원인으로 지목하는 것은 그 레이어를 적용하기 직전까지 병합 결과가 메타데이터 스키마를 만족했을 때뿐입니다. 그래서 기본 파일이 이미 스키마를 어기고 있으면 그 위에 얹힌 멀쩡한 드롭인들이 아니라 기본 파일이 원인으로 보고됩니다. metadata show는 이 정보를 Schema failure introduced by 항목으로 출력합니다.
파일은 최대 64개, 합계 크기는 최대 8 MiB까지 조립합니다. 한도를 넘으면 잘라내지 않고 오류로 처리합니다. 오버라이드 집합을 일부만 조용히 적용하는 쪽이 조립을 거부하는 쪽보다 나쁘기 때문입니다.
핫 리로드 도중 조립이 치명적으로 실패하면 메타데이터 계층만이 아니라 리로드 전체가 중단됩니다. 라우터는 조립 실패를 원인으로 지목하는 오류를 남기고, 검증에 실패한 설정 파일을 만났을 때와 똑같이 직전에 읽어 둔 설정과 그때 함께 적재한 모델 메타데이터를 그대로 유지한 채 서비스를 이어갑니다. 리로드는 전부 적용하거나 전혀 적용하지 않습니다. 메타데이터 캐시가 빈 설정을 그대로 발행하면 재시작도 없이 가격, 컨텍스트 윈도, 기능, /v1/models 응답 기본값이 조용히 백엔드 보고값으로 되돌아가기 때문입니다. 특히 드롭인 디렉터리에서 중요합니다. 65번째 파일을 넣거나 합계를 8 MiB 너머로 밀어 올릴 만큼 큰 파일 하나를 넣는 것만으로 치명적 조립 실패가 발생하며, model-metadata.d/ 디렉터리에 쓰기 권한이 있는 사람은 기존 파일을 건드리지 않고도 이 상태를 만들 수 있습니다.
결과 확인¶
건너뛴 파일은 클라이언트 쪽에서 보이지 않으므로, 확인 수단은 metadata show입니다.
continuum-router metadata show # 원본 병합 결과와 레이어 보고서
continuum-router metadata show --resolved # 라우터가 실제로 쓰는 타입 문서
continuum-router metadata show --json # 같은 보고서를 기계가 읽는 객체로
두 모드 모두 탐색 경로, 적용 순서대로의 레이어 목록(나중 레이어가 가져간 모델 id와 그 이전 파일 포함), 건너뛴 파일과 사유를 출력합니다. 머리말은 YAML 주석으로 쓰므로 metadata show > merged.yaml로 저장해도 라우터가 읽을 수 있는 파일이 됩니다. --resolved 없이 실행하면 스키마가 무시하는 키까지 포함한 원본 병합 결과를 그대로 출력하므로 오타가 눈에 보이고, --resolved를 붙이면 병합 결과를 역직렬화해 response_defaults를 검증·정제한 뒤 타입 값을 다시 직렬화합니다.
metadata show는 탐색 경로를 조립할 수 있었다면 건너뛴 파일이 있어도 0으로 종료하고, 기본 파일을 읽을 수 없거나 한도를 넘긴 것 같은 치명적 실패에만 1로 종료합니다.
찾아낸 설정 파일이나 --config로 직접 지정한 설정 파일을 찾지 못했거나 불러오지 못했다면, metadata show는 그 설정의 model_metadata_file과 model_metadata_dirs가 빠진 탐색 경로를 아무 말 없이 보여주는 대신 이를 알립니다. 사람이 읽는 보고서에는 # WARNING: 머리글 줄로, --json에는 config_warning 필드로 나타납니다.
metadata download와의 관계¶
metadata download는 기본 model_metadata_file만 씁니다. 드롭인 디렉터리는 읽지도 쓰지도 않습니다. 이 분리 덕분에 내려받기를 몇 번이든 반복해도 안전합니다. 벤더 계층은 언제든 버리고 다시 만들 수 있고, 운영자 계층은 손대지 않습니다. 업그레이드 시 권장 절차는 "metadata download를 실행하고, 내가 바꾼 내용은 model-metadata.d/에 두기"입니다.
드롭인 변경도 핫 리로드되지 않습니다. model_metadata_dirs는 model_metadata_file과 마찬가지로 admin 설정 스키마에서 requires_restart입니다.
CLI 사용 예제¶
# 설정 파일과 오버라이드 사용
continuum-router --config config.yaml --bind "0.0.0.0:9000"
# 백엔드 임시 오버라이드
continuum-router --config config.yaml --backends "http://localhost:11434"
# 사용자 정의 모델 메타데이터 파일 사용
continuum-router --config config.yaml --model-metadata /path/to/custom-metadata.yaml
# 틸드 확장과 함께 모델 메타데이터 사용
continuum-router --model-metadata ~/configs/model-metadata.yaml
# 테스트용 헬스 체크 설정 조정
continuum-router --config config.yaml --health-check-interval 10
# 샘플 설정 생성
continuum-router --generate-config > my-config.yaml
# 검증하고 목적별 템플릿 생성
continuum-router config validate my-config.yaml
continuum-router config generate --template production-ha --output production.yaml
# 설정 조회 또는 비교 (`--resolved` 출력에는 비밀 값이 포함될 수 있음)
continuum-router config show my-config.yaml
continuum-router config diff my-config.yaml production.yaml
# 구버전 설정 파일 마이그레이션 (미리보기 후 적용)
continuum-router --migrate-config-file config.yaml --dry-run
continuum-router --migrate-config-file config.yaml
# Docker HEALTHCHECK 프로브
continuum-router --health-check --health-check-url http://localhost:8080/health
# ChatGPT/Codex 백엔드용 OAuth 디바이스 플로 로그인
continuum-router --config config.yaml auth login --backend chatgpt
# MCP 클라이언트에 설정 도우미 등록
claude mcp add continuum-router-config -- continuum-router mcp-serve
# 모델 메타데이터 갱신, 또는 로컬 사본이 오래됐는지 확인 (종료 코드 2 = 업데이트 있음)
export CONTINUUM_GITHUB_TOKEN="$(gh auth token)"
continuum-router metadata download
continuum-router metadata download --check --json
# 이 라우터 인스턴스가 읽는 경로에 설치
continuum-router --model-metadata /etc/continuum-router/model-metadata.yaml metadata download
# model-metadata.d 계층까지 반영된 실제 적용 메타데이터 확인
continuum-router metadata show --resolved
continuum-router metadata show --json