API 레퍼런스¶
Continuum Router는 모니터링 및 관리를 위한 추가 관리 엔드포인트와 함께 포괄적인 OpenAI 호환 API를 제공합니다. 이 문서는 사용 가능한 모든 엔드포인트, 요청/응답 형식 및 오류 처리에 대한 상세 정보를 제공합니다.
개요¶
기본 URL¶
Content Type¶
별도로 명시되지 않는 한 모든 요청과 응답은 application/json을 사용합니다.
OpenAI 호환성¶
Continuum Router는 OpenAI API v1과 완벽하게 호환되며 다음을 지원합니다:
- 스트리밍을 포함한 채팅 완료
- 텍스트 완료
- 임베딩 (text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002)
- 리랭킹 (Cohere 호환 /v1/rerank)
- 희소 임베딩 (TEI/Jina 호환 /embed_sparse)
- 이미지 생성 (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/v1/embeddings
참고: 헬스 엔드포인트 (/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분간 결과 캐시
- 헬스 인식: 정상 백엔드의 모델만 포함
단일 모델 조회¶
특정 모델의 정보와 가용성 상태를 조회합니다.
경로 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 모델 식별자 (예: "gpt-4", "llama2:7b") |
응답:
{
"id": "gpt-4",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"available": true
}
응답 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
id | string | 모델 식별자 |
object | string | 객체 타입 (항상 "model") |
created | integer | 모델 생성 시점의 Unix 타임스탬프 |
owned_by | string | 모델을 소유/제공하는 조직 |
available | boolean | 모델 사용 가능 여부 (최소 하나의 정상 백엔드에서 제공되면 true) |
상태 코드:
200: 모델이 조회되어 정보가 반환됨404: 구성된 모든 백엔드에 해당 모델이 존재하지 않음
기능:
- OpenAI 호환: 응답 형식이 OpenAI API와 호환되며
available필드가 추가됨 - 헬스 인식:
available필드는 실시간 백엔드 헬스 상태를 반영 - 프라이버시: 내부 백엔드 정보를 노출하지 않음
요청 예시:
응답 예시 (모델 사용 가능):
{
"id": "gpt-4",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"available": true
}
응답 예시 (모델 존재하지만 사용 불가):
{
"id": "gpt-4",
"object": "model",
"created": 1677610602,
"owned_by": "openai",
"available": false
}
채팅 완료¶
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 | 아니오 | 추적을 위한 사용자 식별자 |
reasoning_effort | string | 아니오 | 추론 가능 모델의 추론 노력 수준. 유효한 값은 백엔드에 따라 다름 (아래 참조). OpenAI O-series (o1, o3, o4) 및 GPT-5.2 thinking 모델, Gemini thinking 모델 지원. |
reasoning | object | 아니오 | 대체 중첩 형식: {"effort": "high"}. 자동으로 reasoning_effort로 정규화됨. |
백엔드별 유효한 reasoning_effort 값:
- OpenAI O-series (o1, o3, o4-mini):
low,medium,high - OpenAI GPT-5.2 thinking (gpt-5.2, gpt-5.2-thinking, gpt-5.2-pro):
low,medium,high,xhigh- 참고:
xhigh는 GPT-5.2 패밀리 thinking 모델에서만 지원됩니다. 다른 모델에서는xhigh가 자동으로high로 다운그레이드됩니다.
- 참고:
- Gemini (2.0-flash, 2.5-flash, 2.5-pro, 3-flash, 3-pro):
none,minimal,low,medium,high- 참고:
none은 Flash 모델 (2.0-flash, 2.5-flash, 3-flash)에서만 지원됩니다.
- 참고:
라우터는 자동으로 값을 검증하고 지능적인 폴백을 적용합니다 (예: O-series에서 xhigh → high).
응답 (비스트리밍):
{
"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를 통한 실시간 응답 스트리밍
- 오류 복구: 일시적 실패 시 자동 재시도
- 요청 중복 제거: 동일한 요청의 중복 처리 방지
- 추론 파라미터 정규화: 중첩된
reasoning형식을 평면reasoning_effort형식으로 자동 정규화; 지원하지 않는 모델에서는 추론 파라미터 제거
Responses API¶
OpenAI의 Responses API 형식을 사용하여 응답을 생성합니다. 이 엔드포인트는 Chat Completions에 대한 대안적 인터페이스를 제공하며, 내부적으로 요청을 Chat Completions 형식으로 변환하여 백엔드에서 처리합니다.
요청 본문:
{
"model": "gpt-4o",
"input": "양자 컴퓨팅을 간단한 용어로 설명해주세요.",
"instructions": "당신은 복잡한 주제를 간단하게 설명하는 유용한 어시스턴트입니다.",
"max_output_tokens": 1000,
"temperature": 0.7,
"reasoning": {
"effort": "high"
}
}
파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 모델 식별자 (최소 하나의 정상 백엔드에서 사용 가능해야 함) |
input | string/array | 예 | 입력 텍스트 또는 입력 항목 배열 |
instructions | string | 아니오 | 모델에 대한 시스템 지시사항 (시스템 메시지로 변환됨) |
max_output_tokens | integer | 아니오 | 생성할 최대 토큰 수 |
temperature | number | 아니오 | 샘플링 온도 (0.0 ~ 2.0) |
top_p | number | 아니오 | 핵 샘플링 파라미터 (0.0 ~ 1.0) |
stream | boolean | 아니오 | 스트리밍 응답 활성화 (기본값: false) |
include_reasoning | boolean | 아니오 | 응답에 추론 콘텐츠 포함 |
reasoning | object | 아니오 | 중첩 형식의 추론 설정 (아래 참조) |
tools | array | 아니오 | 모델에서 사용 가능한 도구 목록 (플랫 형식) |
tool_choice | string/object | 아니오 | 도구 사용 제어 |
previous_response_id | string | 아니오 | 다중 턴 대화를 위한 이전 응답 참조 |
도구 정의 형식:
Responses API는 함수 속성이 type 필드와 같은 레벨에 있는 플랫 도구 형식을 사용합니다. 이는 중첩된 function 객체를 사용하는 Chat Completions API와 다릅니다.
{
"type": "function",
"name": "get_weather",
"description": "위치의 날씨 조회",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "도시 이름"}
},
"required": ["location"]
},
"strict": true
}
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
type | string | 예 | "function"이어야 함 |
name | string | 예 | 함수 이름 |
description | string | 아니오 | 함수가 수행하는 작업 설명 |
parameters | object | 아니오 | 함수 파라미터에 대한 JSON Schema |
strict | boolean | 아니오 | 엄격한 파라미터 검증 활성화 |
기타 지원되는 도구 유형: code_interpreter, file_search, web_search, computer_use
멀티모달 입력 유형:
input이 항목 배열인 경우 각 항목은 멀티모달 콘텐츠 파트를 포함하는 메시지가 될 수 있습니다. 다음 콘텐츠 파트 유형이 지원됩니다:
| 유형 | 설명 |
|---|---|
text | 일반 텍스트 콘텐츠 |
input_text | 텍스트 콘텐츠 (Responses API 대체 형식) |
input_file | 파일 콘텐츠 (PDF, 이미지 또는 기타 파일) |
input_image | 이미지 콘텐츠 |
image_url | URL 또는 base64 데이터의 이미지 |
Input File 형식:
input_file 콘텐츠 파트는 세 가지 입력 방법을 지원합니다:
{
"type": "input_file",
"filename": "document.pdf",
"file_data": "data:application/pdf;base64,JVBERi0xLjQ..."
}
| 필드 | 유형 | 설명 |
|---|---|---|
filename | string | 파일의 선택적 파일명 |
file_data | string | Base64 데이터 URL (예: data:application/pdf;base64,...) |
file_url | string | 파일의 외부 URL (SSRF 검증됨) |
file_id | string | Files API를 통해 업로드된 파일 참조 |
Input Image 형식:
| 필드 | 유형 | 설명 |
|---|---|---|
image_url | string | 이미지 URL 또는 base64 데이터 URL |
detail | string | 이미지 상세 수준: low, high 또는 auto (기본값) |
멀티모달 요청 예시:
curl -X POST http://localhost:8080/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o",
"input": [
{
"type": "message",
"role": "user",
"content": [
{"type": "input_text", "text": "이 문서에 무엇이 적혀있나요?"},
{"type": "input_file", "filename": "report.pdf", "file_data": "data:application/pdf;base64,..."}
]
}
]
}'
보안 참고 사항:
file_url의 외부 URL은 SSRF 공격 방지를 위해 검증됩니다- 개인 IP 주소와 localhost URL은 거부됩니다
- 외부 파일에는 HTTPS URL만 권장됩니다
file_id필드는 Files API를 통해 업로드된 파일을 참조합니다. 파일은 백엔드로 전송되기 전에 base64로 변환됩니다. 파일 소유권이 검증되며 파일 주입에 10MB 크기 제한이 적용됩니다
Reasoning 파라미터:
reasoning 파라미터는 추론 가능 모델의 추론 노력 수준을 제어합니다. 중첩 형식을 사용합니다:
유효한 effort 값:
| 값 | 설명 |
|---|---|
low | 최소 추론 노력, 더 빠른 응답 |
medium | 균형 잡힌 추론 노력 |
high | 최대 표준 추론 노력 |
xhigh | 확장 추론 (GPT-5.2 패밀리 전용) |
라우터는 이 중첩 형식을 Chat Completions 백엔드에서 사용하는 평면 reasoning_effort 형식으로 자동 변환합니다. 잘못된 노력 수준은 400 Bad Request 오류로 거부됩니다.
Reasoning을 포함한 요청 예시:
curl -X POST http://localhost:8080/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model": "o1",
"input": "이 복잡한 수학 문제를 단계별로 풀어주세요.",
"reasoning": {
"effort": "high"
}
}'
응답:
{
"id": "resp_abc123",
"object": "response",
"created_at": 1699000000,
"model": "o1",
"output": [
{
"type": "message",
"id": "msg_001",
"role": "assistant",
"content": [
{
"type": "output_text",
"text": "단계별로 풀어보겠습니다..."
}
]
}
],
"usage": {
"input_tokens": 25,
"output_tokens": 150
},
"status": "completed"
}
상태 코드:
200: 응답 생성 성공400: 잘못된 요청 형식, 파라미터 또는 잘못된 reasoning effort 값404: 정상 백엔드에서 모델을 찾을 수 없음502: 백엔드 연결 오류504: 요청 타임아웃503: 모든 백엔드가 비정상
기능:
- 스마트 라우팅: 백엔드 기능에 따라 요청 라우팅 - OpenAI/Azure는 네이티브 패스스루, 기타는 자동 변환
- 네이티브 패스스루: OpenAI 및 Azure OpenAI 백엔드의 경우 요청이
/v1/responses엔드포인트로 직접 전달되어 모든 네이티브 기능 유지 - 자동 변환: 기타 백엔드(Anthropic, Gemini, vLLM, Ollama 등)의 경우 Responses API 형식을 해당 네이티브 형식으로 변환
- 추론 지원: 타입 안전 검증을 통한 reasoning 파라미터 전체 지원
- 다중 백엔드 지원: OpenAI, Anthropic, Gemini, Ollama, vLLM 및 기타 백엔드와 호환
- 스트리밍 지원:
stream: true일 때 SSE를 통한 실시간 응답 스트리밍 - 세션 관리:
previous_response_id를 통한 다중 턴 대화 지원
라우팅 전략:
라우터는 각 백엔드에 대해 최적의 전략을 자동으로 결정합니다:
| 백엔드 유형 | 전략 | 설명 |
|---|---|---|
| OpenAI | 패스스루 | 네이티브 Responses API 지원 - 요청 직접 전달 |
| Azure OpenAI | 패스스루 | 네이티브 Responses API 지원 - 요청 직접 전달 |
| Anthropic | 네이티브 변환 | 네이티브 Anthropic Messages API 형식으로 변환, PDF/이미지 완전 지원 |
| Gemini | 변환 | Gemini generateContent API 형식으로 변환 |
| vLLM | 변환 | Chat Completions 형식으로 변환 |
| Ollama | 변환 | Chat Completions 형식으로 변환 |
| LlamaCpp | 변환 | Chat Completions 형식으로 변환 |
| Generic | 변환 | Chat Completions 형식으로 변환 |
패스스루 이점:
OpenAI 또는 Azure OpenAI 백엔드를 패스스루 모드로 사용할 때:
- 네이티브 PDF 파일 지원 (Chat Completions는 이미지만 지원)
- 턴 간 추론 상태 보존으로 성능 향상
- 내장 도구(websearch, filesearch 등) 접근 가능
- 향상된 캐시 활용 (OpenAI 문서에 따르면 40-80% 개선)
- 최신 OpenAI Responses API 기능과의 완벽한 호환성
Anthropic 네이티브 변환 이점:
Anthropic (Claude) 백엔드를 네이티브 변환 모드로 사용할 때:
- Anthropic 문서 이해 기능을 통한 네이티브 PDF 파일 지원
- 자동 형식 감지를 통한 이미지 파일 지원
- Claude 3+ 모델의 확장 사고(Extended Thinking) 지원
- 외부 파일 URL에 대한 SSRF 보호
- 보안을 위한 미디어 타입 화이트리스트
이미지 생성¶
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
}
}
상태 코드: 채팅 완료와 동일
임베딩¶
OpenAI 임베딩 API 형식을 사용하여 입력 텍스트에 대한 임베딩을 생성합니다.
요청 본문:
{
"model": "text-embedding-3-small",
"input": "The quick brown fox jumps over the lazy dog",
"encoding_format": "float",
"dimensions": 512,
"user": "user123"
}
요청 파라미터:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 사용할 모델의 ID (예: text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002) |
input | string 또는 array | 예 | 임베딩할 입력 텍스트. 단일 문자열, 문자열 배열 또는 토큰 배열이 될 수 있음 |
encoding_format | string | 아니오 | 임베딩 반환 형식: float 또는 base64 (기본값: float) |
dimensions | integer | 아니오 | 출력 임베딩의 차원 수 (text-embedding-3-* 모델만 지원) |
user | string | 아니오 | 최종 사용자의 고유 식별자 |
입력 형식 예시:
단일 문자열:
문자열 배열:
{
"model": "text-embedding-3-large",
"input": [
"임베딩할 첫 번째 텍스트",
"임베딩할 두 번째 텍스트",
"임베딩할 세 번째 텍스트"
]
}
토큰 배열:
응답:
{
"object": "list",
"data": [
{
"object": "embedding",
"index": 0,
"embedding": [0.0023064255, -0.009327292, 0.0045318254, ...]
}
],
"model": "text-embedding-3-small",
"usage": {
"prompt_tokens": 8,
"total_tokens": 8
}
}
응답 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
object | string | 항상 "list" |
data | array | 임베딩 객체 배열 |
data[].object | string | 항상 "embedding" |
data[].index | integer | 입력 배열에서 임베딩의 인덱스 |
data[].embedding | array | 임베딩 벡터 (부동소수점 배열) |
model | string | 임베딩 생성에 사용된 모델 |
usage | object | 토큰 사용 정보 |
usage.prompt_tokens | integer | 입력의 토큰 수 |
usage.total_tokens | integer | 사용된 총 토큰 (임베딩의 경우 prompt_tokens와 동일) |
지원 모델:
| 백엔드 | 모델 | 참고 |
|---|---|---|
| OpenAI | text-embedding-3-small | 기본 1536 차원, dimensions 파라미터 지원 |
| OpenAI | text-embedding-3-large | 기본 3072 차원, dimensions 파라미터 지원 |
| OpenAI | text-embedding-ada-002 | 1536 차원, 레거시 모델 |
| Gemini | text-embedding-004 | OpenAI 호환 엔드포인트 사용 |
| 자체 호스팅 | bge-m3 | 1024 차원, 100개 이상 언어, 8192 컨텍스트. Dense, sparse, ColBERT 검색 지원 |
| 자체 호스팅 | bge-large-en-v1.5 | 1024 차원, 영어 전용, 512 컨텍스트 |
| 자체 호스팅 | multilingual-e5-large | 1024 차원, 100개 이상 언어, 514 컨텍스트 |
| vLLM | 배포별 다름 | 배포된 모델에 따라 다름 |
| llama.cpp | 배포별 다름 | 네이티브 /v1/embeddings 지원 |
| TEI | 배포별 다름 | Hugging Face Text Embeddings Inference 서버 |
| Ollama | 배포별 다름 | Ollama 임베딩 모델 사용 |
상태 코드:
200: 임베딩이 성공적으로 생성됨400: 유효하지 않은 요청 (model/input 누락, 유효하지 않은 dimensions)401: 유효하지 않은 API 키404: 모델을 찾을 수 없거나 임베딩을 지원하지 않음429: 속도 제한 초과500: 백엔드 오류503: 백엔드 사용 불가
기능:
- 다양한 입력 형식: 단일 문자열, 문자열 배열 또는 토큰 배열 지원
- 차원 제어: text-embedding-3 모델의 경우 축소된 벡터 크기를 위한 사용자 정의 차원 지정
- 백엔드 독립적: 모델에 따라 적절한 백엔드로 라우팅
- 로드 밸런싱: 설정된 로드 밸런싱 전략 적용
- 오류 처리: 유효하지 않은 요청에 대한 상세 오류 메시지 제공
요청 예제:
curl -X POST http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "text-embedding-3-small",
"input": "The quick brown fox jumps over the lazy dog",
"encoding_format": "float"
}'
여러 입력 예제:
curl -X POST http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "text-embedding-3-large",
"input": [
"첫 번째 문서 텍스트",
"두 번째 문서 텍스트",
"세 번째 문서 텍스트"
]
}'
사용자 정의 차원 예제:
curl -X POST http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "text-embedding-3-small",
"input": "샘플 텍스트",
"dimensions": 512
}'
리랭킹¶
Cohere 호환 Rerank API를 사용하여 쿼리와의 관련성을 기준으로 문서를 리랭킹합니다. 이는 일반적으로 초기 벡터 검색 후 정확도를 향상시키기 위한 2단계 검색 단계로 사용됩니다.
요청 본문:
{
"model": "bge-reranker-v2-m3",
"query": "머신러닝이란 무엇인가요?",
"documents": ["문서 1 내용", "문서 2 내용", "문서 3 내용"],
"top_n": 3,
"return_documents": false
}
요청 파라미터:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 사용할 리랭킹 모델의 ID (예: bge-reranker-v2-m3, rerank-english-v3.0, jina-reranker-v2-base-multilingual) |
query | string | 예 | 문서와 비교할 검색 쿼리 |
documents | array | 예 | 리랭킹할 문서 목록. 문자열 배열 또는 text 필드가 있는 객체 배열이 될 수 있음 |
top_n | integer | 아니오 | 반환할 상위 결과 수. 지정하지 않으면 모든 문서가 순위대로 반환됨 |
return_documents | boolean | 아니오 | 응답에 문서 텍스트를 포함할지 여부 (기본값: false) |
max_chunks_per_doc | integer | 아니오 | 긴 문서 처리를 위해 문서당 처리할 최대 청크 수 |
문서 형식 옵션:
단순 문자열 배열:
{
"model": "bge-reranker-v2-m3",
"query": "딥러닝이란 무엇인가요?",
"documents": [
"딥러닝은 여러 층의 신경망을 사용합니다",
"머신러닝은 인공지능의 하위 분야입니다",
"자연어 처리는 텍스트 이해를 다룹니다"
]
}
text 필드가 있는 구조화된 문서:
{
"model": "rerank-english-v3.0",
"query": "딥러닝이란 무엇인가요?",
"documents": [
{"text": "딥러닝은 여러 층의 신경망을 사용합니다"},
{"text": "머신러닝은 인공지능의 하위 분야입니다"}
]
}
응답:
{
"results": [
{
"index": 0,
"relevance_score": 0.95
},
{
"index": 2,
"relevance_score": 0.72
},
{
"index": 1,
"relevance_score": 0.45
}
],
"model": "bge-reranker-v2-m3",
"id": "rerank-abc123",
"usage": {
"prompt_tokens": 150,
"total_tokens": 150
}
}
문서 포함 응답 (return_documents: true 인 경우):
{
"results": [
{
"index": 0,
"relevance_score": 0.95,
"document": {
"text": "딥러닝은 여러 층의 신경망을 사용합니다"
}
}
],
"model": "bge-reranker-v2-m3"
}
응답 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
results | array | 관련성 점수 순으로 정렬된 리랭킹 결과 목록 (높은 순) |
results[].index | integer | 원본 입력 목록에서 문서의 인덱스 |
results[].relevance_score | number | 관련성 점수 (일반적으로 0.0에서 1.0, 높을수록 더 관련됨) |
results[].document | object | 문서 텍스트 (return_documents가 true인 경우에만 존재) |
model | string | 리랭킹에 사용된 모델 |
id | string | 이 요청의 고유 식별자 (선택적) |
usage | object | 토큰 사용 정보 (선택적) |
지원 백엔드:
| 백엔드 | 엔드포인트 | 참고 |
|---|---|---|
| vLLM | /v1/rerank | Cohere 호환, BGE, Jina 리랭커 지원 |
| llama.cpp | /v1/rerank | 시작 시 --reranking 플래그 필요 |
| Hugging Face TEI | /rerank | Text Embeddings Inference 서버 |
| Cohere API | /v1/rerank | 네이티브 Cohere rerank 엔드포인트 |
| Jina AI | /v1/rerank | 네이티브 Jina rerank 엔드포인트 |
상태 코드:
200: 문서가 성공적으로 리랭킹됨400: 유효하지 않은 요청 (model/query/documents 누락, 빈 documents 배열)401: 유효하지 않은 API 키404: 모델을 찾을 수 없거나 리랭킹을 지원하지 않음429: 속도 제한 초과500: 백엔드 오류503: 백엔드 사용 불가
사용 사례:
- 2단계 검색: 벡터 검색으로 후보를 검색한 다음 더 높은 정밀도를 위해 리랭킹
- RAG 시스템: LLM 처리 전에 검색된 문서를 리랭킹하여 컨텍스트 품질 향상
- 검색 결과 정제: 의미적 관련성에 따라 검색 결과 재정렬
요청 예제:
curl -X POST http://localhost:8080/v1/rerank \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "bge-reranker-v2-m3",
"query": "재생 에너지의 장점은 무엇인가요?",
"documents": [
"태양광 패널은 햇빛을 전기로 변환합니다",
"풍력 터빈은 바람에서 전력을 생성합니다",
"석탄은 전기에 사용되는 화석 연료입니다"
],
"top_n": 2
}'
희소 임베딩¶
TEI/Jina 호환 Sparse Embedding API를 사용하여 입력 텍스트에 대한 희소 임베딩을 생성합니다. 희소 임베딩(예: SPLADE)은 명시적인 용어 가중치를 통해 어휘 정보를 보존하여 하이브리드 검색에서 밀집 임베딩을 보완합니다.
요청 본문:
요청 파라미터:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 사용할 희소 임베딩 모델의 ID (예: naver/splade-v3, naver/splade-cocondenser-ensembledistil) |
input | string 또는 array | 예 | 임베딩할 입력 텍스트. 단일 문자열 또는 문자열 배열이 될 수 있음 |
입력 형식 예시:
단일 문자열:
문자열 배열:
응답:
{
"data": [
{
"index": 0,
"sparse_embedding": {
"indices": [123, 456, 789, 1024, 2048],
"values": [0.5, 0.3, 0.1, 0.8, 0.2]
}
}
],
"model": "naver/splade-v3",
"usage": {
"prompt_tokens": 8,
"total_tokens": 8
}
}
응답 필드:
| 필드 | 타입 | 설명 |
|---|---|---|
data | array | 희소 임베딩 객체 배열 |
data[].index | integer | 입력 배열에서 임베딩의 인덱스 |
data[].sparse_embedding | object | 희소 임베딩 벡터 |
data[].sparse_embedding.indices | array | 어휘에서 0이 아닌 요소의 인덱스 |
data[].sparse_embedding.values | array | 해당 인덱스의 값 |
model | string | 임베딩 생성에 사용된 모델 (선택적) |
usage | object | 토큰 사용 정보 (선택적) |
희소 벡터 이해:
희소 벡터는 어휘 인덱스와 함께 0이 아닌 값만 저장합니다. 예를 들어:
indices: [123, 456, 789]- 어휘에서의 위치values: [0.5, 0.3, 0.1]- 해당 용어의 가중치
이는 0이 아닌 요소가 적은 고차원 벡터에 대해 메모리 효율적입니다 (일반적으로 30,000개 이상의 어휘 크기 중 100-500개의 0이 아닌 값).
지원 백엔드:
| 백엔드 | 엔드포인트 | 참고 |
|---|---|---|
| vLLM | /embed_sparse | OpenAI 호환 서버를 통한 SPLADE 모델 지원 |
| Hugging Face TEI | /embed_sparse | --pooling splade 플래그 필요 |
| Jina AI | 네이티브 | 네이티브 희소 임베딩 지원 |
상태 코드:
200: 희소 임베딩이 성공적으로 생성됨400: 유효하지 않은 요청 (model/input 누락, 빈 입력)401: 유효하지 않은 API 키404: 모델을 찾을 수 없거나 희소 임베딩을 지원하지 않음429: 속도 제한 초과500: 백엔드 오류503: 백엔드 사용 불가
사용 사례:
- 하이브리드 검색: 더 나은 결과를 위해 밀집(의미) 및 희소(어휘) 검색 결합
- 키워드 매칭: 학습된 가중치를 통한 정확한 용어 매칭
- 도메인별 검색: 전문 용어 및 희귀 단어의 더 나은 처리
- 교차 언어 검색: 일부 SPLADE 모델은 다국어 희소 검색 지원
요청 예제:
curl -X POST http://localhost:8080/embed_sparse \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "naver/splade-v3",
"input": "검색을 위한 희소 임베딩의 장점은 무엇인가요?"
}'
여러 입력 예제:
curl -X POST http://localhost:8080/embed_sparse \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "naver/splade-v3",
"input": [
"첫 번째 쿼리 텍스트",
"두 번째 쿼리 텍스트"
]
}'
Files API¶
Files API를 사용하면 채팅 완료에서 파일을 업로드, 관리 및 사용할 수 있습니다. 업로드된 파일은 image_file 콘텐츠 타입을 사용하여 메시지에서 참조할 수 있으며, 라우터가 파일 콘텐츠를 주입하여 이러한 참조를 자동으로 해결합니다.
파일 업로드¶
채팅 완료에서 사용할 파일을 업로드합니다.
폼 필드:
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
file | file | 예 | 업로드할 파일 |
purpose | string | 예 | 파일의 용도: vision, assistants, fine-tune, batch, user_data, evals |
예제:
응답:
{
"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/png- 모든 백엔드image/jpeg- 모든 백엔드image/gif- 모든 백엔드image/webp- 모든 백엔드application/pdf- OpenAI, Anthropic (최대 32MB, 100페이지)text/plain- Anthropic (최대 32MB)
Anthropic 네이티브 API¶
Continuum Router는 Anthropic의 API 형식을 직접 사용하면서도 라우터의 로드 밸런싱, 장애 조치 및 다중 백엔드 라우팅 기능을 활용할 수 있는 네이티브 Anthropic API 엔드포인트를 제공합니다.
메시지 API¶
Anthropic의 네이티브 API 형식을 사용하여 메시지를 전송합니다.
헤더:
| 헤더 | 필수 | 설명 |
|---|---|---|
x-api-key | 예* | 인증용 API 키 (blocking 모드에서 필수) |
anthropic-version | 아니오 | API 버전 (예: 2023-06-01). 네이티브 Anthropic 백엔드로 전달됨 |
anthropic-beta | 아니오 | 베타 기능 (예: prompt-caching-2024-07-31). 네이티브 Anthropic 백엔드로 전달됨 |
요청 본문:
{
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "안녕하세요, Claude!"
}
],
"stream": false
}
요청 파라미터:
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
model | string | 예 | 모델 식별자 |
max_tokens | integer | 예 | 생성할 최대 토큰 수 |
messages | array | 예 | 메시지 객체 배열 |
system | string/array | 아니오 | 시스템 프롬프트 (문자열 또는 콘텐츠 블록 배열) |
stream | boolean | 아니오 | 스트리밍 활성화 (기본값: false) |
temperature | number | 아니오 | 샘플링 온도 (0-1) |
top_p | number | 아니오 | 핵 샘플링 파라미터 |
top_k | integer | 아니오 | Top-k 샘플링 파라미터 |
stop_sequences | array | 아니오 | 정지 시퀀스 |
metadata | object | 아니오 | 요청 메타데이터 |
tools | array | 아니오 | 함수 호출을 위한 도구 정의 |
tool_choice | object | 아니오 | 도구 선택 설정 |
응답 (비스트리밍):
{
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"content": [
{
"type": "text",
"text": "안녕하세요! 무엇을 도와드릴까요?"
}
],
"model": "claude-sonnet-4-20250514",
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 12,
"output_tokens": 15,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}
백엔드 라우팅:
라우터는 대상 백엔드에 따라 요청을 자동으로 변환합니다:
| 백엔드 타입 | 변환 |
|---|---|
| Anthropic | 네이티브 API 형식으로 패스스루 |
| Gemini | Gemini 형식으로 직접 변환 |
| OpenAI/vLLM/Ollama | OpenAI 형식으로 변환 후 응답을 다시 변환 |
토큰 카운팅¶
메시지 요청 페이로드의 토큰 수를 계산합니다.
요청 본문:
{
"model": "claude-sonnet-4-20250514",
"messages": [
{
"role": "user",
"content": "안녕하세요, 어떠세요?"
}
],
"system": "당신은 도움이 되는 어시스턴트입니다."
}
응답:
계층적 토큰 카운팅¶
토큰 카운팅은 백엔드 타입에 따라 다른 전략을 사용합니다:
| 백엔드 타입 | 전략 | 정확도 |
|---|---|---|
| Anthropic | 네이티브 /v1/messages/count_tokens API 프록시 | 정확 |
| llama.cpp | 백엔드 /tokenize 엔드포인트 프록시 | 정확 |
| vLLM | 백엔드 /tokenize 엔드포인트 프록시 | 정확 |
| 기타 | 문자 기반 추정 (~4자/토큰) | 근사 |
참고: 네이티브 토큰화를 지원하지 않는 백엔드의 경우, 라우터는 토큰당 약 4자를 기준으로 하는 문자 기반 추정을 사용합니다. 이는 계획 목적으로 합리적인 근사치를 제공하지만 모델이 사용하는 정확한 토큰 수와 일치하지 않을 수 있습니다.
모델 목록¶
Anthropic API 형식으로 사용 가능한 모델을 나열합니다.
응답:
{
"data": [
{
"id": "claude-sonnet-4-20250514",
"type": "model",
"display_name": "Claude Sonnet 4",
"created_at": "2025-05-14T00:00:00Z"
},
{
"id": "claude-opus-4-20250514",
"type": "model",
"display_name": "Claude Opus 4",
"created_at": "2025-05-14T00:00:00Z"
}
],
"has_more": false,
"first_id": "claude-sonnet-4-20250514",
"last_id": "claude-opus-4-20250514"
}
Claude Code 호환성¶
Anthropic 네이티브 API는 Claude Code 및 고급 기능이 필요한 기타 Anthropic API 클라이언트와의 완전한 호환성을 포함합니다.
프롬프트 캐싱¶
프롬프트 캐싱은 콘텐츠 블록의 cache_control 필드를 통해 완벽하게 지원됩니다:
{
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"system": [
{
"type": "text",
"text": "당신은 광범위한 지식을 가진 유용한 코딩 어시스턴트입니다...",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "이전 컨텍스트...",
"cache_control": {"type": "ephemeral"}
},
{
"type": "text",
"text": "현재 질문"
}
]
}
]
}
지원되는 cache_control 위치:
- 시스템 프롬프트 텍스트 블록
- 사용자 메시지 텍스트 블록
- 사용자 메시지 이미지 블록
- 도구 정의
- 도구 사용 블록
- 도구 결과 블록
베타 기능 헤더¶
anthropic-beta 헤더는 네이티브 Anthropic 백엔드로 전달되어 베타 기능을 활성화합니다:
curl -X POST http://localhost:8080/anthropic/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: prompt-caching-2024-07-31,interleaved-thinking-2025-05-14" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-20250514",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "안녕하세요"}]
}'
스트리밍에서의 캐시 사용량¶
네이티브 Anthropic 백엔드로 스트리밍할 때 캐시 사용량 정보가 message_start 이벤트에 포함됩니다:
{
"type": "message_start",
"message": {
"id": "msg_01XFDUDYJgAACzvnptvVoYEL",
"type": "message",
"role": "assistant",
"content": [],
"model": "claude-sonnet-4-20250514",
"usage": {
"input_tokens": 2159,
"cache_creation_input_tokens": 2048,
"cache_read_input_tokens": 0
}
}
}
인터리브드 씽킹¶
인터리브드 출력을 포함한 확장 사고(Extended Thinking)는 스트리밍 모드에서 지원됩니다. 모델이 사고와 텍스트 콘텐츠를 교대로 생성할 때, 스트리밍 이벤트는 각 블록에 대해 적절한 content_block_start, content_block_delta, content_block_stop 이벤트와 함께 이 인터리브드 구조를 올바르게 표현합니다.
관리 엔드포인트¶
백엔드 상태¶
설정된 모든 백엔드에 대한 상세 상태 정보를 가져옵니다.
응답:
{
"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 호환성을 유지합니다.