Chat Completions
지원 모델에 대화를 보내고 OpenAI 호환 응답을 받으세요.
메시지 배열, 스트리밍, 도구 호출을 OpenAI 호환 형식으로 다룹니다.
https://gw.letsur.ai/v1/chat/completionsAuthorization: Bearer <API_KEY>요청 필드
| 필드 | 타입 | 요구 여부 | 기본값 | 설명 |
|---|---|---|---|---|
model | string | 필수 | — | 모델 코드 (에셋) |
messages | array | 필수 | — | {role, content} 객체의 배열 |
temperature | number | 선택 | 1 | 0 ~ 2 |
top_p | number | 선택 | 1 | nucleus sampling |
max_tokens | integer | 선택 | 모델별 | 응답 최대 토큰 |
stream | boolean | 선택 | false | Server-Sent Events 스트리밍 |
stream_options | object | 선택 | — | include_usage: true로 마지막 사용량 요약을 요청합니다 |
stop | string | array | 선택 | — | 응답 중단 시퀀스 |
n | integer | 선택 | 1 | 응답 개수 (대부분 1) |
tools | array | 선택 | — | Tool calling 정의 |
tool_choice | string | object | 선택 | auto | Tool 선택 정책 |
response_format | object | 선택 | — | JSON mode 등 |
모델별 지원 파라미터
이미지 입력, tool calling, JSON mode, streaming의 지원 여부와 세부 제한은 모델마다 다릅니다.
정확한 지원 여부는 에셋의 모델 상세에서 확인합니다. 지원하지 않는 파라미터를 포함한 요청은 실패할 수 있습니다.
messages 배열
role | 의미 |
|---|---|
system | 시스템 프롬프트 (모델 행동 지정) |
user | 사용자 입력 |
assistant | 모델의 이전 응답 (대화 이어가기) |
tool | tool 호출 결과 (tool calling 시) |
content에는 텍스트 문자열이나 배열을 넣습니다. 이미지를 함께 보낼 때는 배열을 씁니다. 자세한 내용은 이미지 입력에서 확인합니다.
응답 (200)
{
"id": "chatcmpl-...",
"object": "chat.completion",
"created": 1730000000,
"model": "<MODEL_CODE>",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "..." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 12,
"completion_tokens": 48,
"total_tokens": 60
},
"estimated_cost": {
"amount": "0.00032400",
"currency": "unit",
"disclaimer": "Estimated based on published pricing. Actual charges may differ."
}
}| 필드 | 의미 |
|---|---|
id | 호출 식별자 (추적 ID와 매칭) |
model | 응답이 사용한 모델 식별자 |
choices[0].message.content | 모델 응답 본문 |
choices[0].finish_reason | stop / length / tool_calls / content_filter (finish_reason 별 의미) |
estimated_cost | 비스트리밍 응답 최상위의 호출별 비용 객체입니다. 이름에는 estimated가 남아 있지만 과금 기록에 사용한 같은 비용 값을 반환합니다 (요금) |
finish_reason
응답 종료 이유를 나타냅니다. 같은 200 OK라도 값에 따라 의미가 다릅니다.
| 값 | 의미 | 대응 |
|---|---|---|
stop | 모델이 자연스럽게 응답을 끝냈습니다 | 정상입니다. 그대로 사용합니다 |
length | max_tokens 또는 모델 컨텍스트 한도에 걸려 잘렸습니다 | max_tokens을 키우거나, 같은 프롬프트로 이어 받습니다 (대화 컨텍스트에 부분 응답을 포함해 재요청) |
tool_calls | 모델이 tool 호출을 요청했습니다. 응답 본문 대신 tool_calls 필드를 봅니다 | Tool Calling 흐름으로 진입합니다 |
content_filter | 공급사 안전 필터가 응답을 차단했습니다 | 사용자 입력의 어느 부분이 걸렸는지 검토합니다. 같은 프롬프트로 다시 보내면 결과도 같으니, 프롬프트나 시스템 메시지를 고친 뒤 재요청합니다 |
finish_reason이 content_filter라면 응답 본문은 비거나 짧을 수 있습니다. 클라이언트에서 이 경우를 별도로 처리합니다.
요청과 응답 예시
아래 예제는 Bash 또는 서버 runtime의 LETSUR_API_KEY 환경 변수를 읽습니다. 키 설정과 첫 실행은 AI 게이트웨이 시작하기에서 확인합니다.
cURL
(
test -n "${LETSUR_API_KEY:-}" || { echo "LETSUR_API_KEY가 필요합니다." >&2; exit 1; }
env -u LETSUR_API_KEY curl https://gw.letsur.ai/v1/chat/completions \
--header @- \
-H "Content-Type: application/json" \
-d '{
"model": "<MODEL_CODE>",
"messages": [{"role": "user", "content": "안녕"}]
}' <<EOF
Authorization: Bearer ${LETSUR_API_KEY}
EOF
)스트리밍
stream: true로 요청하면 게이트웨이가 응답을 Server-Sent Events(SSE)로 나눠서 보냅니다.
(
test -n "${LETSUR_API_KEY:-}" || { echo "LETSUR_API_KEY가 필요합니다." >&2; exit 1; }
env -u LETSUR_API_KEY curl https://gw.letsur.ai/v1/chat/completions \
--header @- \
-H "Content-Type: application/json" \
-d '{
"model": "<MODEL_CODE>",
"messages": [{"role": "user", "content": "안녕"}],
"stream": true,
"stream_options": {"include_usage": true}
}' <<EOF
Authorization: Bearer ${LETSUR_API_KEY}
EOF
)각 chunk는 다음 형태로 들어옵니다.
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"안"},"finish_reason":null}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"녕"},"finish_reason":null}]}
...
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":48,"total_tokens":60},"estimated_cost":{"amount":"0.00032400","currency":"unit","disclaimer":"Estimated based on published pricing. Actual charges may differ."}}
data: [DONE]| 시점 | chunk |
|---|---|
| 첫 chunk | delta.role: "assistant" |
| 중간 chunks | delta.content에 부분 텍스트 |
| 마지막 사용량 chunk | stream_options.include_usage: true일 때 누적 usage와 계산 가능한 경우 estimated_cost |
| 종료 신호 | data: [DONE] |
누적 usage는 stream_options.include_usage: true를 지정했을 때 마지막 사용량 chunk에 들어갑니다. 계산 가능한 호출 비용은 같은 event의 estimated_cost에서 확인하고, event를 받지 못했다면 분석의 누적 값을 확인합니다.
스트리밍 끊김 처리
스트리밍 응답은 마지막 chunk와 [DONE]을 받기 전에 연결이 종료될 수 있습니다. 클라이언트는 [DONE] 수신 여부를 기록하고, 받지 못한 출력은 부분 응답으로 취급합니다.
오류 응답을 받았다면 HTTP 상태와 type, error_ref를 기록하고 에러 코드의 기준으로 처리합니다. 연결이 종료됐다는 이유만으로 같은 요청을 즉시 반복하지 않습니다.
이미지 입력
지원 모델에서는 이미지를 입력으로 보낼 수 있습니다.
client.chat.completions.create(
model="<VISION_MODEL_CODE>",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "이 이미지를 설명해 줘"},
{"type": "image_url", "image_url": {"url": "https://.../image.png"}},
],
}],
)| 입력 형식 | 값 |
|---|---|
| URL | {"type": "image_url", "image_url": {"url": "https://..."}} |
| Base64 | {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}} |
이미지 크기와 해상도 제한은 모델마다 다릅니다. 에셋의 모델 상세에서 확인합니다.
Tool Calling
모델이 외부 함수를 호출하게 하려면 tools에 함수를 정의해 보냅니다.
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "도시의 현재 날씨를 가져옵니다.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}]
response = client.chat.completions.create(
model="<TOOL_CALLING_MODEL_CODE>",
messages=[{"role": "user", "content": "서울 날씨 알려 줘"}],
tools=tools,
tool_choice="auto",
)tool 호출 정보는 응답의 choices[0].message.tool_calls에 들어 있습니다. 직접 tool을 실행한 뒤 그 결과를 role: "tool" 메시지로 다시 보냅니다.
tool_choice | 의미 |
|---|---|
"auto" (기본) | 모델이 판단합니다 |
"none" | tool을 호출하지 않습니다 |
"required" | 반드시 tool을 호출합니다 |
{"type": "function", "function": {"name": "..."}} | 특정 tool을 강제합니다 |
tool calling 지원 여부와 요청 형식은 모델마다 다릅니다. 현재 지원 범위는 에셋에서 확인합니다.
오류와 복구
이 엔드포인트 문맥에서 자주 확인할 오류를 표시합니다. 인증과 월 사용 한도 같은 공통 에러는 에러 코드와 한도에서 확인합니다.
| 오류 | 의미와 대응 |
|---|---|
model_not_found (404) | 에셋 목록에 없는 모델입니다. 대응: 에셋에서 현재 모델 코드와 Chat Completions 지원 여부를 다시 확인합니다. |
context_length_exceeded (400) | 프롬프트와 응답이 모델 컨텍스트를 초과했습니다. 대응: 대화 이력이나 입력을 줄이고 max_tokens를 조정합니다. |
tool_format_invalid (400) | tools 스키마가 올바르지 않습니다. 대응: 함수 이름과 parameters JSON Schema를 수정합니다. |
vision_not_supported (400) | 선택한 모델이 이미지 입력을 지원하지 않습니다. 대응: 이미지 입력을 제거하거나 지원 모델을 선택합니다. |
response_format_not_supported (400) | 선택한 모델이 JSON mode 등의 응답 형식을 지원하지 않습니다. 대응: response_format을 제거하거나 지원 모델을 선택합니다. |