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 모델, 확장 사고를 지원하는 Claude 모델 (Anthropic), Gemini thinking 모델 지원. 적응형 사고(Anthropic)에는 auto를 사용하거나, 다른 백엔드에서는 자동으로 medium으로 폴백됩니다. |
reasoning | object | 아니오 | 대체 중첩 형식: {"effort": "high"}. 자동으로 reasoning_effort로 정규화됨. |
백엔드별 유효한 reasoning_effort 값:
- OpenAI O-series (o1, o3, o4-mini):
auto*,low,medium,high - OpenAI GPT-5.2 thinking (gpt-5.2, gpt-5.2-thinking, gpt-5.2-pro):
auto*,low,medium,high,xhigh- 참고:
xhigh는 GPT-5.2 패밀리 thinking 모델에서만 지원됩니다. 다른 모델에서는xhigh가 자동으로high로 다운그레이드됩니다. - *
auto는medium으로 자동 다운그레이드됩니다.
- 참고:
- Anthropic Claude (opus, sonnet-4):
none,minimal,auto,low,medium,highauto는 적응형 사고({"type": "adaptive"})로 매핑됩니다. 모델이 사고의 시점과 정도를 동적으로 결정합니다.
- Gemini (2.0-flash, 2.5-flash, 2.5-pro, 3-flash, 3-pro):
none,auto*,minimal,low,medium,high- *
none은 Flash 모델 (2.0-flash, 2.5-flash, 3-flash)에서만 지원됩니다. - **
auto는medium으로 자동 다운그레이드됩니다.
- *
라우터는 자동으로 값을 검증하고 지능적인 폴백을 적용합니다 (예: O-series에서 xhigh → high, 비Anthropic 백엔드에서 auto → medium).
응답 (비스트리밍):
{
"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 값:
| 값 | 설명 |
|---|---|
auto | 적응형 사고 (Anthropic); 다른 백엔드에서는 medium으로 다운그레이드 |
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, gemini-embedding-2) |
input | string, array, 또는 콘텐츠 파트 | 예 | 임베딩할 입력. 단일 문자열, 문자열 배열, 토큰 배열, 또는 멀티모달 콘텐츠 파트 배열(Gemini Embedding 2 전용)이 될 수 있음 |
encoding_format | string | 아니오 | 임베딩 반환 형식: float 또는 base64 (기본값: float) |
dimensions | integer | 아니오 | 출력 임베딩의 차원 수 (text-embedding-3-* 및 gemini-embedding-2* 모델 지원) |
user | string | 아니오 | 최종 사용자의 고유 식별자 |
입력 형식 예시:
단일 문자열:
문자열 배열:
{
"model": "text-embedding-3-large",
"input": [
"임베딩할 첫 번째 텍스트",
"임베딩할 두 번째 텍스트",
"임베딩할 세 번째 텍스트"
]
}
토큰 배열:
멀티모달 콘텐츠 파트 (Gemini Embedding 2 전용):
{
"model": "gemini-embedding-2",
"input": [
{"type": "text", "text": "골든 리트리버 사진"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ..."}}
]
}
응답:
{
"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 | gemini-embedding-2 | 3072 차원, 멀티모달 지원 (텍스트, 이미지, 오디오, 비디오, 문서) |
| Gemini | gemini-embedding-2-preview | Gemini Embedding 2 프리뷰, 멀티모달 지원 |
| 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: 백엔드 사용 불가
기능:
- 다양한 입력 형식: 단일 문자열, 문자열 배열, 토큰 배열 또는 멀티모달 콘텐츠 파트 지원
- 멀티모달 임베딩:
gemini-embedding-2및gemini-embedding-2-preview는 텍스트, 이미지, 오디오, 비디오, 문서를 하나의 요청에 혼합하여 처리 가능 - 차원 제어:
text-embedding-3-*및gemini-embedding-2*모델의 경우 축소된 벡터 크기를 위한 사용자 정의 차원 지정 - 백엔드 독립적: 모델에 따라 적절한 백엔드로 라우팅
- 로드 밸런싱: 설정된 로드 밸런싱 전략 적용
- 오류 처리: 텍스트 전용 모델에 멀티모달 입력을 전송하면
400오류와 명확한 메시지 반환
멀티모달 콘텐츠 파트 타입 (Gemini Embedding 2 전용):
| 타입 | 필드 | 제약 조건 |
|---|---|---|
text | text (string) | 비어있지 않아야 함 |
image_url | image_url.url (data URI 또는 file://file-* 참조) | MIME: image/jpeg, image/png; 최대 20 MiB; 요청당 최대 6개 이미지 |
audio | audio.data (base64), audio.format | 형식: mp3, wav; 최대 20 MiB |
video | video.data (base64), video.format | 형식: mp4, mov; 최대 20 MiB |
document | document.data (base64), document.format | 형식: pdf; 최대 20 MiB |
요청 예제:
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
}'
멀티모달 입력 예제 (Gemini Embedding 2):
curl -X POST http://localhost:8080/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-api-key" \
-d '{
"model": "gemini-embedding-2",
"input": [
{"type": "text", "text": "바다 위 석양 사진"},
{"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,/9j/4AAQ..."}}
],
"dimensions": 768
}'
리랭킹¶
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블록으로 대체합니다
지원되는 파일 타입¶
채팅 완료에서의 파일 해결은 다음 파일 타입을 지원합니다:
| 파일 타입 | MIME 타입 | 지원 |
|---|---|---|
| PNG | image/png | 모든 백엔드 |
| JPEG | image/jpeg | 모든 백엔드 |
| GIF | image/gif | 모든 백엔드 |
| WebP | image/webp | 모든 백엔드 |
application/pdf | OpenAI, Anthropic | |
| Plain Text | text/plain | Anthropic |
참고: PDF 및 일반 텍스트 지원은 Anthropic 백엔드(및 OpenAI의 PDF)에서 사용할 수 있습니다. 파일 변환기는 각 백엔드에 적합한 형식으로 문서 파일을 자동으로 변환합니다 (OpenAI는 PDF에
file블록을 사용하고, Anthropic은 PDF와 일반 텍스트 모두에document블록을 사용합니다). 이미지가 아닌 파일과 문서가 아닌 파일은 지원되는 파일 타입을 안내하는 유용한 메시지와 함께400 Bad Request오류를 반환합니다.
파일 참조가 포함된 요청:
{
"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: 백엔드를 찾을 수 없음
설정 API 예제¶
전체 설정 가져오기¶
로깅 레벨 업데이트¶
curl -X PATCH http://localhost:8080/admin/config/logging \
-H "Content-Type: application/json" \
-d '{"level": "debug"}'
새 백엔드 추가¶
curl -X POST http://localhost:8080/admin/backends \
-H "Content-Type: application/json" \
-d '{
"name": "remote-ollama",
"url": "http://192.168.1.50:11434",
"weight": 2,
"models": ["llama2", "mistral"]
}'
JSON으로 설정 내보내기¶
curl -X POST http://localhost:8080/admin/config/export \
-H "Content-Type: application/json" \
-d '{"format": "json"}' | jq -r '.content' > config-backup.json
설정 히스토리 보기¶
설정 API 오류 응답¶
모든 설정 관리 API 오류는 표준 오류 형식을 따릅니다:
{
"error": {
"message": "Human-readable error description",
"type": "error_type_identifier",
"code": 400,
"details": {
"additional": "context information"
}
}
}
설정 관련 오류 타입:
| 타입 | HTTP 코드 | 설명 |
|---|---|---|
config_validation_error | 400 | 설정 검증 실패 |
config_section_not_found | 404 | 요청된 설정 섹션이 존재하지 않음 |
config_version_not_found | 404 | 요청된 버전이 히스토리에 없음 |
config_conflict | 409 | 동시 수정 충돌 |
config_permission_denied | 403 | 작업에 대한 권한 부족 |
config_parse_error | 422 | 설정 콘텐츠 파싱 실패 |
검증 오류 예제:
{
"error": {
"message": "Configuration validation failed",
"type": "config_validation_error",
"code": 400,
"details": {
"section": "backends",
"errors": [
{
"field": "url",
"message": "URL must include scheme (http:// or https://)",
"value": "localhost:8000"
}
]
}
}
}
충돌 오류 예제:
{
"error": {
"message": "Configuration was modified by another request",
"type": "config_conflict",
"code": 409,
"details": {
"expected_version": 15,
"current_version": 16,
"conflicting_sections": ["backends"]
}
}
}
오류 처리¶
오류 응답 형식¶
모든 오류는 일관된 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 호환성을 유지합니다.