API 레퍼런스¶
Continuum Router는 모니터링 및 관리를 위한 추가 관리 엔드포인트와 함께 포괄적인 OpenAI 호환 API를 제공합니다. 이 문서는 사용 가능한 모든 엔드포인트, 요청/응답 형식 및 오류 처리에 대한 상세 정보를 제공합니다.
개요¶
기본 URL¶
Content Type¶
별도로 명시되지 않는 한 모든 요청과 응답은 application/json을 사용합니다.
OpenAI 호환성¶
Continuum Router는 OpenAI API v1과 완벽하게 호환되며 다음을 지원합니다:
- 스트리밍을 포함한 채팅 완료
- 텍스트 완료
- 이미지 생성 (DALL-E, gpt-image-1)
- 이미지 편집/인페인팅 (DALL-E 2, gpt-image-1)
- 이미지 변형 (DALL-E 2)
- Files API (업로드, 목록, 조회, 삭제)
- 채팅 완료에서의 파일 해결 (image_file 참조)
- 모델 목록
- 오류 응답 형식
인증¶
Continuum Router는 설정 가능한 적용 모드를 통한 API 키 인증을 지원합니다.
인증 모드¶
라우터는 API 엔드포인트에 대해 두 가지 인증 모드를 지원합니다:
| 모드 | 동작 |
|---|---|
permissive (기본값) | API 키 없는 요청이 허용됩니다. 유효한 API 키가 있는 요청은 인증되어 사용자별 기능에 접근할 수 있습니다. |
blocking | 인증된 요청만 처리됩니다. 유효한 API 키가 없는 요청은 401 Unauthorized를 받습니다. |
설정¶
api_keys:
# 인증 모드: "permissive" (기본값) 또는 "blocking"
mode: blocking
# API 키 정의
api_keys:
- key: "${API_KEY_1}"
id: "key-production-1"
user_id: "user-admin"
organization_id: "org-main"
scopes: [read, write, files, admin]
보호된 엔드포인트 (mode가 blocking일 때)¶
/v1/chat/completions/v1/completions/v1/responses/v1/images/generations/v1/images/edits/v1/images/variations/v1/models
참고: 헬스 엔드포인트 (/health, /healthz)는 항상 인증 없이 접근 가능합니다. Admin, Files, Metrics 엔드포인트는 별도의 인증 메커니즘을 가집니다.
인증된 요청 만들기¶
Authorization 헤더에 API 키를 포함하세요:
POST /v1/chat/completions HTTP/1.1
Authorization: Bearer sk-your-api-key
Content-Type: application/json
{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello"}]
}
인증 오류¶
인증 실패 시 API는 다음을 반환합니다:
{
"error": {
"message": "Missing or invalid Authorization header. Expected: Bearer <api_key>",
"type": "authentication_error",
"code": "invalid_api_key"
}
}
상태 코드:
401 Unauthorized: API 키가 없거나 유효하지 않음
Core API 엔드포인트¶
헬스 체크¶
라우터 서비스의 헬스 상태를 확인합니다.
응답:
상태 코드:
200: 서비스가 정상
모델 목록¶
모든 정상 백엔드에서 사용 가능한 모든 모델을 조회합니다.
응답:
{
"object": "list",
"data": [
{
"id": "gpt-4",
"object": "model",
"created": 1677610602,
"owned_by": "openai-compatible",
"permission": [],
"root": "gpt-4",
"parent": null
},
{
"id": "llama2:7b",
"object": "model",
"created": 1677610602,
"owned_by": "local-ollama",
"permission": [],
"root": "llama2:7b",
"parent": null
}
]
}
상태 코드:
200: 모델이 성공적으로 조회됨503: 모든 백엔드가 비정상
기능:
- 모델 집계: 모든 정상 백엔드의 모델을 결합
- 중복 제거: 백엔드 간 중복 모델 제거
- 캐싱: 기본적으로 5분간 결과 캐시
- 헬스 인식: 정상 백엔드의 모델만 포함
채팅 완료¶
OpenAI Chat API 형식을 사용하여 채팅 완료를 생성합니다.
요청 본문:
{
"model": "gpt-3.5-turbo",
"messages": [
{
"role": "system",
"content": "You are a helpful assistant."
},
{
"role": "user",
"content": "Explain quantum computing in simple terms."
}
],
"temperature": 0.7,
"max_tokens": 150,
"top_p": 1.0,
"frequency_penalty": 0.0,
"presence_penalty": 0.0,
"stream": false,
"stop": null,
"logit_bias": {},
"user": "user123"
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 모델 식별자 (최소 하나의 정상 백엔드에서 사용 가능해야 함) |
messages | array | 예 | role과 content를 포함하는 메시지 객체 배열 |
temperature | number | 아니오 | 샘플링 온도 (0.0 ~ 2.0, 기본값: 1.0) |
max_tokens | integer | 아니오 | 생성할 최대 토큰 수 |
top_p | number | 아니오 | 핵 샘플링 파라미터 (0.0 ~ 1.0) |
frequency_penalty | number | 아니오 | 빈도 패널티 (-2.0 ~ 2.0) |
presence_penalty | number | 아니오 | 존재 패널티 (-2.0 ~ 2.0) |
stream | boolean | 아니오 | 스트리밍 응답 활성화 (기본값: false) |
stop | string/array | 아니오 | 중지 시퀀스 |
logit_bias | object | 아니오 | 토큰 로짓 바이어스 |
user | string | 아니오 | 추적을 위한 사용자 식별자 |
응답 (비스트리밍):
{
"id": "chatcmpl-123456789",
"object": "chat.completion",
"created": 1677652288,
"model": "gpt-3.5-turbo",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Quantum computing is a revolutionary computing paradigm that harnesses quantum mechanical phenomena..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 25,
"completion_tokens": 150,
"total_tokens": 175
}
}
응답 (스트리밍): stream: true일 때 응답은 Server-Sent Events (SSE)를 사용합니다:
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"delta":{"role":"assistant","content":""},"index":0,"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"delta":{"content":"Quantum"},"index":0,"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"delta":{"content":" computing"},"index":0,"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","created":1677652288,"model":"gpt-3.5-turbo","choices":[{"delta":{},"index":0,"finish_reason":"stop"}]}
data: [DONE]
상태 코드:
200: 완료가 성공적으로 생성됨400: 유효하지 않은 요청 형식 또는 파라미터404: 정상 백엔드에서 모델을 찾을 수 없음502: 백엔드 연결 오류504: 요청 타임아웃503: 모든 백엔드가 비정상
기능:
- 모델 기반 라우팅: 요청된 모델을 제공하는 백엔드로 자동 라우팅
- 로드 밸런싱: 정상 백엔드 간 로드 분산
- 스트리밍 지원: SSE를 통한 실시간 응답 스트리밍
- 오류 복구: 일시적 실패 시 자동 재시도
- 요청 중복 제거: 동일한 요청의 중복 처리 방지
이미지 생성¶
OpenAI의 DALL-E, GPT Image 모델 또는 Google의 Nano Banana (Gemini) 모델을 사용하여 이미지를 생성합니다.
요청 본문:
{
"model": "dall-e-3",
"prompt": "A serene Japanese garden with cherry blossoms",
"n": 1,
"size": "1024x1024",
"quality": "standard",
"response_format": "url"
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 이미지 모델: dall-e-2, dall-e-3, gpt-image-1, gpt-image-1.5, gpt-image-1-mini, nano-banana, 또는 nano-banana-pro |
prompt | string | 예 | 생성할 이미지에 대한 설명 |
n | integer | 아니오 | 이미지 수 (1-10, 모델에 따라 다름) |
size | string | 아니오 | 이미지 크기 (모델에 따라 다름, 아래 참조) |
quality | string | 아니오 | 이미지 품질 (모델에 따라 다름, 아래 참조) |
style | string | 아니오 | 이미지 스타일: vivid 또는 natural (DALL-E 3만) |
response_format | string | 아니오 | 응답 형식: url 또는 b64_json |
output_format | string | 아니오 | 출력 파일 형식: png, jpeg, webp (GPT Image 모델만, 기본값: png) |
output_compression | integer | 아니오 | jpeg/webp의 압축 레벨 0-100 (GPT Image 모델만) |
background | string | 아니오 | 배경: transparent, opaque, auto (GPT Image 모델만) |
stream | boolean | 아니오 | 부분 이미지 스트리밍 활성화 (GPT Image 모델만, 기본값: false) |
partial_images | integer | 아니오 | 스트리밍 중 부분 이미지 수 0-3 (GPT Image 모델만) |
user | string | 아니오 | 추적을 위한 사용자 식별자 |
모델별 제약 조건:
| 모델 | 크기 | n | 품질 | 참고 |
|---|---|---|---|---|
dall-e-2 | 256x256, 512x512, 1024x1024 | 1-10 | N/A | 클래식 DALL-E 2 |
dall-e-3 | 1024x1024, 1792x1024, 1024x1792 | 1 | standard, hd | 프롬프트 수정이 포함된 고품질 |
gpt-image-1 | 1024x1024, 1536x1024, 1024x1536, auto | 1 | low, medium, high, auto | 최신 GPT Image 모델, 스트리밍 지원 |
gpt-image-1.5 | 1024x1024, 1536x1024, 1024x1536, auto | 1 | low, medium, high, auto | 4배 빠름, 향상된 텍스트 렌더링 |
gpt-image-1-mini | 1024x1024, 1536x1024, 1024x1536, auto | 1 | low, medium, high, auto | 비용 효율적인 옵션 |
nano-banana | 256x256 ~ 1024x1024 | 1-4 | N/A | Gemini 2.5 Flash Image (빠름) |
nano-banana-pro | 256x256 ~ 4096x4096 | 1-4 | N/A | Gemini 2.0 Flash Image (고급, 최대 4K) |
품질 파라미터 (GPT Image 모델):
하위 호환성을 위해 GPT Image 모델 사용 시 standard는 medium으로, hd는 high로 매핑됩니다.
| 품질 | 설명 |
|---|---|
low | 낮은 품질로 빠른 생성 |
medium | 품질과 속도의 균형 (기본값) |
high | 최고 품질, 느린 생성 |
auto | 모델이 최적 품질 선택 |
출력 형식 옵션 (GPT Image 모델):
| 형식 | 설명 | 투명도 지원 |
|---|---|---|
png | 무손실 형식 (기본값) | 예 |
jpeg | 손실 형식, 작은 파일 크기 | 아니오 |
webp | 현대적인 형식, 좋은 압축률 | 예 |
참고: 투명 배경 (
background: "transparent")은png또는webp형식이 필요합니다.
Nano Banana (Gemini) 모델:
Nano Banana는 OpenAI 호환 인터페이스를 통해 Google의 Gemini 이미지 생성 기능에 대한 액세스를 제공합니다:
nano-banana: Gemini 2.5 Flash Image에 매핑 - 빠른 범용 이미지 생성nano-banana-pro: Gemini 2.0 Flash Image에 매핑 - 고해상도 지원 고급 모델 (최대 4K)
Nano Banana 크기 매핑:
라우터는 OpenAI 스타일 크기 파라미터를 Gemini의 aspectRatio 및 imageSize 형식으로 자동 변환합니다:
| OpenAI 크기 | Gemini aspectRatio | Gemini imageSize | 참고 |
|---|---|---|---|
256x256 | 1:1 | 1K | Gemini 최소값으로 폴백 |
512x512 | 1:1 | 1K | Gemini 최소값으로 폴백 |
1024x1024 | 1:1 | 1K | 기본값 |
1536x1024 | 3:2 | 1K | 가로 (신규) |
1024x1536 | 2:3 | 1K | 세로 (신규) |
1024x1792 | 9:16 | 1K | 긴 세로 |
1792x1024 | 16:9 | 1K | 넓은 가로 |
2048x2048 | 1:1 | 2K | Pro만 |
4096x4096 | 1:1 | 4K | Pro만 |
auto | 1:1 | 1K | 기본 폴백 |
변환은 다음 Gemini API 구조를 전송합니다:
{
"contents": [{"parts": [{"text": "Your prompt"}]}],
"generationConfig": {
"imageConfig": {
"aspectRatio": "3:2",
"imageSize": "1K"
}
}
}
Nano Banana 요청 예제:
{
"model": "nano-banana",
"prompt": "A white siamese cat with blue eyes, photorealistic",
"n": 1,
"size": "1024x1024",
"response_format": "b64_json"
}
응답:
{
"created": 1677652288,
"data": [
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/...",
"revised_prompt": "A tranquil Japanese garden featuring..."
}
]
}
응답 (b64_json 포함):
{
"created": 1677652288,
"data": [
{
"b64_json": "/9j/4AAQSkZJRgABAQAA...",
"revised_prompt": "A tranquil Japanese garden featuring..."
}
]
}
Nano Banana 응답 참고 사항:
- Nano Banana에서
response_format: "url"을 사용할 때, Gemini의 네이티브 API가 인라인 base64 데이터를 반환하므로 이미지는 data URL (data:image/png;base64,...)로 반환됩니다 revised_prompt필드에는 생성된 이미지를 설명하는 Gemini의 텍스트 응답이 포함됩니다
스트리밍 이미지 생성 (GPT Image 모델):
GPT Image 모델에 대해 stream: true가 지정되면 응답이 Server-Sent Events (SSE)로 스트리밍됩니다:
스트리밍 요청 예제:
{
"model": "gpt-image-1",
"prompt": "A beautiful sunset over mountains",
"stream": true,
"partial_images": 2,
"response_format": "b64_json"
}
스트리밍 응답 형식:
data: {"type":"image_generation.partial_image","partial_image_index":0,"b64_json":"...","created":1702345678}
data: {"type":"image_generation.partial_image","partial_image_index":1,"b64_json":"...","created":1702345679}
data: {"type":"image_generation.complete","b64_json":"...","created":1702345680}
data: {"type":"image_generation.usage","usage":{"input_tokens":25,"output_tokens":1024}}
data: {"type":"done"}
SSE 이벤트 타입:
| 이벤트 타입 | 설명 |
|---|---|
image_generation.partial_image | 생성 중 중간 이미지 |
image_generation.complete | 최종 완성 이미지 |
image_generation.usage | 토큰 사용량 정보 (비용 추적용) |
done | 스트림 완료 마커 |
새 옵션이 포함된 GPT Image 요청 예제:
{
"model": "gpt-image-1.5",
"prompt": "A white cat with blue eyes, photorealistic",
"size": "auto",
"quality": "high",
"output_format": "webp",
"output_compression": 85,
"background": "transparent",
"response_format": "b64_json"
}
상태 코드:
200: 이미지가 성공적으로 생성됨400: 유효하지 않은 요청 (예: 모델에 대해 유효하지 않은 크기, DALL-E 3에서 n > 1)401: 유효하지 않은 API 키429: 속도 제한 초과500: 백엔드 오류503: Gemini 백엔드 사용 불가 (Nano Banana 모델의 경우)
타임아웃 설정: 이미지 생성 요청은 설정 가능한 타임아웃을 사용합니다 (기본값: 3분). 설정의 timeouts.request.image_generation을 참조하세요.
이미지 편집 (인페인팅)¶
OpenAI의 인페인팅 기능을 사용하여 기존 이미지를 편집합니다. 이 엔드포인트를 사용하면 텍스트 프롬프트와 선택적 마스크를 기반으로 이미지의 특정 영역을 수정할 수 있습니다. GPT Image 모델과 DALL-E 2를 지원합니다.
요청 파라미터 (multipart/form-data):
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
image | file | 예 | 편집할 소스 이미지 (PNG, < 4MB, 정사각형) |
prompt | string | 예 | 원하는 편집에 대한 설명 |
mask | file | 아니오 | 편집 영역을 나타내는 마스크 이미지 (PNG, 이미지와 동일한 크기) |
model | string | 아니오 | 사용할 모델 (기본값: gpt-image-1) |
n | integer | 아니오 | 생성할 이미지 수 (1-10, 기본값: 1) |
size | string | 아니오 | 출력 크기 (모델에 따라 다름, 기본값: 1024x1024) |
response_format | string | 아니오 | 응답 형식: url 또는 b64_json (기본값: url) |
user | string | 아니오 | 추적을 위한 고유 사용자 식별자 |
지원되는 모델 및 크기:
| 모델 | 크기 | 참고 |
|---|---|---|
gpt-image-1 | 1024x1024, 1536x1024, 1024x1536, auto | 최신 GPT Image 모델 (권장) |
gpt-image-1-mini | 1024x1024, 1536x1024, 1024x1536, auto | 비용 최적화 버전 |
gpt-image-1.5 | 1024x1024, 1536x1024, 1024x1536, auto | 향상된 지시 따르기 기능의 최신 버전 |
dall-e-2 | 256x256, 512x512, 1024x1024 | 레거시 DALL-E 2 모델 |
참고: DALL-E 3와 Gemini (nano-banana)는 이 엔드포인트를 통한 이미지 편집을 지원하지 않습니다. Gemini는 자연어를 통한 시맨틱 마스킹을 사용하며, 이는 OpenAI의 마스크 기반 편집 형식과 호환되지 않습니다.
이미지 요구 사항:
- 형식: PNG만
- 크기: 4MB 미만
- 크기: 정사각형이어야 함 (가로 = 세로)
마스크 요구 사항:
- 형식: 알파 채널이 있는 PNG (RGBA)
- 크기: 소스 이미지와 정확히 일치해야 함
- 투명 영역: 편집/생성할 영역을 나타냄
- 불투명 영역: 보존할 영역을 나타냄
요청 예제:
curl -X POST http://localhost:8080/v1/images/edits \
-F "image=@source_image.png" \
-F "mask=@mask.png" \
-F "prompt=A sunlit indoor lounge area with a pool containing a flamingo" \
-F "n=1" \
-F "size=1024x1024" \
-F "response_format=url"
요청 예제 (마스크 없이):
curl -X POST http://localhost:8080/v1/images/edits \
-F "image=@source_image.png" \
-F "prompt=Add a sunset in the background" \
-F "n=1" \
-F "size=512x512"
응답:
{
"created": 1677652288,
"data": [
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/..."
}
]
}
응답 (b64_json 포함):
상태 코드:
200: 이미지가 성공적으로 편집됨400: 유효하지 않은 요청 (예: 정사각형이 아닌 이미지, 유효하지 않은 크기, 필수 필드 누락)401: 유효하지 않은 API 키503: OpenAI 백엔드 사용 불가
오류 예제:
정사각형이 아닌 이미지:
{
"error": {
"message": "Image must be square (800x600 is not square)",
"type": "invalid_request_error",
"param": "image",
"code": "image_not_square"
}
}
마스크 크기 불일치:
{
"error": {
"message": "Mask dimensions (256x256) do not match image dimensions (512x512)",
"type": "invalid_request_error",
"param": "mask",
"code": "dimension_mismatch"
}
}
지원되지 않는 모델:
{
"error": {
"message": "Model 'dall-e-3' does not support image editing. Supported models: gpt-image-1, gpt-image-1-mini, gpt-image-1.5, dall-e-2. Note: dall-e-3 does NOT support image editing.",
"type": "invalid_request_error",
"param": "model",
"code": "unsupported_model"
}
}
참고 사항:
- 지원되는 모델:
gpt-image-1,gpt-image-1-mini,gpt-image-1.5,dall-e-2 - DALL-E 3는 API를 통한 이미지 편집을 지원하지 않습니다
- Gemini (nano-banana)는 지원되지 않음 - 다른 편집 접근 방식 사용 (시맨틱 마스킹)
- 마스크가 제공되지 않으면 전체 이미지가 수정될 수 있습니다
- 마스크 없이 편집하는 경우 소스 이미지에 투명 영역이 있어야 합니다
- 요청 타임아웃은 이미지 생성 타임아웃 설정을 사용합니다
이미지 변형¶
OpenAI의 DALL-E 2 모델을 사용하여 기존 이미지의 변형을 생성합니다.
폼 필드:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
image | file | 예 | 변형을 위한 소스 이미지 (PNG, < 4MB, 정사각형이어야 함) |
model | string | 아니오 | 사용할 모델 (기본값: dall-e-2) |
n | integer | 아니오 | 생성할 변형 수 (1-10, 기본값: 1) |
size | string | 아니오 | 출력 크기: 256x256, 512x512, 1024x1024 (기본값: 1024x1024) |
response_format | string | 아니오 | 응답 형식: url 또는 b64_json (기본값: url) |
user | string | 아니오 | 추적을 위한 사용자 식별자 |
요청 예제:
curl -X POST http://localhost:8080/v1/images/variations \
-F "image=@source_image.png" \
-F "model=dall-e-2" \
-F "n=2" \
-F "size=512x512" \
-F "response_format=url"
응답:
{
"created": 1677652288,
"data": [
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/..."
},
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/..."
}
]
}
응답 (b64_json 포함):
모델 지원:
| 모델 | 변형 지원 | 참고 |
|---|---|---|
dall-e-2 | 예 (네이티브) | 완전 지원, 1-10개 변형 |
dall-e-3 | 아니오 | OpenAI API에서 지원하지 않음 |
gpt-image-1 | 아니오 | 지원되지 않음 |
nano-banana | 아니오 | Gemini는 변형 API를 지원하지 않음 |
nano-banana-pro | 아니오 | Gemini는 변형 API를 지원하지 않음 |
이미지 요구 사항:
- 형식: PNG만
- 크기: 4MB 미만
- 크기: 정사각형이어야 함 (가로 == 세로)
- 지원되는 입력 크기: 모든 정사각형 크기 (모델에서 처리됨)
오류 시나리오:
| 오류 | 상태 | 설명 |
|---|---|---|
| PNG가 아닌 이미지 | 400 | PNG 형식만 지원됨 |
| 정사각형이 아닌 이미지 | 400 | 이미지 크기가 동일해야 함 |
| 이미지가 너무 큼 | 400 | 이미지가 4MB 크기 제한 초과 |
| 지원되지 않는 모델 | 400 | 요청된 모델이 변형을 지원하지 않음 |
| 이미지 누락 | 400 | image 필드 필수 |
| 유효하지 않은 n 값 | 400 | n은 1과 10 사이여야 함 |
| 유효하지 않은 크기 | 400 | 크기는 지원되는 값 중 하나여야 함 |
상태 코드:
200: 변형이 성공적으로 생성됨400: 유효하지 않은 요청 (유효하지 않은 형식, 정사각형이 아닌 이미지, 지원되지 않는 모델)401: 유효하지 않은 API 키429: 속도 제한 초과500: 백엔드 오류503: 백엔드 사용 불가
텍스트 완료¶
OpenAI Completions API 형식을 사용하여 텍스트 완료를 생성합니다.
요청 본문:
{
"model": "gpt-3.5-turbo-instruct",
"prompt": "Once upon a time in a distant galaxy",
"max_tokens": 100,
"temperature": 0.7,
"top_p": 1.0,
"frequency_penalty": 0.0,
"presence_penalty": 0.0,
"stream": false,
"stop": null,
"logit_bias": {},
"user": "user123"
}
응답:
{
"id": "cmpl-123456789",
"object": "text_completion",
"created": 1677652288,
"model": "gpt-3.5-turbo-instruct",
"choices": [
{
"text": ", there lived a young explorer named Zara who dreamed of discovering new worlds...",
"index": 0,
"finish_reason": "stop",
"logprobs": null
}
],
"usage": {
"prompt_tokens": 10,
"completion_tokens": 90,
"total_tokens": 100
}
}
상태 코드: 채팅 완료와 동일
Files API¶
Files API를 사용하면 채팅 완료에서 파일을 업로드, 관리 및 사용할 수 있습니다. 업로드된 파일은 image_file 콘텐츠 타입을 사용하여 메시지에서 참조할 수 있으며, 라우터가 파일 콘텐츠를 주입하여 이러한 참조를 자동으로 해결합니다.
파일 업로드¶
채팅 완료에서 사용할 파일을 업로드합니다.
폼 필드:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
file | file | 예 | 업로드할 파일 |
purpose | string | 예 | 파일의 용도: vision, assistants, fine-tune, batch |
예제:
응답:
{
"id": "file-abc123def456",
"object": "file",
"bytes": 12345,
"created_at": 1699061776,
"filename": "image.png",
"purpose": "vision"
}
상태 코드:
200: 파일이 성공적으로 업로드됨400: 유효하지 않은 요청 (파일 누락, 유효하지 않은 용도)413: 파일이 너무 큼 (설정된 maxfilesize 초과)
파일 목록¶
업로드된 파일 목록을 조회합니다.
쿼리 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
purpose | string | 아니오 | 용도별 필터링 |
응답:
{
"object": "list",
"data": [
{
"id": "file-abc123def456",
"object": "file",
"bytes": 12345,
"created_at": 1699061776,
"filename": "image.png",
"purpose": "vision"
}
]
}
파일 메타데이터 가져오기¶
특정 파일의 메타데이터를 조회합니다.
응답:
{
"id": "file-abc123def456",
"object": "file",
"bytes": 12345,
"created_at": 1699061776,
"filename": "image.png",
"purpose": "vision"
}
상태 코드:
200: 파일 메타데이터 조회됨404: 파일을 찾을 수 없음
파일 콘텐츠 다운로드¶
업로드된 파일의 콘텐츠를 다운로드합니다.
응답: 적절한 Content-Type 헤더와 함께 바이너리 파일 콘텐츠.
상태 코드:
200: 파일 콘텐츠 반환됨404: 파일을 찾을 수 없음
파일 삭제¶
업로드된 파일을 삭제합니다.
응답:
상태 코드:
200: 파일이 성공적으로 삭제됨404: 파일을 찾을 수 없음
채팅 완료에서의 파일 해결¶
라우터는 채팅 완료 요청에서 파일 참조를 자동으로 해결합니다. 메시지에 image_file 콘텐츠 블록이 포함되면 라우터는:
- 파일 ID 형식을 검증합니다
- 스토리지에서 파일 콘텐츠를 로드합니다
- 파일을 base64 data URL로 변환합니다
image_file블록을image_url블록으로 대체합니다
파일 참조가 포함된 요청:
{
"model": "gpt-4-vision-preview",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{"type": "image_file", "image_file": {"file_id": "file-abc123def456"}}
]
}
]
}
변환된 요청 (백엔드로 전송됨):
{
"model": "gpt-4-vision-preview",
"messages": [
{
"role": "user",
"content": [
{"type": "text", "text": "What's in this image?"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}
]
}
]
}
파일 해결 오류:
| 오류 | 상태 | 설명 |
|---|---|---|
| 유효하지 않은 파일 ID 형식 | 400 | 파일 ID는 file-로 시작해야 함 |
| 파일을 찾을 수 없음 | 404 | 참조된 파일이 존재하지 않음 |
| 파일 참조가 너무 많음 | 400 | 요청에 20개 이상의 파일 참조 포함 |
| 해결 타임아웃 | 504 | 파일 해결에 30초 이상 소요 |
이미지 파일에 지원되는 MIME 타입:
image/pngimage/jpegimage/gifimage/webp
관리 엔드포인트¶
백엔드 상태¶
설정된 모든 백엔드에 대한 상세 상태 정보를 가져옵니다.
응답:
{
"backends": [
{
"name": "local-ollama",
"url": "http://localhost:11434",
"is_healthy": true,
"consecutive_failures": 0,
"consecutive_successes": 15,
"last_check": "2024-01-15T10:30:45Z",
"last_error": null,
"response_time_ms": 45,
"models": ["llama2", "mistral", "codellama"],
"weight": 1,
"total_requests": 150,
"failed_requests": 2
},
{
"name": "openai-compatible",
"url": "https://api.openai.com",
"is_healthy": false,
"consecutive_failures": 3,
"consecutive_successes": 0,
"last_check": "2024-01-15T10:29:30Z",
"last_error": "Connection timeout after 5s",
"response_time_ms": null,
"models": [],
"weight": 1,
"total_requests": 45,
"failed_requests": 8
}
],
"healthy_count": 1,
"total_count": 2,
"summary": {
"total_models": 3,
"total_requests": 195,
"total_failures": 10,
"average_response_time_ms": 45
}
}
필드:
| 필드 | 타입 | 설명 |
|---|---|---|
name | string | 설정의 백엔드 식별자 |
url | string | 백엔드 기본 URL |
is_healthy | boolean | 현재 헬스 상태 |
consecutive_failures | integer | 연속 실패한 헬스 체크 |
consecutive_successes | integer | 연속 성공한 헬스 체크 |
last_check | string | 마지막 헬스 체크의 ISO 타임스탬프 |
last_error | string/null | 비정상 시 마지막 오류 메시지 |
response_time_ms | integer/null | 마지막 헬스 체크 응답 시간 |
models | array | 이 백엔드의 사용 가능한 모델 |
weight | integer | 로드 밸런싱 가중치 |
total_requests | integer | 이 백엔드로 라우팅된 총 요청 수 |
failed_requests | integer | 이 백엔드에 대한 실패한 요청 수 |
상태 코드:
200: 백엔드 상태가 성공적으로 조회됨
서비스 헬스¶
전체 서비스 헬스 및 컴포넌트 상태를 가져옵니다.
응답:
{
"status": "healthy",
"version": "1.0.0",
"uptime": "2h 15m 30s",
"timestamp": "2024-01-15T10:30:45Z",
"services": {
"backend_service": {
"status": "healthy",
"message": "All backends operational",
"healthy_backends": 2,
"total_backends": 2
},
"model_service": {
"status": "healthy",
"message": "Model cache operational",
"cached_models": 15,
"cache_hit_rate": 0.95,
"last_refresh": "2024-01-15T10:25:00Z"
},
"proxy_service": {
"status": "healthy",
"message": "Request routing operational",
"total_requests": 1250,
"failed_requests": 12,
"average_latency_ms": 85
},
"health_service": {
"status": "healthy",
"message": "Health monitoring active",
"check_interval": "30s",
"last_check": "2024-01-15T10:30:00Z"
}
},
"metrics": {
"requests_per_second": 5.2,
"error_rate": 0.008,
"memory_usage_mb": 125,
"cpu_usage_percent": 15.5
}
}
상태 값:
healthy: 서비스가 정상 작동 중degraded: 서비스가 제한된 기능으로 작동 중unhealthy: 서비스에 문제가 발생함
상태 코드:
200: 서비스 헬스가 성공적으로 조회됨503: 서비스가 비정상
설정 요약¶
핫 리로드 상태를 포함한 현재 설정 요약을 가져옵니다.
응답:
{
"server": {
"bind_address": "0.0.0.0:8080",
"workers": 4,
"connection_pool_size": 100
},
"backends": {
"count": 3,
"names": ["openai", "local-ollama", "gemini"]
},
"health_checks": {
"interval": "30s",
"timeout": "10s",
"unhealthy_threshold": 3,
"healthy_threshold": 2
},
"rate_limiting": {
"enabled": false
},
"circuit_breaker": {
"enabled": true
},
"selection_strategy": "RoundRobin",
"hot_reload": {
"available": true,
"note": "Configuration changes will be automatically detected and applied"
}
}
필드:
| 필드 | 타입 | 설명 |
|---|---|---|
server | object | 서버 설정 (bindaddress, workers, connectionpool_size) |
backends | object | 백엔드 설정 요약 (count, names) |
health_checks | object | 헬스 체크 설정 |
rate_limiting | object | 속도 제한 상태 |
circuit_breaker | object | 서킷 브레이커 상태 |
selection_strategy | string | 현재 로드 밸런싱 전략 |
hot_reload | object | 핫 리로드 가용성 및 상태 |
상태 코드:
200: 설정 요약이 성공적으로 조회됨
참고: 민감한 정보 (API 키 등)는 응답에서 자동으로 수정됩니다.
핫 리로드 상태¶
핫 리로드 기능 및 설정 항목 분류에 대한 상세 정보를 가져옵니다.
응답:
{
"enabled": true,
"description": "Hot reload is enabled. Configuration file changes are automatically detected and applied.",
"capabilities": {
"immediate_update": {
"description": "Changes applied immediately without service interruption",
"items": [
"logging.level",
"rate_limiting.*",
"circuit_breaker.*",
"retry.*",
"global_prompts.*"
]
},
"gradual_update": {
"description": "Existing connections maintained, new connections use new config",
"items": [
"backends.*",
"health_checks.*",
"timeouts.*"
]
},
"requires_restart": {
"description": "Changes logged as warnings, restart required to take effect",
"items": [
"server.bind_address",
"server.workers"
]
}
}
}
필드:
| 필드 | 타입 | 설명 |
|---|---|---|
enabled | boolean | 핫 리로드 활성화 여부 |
description | string | 핫 리로드 상태에 대한 읽기 쉬운 설명 |
capabilities | object | 핫 리로드 기능별 설정 항목 분류 |
capabilities.immediate_update | object | 중단 없이 즉시 업데이트되는 항목 |
capabilities.gradual_update | object | 새 연결에만 적용되는 항목 |
capabilities.requires_restart | object | 서버 재시작이 필요한 항목 |
설정 항목 분류:
즉시 업데이트 (서비스 중단 없음):
logging.level- 로그 레벨 변경이 즉시 적용rate_limiting.*- 속도 제한 설정이 실시간으로 업데이트circuit_breaker.*- 서킷 브레이커 임계값 및 타임아웃retry.*- 재시도 정책 및 백오프 전략global_prompts.*- 전역 시스템 프롬프트 주입 설정
점진적 업데이트 (기존 연결 유지):
backends.*- 백엔드 추가/제거/수정 (새 요청이 업데이트된 풀 사용)health_checks.*- 헬스 체크 간격 및 임계값timeouts.*- 새 요청에 대한 타임아웃 값
재시작 필요 (경고로 로깅):
server.bind_address- TCP 바인드 주소server.workers- 워커 스레드 수
상태 코드:
200: 핫 리로드 상태가 성공적으로 조회됨
사용 예제:
# 핫 리로드 활성화 여부 확인
curl http://localhost:8080/admin/config/hot-reload-status | jq '.enabled'
# 즉시 업데이트를 지원하는 항목 목록
curl http://localhost:8080/admin/config/hot-reload-status | jq '.capabilities.immediate_update.items'
설정 관리 API¶
설정 관리 API를 사용하면 서버 재시작 없이 런타임에 라우터 설정을 보고 수정할 수 있습니다. 이는 프로덕션 환경에서 동작을 조정하고, 백엔드를 추가하고, 설정을 미세 조정하는 데 운영 유연성을 제공합니다.
개요¶
주요 기능:
- 런타임 설정: 서버 재시작 없이 설정 보기 및 수정
- 핫 리로드 지원: 지원되는 설정에 변경 사항 즉시 적용
- 검증: 적용 전 설정 변경 사항 검증
- 히스토리 및 롤백: 설정 변경 추적 및 이전 버전으로 롤백
- 내보내기/가져오기: 환경 간 설정 백업 및 복원
- 보안: 민감한 정보 (API 키, 비밀번호, 토큰)가 자동으로 마스킹됨
설정 쿼리 API¶
전체 설정 가져오기¶
보안을 위해 민감한 정보가 마스킹된 전체 현재 설정을 반환합니다.
응답:
{
"server": {
"bind_address": "0.0.0.0:8080",
"workers": 4,
"connection_pool_size": 100
},
"backends": [
{
"name": "openai",
"url": "https://api.openai.com",
"api_key": "sk-****...**",
"weight": 1,
"models": ["gpt-4", "gpt-3.5-turbo"]
},
{
"name": "local-ollama",
"url": "http://localhost:11434",
"weight": 1,
"models": []
}
],
"health_checks": {
"interval": "30s",
"timeout": "10s",
"unhealthy_threshold": 3,
"healthy_threshold": 2
},
"logging": {
"level": "info",
"format": "json"
},
"retry": {
"max_attempts": 3,
"backoff": "exponential",
"initial_delay_ms": 100
},
"timeouts": {
"connect": "5s",
"request": "60s"
},
"rate_limiting": {
"enabled": false
},
"circuit_breaker": {
"enabled": true,
"failure_threshold": 5,
"recovery_timeout": "30s"
}
}
참고 사항:
- API 키, 비밀번호, 토큰은 마스킹됨 (예:
sk-****...**) - 모든 설정 섹션이 응답에 포함됨
- 개별 섹션 세부 정보는
/admin/config/{section}사용
상태 코드:
200: 설정이 성공적으로 조회됨
설정 섹션 목록¶
사용 가능한 모든 설정 섹션 목록을 반환합니다.
응답:
{
"sections": [
"server",
"backends",
"health_checks",
"logging",
"retry",
"timeouts",
"rate_limiting",
"circuit_breaker",
"global_prompts",
"admin",
"fallback",
"files",
"api_keys",
"metrics",
"routing"
],
"total": 15
}
상태 코드:
200: 섹션 목록이 성공적으로 조회됨
설정 섹션 가져오기¶
핫 리로드 기능 정보와 함께 특정 섹션의 설정을 반환합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 예 | 설정 섹션 이름 |
요청 예제:
응답:
{
"section": "logging",
"config": {
"level": "info",
"format": "json",
"output": "stdout",
"include_timestamps": true
},
"hot_reload_capability": "immediate_update",
"description": "Changes to this section apply immediately without service interruption"
}
핫 리로드 기능 값:
| 값 | 설명 |
|---|---|
immediate_update | 서비스 중단 없이 변경 사항 즉시 적용 |
gradual_update | 기존 연결 유지, 새 연결이 새 설정 사용 |
requires_restart | 변경 사항 적용에 서버 재시작 필요 |
상태 코드:
200: 섹션 설정이 성공적으로 조회됨404: 유효하지 않은 섹션 이름
오류 응답:
{
"error": {
"message": "Configuration section 'invalid_section' not found",
"type": "not_found",
"code": 404,
"details": {
"requested_section": "invalid_section",
"available_sections": ["server", "backends", "logging", "..."]
}
}
}
설정 스키마 가져오기¶
설정 검증을 위한 JSON Schema를 반환합니다. 변경 사항 제출 전 클라이언트 측 검증에 유용합니다.
응답:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"server": {
"type": "object",
"properties": {
"bind_address": {
"type": "string",
"pattern": "^[0-9.]+:[0-9]+$",
"description": "Server bind address in host:port format"
},
"workers": {
"type": "integer",
"minimum": 1,
"maximum": 256,
"description": "Number of worker threads"
},
"connection_pool_size": {
"type": "integer",
"minimum": 1,
"maximum": 10000,
"description": "HTTP connection pool size per backend"
}
},
"required": ["bind_address"]
},
"backends": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"description": "Unique backend identifier"
},
"url": {
"type": "string",
"format": "uri",
"description": "Backend base URL"
},
"weight": {
"type": "integer",
"minimum": 0,
"maximum": 100,
"default": 1,
"description": "Load balancing weight"
},
"models": {
"type": "array",
"items": {"type": "string"},
"description": "Explicit model list (optional)"
}
},
"required": ["name", "url"]
}
},
"logging": {
"type": "object",
"properties": {
"level": {
"type": "string",
"enum": ["trace", "debug", "info", "warn", "error"],
"description": "Log level"
},
"format": {
"type": "string",
"enum": ["json", "text", "pretty"],
"description": "Log output format"
}
}
}
}
}
상태 코드:
200: 스키마가 성공적으로 조회됨
설정 수정 API¶
설정 섹션 대체¶
전체 설정 섹션을 대체합니다. 검증을 트리거하고 해당하는 경우 핫 리로드합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 예 | 설정 섹션 이름 |
요청 본문: 전체 섹션 설정 객체.
요청 예제:
curl -X PUT http://localhost:8080/admin/config/logging \
-H "Content-Type: application/json" \
-d '{
"level": "debug",
"format": "json",
"output": "stdout",
"include_timestamps": true
}'
응답:
{
"success": true,
"section": "logging",
"hot_reload_applied": true,
"message": "Configuration updated and applied immediately",
"previous": {
"level": "info",
"format": "json",
"output": "stdout",
"include_timestamps": true
},
"current": {
"level": "debug",
"format": "json",
"output": "stdout",
"include_timestamps": true
},
"version": 15
}
상태 코드:
200: 설정이 성공적으로 업데이트됨400: 유효하지 않은 설정 형식 또는 검증 오류404: 유효하지 않은 섹션 이름
설정 섹션 부분 업데이트¶
JSON 병합 패치 의미론을 사용하여 부분 업데이트를 수행합니다. 지정된 필드만 업데이트되고 지정되지 않은 필드는 현재 값을 유지합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 예 | 설정 섹션 이름 |
요청 본문: 업데이트할 필드가 포함된 부분 설정 객체.
요청 예제:
curl -X PATCH http://localhost:8080/admin/config/logging \
-H "Content-Type: application/json" \
-d '{
"level": "warn"
}'
응답:
{
"success": true,
"section": "logging",
"hot_reload_applied": true,
"message": "Configuration partially updated and applied",
"changes": {
"level": {
"from": "info",
"to": "warn"
}
},
"current": {
"level": "warn",
"format": "json",
"output": "stdout",
"include_timestamps": true
},
"version": 16
}
병합 동작:
- 스칼라 값은 대체됨
- 객체는 재귀적으로 병합됨
- 배열은 전체가 대체됨 (병합 안 됨)
null값은 필드를 제거함 (선택 사항인 경우)
상태 코드:
200: 설정이 성공적으로 업데이트됨400: 유효하지 않은 설정 형식 또는 검증 오류404: 유효하지 않은 섹션 이름
설정 검증¶
변경 사항을 적용하지 않고 설정을 검증합니다. 설정 변경 사항을 안전하게 테스트하기 위한 dry_run 모드를 지원합니다.
요청 본문:
{
"section": "backends",
"config": {
"name": "new-backend",
"url": "http://localhost:8000",
"weight": 2
},
"dry_run": true
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
section | string | 예 | 검증할 설정 섹션 |
config | object | 예 | 검증할 설정 |
dry_run | boolean | 아니오 | true인 경우, 적용 준비 없이 검증만 (기본값: true) |
응답 (유효):
{
"valid": true,
"section": "backends",
"warnings": [
"Backend 'new-backend' has no explicit model list; models will be auto-discovered"
],
"info": {
"hot_reload_capability": "gradual_update",
"estimated_impact": "New requests may be routed to this backend after apply"
}
}
응답 (유효하지 않음):
{
"valid": false,
"section": "backends",
"errors": [
{
"field": "url",
"message": "Invalid URL format: missing scheme",
"value": "localhost:8000"
},
{
"field": "weight",
"message": "Weight must be between 0 and 100",
"value": 150
}
],
"warnings": []
}
상태 코드:
200: 검증 완료 (결과는valid필드 확인)400: 유효하지 않은 요청 형식
보류 중인 변경 사항 적용¶
보류 중인 설정 변경 사항을 즉시 적용합니다. 적용 가능한 설정에 대해 핫 리로드를 트리거합니다.
요청 본문 (선택 사항):
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
sections | array | 아니오 | 적용할 특정 섹션 (기본값: 모든 보류 중) |
force | boolean | 아니오 | 경고가 있어도 강제 적용 (기본값: false) |
응답:
{
"success": true,
"applied_sections": ["logging", "rate_limiting"],
"results": {
"logging": {
"status": "applied",
"hot_reload": "immediate_update"
},
"rate_limiting": {
"status": "applied",
"hot_reload": "immediate_update"
}
},
"version": 17,
"timestamp": "2024-01-15T10:45:30Z"
}
상태 코드:
200: 변경 사항이 성공적으로 적용됨400: 보류 중인 변경 사항이 없거나 검증 오류409: 동시 수정과 충돌
설정 저장/복원 API¶
설정 내보내기¶
지정된 형식으로 현재 설정을 내보냅니다.
요청 본문:
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
format | string | 아니오 | 내보내기 형식: yaml, json, 또는 toml (기본값: yaml) |
include_sensitive | boolean | 아니오 | 마스킹 안 된 민감 데이터 포함 (권한 상승 필요, 기본값: false) |
sections | array | 아니오 | 내보낼 특정 섹션 (기본값: 전체) |
응답 (format: json):
{
"format": "json",
"content": "{\"server\":{\"bind_address\":\"0.0.0.0:8080\",...}}",
"sections_exported": ["server", "backends", "logging"],
"exported_at": "2024-01-15T10:45:30Z",
"version": 17,
"checksum": "sha256:a1b2c3d4..."
}
응답 (format: yaml):
{
"format": "yaml",
"content": "server:\n bind_address: \"0.0.0.0:8080\"\n workers: 4\n...",
"sections_exported": ["server", "backends", "logging"],
"exported_at": "2024-01-15T10:45:30Z",
"version": 17,
"checksum": "sha256:a1b2c3d4..."
}
상태 코드:
200: 내보내기 성공400: 지정된 형식이 유효하지 않음403:include_sensitive: true에 대해 권한 상승 필요
설정 가져오기¶
제공된 콘텐츠에서 설정을 가져옵니다.
요청 본문:
{
"format": "yaml",
"content": "server:\n bind_address: \"0.0.0.0:8080\"\n workers: 8\nlogging:\n level: debug",
"dry_run": true,
"merge": false
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
format | string | 예 | 콘텐츠 형식: yaml, json, 또는 toml |
content | string | 예 | 가져올 설정 콘텐츠 |
dry_run | boolean | 아니오 | 적용 없이 검증만 (기본값: false) |
merge | boolean | 아니오 | 기존 설정과 병합 vs 대체 (기본값: false) |
응답 (dry_run: true):
{
"valid": true,
"dry_run": true,
"changes_preview": {
"server": {
"workers": {"from": 4, "to": 8}
},
"logging": {
"level": {"from": "info", "to": "debug"}
}
},
"sections_affected": ["server", "logging"],
"warnings": [
"server.workers change requires restart to take effect"
]
}
응답 (dry_run: false):
{
"success": true,
"imported_sections": ["server", "logging"],
"hot_reload_results": {
"logging": "applied_immediately",
"server": "requires_restart"
},
"version": 18,
"timestamp": "2024-01-15T10:50:00Z"
}
상태 코드:
200: 가져오기 성공 (또는 dry_run 검증 통과)400: 유효하지 않은 형식 또는 콘텐츠 파싱 오류422: 설정 검증 실패
설정 히스토리 가져오기¶
설정 변경 히스토리를 조회합니다.
쿼리 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
limit | integer | 아니오 | 반환할 최대 항목 수 (기본값: 20, 최대: 100) |
offset | integer | 아니오 | 건너뛸 항목 수 (기본값: 0) |
section | string | 아니오 | 섹션 이름으로 필터링 |
요청 예제:
응답:
{
"history": [
{
"version": 18,
"timestamp": "2024-01-15T10:50:00Z",
"sections_changed": ["logging"],
"source": "api",
"user": "admin",
"changes": {
"logging": {
"level": {"from": "info", "to": "debug"}
}
}
},
{
"version": 17,
"timestamp": "2024-01-15T09:30:00Z",
"sections_changed": ["backends"],
"source": "file_reload",
"user": null,
"changes": {
"backends": {
"added": ["new-backend"],
"modified": [],
"removed": []
}
}
},
{
"version": 16,
"timestamp": "2024-01-14T15:20:00Z",
"sections_changed": ["rate_limiting"],
"source": "api",
"user": "admin",
"changes": {
"rate_limiting": {
"enabled": {"from": false, "to": true}
}
}
}
],
"total": 18,
"limit": 10,
"offset": 0
}
Source 값:
| Source | 설명 |
|---|---|
api | 설정 관리 API를 통해 변경됨 |
file_reload | 설정 파일 핫 리로드를 통해 변경됨 |
startup | 서버 시작 시 초기 설정 |
rollback | 이전 버전에서 복원됨 |
상태 코드:
200: 히스토리가 성공적으로 조회됨
설정 롤백¶
이전 설정 버전으로 롤백합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
version | integer | 예 | 롤백할 버전 번호 |
요청 본문 (선택 사항):
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
dry_run | boolean | 아니오 | 적용 없이 변경 사항 미리보기 (기본값: false) |
sections | array | 아니오 | 롤백할 특정 섹션 (기본값: 변경된 모든 섹션) |
응답:
{
"success": true,
"rolled_back_from": 18,
"rolled_back_to": 15,
"sections_restored": ["logging", "backends"],
"changes": {
"logging": {
"level": {"from": "debug", "to": "info"}
},
"backends": {
"removed": ["new-backend"]
}
},
"new_version": 19,
"timestamp": "2024-01-15T11:00:00Z"
}
상태 코드:
200: 롤백 성공400: 대상 설정에 대한 검증 오류404: 히스토리에서 버전을 찾을 수 없음
백엔드 관리 API¶
이 엔드포인트는 전체 백엔드 설정 섹션을 수정하지 않고 백엔드를 관리하기 위한 편리한 단축키를 제공합니다.
백엔드 추가¶
라우터에 새 백엔드를 동적으로 추가합니다.
요청 본문:
{
"name": "new-ollama",
"url": "http://192.168.1.100:11434",
"weight": 2,
"models": ["llama2", "codellama"],
"api_key": null,
"health_check_path": "/api/tags"
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 고유한 백엔드 식별자 |
url | string | 예 | 백엔드 기본 URL |
weight | integer | 아니오 | 로드 밸런싱 가중치 (기본값: 1) |
models | array | 아니오 | 명시적 모델 목록 (비어 있으면 자동 검색) |
api_key | string | 아니오 | 인증을 위한 API 키 |
health_check_path | string | 아니오 | 커스텀 헬스 체크 엔드포인트 |
응답:
{
"success": true,
"backend": {
"name": "new-ollama",
"url": "http://192.168.1.100:11434",
"weight": 2,
"models": ["llama2", "codellama"],
"is_healthy": null,
"status": "pending_health_check"
},
"message": "Backend added successfully. Health check scheduled.",
"config_version": 20
}
상태 코드:
200: 백엔드가 성공적으로 추가됨400: 유효하지 않은 백엔드 설정409: 이 이름의 백엔드가 이미 존재함
백엔드 설정 가져오기¶
특정 백엔드의 설정을 조회합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 백엔드 식별자 |
응답:
{
"name": "local-ollama",
"url": "http://localhost:11434",
"weight": 1,
"models": ["llama2", "mistral", "codellama"],
"api_key": null,
"health_check_path": "/api/tags",
"is_healthy": true,
"consecutive_failures": 0,
"consecutive_successes": 25,
"last_check": "2024-01-15T10:55:00Z",
"total_requests": 1250,
"failed_requests": 3
}
상태 코드:
200: 백엔드 설정 조회됨404: 백엔드를 찾을 수 없음
백엔드 설정 업데이트¶
기존 백엔드의 설정을 업데이트합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 백엔드 식별자 |
요청 본문:
{
"url": "http://localhost:11434",
"weight": 3,
"models": ["llama2", "mistral", "codellama", "phi"],
"api_key": null
}
응답:
{
"success": true,
"backend": {
"name": "local-ollama",
"url": "http://localhost:11434",
"weight": 3,
"models": ["llama2", "mistral", "codellama", "phi"]
},
"changes": {
"weight": {"from": 1, "to": 3},
"models": {"added": ["phi"], "removed": []}
},
"config_version": 21
}
상태 코드:
200: 백엔드가 성공적으로 업데이트됨400: 유효하지 않은 설정404: 백엔드를 찾을 수 없음
백엔드 삭제¶
라우터에서 백엔드를 제거합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 백엔드 식별자 |
쿼리 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
drain | boolean | 아니오 | 활성 요청이 완료될 때까지 대기 (기본값: true) |
timeout | integer | 아니오 | 드레인 타임아웃 (초) (기본값: 30) |
요청 예제:
응답:
{
"success": true,
"deleted_backend": "old-backend",
"drained": true,
"active_requests_completed": 5,
"config_version": 22,
"message": "Backend removed from rotation"
}
상태 코드:
200: 백엔드가 성공적으로 삭제됨404: 백엔드를 찾을 수 없음409: 마지막 남은 백엔드를 삭제할 수 없음
백엔드 가중치 업데이트¶
백엔드의 로드 밸런싱 가중치만 업데이트합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 백엔드 식별자 |
요청 본문:
응답:
{
"success": true,
"backend": "local-ollama",
"weight": {
"from": 1,
"to": 5
},
"config_version": 23
}
상태 코드:
200: 가중치가 성공적으로 업데이트됨400: 유효하지 않은 가중치 값404: 백엔드를 찾을 수 없음
백엔드 모델 업데이트¶
백엔드의 모델 목록만 업데이트합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
name | string | 예 | 백엔드 식별자 |
요청 본문:
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
models | array | 예 | 모델 목록 |
mode | string | 아니오 | 업데이트 모드: replace, add, 또는 remove (기본값: replace) |
응답:
{
"success": true,
"backend": "local-ollama",
"models": {
"previous": ["llama2", "mistral", "codellama"],
"current": ["llama2", "mistral", "codellama", "phi", "gemma"],
"added": ["phi", "gemma"],
"removed": []
},
"config_version": 24
}
상태 코드:
200: 모델이 성공적으로 업데이트됨400: 유효하지 않은 모델 목록404: 백엔드를 찾을 수 없음
오류 처리¶
오류 응답 형식¶
모든 오류는 일관된 JSON 구조를 따릅니다:
{
"error": {
"message": "Human-readable error description",
"type": "error_type_identifier",
"code": 404,
"details": {
"additional": "context information"
}
}
}
오류 타입¶
| 타입 | HTTP 코드 | 설명 |
|---|---|---|
bad_request | 400 | 유효하지 않은 요청 형식 또는 파라미터 |
unauthorized | 401 | 인증 필요 (향후 기능) |
forbidden | 403 | 접근 거부 (향후 기능) |
model_not_found | 404 | 요청된 모델을 사용할 수 없음 |
rate_limit_exceeded | 429 | 속도 제한 초과 (향후 기능) |
internal_error | 500 | 라우터 내부 오류 |
bad_gateway | 502 | 백엔드 연결/응답 오류 |
service_unavailable | 503 | 모든 백엔드가 비정상 |
gateway_timeout | 504 | 백엔드 요청 타임아웃 |
오류 응답 예제¶
모델을 찾을 수 없음:
{
"error": {
"message": "Model 'invalid-model' not found on any healthy backend",
"type": "model_not_found",
"code": 404,
"details": {
"requested_model": "invalid-model",
"available_models": ["gpt-4", "gpt-3.5-turbo", "llama2"]
}
}
}
백엔드 오류:
{
"error": {
"message": "Failed to connect to backend 'local-ollama'",
"type": "bad_gateway",
"code": 502,
"details": {
"backend": "local-ollama",
"backend_error": "Connection refused"
}
}
}
서비스 사용 불가:
{
"error": {
"message": "All backends are currently unhealthy",
"type": "service_unavailable",
"code": 503,
"details": {
"healthy_backends": 0,
"total_backends": 3
}
}
}
속도 제한¶
참고: 속도 제한은 현재 구현되지 않았지만 향후 릴리스에서 계획되어 있습니다.
향후 속도 제한은 다음을 지원할 예정입니다:
- IP별 속도 제한
- API 키별 속도 제한
- 모델별 속도 제한
- 슬라이딩 윈도우 알고리즘
- 응답의 속도 제한 헤더
스트리밍¶
Server-Sent Events (SSE)¶
stream: true가 지정되면 응답은 다음과 함께 Server-Sent Events로 전송됩니다:
Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive
SSE 형식¶
data: {"id":"chatcmpl-123","object":"chat.completion.chunk",...}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk",...}
data: [DONE]
SSE 호환성¶
라우터는 최대 호환성을 위해 여러 SSE 형식을 지원합니다:
- 표준 형식:
data: {...} - 스페이스 형식:
data: {...} - 혼합 줄 바꿈:
\r\n,\n,\r처리 - 빈 줄: 청크 구분자 올바르게 처리
연결 관리¶
- Keep-Alive: 스트리밍 중 연결 유지
- 타임아웃: 장시간 실행 요청에 대해 5분 타임아웃
- 오류 처리: 부분 응답에 오류 정보 포함
- 클라이언트 연결 해제: 클라이언트 연결 해제를 정상적으로 처리
예제¶
기본 채팅 완료¶
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": "Hello, how are you?"}
]
}'
스트리밍 채팅 완료¶
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "user", "content": "Write a short story"}
],
"stream": true,
"max_tokens": 200
}'
파라미터가 포함된 텍스트 완료¶
curl -X POST http://localhost:8080/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-3.5-turbo-instruct",
"prompt": "The future of AI is",
"max_tokens": 50,
"temperature": 0.8,
"top_p": 0.9
}'
백엔드 상태 확인¶
서비스 헬스 모니터링¶
사용 가능한 모델 목록¶
Python 클라이언트 예제¶
import requests
import json
# 클라이언트 설정
BASE_URL = "http://localhost:8080"
def chat_completion(messages, model="gpt-3.5-turbo", stream=False):
"""채팅 완료 요청 전송"""
response = requests.post(
f"{BASE_URL}/v1/chat/completions",
headers={"Content-Type": "application/json"},
json={
"model": model,
"messages": messages,
"stream": stream,
"temperature": 0.7
},
stream=stream
)
if stream:
# 스트리밍 응답 처리
for line in response.iter_lines():
if line:
line = line.decode('utf-8')
if line.startswith('data: '):
data = line[6:] # 'data: ' 접두사 제거
if data == '[DONE]':
break
try:
chunk = json.loads(data)
content = chunk['choices'][0]['delta'].get('content', '')
if content:
print(content, end='', flush=True)
except json.JSONDecodeError:
continue
print() # 스트리밍 후 새 줄
else:
# 비스트리밍 응답 처리
result = response.json()
return result['choices'][0]['message']['content']
# 사용 예제
messages = [
{"role": "user", "content": "Explain machine learning in simple terms"}
]
print("스트리밍 응답:")
chat_completion(messages, stream=True)
print("\n비스트리밍 응답:")
response = chat_completion(messages, stream=False)
print(response)
JavaScript/Node.js 클라이언트 예제¶
const fetch = require('node-fetch');
const BASE_URL = 'http://localhost:8080';
async function chatCompletion(messages, options = {}) {
const response = await fetch(`${BASE_URL}/v1/chat/completions`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: options.model || 'gpt-3.5-turbo',
messages: messages,
stream: options.stream || false,
temperature: options.temperature || 0.7,
...options
})
});
if (options.stream) {
// 스트리밍 응답 처리
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const data = line.slice(6);
if (data === '[DONE]') return;
try {
const parsed = JSON.parse(data);
const content = parsed.choices[0]?.delta?.content;
if (content) {
process.stdout.write(content);
}
} catch (e) {
// JSON 파싱 오류 무시
}
}
}
}
console.log(); // 새 줄
} else {
const result = await response.json();
return result.choices[0].message.content;
}
}
// 사용 예제
const messages = [
{ role: 'user', content: 'What is the meaning of life?' }
];
// 스트리밍
console.log('스트리밍 응답:');
await chatCompletion(messages, { stream: true });
// 비스트리밍
console.log('\n비스트리밍 응답:');
const response = await chatCompletion(messages);
console.log(response);
이 API 레퍼런스는 Continuum Router와 통합하기 위한 포괄적인 문서를 제공합니다. 라우터는 강력한 다중 백엔드 라우팅 및 관리 기능을 추가하면서 완전한 OpenAI API 호환성을 유지합니다.