# Chat completions > POST /chat/completions 레퍼런스입니다. 요청 파라미터별 지원 상태, 응답과 스트림 청크 필드, 에러, 제한, 예제를 설명합니다. Source: https://kiln.bricksum.com/docs/ko/api-reference/chat-completions `POST https://api.bricksum.com/v1/chat/completions` 대화에 대한 모델 응답을 생성합니다. 요청과 응답은 OpenAI Chat Completions 형식을 따릅니다. 아래 각 파라미터에는 현재 게이트웨이가 그 값을 어떻게 처리하는지 표시했습니다. ## 인증 게이트웨이가 처리하는 엔드포인트의 인증 방식은 모두 같으며, [API 레퍼런스](https://kiln.bricksum.com/docs/ko/api-reference) 페이지에서 설명합니다. ## 요청 본문 | 상태 | 설명 | | --- | --- | | 지원 | 게이트웨이가 처리하거나, 공개된 실측에서 동작이 확인된 항목입니다. | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. | | 무시됨 | 200으로 수락되지만 적용되지 않습니다. 응답의 나머지는 정상입니다. | | 미지원 | 에러로 거부되거나, 설명에 적힌 모델에서 동작하지 않습니다. | ### 공통 파라미터 아래 파라미터의 정의는 [API 레퍼런스](https://kiln.bricksum.com/docs/ko/api-reference) 페이지에 한 번만 정리했습니다. 여기에는 이 엔드포인트에서 다른 점만 적었습니다. | 필드 | 타입 | 필수 | 기본값 | 상태 | 설명 | | --- | --- | --- | --- | --- | --- | | `model` | string | 필수 | | 지원 | 공통 정의와 같습니다. | | `messages` | array | 필수 | | 지원 | 배열이 비어 있거나 없으면 400(empty_array)으로 거부됩니다. 메시지는 role과 content로 이루어지며, 형태는 아래와 같습니다. | | `messages[].role (system 메시지)` | string | 필수 | | 지원 | "system"로 지정합니다. 허용 값: system | | `messages[].content (system 메시지)` | string | 필수 | | 지원 | 대화 전체에 적용할 지시문입니다. | | `messages[].role (user 메시지)` | string | 필수 | | 지원 | "user"로 지정합니다. 허용 값: user | | `messages[].content (user 메시지)` | string \| array | 필수 | | 지원 | 텍스트 또는 content 파트 배열입니다. 게이트웨이는 파트 배열을 변경 없이 전달합니다. 이미지 파트(image_url)는 이미지 입력을 받는 모델에서만 동작합니다. 모델 페이지를 확인하세요. | | `messages[].role (assistant 메시지)` | string | 필수 | | 지원 | "assistant"로 지정합니다. 허용 값: assistant | | `messages[].content (assistant 메시지)` | string \| null | | | 지원 | 이전 모델 응답입니다. 응답이 툴 호출이었다면 null일 수 있습니다. | | `messages[].tool_calls (assistant 메시지)` | array | | | 지원 | 모델이 반환한 tool_calls 배열입니다. 대응하는 tool 메시지 앞에 변경 없이 다시 보냅니다. | | `messages[].role (tool 메시지)` | string | 필수 | | 지원 | "tool"로 지정합니다. 허용 값: tool | | `messages[].tool_call_id (tool 메시지)` | string | 필수 | | 지원 | 이 결과가 응답하는 툴 호출의 id입니다. | | `messages[].content (tool 메시지)` | string | 필수 | | 지원 | 툴을 실행한 결과입니다. 보통 JSON 문자열입니다. | | `max_tokens` | integer | | | 지원 | 보낸 값 그대로 모델 서버로 전달됩니다. 이 상한에서 생성이 멈추면(finish_reason: "length") 비스트리밍 응답의 content가 비어 있을 수 있습니다. | | `stream` | boolean | | `false` | 지원 | 게이트웨이는 문자열 "true"와 숫자 1도 true로 읽으며, 전달하기 전에 이 필드를 boolean으로 다시 씁니다. | | `tools` | array | | | 지원 | OpenAI function 정의 형식으로 보냅니다. | | `tools[].type` | string | 필수 | | 지원 | "function"으로 지정합니다. 허용 값: function | | `tools[].function.name` | string | 필수 | | 지원 | 모델이 tool_calls에서 사용하는 이름입니다. | | `tools[].function.description` | string | 필수 | | 지원 | 함수가 하는 일입니다. description이 없는 함수는 400으로 거부됩니다. | | `tools[].function.parameters` | object | | | 지원 | 함수 인자의 JSON Schema입니다. | | `tool_choice = "auto"` | string | | | 지원 | 문자열 "auto"로 보냅니다. | | `tool_choice = "required" \| {"type": "function", ...}` | string \| object | | | 미지원 | 강제 툴 선택입니다. "required" 또는 함수 이름을 지정해 보냅니다. qwen3-32b에서는 강제 툴 선택이 명확한 에러 없이 실패합니다(2026-09-26 실측). tool_choice를 "required"로 보내면 본문이 평문 "Internal Server Error"인 HTTP 500이 오고, 함수를 지정하면 arguments가 빈 200(finish_reason "stop")이 옵니다. 둘 다 4xx가 아니므로 재시도로 해결되지 않습니다. tool_choice는 "auto"만 보내세요. | ### 이 엔드포인트에만 있는 파라미터 | 필드 | 타입 | 필수 | 기본값 | 상태 | 설명 | | --- | --- | --- | --- | --- | --- | | `stream_options` | object | | | 지원 | 스트리밍 응답 옵션입니다. stream: true와 함께 보낼 때만 사용하세요. | | `stream_options.include_usage` | boolean | | `false` | 지원 | true이면 스트림 끝에 choices가 비어 있고 usage 객체에 토큰 수와 cost가 담긴 청크가 하나 더 옵니다. 게이트웨이는 토큰 계측을 위해 모든 스트리밍 요청에 이 값을 설정하며, 요청하지 않은 경우 usage 청크를 제거합니다. | | `parallel_tool_calls` | boolean | | | 미지원 | 모델 페이지에서 병렬 툴 호출이 지원으로 표시된 모델에서만 적용되며, qwen3-32b는 해당하지 않습니다. gpt-oss-120b 실측에서는 요청이 200으로 수락되고, 모델이 응답마다 툴을 최대 하나만 호출했습니다. qwen3-32b에서는 parallel_tool_calls 설정이 적용되지 않습니다. 이는 응답에 툴 호출이 하나만 온다는 뜻이 아닙니다. parallel_tool_calls: false를 보내도 한 응답에 툴 호출이 여러 건 올 수 있습니다. tool_calls의 모든 항목에 각각 tool 메시지로 답하세요. | | `reasoning_effort` | string | | | 지원 | 보낸 값 그대로 모델에 전달됩니다. gpt-oss-120b는 low, medium, high를 받으며, 다른 모델이 이 값을 따르는지는 공개되지 않았습니다. 값이 높을수록 reasoning 토큰을 더 쓰므로 지연 시간과 출력 토큰이 늘어납니다. 허용 값: low, medium, high | | `temperature` | number | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. 범위: 0–2 | | `top_p` | number | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. 범위: 0–1 | | `n` | integer | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. | | `seed` | integer | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. | | `presence_penalty` | number | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. 범위: -2–2 | | `frequency_penalty` | number | | | 전달만 함 | 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않았습니다. 범위: -2–2 | | `stop` | string \| array | | | 무시됨 | 수락되지만 적용되지 않습니다. stop 문자열 이후에도 생성이 계속됩니다. | | `response_format` | object | | | 미지원 | json_object와 json_schema는 아직 동작하지 않습니다. 요청은 200으로 수락되지만 content가 비어 반환됩니다. JSON이 필요하면 프롬프트에서 JSON으로만 답하도록 지시하고, 클라이언트에서 결과를 파싱해 검증하세요. | | `ignore_eos` | boolean | | | 미지원 | gpt-oss 모델에서 true를 보내면 모델에 도달하기 전에 400(unsupported_parameter)으로 거부됩니다. 다른 모델에서는 모델 서버로 전달됩니다. | 여기에 없는 OpenAI chat 파라미터도 같은 방식으로 모델 서버로 전달됩니다. Kiln이 동작을 검증하지 않은 항목입니다. ## 응답 본문 | 필드 | 타입 | 설명 | | --- | --- | --- | | `id` | string | chat completion의 ID입니다. | | `object` | string | "chat.completion"입니다. | | `created` | integer | 생성 시각(Unix 초)입니다. | | `model` | string | 응답을 생성한 모델 ID입니다. | | `choices[].index` | integer | choice의 순번입니다. | | `choices[].message.role` | string | "assistant"입니다. | | `choices[].message.content` | string \| null | 생성된 텍스트입니다. finish_reason이 "length"이면 비어 있을 수 있고, 응답이 툴 호출이면 null일 수 있습니다. | | `choices[].message.tool_calls` | array | 모델이 실행을 요청한 툴 호출입니다. id, type, function.name과 JSON 문자열인 function.arguments를 담습니다. | | `choices[].finish_reason` | string | "stop", "length"(max_tokens에서 잘림), "tool_calls" 중 하나입니다. | | `usage.prompt_tokens` | integer | 입력 토큰 수입니다. | | `usage.completion_tokens` | integer | 출력 토큰 수입니다. reasoning 토큰을 포함합니다. | | `usage.total_tokens` | integer | 입력과 출력 토큰의 합계입니다. | | `usage.prompt_tokens_details.cached_tokens` | integer | 프리픽스 캐시에서 처리된 입력 토큰 수입니다. 모델 서버가 보고할 때만 포함됩니다. | | `usage.cost` | number | 이 요청으로 크레딧에서 차감되는 금액(USD)입니다. 게이트웨이가 추가합니다. | | `X-Neocloud-Generation-Id` | header | 이 요청의 usage 이벤트 ID를 담은 응답 헤더입니다. 로그와 함께 저장하세요. | ## 스트림 청크 | 필드 | 타입 | 설명 | | --- | --- | --- | | `object` | string | "chat.completion.chunk"입니다. | | `choices[].delta.content` | string | 이 청크에서 새로 생성된 텍스트입니다. | | `choices[].delta.tool_calls` | array | 툴 호출 조각입니다. function.arguments를 index별로 이어 붙이세요. | | `choices[].finish_reason` | string \| null | 마지막 content 청크 전까지 null이며, 마지막 청크에 종료 사유가 담깁니다. | | `usage` | object | stream_options.include_usage가 true일 때만 마지막 청크에 포함됩니다. 이 청크의 choices 배열은 비어 있습니다. | | `usage.cost` | number | 이 요청으로 크레딧에서 차감되는 금액(USD)입니다. 게이트웨이가 usage 청크에 추가합니다. | stream: true이면 각 data: 줄에 아래 필드를 가진 청크가 하나씩 담깁니다. keepalive 주석, data: [DONE], 연결 끊김은 [스트리밍](https://kiln.bricksum.com/docs/ko/streaming) 페이지에서 설명합니다. ## 에러 | 상태 | error.code | 원인 | 조치 | | --- | --- | --- | --- | | 400 | `empty_array` | messages가 비어 있거나 없습니다. | 메시지를 하나 이상 보내세요. | | 400 | `unsupported_parameter` | gpt-oss 모델에 ignore_eos: true를 보냈습니다. | ignore_eos를 제거하세요. | | 400 | | 모델 서버가 요청을 거부했습니다. JSON 형식 에러, 잘못된 파라미터, description이 없는 함수, 모델 페이지에 나오는 모델별 컨텍스트 길이를 넘는 컨텍스트가 원인입니다. | 요청 본문을 수정하세요. 그대로 재시도하지 마세요. | | 404 | `model_not_found` | 모델 ID가 카탈로그에 없습니다. | GET /models로 ID를 확인하세요. | | 429 | `rate_limit_exceeded` | 조직에서 이미 8개의 요청이 처리 중입니다. 레이트 리밋 헤더는 포함되지 않습니다. | 지수 백오프로 재시도하세요. | | 502 | | 모델 백엔드가 에러를 반환했거나 연결할 수 없습니다. 본문은 일반 텍스트입니다. | 지수 백오프로 재시도하세요. | | 503 | | 서비스가 점검 중이거나 사용 가능한 모델 백엔드가 없습니다. | 점검 중에는 Retry-After 시각까지 기다리세요. 그 밖에는 지수 백오프로 재시도하세요. | 401, 402, 403, 429는 요청이 이 엔드포인트에 도달하기 전에 게이트웨이가 반환합니다. 이 에러들은 [API 레퍼런스](https://kiln.bricksum.com/docs/ko/api-reference) 페이지에 한 번만 정리했습니다. 메시지 문구가 아니라 HTTP 상태와 error.code로 분기하세요. error.code 칸이 비어 있으면 본문에 code가 없다는 뜻입니다. 전체 상태 코드는 [에러](https://kiln.bricksum.com/docs/ko/errors) 페이지에 있습니다. ## 제한 컨텍스트 길이, 요청 본문 크기, 타임아웃, 조직별 레이트 리밋도 여기에 그대로 적용되며, [API 레퍼런스](https://kiln.bricksum.com/docs/ko/api-reference) 페이지에 한 번만 정리했습니다. 429의 헤더와 재시도 방법은 [레이트 리밋](https://kiln.bricksum.com/docs/ko/rate-limits) 페이지에 있습니다. ## 예제 ### 요청 **cURL** ```bash curl https://api.bricksum.com/v1/chat/completions \ -H "Authorization: Bearer $KILN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "qwen3-32b", "messages": [ {"role": "system", "content": "Answer briefly."}, {"role": "user", "content": "Hello!"} ], "max_tokens": 800 }' ``` **Python** ```python import os from openai import OpenAI client = OpenAI( base_url="https://api.bricksum.com/v1", api_key=os.environ["KILN_API_KEY"], ) resp = client.chat.completions.create( model="qwen3-32b", messages=[ {"role": "system", "content": "Answer briefly."}, {"role": "user", "content": "Hello!"}, ], max_tokens=800, ) print(resp.choices[0].message.content) print(resp.usage) ``` **JavaScript** ```javascript import OpenAI from "openai"; const client = new OpenAI({ baseURL: "https://api.bricksum.com/v1", apiKey: process.env.KILN_API_KEY, }); const resp = await client.chat.completions.create({ model: "qwen3-32b", messages: [ { role: "system", content: "Answer briefly." }, { role: "user", content: "Hello!" }, ], max_tokens: 800, }); console.log(resp.choices[0].message.content); console.log(resp.usage); ``` ### 응답 **200 OK** ```json { "id": "chatcmpl-...", "object": "chat.completion", "created": 1710000000, "model": "qwen3-32b", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "Hello! How can I help?" }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 9, "completion_tokens": 12, "total_tokens": 21, "cost": 0.000001155 } } ``` **text/event-stream** ```text data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1710000000,"model":"qwen3-32b","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]} data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1710000000,"model":"qwen3-32b","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":1710000000,"model":"qwen3-32b","choices":[],"usage":{"prompt_tokens":9,"completion_tokens":12,"total_tokens":21,"cost":0.000001155}} data: [DONE] ``` **400 Bad Request** ```json { "error": { "message": "Invalid 'messages': the array must contain at least one message.", "type": "invalid_request_error", "param": "messages", "code": "empty_array" } } ```