콘텐츠로 이동

API 레퍼런스

Continuum Router는 모니터링 및 관리를 위한 추가 관리 엔드포인트와 함께 포괄적인 OpenAI 호환 API를 제공합니다. 이 문서는 사용 가능한 모든 엔드포인트, 요청/응답 형식 및 오류 처리에 대한 상세 정보를 제공합니다.

개요

기본 URL

http://localhost:8080

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 엔드포인트

헬스 체크

라우터 서비스의 헬스 상태를 확인합니다.

GET /health

응답:

{
  "status": "ok",
  "service": "continuum-router"
}

상태 코드:

  • 200: 서비스가 정상

모델 목록

모든 정상 백엔드에서 사용 가능한 모든 모델을 조회합니다.

GET /v1/models

응답:

{
  "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 형식을 사용하여 채팅 완료를 생성합니다.

POST /v1/chat/completions

요청 본문:

{
  "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) 모델을 사용하여 이미지를 생성합니다.

POST /v1/images/generations

요청 본문:

{
  "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 모델 사용 시 standardmedium으로, hdhigh로 매핑됩니다.

품질 설명
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의 aspectRatioimageSize 형식으로 자동 변환합니다:

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를 지원합니다.

POST /v1/images/edits
Content-Type: multipart/form-data

요청 파라미터 (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 포함):

{
  "created": 1677652288,
  "data": [
    {
      "b64_json": "/9j/4AAQSkZJRgABAQAA..."
    }
  ]
}

상태 코드:

  • 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 모델을 사용하여 기존 이미지의 변형을 생성합니다.

POST /v1/images/variations
Content-Type: multipart/form-data

폼 필드:

파라미터 타입 필수 설명
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 포함):

{
  "created": 1677652288,
  "data": [
    {
      "b64_json": "/9j/4AAQSkZJRgABAQAA..."
    }
  ]
}

모델 지원:

모델 변형 지원 참고
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 형식을 사용하여 텍스트 완료를 생성합니다.

POST /v1/completions

요청 본문:

{
  "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 콘텐츠 타입을 사용하여 메시지에서 참조할 수 있으며, 라우터가 파일 콘텐츠를 주입하여 이러한 참조를 자동으로 해결합니다.

파일 업로드

채팅 완료에서 사용할 파일을 업로드합니다.

POST /v1/files
Content-Type: multipart/form-data

폼 필드:

필드 타입 필수 설명
file file 업로드할 파일
purpose string 파일의 용도: vision, assistants, fine-tune, batch

예제:

curl -X POST http://localhost:8080/v1/files \
  -F "file=@image.png" \
  -F "purpose=vision"

응답:

{
  "id": "file-abc123def456",
  "object": "file",
  "bytes": 12345,
  "created_at": 1699061776,
  "filename": "image.png",
  "purpose": "vision"
}

상태 코드:

  • 200: 파일이 성공적으로 업로드됨
  • 400: 유효하지 않은 요청 (파일 누락, 유효하지 않은 용도)
  • 413: 파일이 너무 큼 (설정된 maxfilesize 초과)

파일 목록

업로드된 파일 목록을 조회합니다.

GET /v1/files
GET /v1/files?purpose=vision

쿼리 파라미터:

파라미터 타입 필수 설명
purpose string 아니오 용도별 필터링

응답:

{
  "object": "list",
  "data": [
    {
      "id": "file-abc123def456",
      "object": "file",
      "bytes": 12345,
      "created_at": 1699061776,
      "filename": "image.png",
      "purpose": "vision"
    }
  ]
}


파일 메타데이터 가져오기

특정 파일의 메타데이터를 조회합니다.

GET /v1/files/{file_id}

응답:

{
  "id": "file-abc123def456",
  "object": "file",
  "bytes": 12345,
  "created_at": 1699061776,
  "filename": "image.png",
  "purpose": "vision"
}

상태 코드:

  • 200: 파일 메타데이터 조회됨
  • 404: 파일을 찾을 수 없음

파일 콘텐츠 다운로드

업로드된 파일의 콘텐츠를 다운로드합니다.

GET /v1/files/{file_id}/content

응답: 적절한 Content-Type 헤더와 함께 바이너리 파일 콘텐츠.

상태 코드:

  • 200: 파일 콘텐츠 반환됨
  • 404: 파일을 찾을 수 없음

파일 삭제

업로드된 파일을 삭제합니다.

DELETE /v1/files/{file_id}

응답:

{
  "id": "file-abc123def456",
  "object": "file",
  "deleted": true
}

상태 코드:

  • 200: 파일이 성공적으로 삭제됨
  • 404: 파일을 찾을 수 없음

채팅 완료에서의 파일 해결

라우터는 채팅 완료 요청에서 파일 참조를 자동으로 해결합니다. 메시지에 image_file 콘텐츠 블록이 포함되면 라우터는:

  1. 파일 ID 형식을 검증합니다
  2. 스토리지에서 파일 콘텐츠를 로드합니다
  3. 파일을 base64 data URL로 변환합니다
  4. 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/png
  • image/jpeg
  • image/gif
  • image/webp

관리 엔드포인트

백엔드 상태

설정된 모든 백엔드에 대한 상세 상태 정보를 가져옵니다.

GET /admin/backends

응답:

{
  "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: 백엔드 상태가 성공적으로 조회됨

서비스 헬스

전체 서비스 헬스 및 컴포넌트 상태를 가져옵니다.

GET /admin/health

응답:

{
  "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: 서비스가 비정상

설정 요약

핫 리로드 상태를 포함한 현재 설정 요약을 가져옵니다.

GET /admin/config

응답:

{
  "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 키 등)는 응답에서 자동으로 수정됩니다.


핫 리로드 상태

핫 리로드 기능 및 설정 항목 분류에 대한 상세 정보를 가져옵니다.

GET /admin/config/hot-reload-status

응답:

{
  "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

전체 설정 가져오기

보안을 위해 민감한 정보가 마스킹된 전체 현재 설정을 반환합니다.

GET /admin/config/full

응답:

{
  "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: 설정이 성공적으로 조회됨

설정 섹션 목록

사용 가능한 모든 설정 섹션 목록을 반환합니다.

GET /admin/config/sections

응답:

{
  "sections": [
    "server",
    "backends",
    "health_checks",
    "logging",
    "retry",
    "timeouts",
    "rate_limiting",
    "circuit_breaker",
    "global_prompts",
    "admin",
    "fallback",
    "files",
    "api_keys",
    "metrics",
    "routing"
  ],
  "total": 15
}

상태 코드:

  • 200: 섹션 목록이 성공적으로 조회됨

설정 섹션 가져오기

핫 리로드 기능 정보와 함께 특정 섹션의 설정을 반환합니다.

GET /admin/config/{section}

경로 파라미터:

파라미터 타입 필수 설명
section string 설정 섹션 이름

요청 예제:

curl http://localhost:8080/admin/config/logging

응답:

{
  "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를 반환합니다. 변경 사항 제출 전 클라이언트 측 검증에 유용합니다.

GET /admin/config/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

설정 섹션 대체

전체 설정 섹션을 대체합니다. 검증을 트리거하고 해당하는 경우 핫 리로드합니다.

PUT /admin/config/{section}

경로 파라미터:

파라미터 타입 필수 설명
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 병합 패치 의미론을 사용하여 부분 업데이트를 수행합니다. 지정된 필드만 업데이트되고 지정되지 않은 필드는 현재 값을 유지합니다.

PATCH /admin/config/{section}

경로 파라미터:

파라미터 타입 필수 설명
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 모드를 지원합니다.

POST /admin/config/validate

요청 본문:

{
  "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: 유효하지 않은 요청 형식

보류 중인 변경 사항 적용

보류 중인 설정 변경 사항을 즉시 적용합니다. 적용 가능한 설정에 대해 핫 리로드를 트리거합니다.

POST /admin/config/apply

요청 본문 (선택 사항):

{
  "sections": ["logging", "rate_limiting"],
  "force": false
}

파라미터:

파라미터 타입 필수 설명
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

설정 내보내기

지정된 형식으로 현재 설정을 내보냅니다.

POST /admin/config/export

요청 본문:

{
  "format": "yaml",
  "include_sensitive": false,
  "sections": ["server", "backends", "logging"]
}

파라미터:

파라미터 타입 필수 설명
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에 대해 권한 상승 필요

설정 가져오기

제공된 콘텐츠에서 설정을 가져옵니다.

POST /admin/config/import

요청 본문:

{
  "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: 설정 검증 실패

설정 히스토리 가져오기

설정 변경 히스토리를 조회합니다.

GET /admin/config/history

쿼리 파라미터:

파라미터 타입 필수 설명
limit integer 아니오 반환할 최대 항목 수 (기본값: 20, 최대: 100)
offset integer 아니오 건너뛸 항목 수 (기본값: 0)
section string 아니오 섹션 이름으로 필터링

요청 예제:

curl "http://localhost:8080/admin/config/history?limit=10&section=logging"

응답:

{
  "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: 히스토리가 성공적으로 조회됨

설정 롤백

이전 설정 버전으로 롤백합니다.

POST /admin/config/rollback/{version}

경로 파라미터:

파라미터 타입 필수 설명
version integer 롤백할 버전 번호

요청 본문 (선택 사항):

{
  "dry_run": false,
  "sections": ["logging", "backends"]
}

파라미터:

파라미터 타입 필수 설명
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

이 엔드포인트는 전체 백엔드 설정 섹션을 수정하지 않고 백엔드를 관리하기 위한 편리한 단축키를 제공합니다.

백엔드 추가

라우터에 새 백엔드를 동적으로 추가합니다.

POST /admin/backends

요청 본문:

{
  "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: 이 이름의 백엔드가 이미 존재함

백엔드 설정 가져오기

특정 백엔드의 설정을 조회합니다.

GET /admin/backends/{name}

경로 파라미터:

파라미터 타입 필수 설명
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: 백엔드를 찾을 수 없음

백엔드 설정 업데이트

기존 백엔드의 설정을 업데이트합니다.

PUT /admin/backends/{name}

경로 파라미터:

파라미터 타입 필수 설명
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: 백엔드를 찾을 수 없음

백엔드 삭제

라우터에서 백엔드를 제거합니다.

DELETE /admin/backends/{name}

경로 파라미터:

파라미터 타입 필수 설명
name string 백엔드 식별자

쿼리 파라미터:

파라미터 타입 필수 설명
drain boolean 아니오 활성 요청이 완료될 때까지 대기 (기본값: true)
timeout integer 아니오 드레인 타임아웃 (초) (기본값: 30)

요청 예제:

curl -X DELETE "http://localhost:8080/admin/backends/old-backend?drain=true&timeout=60"

응답:

{
  "success": true,
  "deleted_backend": "old-backend",
  "drained": true,
  "active_requests_completed": 5,
  "config_version": 22,
  "message": "Backend removed from rotation"
}

상태 코드:

  • 200: 백엔드가 성공적으로 삭제됨
  • 404: 백엔드를 찾을 수 없음
  • 409: 마지막 남은 백엔드를 삭제할 수 없음

백엔드 가중치 업데이트

백엔드의 로드 밸런싱 가중치만 업데이트합니다.

PUT /admin/backends/{name}/weight

경로 파라미터:

파라미터 타입 필수 설명
name string 백엔드 식별자

요청 본문:

{
  "weight": 5
}

응답:

{
  "success": true,
  "backend": "local-ollama",
  "weight": {
    "from": 1,
    "to": 5
  },
  "config_version": 23
}

상태 코드:

  • 200: 가중치가 성공적으로 업데이트됨
  • 400: 유효하지 않은 가중치 값
  • 404: 백엔드를 찾을 수 없음

백엔드 모델 업데이트

백엔드의 모델 목록만 업데이트합니다.

PUT /admin/backends/{name}/models

경로 파라미터:

파라미터 타입 필수 설명
name string 백엔드 식별자

요청 본문:

{
  "models": ["llama2", "mistral", "codellama", "phi", "gemma"],
  "mode": "replace"
}

파라미터:

파라미터 타입 필수 설명
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
  }'

백엔드 상태 확인

curl http://localhost:8080/admin/backends | jq

서비스 헬스 모니터링

curl http://localhost:8080/admin/health | jq '.services'

사용 가능한 모델 목록

curl http://localhost:8080/v1/models | jq '.data[].id'

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 호환성을 유지합니다.