본문으로 건너뛰기

Chat Completions

지원 모델에 대화를 보내고 OpenAI 호환 응답을 받으세요.

메시지 배열, 스트리밍, 도구 호출을 OpenAI 호환 형식으로 다룹니다.

POSThttps://gw.letsur.ai/v1/chat/completions
AUTHAuthorization: Bearer <API_KEY>

요청 필드

필드타입요구 여부기본값설명
modelstring필수모델 코드 (에셋)
messagesarray필수{role, content} 객체의 배열
temperaturenumber선택10 ~ 2
top_pnumber선택1nucleus sampling
max_tokensinteger선택모델별응답 최대 토큰
streamboolean선택falseServer-Sent Events 스트리밍
stream_optionsobject선택include_usage: true로 마지막 사용량 요약을 요청합니다
stopstring | array선택응답 중단 시퀀스
ninteger선택1응답 개수 (대부분 1)
toolsarray선택Tool calling 정의
tool_choicestring | object선택autoTool 선택 정책
response_formatobject선택JSON mode 등

모델별 지원 파라미터

이미지 입력, tool calling, JSON mode, streaming의 지원 여부와 세부 제한은 모델마다 다릅니다.

정확한 지원 여부는 에셋의 모델 상세에서 확인합니다. 지원하지 않는 파라미터를 포함한 요청은 실패할 수 있습니다.

messages 배열

role의미
system시스템 프롬프트 (모델 행동 지정)
user사용자 입력
assistant모델의 이전 응답 (대화 이어가기)
tooltool 호출 결과 (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_reasonstop / length / tool_calls / content_filter (finish_reason 별 의미)
estimated_cost비스트리밍 응답 최상위의 호출별 비용 객체입니다. 이름에는 estimated가 남아 있지만 과금 기록에 사용한 같은 비용 값을 반환합니다 (요금)

finish_reason

응답 종료 이유를 나타냅니다. 같은 200 OK라도 값에 따라 의미가 다릅니다.

의미대응
stop모델이 자연스럽게 응답을 끝냈습니다정상입니다. 그대로 사용합니다
lengthmax_tokens 또는 모델 컨텍스트 한도에 걸려 잘렸습니다max_tokens을 키우거나, 같은 프롬프트로 이어 받습니다 (대화 컨텍스트에 부분 응답을 포함해 재요청)
tool_calls모델이 tool 호출을 요청했습니다. 응답 본문 대신 tool_calls 필드를 봅니다Tool Calling 흐름으로 진입합니다
content_filter공급사 안전 필터가 응답을 차단했습니다사용자 입력의 어느 부분이 걸렸는지 검토합니다. 같은 프롬프트로 다시 보내면 결과도 같으니, 프롬프트나 시스템 메시지를 고친 뒤 재요청합니다

finish_reasoncontent_filter라면 응답 본문은 비거나 짧을 수 있습니다. 클라이언트에서 이 경우를 별도로 처리합니다.

요청과 응답 예시

아래 예제는 Bash 또는 서버 runtime의 LETSUR_API_KEY 환경 변수를 읽습니다. 키 설정과 첫 실행은 AI 게이트웨이 시작하기에서 확인합니다.

( 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
첫 chunkdelta.role: "assistant"
중간 chunksdelta.content에 부분 텍스트
마지막 사용량 chunkstream_options.include_usage: true일 때 누적 usage와 계산 가능한 경우 estimated_cost
종료 신호data: [DONE]

누적 usagestream_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을 제거하거나 지원 모델을 선택합니다.
마지막 업데이트