Admin REST API 레퍼런스¶
이 문서는 Continuum Router의 Admin REST API를 사용하여 설정 제어 애플리케이션을 구축하는 개발자를 위한 포괄적인 가이드를 제공합니다. 설정 관리 API를 사용하면 서버 재시작 없이 런타임에 설정을 보고, 수정하고, 관리할 수 있습니다.
개요¶
Admin REST API는 Continuum Router의 설정 시스템에 프로그래밍 방식으로 액세스할 수 있게 하며 다음을 지원합니다:
- 실시간 설정 보기: 민감한 데이터가 자동으로 마스킹된 현재 설정 조회
- 동적 설정 업데이트: 서버 재시작 없이 설정 섹션 수정
- 설정 버전 관리: 전체 히스토리 및 롤백 기능으로 변경 사항 추적
- 백엔드 관리: 백엔드를 동적으로 추가, 제거, 수정
- 내보내기/가져오기: 여러 형식 (YAML, JSON, TOML)으로 설정 저장 및 복원
주요 기능¶
| 기능 | 설명 |
|---|---|
| 핫 리로드 | 섹션 타입에 따라 변경 사항이 즉시 또는 점진적으로 적용됨 |
| 민감 정보 마스킹 | API 키, 비밀번호, 토큰이 응답에서 자동으로 마스킹됨 |
| 검증 | dry-run 지원으로 적용 전 모든 변경 사항 검증 |
| 감사 로깅 | 보안 및 규정 준수를 위해 모든 수정 사항 로깅 |
| 히스토리 추적 | 롤백을 위해 최대 100개의 설정 버전 유지 |
인증¶
모든 Admin API 엔드포인트는 Admin Auth 시스템을 통한 인증이 필요합니다.
인증 방법¶
1. Bearer 토큰¶
2. Basic 인증¶
3. API 키 헤더¶
설정¶
config.yaml에서 admin 인증을 설정합니다:
admin:
auth:
method: bearer_token # 옵션: none, bearer_token, basic, api_key
token: "${ADMIN_TOKEN}" # 환경 변수 지원
# Basic auth의 경우:
# username: admin
# password: "${ADMIN_PASSWORD}"
# IP 화이트리스트 (선택 사항)
ip_whitelist:
- "127.0.0.1"
- "10.0.0.0/8"
# 설정 가능한 제한
max_history_entries: 100
max_backend_name_length: 256
기본 URL 및 헤더¶
기본 URL¶
일반 요청 헤더¶
일반 응답 헤더¶
설정 쿼리 API¶
전체 설정 가져오기¶
민감한 정보가 마스킹된 전체 설정을 조회합니다.
응답¶
{
"config": {
"server": {
"bind_address": "0.0.0.0:8080",
"workers": 4
},
"backends": [
{
"name": "openai",
"url": "https://api.openai.com",
"api_key": "sk-***abcd",
"weight": 1
}
],
"logging": {
"level": "info"
},
"rate_limiting": {
"enabled": true,
"requests_per_minute": 100
}
},
"hot_reload_enabled": true,
"last_modified": "2025-12-13T10:30:00Z"
}
예제¶
설정 섹션 목록¶
핫 리로드 기능과 함께 사용 가능한 모든 설정 섹션을 가져옵니다.
응답¶
{
"sections": [
{
"name": "server",
"description": "Server configuration including bind address and workers",
"hot_reload_capability": "requires_restart"
},
{
"name": "backends",
"description": "Backend server configurations",
"hot_reload_capability": "gradual"
},
{
"name": "logging",
"description": "Logging configuration",
"hot_reload_capability": "immediate"
},
{
"name": "rate_limiting",
"description": "Rate limiting configuration",
"hot_reload_capability": "immediate"
},
{
"name": "circuit_breaker",
"description": "Circuit breaker configuration",
"hot_reload_capability": "immediate"
},
{
"name": "retry",
"description": "Retry policy configuration",
"hot_reload_capability": "immediate"
},
{
"name": "timeouts",
"description": "Timeout configuration",
"hot_reload_capability": "gradual"
},
{
"name": "health_checks",
"description": "Health check configuration",
"hot_reload_capability": "gradual"
},
{
"name": "global_prompts",
"description": "Global prompt injection configuration",
"hot_reload_capability": "immediate"
},
{
"name": "fallback",
"description": "Model fallback configuration",
"hot_reload_capability": "gradual"
},
{
"name": "files",
"description": "Files API configuration",
"hot_reload_capability": "gradual"
},
{
"name": "api_keys",
"description": "API keys configuration",
"hot_reload_capability": "immediate"
},
{
"name": "metrics",
"description": "Metrics and monitoring configuration",
"hot_reload_capability": "gradual"
},
{
"name": "admin",
"description": "Admin API configuration",
"hot_reload_capability": "gradual"
},
{
"name": "routing",
"description": "Request routing configuration",
"hot_reload_capability": "gradual"
}
]
}
예제¶
curl -s http://localhost:8080/admin/config/sections \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq '.sections[].name'
섹션 설정 가져오기¶
특정 섹션의 설정을 조회합니다.
경로 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 예 | 섹션 이름 (위 목록 참조) |
응답¶
{
"section": "logging",
"config": {
"level": "info",
"format": "json",
"file": "/var/log/continuum-router.log"
},
"hot_reload_capability": "immediate",
"description": "Logging configuration"
}
예제¶
# 로깅 설정 가져오기
curl -s http://localhost:8080/admin/config/logging \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
# 백엔드 설정 가져오기
curl -s http://localhost:8080/admin/config/backends \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
설정 스키마 가져오기¶
설정 검증을 위한 JSON Schema를 조회합니다.
쿼리 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 아니오 | 특정 섹션에 대한 스키마만 가져오기 |
응답¶
{
"schema": {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"server": {
"type": "object",
"properties": {
"bind_address": {
"type": "string",
"pattern": "^[^:]+:[0-9]+$",
"description": "Server bind address in host:port format"
},
"workers": {
"type": "integer",
"minimum": 1,
"description": "Number of worker threads"
}
}
},
"logging": {
"type": "object",
"properties": {
"level": {
"type": "string",
"enum": ["trace", "debug", "info", "warn", "error"]
}
}
}
}
}
}
예제¶
# 전체 스키마 가져오기
curl -s http://localhost:8080/admin/config/schema \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
# 특정 섹션 스키마 가져오기
curl -s "http://localhost:8080/admin/config/schema?section=logging" \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
설정 수정 API¶
섹션 설정 대체¶
전체 섹션 설정을 새 값으로 대체합니다.
요청 본문¶
응답¶
{
"success": true,
"message": "Configuration updated successfully",
"version": 5,
"hot_reload_capability": "immediate",
"applied": true,
"warnings": []
}
예제¶
# 로깅 레벨을 debug로 업데이트
curl -X PUT http://localhost:8080/admin/config/logging \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"config": {
"level": "debug"
}
}'
섹션 부분 업데이트¶
JSON 병합 패치 의미론을 사용하여 부분 업데이트를 적용합니다.
요청 본문¶
지정된 필드만 업데이트되고 다른 필드는 변경되지 않습니다.
응답¶
{
"success": true,
"message": "Configuration partially updated",
"version": 6,
"hot_reload_capability": "immediate",
"applied": true,
"merged_config": {
"level": "warn",
"format": "json",
"file": "/var/log/continuum-router.log"
}
}
예제¶
# 속도 제한 값만 업데이트
curl -X PATCH http://localhost:8080/admin/config/rate_limiting \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"config": {
"requests_per_minute": 200
}
}'
설정 검증¶
변경 사항을 적용하지 않고 설정을 검증합니다.
요청 본문¶
{
"section": "server",
"config": {
"bind_address": "0.0.0.0:9090",
"workers": 8
},
"dry_run": true
}
응답 (유효)¶
{
"valid": true,
"errors": [],
"warnings": [
{
"field": "bind_address",
"message": "Changing bind_address requires server restart"
}
],
"hot_reload_capability": "requires_restart"
}
응답 (유효하지 않음)¶
{
"valid": false,
"errors": [
{
"field": "workers",
"message": "workers must be greater than 0",
"code": "VALIDATION_ERROR"
}
],
"warnings": []
}
예제¶
# 적용 전 검증
curl -X POST http://localhost:8080/admin/config/validate \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"section": "rate_limiting",
"config": {
"enabled": true,
"requests_per_minute": 500
}
}'
설정 적용¶
보류 중인 설정 변경 사항을 즉시 적용합니다 (핫 리로드 트리거).
요청 본문¶
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
sections | array | 아니오 | 적용할 특정 섹션 (기본값: 모든 보류 중) |
force | boolean | 아니오 | 경고가 있어도 강제 적용 (기본값: false) |
응답¶
{
"success": true,
"applied_sections": ["logging", "rate_limiting"],
"version": 7,
"results": {
"logging": {
"status": "applied",
"hot_reload_type": "immediate"
},
"rate_limiting": {
"status": "applied",
"hot_reload_type": "immediate"
}
}
}
예제¶
curl -X POST http://localhost:8080/admin/config/apply \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sections": ["logging"]
}'
설정 저장/복원 API¶
설정 내보내기¶
지정된 형식으로 현재 설정을 내보냅니다.
요청 본문¶
{
"format": "yaml",
"sections": ["server", "backends", "logging"],
"include_sensitive": false,
"include_defaults": true
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
format | string | 예 | 출력 형식: yaml, json, 또는 toml |
sections | array | 아니오 | 내보낼 섹션 (기본값: 전체) |
include_sensitive | boolean | 아니오 | 마스킹 안 된 민감 데이터 포함 (기본값: false) |
include_defaults | boolean | 아니오 | 기본값 포함 (기본값: true) |
응답¶
{
"format": "yaml",
"content": "server:\n bind_address: \"0.0.0.0:8080\"\n workers: 4\n\nbackends:\n - name: openai\n url: https://api.openai.com\n api_key: \"sk-***abcd\"\n",
"exported_at": "2025-12-13T10:30:00Z",
"sections_exported": ["server", "backends", "logging"]
}
예제¶
# YAML로 내보내기
curl -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"format": "yaml"}' | jq -r '.content' > config-backup.yaml
# JSON으로 내보내기
curl -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"format": "json"}' | jq -r '.content' > config-backup.json
# 특정 섹션 내보내기
curl -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"format": "yaml",
"sections": ["backends", "rate_limiting"]
}'
설정 가져오기¶
콘텐츠에서 설정을 가져오고 적용합니다.
요청 본문¶
{
"format": "yaml",
"content": "logging:\n level: info\n format: json\n",
"apply": true,
"dry_run": false,
"merge": true
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
format | string | 예 | 콘텐츠 형식: yaml, json, 또는 toml |
content | string | 예 | 설정 콘텐츠 (최대 1MB) |
apply | boolean | 아니오 | 검증 후 적용 (기본값: true) |
dry_run | boolean | 아니오 | 적용 없이 검증만 (기본값: false) |
merge | boolean | 아니오 | 기존 설정과 병합 (기본값: false) |
응답¶
{
"success": true,
"message": "Configuration imported and applied",
"version": 8,
"validation": {
"valid": true,
"errors": [],
"warnings": []
},
"sections_imported": ["logging"],
"applied": true
}
예제¶
# 파일에서 가져오기
curl -X POST http://localhost:8080/admin/config/import \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"format\": \"yaml\",
\"content\": $(cat config-backup.yaml | jq -Rs .),
\"apply\": true
}"
# 가져오기 미리보기 (dry run)
curl -X POST http://localhost:8080/admin/config/import \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"format": "yaml",
"content": "logging:\n level: debug\n",
"dry_run": true
}'
설정 히스토리 가져오기¶
설정 변경 히스토리를 확인합니다.
쿼리 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
limit | integer | 아니오 | 반환할 항목 수 (기본값: 20, 최대: 100) |
offset | integer | 아니오 | 건너뛸 항목 수 (기본값: 0) |
section | string | 아니오 | 섹션 이름으로 필터링 |
응답¶
{
"history": [
{
"version": 8,
"timestamp": "2025-12-13T10:30:00Z",
"sections_changed": ["logging"],
"source": "api",
"user": "admin",
"description": "Updated logging level to debug",
"rollback_available": true
},
{
"version": 7,
"timestamp": "2025-12-13T10:25:00Z",
"sections_changed": ["rate_limiting"],
"source": "api",
"user": "admin",
"description": "Increased rate limit to 200 rpm",
"rollback_available": true
},
{
"version": 6,
"timestamp": "2025-12-13T09:00:00Z",
"sections_changed": ["backends"],
"source": "file_reload",
"user": "system",
"description": "Configuration file changed",
"rollback_available": true
}
],
"total_entries": 8,
"current_version": 8
}
예제¶
# 최근 히스토리 가져오기
curl -s http://localhost:8080/admin/config/history \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
# 특정 섹션 히스토리 가져오기
curl -s "http://localhost:8080/admin/config/history?section=backends&limit=10" \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
설정 롤백¶
이전 설정 버전으로 롤백합니다.
경로 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
version | integer | 예 | 롤백할 버전 번호 |
요청 본문¶
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
sections | array | 아니오 | 롤백할 특정 섹션 (기본값: 변경된 모든 섹션) |
dry_run | boolean | 아니오 | 적용 없이 미리보기 (기본값: false) |
응답¶
{
"success": true,
"message": "Rolled back to version 5",
"previous_version": 8,
"new_version": 9,
"sections_rolled_back": ["logging", "rate_limiting"],
"changes": {
"logging": {
"level": {
"from": "debug",
"to": "info"
}
}
}
}
예제¶
# 버전 5로 롤백
curl -X POST http://localhost:8080/admin/config/rollback/5 \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
# 롤백 미리보기 (dry run)
curl -X POST http://localhost:8080/admin/config/rollback/5 \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dry_run": true}'
백엔드 관리 API¶
백엔드 추가¶
새 백엔드를 동적으로 추가합니다.
요청 본문¶
{
"name": "new-ollama",
"url": "http://192.168.1.100:11434",
"weight": 1,
"models": ["llama3.2", "mistral"],
"api_key": "optional-key",
"enabled": true,
"health_check": {
"enabled": true,
"path": "/v1/models"
}
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 고유한 백엔드 이름 (영숫자, -, _) |
type | string | 아니오 | 백엔드 타입: openai, azure, vllm, ollama, anthropic, gemini, llamacpp, generic. 기본값: generic (자동 감지) |
url | string | 예 | 백엔드 URL (http:// 또는 https://) |
weight | integer | 아니오 | 로드 밸런싱 가중치 (기본값: 1) |
models | array | 아니오 | 이 백엔드가 제공하는 모델 목록 |
api_key | string | 아니오 | 백엔드 인증용 API 키 |
enabled | boolean | 아니오 | 백엔드 활성화 여부 (기본값: true) |
백엔드 타입 자동 감지¶
type이 지정되지 않거나 generic으로 설정된 경우, 라우터는 백엔드의 /v1/models 엔드포인트를 자동으로 탐색하여 백엔드 타입을 감지합니다. 현재 자동 감지가 지원되는 백엔드:
- llama.cpp: 응답의
owned_by: "llamacpp"또는 llama.cpp 전용 메타데이터 필드로 식별
이를 통해 명시적인 타입 설정 없이도 llama.cpp 백엔드를 원활하게 통합할 수 있습니다:
# llama.cpp 백엔드 - 타입 자동 감지
curl -X POST http://localhost:8080/admin/backends \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "local-llama",
"url": "http://localhost:8080"
}'
응답¶
{
"success": true,
"message": "Backend 'new-ollama' added successfully",
"backend": {
"name": "new-ollama",
"url": "http://192.168.1.100:11434",
"weight": 1,
"models": ["llama3.2", "mistral"],
"enabled": true,
"health_status": "unknown"
}
}
예제¶
curl -X POST http://localhost:8080/admin/backends \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "new-backend",
"url": "http://192.168.1.100:11434",
"weight": 2,
"models": ["llama3.2"]
}'
백엔드 가져오기¶
특정 백엔드의 설정을 가져옵니다.
응답¶
{
"name": "openai",
"url": "https://api.openai.com",
"api_key": "sk-***abcd",
"weight": 1,
"models": ["gpt-4", "gpt-3.5-turbo"],
"enabled": true,
"health_status": "healthy",
"stats": {
"total_requests": 1250,
"failed_requests": 12,
"average_latency_ms": 150,
"last_used": "2025-12-13T10:29:55Z"
}
}
예제¶
백엔드 업데이트¶
백엔드 설정을 업데이트합니다.
요청 본문¶
{
"url": "https://api.openai.com",
"weight": 2,
"models": ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"],
"enabled": true
}
응답¶
{
"success": true,
"message": "Backend 'openai' updated successfully",
"backend": {
"name": "openai",
"url": "https://api.openai.com",
"weight": 2,
"models": ["gpt-4", "gpt-4-turbo", "gpt-3.5-turbo"],
"enabled": true
}
}
예제¶
curl -X PUT http://localhost:8080/admin/backends/openai \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"weight": 3,
"models": ["gpt-4", "gpt-4-turbo"]
}'
백엔드 삭제¶
라우터에서 백엔드를 제거합니다.
쿼리 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
force | boolean | 아니오 | 활성 연결이 있어도 강제 삭제 |
응답¶
{
"success": true,
"message": "Backend 'old-backend' removed successfully",
"removed_backend": "old-backend"
}
참고사항¶
- 마지막 백엔드 삭제 허용: 라우터는 백엔드가 없는 상태로도 운영할 수 있습니다. 마지막 백엔드가 삭제되면:
/v1/models는 빈 목록을 반환- 라우팅 요청은 503 "No backends available" 반환
POST /admin/backends를 통해 새 백엔드 추가 가능
예제¶
curl -X DELETE http://localhost:8080/admin/backends/old-backend \
-H "Authorization: Bearer $ADMIN_TOKEN"
# 강제 삭제
curl -X DELETE "http://localhost:8080/admin/backends/old-backend?force=true" \
-H "Authorization: Bearer $ADMIN_TOKEN"
백엔드 가중치 업데이트¶
로드 밸런싱을 위한 백엔드 가중치만 업데이트합니다.
요청 본문¶
응답¶
{
"success": true,
"message": "Backend 'openai' weight updated to 5",
"previous_weight": 2,
"new_weight": 5
}
예제¶
curl -X PUT http://localhost:8080/admin/backends/openai/weight \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"weight": 5}'
백엔드 모델 업데이트¶
백엔드의 모델 목록을 업데이트합니다.
요청 본문¶
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
models | array | 예 | 모델 이름 목록 |
append | boolean | 아니오 | 기존 목록에 추가 (기본값: false, 대체) |
응답¶
{
"success": true,
"message": "Backend 'openai' models updated",
"models": ["gpt-4", "gpt-4-turbo", "gpt-4o", "gpt-3.5-turbo"]
}
예제¶
# 모델 대체
curl -X PUT http://localhost:8080/admin/backends/openai/models \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"models": ["gpt-4", "gpt-4o"]}'
# 모델 추가
curl -X PUT http://localhost:8080/admin/backends/openai/models \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"models": ["gpt-4.5-turbo"], "append": true}'
데이터 모델¶
설정 섹션¶
| 섹션 | 설명 | 핫 리로드 |
|---|---|---|
server | 바인드 주소, 워커, 연결 풀 | 재시작 필요 |
backends | 백엔드 URL, 가중치, 모델 | 점진적 |
health_checks | 간격, 임계값 | 점진적 |
logging | 로그 레벨, 형식, 출력 | 즉시 |
retry | 최대 시도, 지연, 백오프 | 즉시 |
timeouts | 연결, 요청, 유휴 타임아웃 | 점진적 |
rate_limiting | 제한, 스토리지, 화이트리스트 | 즉시 |
circuit_breaker | 임계값, 복구 시간 | 즉시 |
global_prompts | 시스템 프롬프트 주입 | 즉시 |
fallback | 폴백 체인, 정책 | 점진적 |
files | Files API 설정 | 점진적 |
api_keys | API 키 설정 | 즉시 |
metrics | Prometheus, 레이블 | 점진적 |
admin | Admin API 설정 | 점진적 |
routing | 모델 라우팅 규칙 | 점진적 |
백엔드 객체¶
{
"name": "string",
"url": "string (http:// 또는 https://)",
"api_key": "string (선택 사항, 응답에서 마스킹)",
"weight": "integer (1-100)",
"models": ["string"],
"enabled": "boolean",
"health_check": {
"enabled": "boolean",
"path": "string",
"interval": "string (duration)"
}
}
히스토리 항목 객체¶
{
"version": "integer",
"timestamp": "string (ISO 8601)",
"sections_changed": ["string"],
"source": "string (api|file_reload|initial|rollback)",
"user": "string",
"description": "string (선택 사항)",
"rollback_available": "boolean"
}
검증 결과 객체¶
{
"valid": "boolean",
"errors": [
{
"field": "string",
"message": "string",
"code": "string"
}
],
"warnings": [
{
"field": "string",
"message": "string"
}
]
}
핫 리로드 동작¶
업데이트 타입¶
| 타입 | 동작 | 섹션 |
|---|---|---|
| 즉시 | 즉시 적용, 중단 없음 | logging, ratelimiting, circuitbreaker, retry, globalprompts, apikeys |
| 점진적 | 기존 연결 유지, 새 연결이 새 설정 사용 | backends, health_checks, timeouts, fallback, files, metrics, admin, routing |
| 재시작 필요 | 경고로 로깅, 서버 재시작 필요 | server.bind_address, server.workers |
예제 워크플로우¶
# 1. 현재 설정 확인
curl -s http://localhost:8080/admin/config/logging | jq
# 2. 변경 검증
curl -X POST http://localhost:8080/admin/config/validate \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"section": "logging", "config": {"level": "debug"}}'
# 3. 변경 적용 (즉시 효과)
curl -X PATCH http://localhost:8080/admin/config/logging \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"config": {"level": "debug"}}'
# 4. 변경 확인
curl -s http://localhost:8080/admin/config/logging | jq '.config.level'
오류 처리¶
오류 응답 형식¶
오류 코드¶
| 코드 | HTTP 상태 | 설명 |
|---|---|---|
VALIDATION_ERROR | 400 | 설정 검증 실패 |
INVALID_SECTION | 400 | 알 수 없는 설정 섹션 |
PARSE_ERROR | 400 | 설정 콘텐츠 파싱 실패 |
SECTION_NOT_FOUND | 404 | 섹션을 찾을 수 없음 |
VERSION_NOT_FOUND | 404 | 히스토리 버전을 찾을 수 없음 |
BACKEND_NOT_FOUND | 404 | 백엔드를 찾을 수 없음 |
BACKEND_EXISTS | 409 | 해당 이름의 백엔드가 이미 존재함 |
CONTENT_TOO_LARGE | 413 | 설정 콘텐츠가 1MB 제한 초과 |
INTERNAL_ERROR | 500 | 내부 서버 오류 |
오류 예제¶
// 검증 오류
{
"error_code": "VALIDATION_ERROR",
"message": "Configuration validation failed",
"details": {
"errors": [
{"field": "workers", "message": "workers must be greater than 0"}
]
}
}
// 섹션을 찾을 수 없음
{
"error_code": "SECTION_NOT_FOUND",
"message": "Configuration section 'invalid' not found",
"details": {
"available_sections": ["server", "backends", "logging", "..."]
}
}
// 백엔드가 이미 존재함
{
"error_code": "BACKEND_EXISTS",
"message": "Backend 'openai' already exists",
"details": {
"existing_backend": "openai"
}
}
클라이언트 SDK 예제¶
Python¶
import requests
from typing import Optional, Dict, Any, List
from dataclasses import dataclass
@dataclass
class ContinuumAdminClient:
"""Continuum Router Admin API 클라이언트"""
base_url: str
token: str
def __post_init__(self):
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {self.token}",
"Content-Type": "application/json"
})
# 설정 쿼리 API
def get_full_config(self) -> Dict[str, Any]:
"""마스킹된 민감 데이터가 포함된 전체 설정 가져오기"""
resp = self.session.get(f"{self.base_url}/admin/config/full")
resp.raise_for_status()
return resp.json()
def get_sections(self) -> List[Dict[str, Any]]:
"""모든 설정 섹션 가져오기"""
resp = self.session.get(f"{self.base_url}/admin/config/sections")
resp.raise_for_status()
return resp.json()["sections"]
def get_section(self, section: str) -> Dict[str, Any]:
"""특정 섹션의 설정 가져오기"""
resp = self.session.get(f"{self.base_url}/admin/config/{section}")
resp.raise_for_status()
return resp.json()
def get_schema(self, section: Optional[str] = None) -> Dict[str, Any]:
"""검증을 위한 JSON 스키마 가져오기"""
params = {"section": section} if section else {}
resp = self.session.get(
f"{self.base_url}/admin/config/schema",
params=params
)
resp.raise_for_status()
return resp.json()
# 설정 수정 API
def update_section(self, section: str, config: Dict[str, Any]) -> Dict[str, Any]:
"""섹션 설정 대체"""
resp = self.session.put(
f"{self.base_url}/admin/config/{section}",
json={"config": config}
)
resp.raise_for_status()
return resp.json()
def patch_section(self, section: str, config: Dict[str, Any]) -> Dict[str, Any]:
"""섹션 설정 부분 업데이트"""
resp = self.session.patch(
f"{self.base_url}/admin/config/{section}",
json={"config": config}
)
resp.raise_for_status()
return resp.json()
def validate_config(
self,
section: str,
config: Dict[str, Any],
dry_run: bool = True
) -> Dict[str, Any]:
"""적용 없이 설정 검증"""
resp = self.session.post(
f"{self.base_url}/admin/config/validate",
json={"section": section, "config": config, "dry_run": dry_run}
)
resp.raise_for_status()
return resp.json()
def apply_config(
self,
sections: Optional[List[str]] = None,
force: bool = False
) -> Dict[str, Any]:
"""보류 중인 설정 변경 적용"""
body = {"force": force}
if sections:
body["sections"] = sections
resp = self.session.post(
f"{self.base_url}/admin/config/apply",
json=body
)
resp.raise_for_status()
return resp.json()
# 설정 저장/복원 API
def export_config(
self,
format: str = "yaml",
sections: Optional[List[str]] = None,
include_sensitive: bool = False
) -> str:
"""지정된 형식으로 설정 내보내기"""
body = {"format": format, "include_sensitive": include_sensitive}
if sections:
body["sections"] = sections
resp = self.session.post(
f"{self.base_url}/admin/config/export",
json=body
)
resp.raise_for_status()
return resp.json()["content"]
def import_config(
self,
content: str,
format: str = "yaml",
apply: bool = True,
dry_run: bool = False
) -> Dict[str, Any]:
"""콘텐츠에서 설정 가져오기"""
resp = self.session.post(
f"{self.base_url}/admin/config/import",
json={
"format": format,
"content": content,
"apply": apply,
"dry_run": dry_run
}
)
resp.raise_for_status()
return resp.json()
def get_history(
self,
limit: int = 20,
offset: int = 0,
section: Optional[str] = None
) -> Dict[str, Any]:
"""설정 변경 히스토리 가져오기"""
params = {"limit": limit, "offset": offset}
if section:
params["section"] = section
resp = self.session.get(
f"{self.base_url}/admin/config/history",
params=params
)
resp.raise_for_status()
return resp.json()
def rollback(
self,
version: int,
sections: Optional[List[str]] = None,
dry_run: bool = False
) -> Dict[str, Any]:
"""이전 버전으로 롤백"""
body = {"dry_run": dry_run}
if sections:
body["sections"] = sections
resp = self.session.post(
f"{self.base_url}/admin/config/rollback/{version}",
json=body
)
resp.raise_for_status()
return resp.json()
# 백엔드 관리 API
def list_backends(self) -> List[Dict[str, Any]]:
"""모든 백엔드 목록"""
resp = self.session.get(f"{self.base_url}/admin/backends")
resp.raise_for_status()
return resp.json()["backends"]
def get_backend(self, name: str) -> Dict[str, Any]:
"""백엔드 설정 가져오기"""
resp = self.session.get(f"{self.base_url}/admin/backends/{name}")
resp.raise_for_status()
return resp.json()
def add_backend(
self,
name: str,
url: str,
weight: int = 1,
models: Optional[List[str]] = None
) -> Dict[str, Any]:
"""새 백엔드 추가"""
body = {"name": name, "url": url, "weight": weight}
if models:
body["models"] = models
resp = self.session.post(
f"{self.base_url}/admin/backends",
json=body
)
resp.raise_for_status()
return resp.json()
def update_backend(self, name: str, **kwargs) -> Dict[str, Any]:
"""백엔드 설정 업데이트"""
resp = self.session.put(
f"{self.base_url}/admin/backends/{name}",
json=kwargs
)
resp.raise_for_status()
return resp.json()
def delete_backend(self, name: str, force: bool = False) -> Dict[str, Any]:
"""백엔드 삭제"""
params = {"force": str(force).lower()} if force else {}
resp = self.session.delete(
f"{self.base_url}/admin/backends/{name}",
params=params
)
resp.raise_for_status()
return resp.json()
def update_backend_weight(self, name: str, weight: int) -> Dict[str, Any]:
"""백엔드 가중치 업데이트"""
resp = self.session.put(
f"{self.base_url}/admin/backends/{name}/weight",
json={"weight": weight}
)
resp.raise_for_status()
return resp.json()
def update_backend_models(
self,
name: str,
models: List[str],
append: bool = False
) -> Dict[str, Any]:
"""백엔드 모델 업데이트"""
resp = self.session.put(
f"{self.base_url}/admin/backends/{name}/models",
json={"models": models, "append": append}
)
resp.raise_for_status()
return resp.json()
# 사용 예제
if __name__ == "__main__":
client = ContinuumAdminClient(
base_url="http://localhost:8080",
token="your-admin-token"
)
# 현재 로깅 설정 가져오기
logging_config = client.get_section("logging")
print(f"현재 로그 레벨: {logging_config['config']['level']}")
# 로깅 레벨 업데이트
result = client.patch_section("logging", {"level": "debug"})
print(f"업데이트됨: {result['success']}")
# 새 백엔드 추가
client.add_backend(
name="new-ollama",
url="http://192.168.1.100:11434",
weight=2,
models=["llama3.2", "mistral"]
)
# 설정 백업 내보내기
backup = client.export_config(format="yaml")
with open("config-backup.yaml", "w") as f:
f.write(backup)
모범 사례¶
1. 적용 전 항상 검증¶
# 1단계: 검증
curl -X POST http://localhost:8080/admin/config/validate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"section": "logging", "config": {"level": "debug"}}'
# 2단계: 유효한 경우에만 적용
curl -X PATCH http://localhost:8080/admin/config/logging \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"config": {"level": "debug"}}'
2. 가져오기에 Dry Run 사용¶
# 가져오기 변경 미리보기
curl -X POST http://localhost:8080/admin/config/import \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"format": "yaml",
"content": "...",
"dry_run": true
}'
3. 정기적인 설정 백업¶
# 일일 백업 스크립트
#!/bin/bash
DATE=$(date +%Y%m%d)
curl -s -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"format": "yaml"}' | jq -r '.content' > "config-backup-$DATE.yaml"
4. 설정 히스토리 모니터링¶
# 최근 변경 확인
curl -s http://localhost:8080/admin/config/history?limit=5 \
-H "Authorization: Bearer $TOKEN" | jq '.history[] | {version, timestamp, sections_changed}'
5. 최소 변경에 부분 업데이트 (PATCH) 사용¶
# 필요한 것만 업데이트
curl -X PATCH http://localhost:8080/admin/config/rate_limiting \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"config": {"requests_per_minute": 200}}'
6. 프로덕션 전 스테이징에서 설정 변경 테스트¶
# 예제: 프로덕션 전 스테이징에서 설정 테스트
staging_client = ContinuumAdminClient("http://staging:8080", staging_token)
production_client = ContinuumAdminClient("http://production:8080", prod_token)
# 먼저 스테이징에 적용
staging_client.patch_section("rate_limiting", {"requests_per_minute": 500})
# 스테이징에서 확인
staging_config = staging_client.get_section("rate_limiting")
assert staging_config["config"]["requests_per_minute"] == 500
# 그 다음 프로덕션에 적용
production_client.patch_section("rate_limiting", {"requests_per_minute": 500})
보안 고려 사항¶
1. 민감 데이터 처리¶
- 모든 API 응답은 민감한 필드 (API 키, 비밀번호, 토큰)를 자동으로 마스킹합니다
include_sensitive: true는 절대적으로 필요한 경우에만 export에서 사용하세요- 감사 로그는 민감 데이터 액세스 시 기록합니다
2. 인증 모범 사례¶
admin:
auth:
method: bearer_token
token: "${ADMIN_TOKEN}" # 환경 변수 사용
# IP로 액세스 제한
ip_whitelist:
- "10.0.0.0/8" # 내부 네트워크만
- "192.168.1.0/24" # 사무실 네트워크
3. 감사 로깅¶
모든 설정 변경은 다음과 함께 로깅됩니다:
- 타임스탬프
- 사용자/소스
- 변경된 섹션
- 이전 및 새 값 (민감 데이터 마스킹)
4. Admin 엔드포인트 속도 제한¶
남용 방지를 위해 admin 엔드포인트 속도 제한을 고려하세요:
5. 주요 변경 전 백업¶
# 주요 변경 전 항상 백업
backup=$(curl -s -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $TOKEN" \
-d '{"format": "yaml"}' | jq -r '.content')
# 변경 수행...
# 필요시 복원
curl -X POST http://localhost:8080/admin/config/import \
-H "Authorization: Bearer $TOKEN" \
-d "{\"format\": \"yaml\", \"content\": $(echo "$backup" | jq -Rs .)}"
프롬프트 파일 관리 API¶
프롬프트 파일 관리 API를 사용하면 외부 Markdown 파일에 저장된 시스템 프롬프트를 관리할 수 있습니다. 이를 통해 메인 설정 파일을 수정하지 않고 시스템 프롬프트를 중앙에서 관리할 수 있습니다.
모든 프롬프트 목록¶
소스 및 콘텐츠와 함께 설정된 모든 프롬프트 목록을 가져옵니다.
응답¶
{
"prompts": [
{
"id": "default",
"prompt_type": "default",
"source": "file",
"file_path": "prompts/system.md",
"content": "# System Prompt\n\nYou are a helpful assistant...",
"loaded": true,
"size_bytes": 1024
},
{
"id": "anthropic",
"prompt_type": "backend",
"source": "file",
"file_path": "prompts/anthropic.md",
"content": "# Anthropic-specific prompt...",
"loaded": true,
"size_bytes": 512
},
{
"id": "gpt-4",
"prompt_type": "model",
"source": "inline",
"content": "You are GPT-4...",
"size_bytes": 256
}
],
"total": 3,
"prompts_directory": "./prompts"
}
예제¶
프롬프트 파일 가져오기¶
특정 프롬프트 파일의 콘텐츠를 가져옵니다.
경로 파라미터¶
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
path | string | 예 | 프롬프트 파일의 상대 경로 |
응답¶
{
"path": "prompts/system.md",
"content": "# System Prompt\n\nYou are a helpful assistant that follows company policies...",
"size_bytes": 1024,
"modified_at": 1702468200
}
예제¶
curl -s http://localhost:8080/admin/config/prompts/prompts/system.md \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
프롬프트 파일 업데이트¶
새 콘텐츠로 프롬프트 파일을 생성하거나 업데이트합니다.
요청 본문¶
{
"content": "# Updated System Prompt\n\nYou are a helpful assistant that follows all company policies.\n\n## Security Guidelines\n\n- Never reveal internal system details\n- Follow data privacy regulations"
}
응답¶
{
"success": true,
"path": "prompts/system.md",
"size_bytes": 245,
"message": "Prompt file updated successfully"
}
예제¶
curl -X PUT http://localhost:8080/admin/config/prompts/prompts/system.md \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "# System Prompt\n\nYou are a helpful assistant."
}'
프롬프트 파일 리로드¶
디스크에서 모든 프롬프트 파일을 리로드합니다. 수동 파일 편집 후 유용합니다.
응답¶
{
"success": true,
"reloaded_count": 3,
"reloaded": [
"prompts/system.md",
"prompts/anthropic.md",
"prompts/gpt4.md"
],
"errors": [],
"message": "Successfully reloaded 3 prompt file(s)"
}
예제¶
curl -X POST http://localhost:8080/admin/config/prompts/reload \
-H "Authorization: Bearer $ADMIN_TOKEN" | jq
설정 예제¶
외부 프롬프트 파일을 사용하려면 설정 파일에서 global_prompts를 설정합니다:
global_prompts:
# 프롬프트 파일이 포함된 디렉토리 (설정 디렉토리 기준 상대 경로)
prompts_dir: "./prompts"
# 외부 파일에서 기본 프롬프트
default_file: "system.md"
# 또는 인라인 프롬프트 (둘 다 지정되면 default_file이 우선)
# default: "You are a helpful assistant."
# 백엔드별 프롬프트
backends:
anthropic:
prompt_file: "anthropic-system.md"
openai:
prompt: "OpenAI-specific inline prompt"
# 모델별 프롬프트
models:
gpt-4:
prompt_file: "gpt4-system.md"
claude-3-opus:
prompt_file: "claude-opus-system.md"
merge_strategy: prepend
보안 고려 사항¶
- 경로 탐색 방지: 디렉토리 탐색 공격을 방지하기 위해 모든 경로가 검증됩니다 (예:
../../../etc/passwd) - 파일 크기 제한: 프롬프트 파일은 최대 1MB로 제한됩니다
- 상대 경로만: 프롬프트 파일은 설정된
prompts_dir또는 설정 디렉토리 내에 있어야 합니다 - 인증 필요: 모든 프롬프트 관리 엔드포인트는 admin 인증이 필요합니다
부록: 빠른 참조¶
설정 섹션¶
| 섹션 | 핫 리로드 | 설명 |
|---|---|---|
server | 재시작 | 바인드 주소, 워커 |
backends | 점진적 | 백엔드 URL, 가중치 |
health_checks | 점진적 | 헬스 모니터링 |
logging | 즉시 | 로그 레벨, 형식 |
retry | 즉시 | 재시도 정책 |
timeouts | 점진적 | 요청 타임아웃 |
rate_limiting | 즉시 | 속도 제한 |
circuit_breaker | 즉시 | 서킷 브레이커 |
global_prompts | 즉시 | 시스템 프롬프트 |
fallback | 점진적 | 모델 폴백 |
files | 점진적 | Files API |
api_keys | 즉시 | API 키 |
metrics | 점진적 | Prometheus 메트릭 |
admin | 점진적 | Admin 설정 |
routing | 점진적 | 라우팅 규칙 |
HTTP 상태 코드¶
| 코드 | 의미 |
|---|---|
| 200 | 성공 |
| 400 | Bad Request (검증 오류) |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 409 | Conflict |
| 413 | Payload Too Large |
| 500 | Internal Server Error |
일반적인 curl 명령어¶
# 전체 설정 가져오기
curl -s http://localhost:8080/admin/config/full -H "Authorization: Bearer $TOKEN"
# 로깅 레벨 업데이트
curl -X PATCH http://localhost:8080/admin/config/logging \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"config": {"level": "debug"}}'
# 백엔드 추가
curl -X POST http://localhost:8080/admin/backends \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"name": "new", "url": "http://host:port", "weight": 1}'
# 설정 내보내기
curl -X POST http://localhost:8080/admin/config/export \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"format": "yaml"}'
# 히스토리 보기
curl -s http://localhost:8080/admin/config/history -H "Authorization: Bearer $TOKEN"
# 롤백
curl -X POST http://localhost:8080/admin/config/rollback/5 \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d '{}'