OpenAI 호환 채팅
베이스 URL과 API 키를 변경하면 OpenAI Python 또는 JavaScript SDK로 POST /v1/chat/completions와 GET /v1/models를 사용할 수 있습니다. 텍스트 Chat Completions 형식만 호환하며 OpenAI의 모든 기능을 제공하지는 않습니다.
인증과 모델
기존 콘솔 API 키를 Authorization: Bearer sk-your-key로 전송합니다. 목록에는 사용 가능한 텍스트 모델의 공개 ID가 표시됩니다. 표시 이름 대신 반환된 id를 사용하세요. 요금과 음성 ID는 /v1/chat/catalog에서 확인할 수 있습니다.
curl https://api.coldstart.win/v1/models -H "Authorization: Bearer sk-your-key"{"object":"list","data":[{"id":"chat-standard","object":"model","created":0,"owned_by":"girllab"}]}요청과 대화 기록
매 요청마다 순서대로 전체 messages 배열을 전송합니다. 지원 역할은 system, developer, user, assistant, tool이며 내용은 문자열 또는 { "type": "text", "text": "..." } 배열입니다. 서버 기록이나 기본 페르소나를 추가하지 않습니다. 매 턴 필요한 시스템 지침과 관련 기록을 포함하세요.
curl https://api.coldstart.win/v1/chat/completions \
-H "Authorization: Bearer sk-your-key" \
-H "Content-Type: application/json" \
-d '{"model":"chat-standard","messages":[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"Hello!"}],"max_tokens":256}'{
"id": "chatcmpl_example",
"object": "chat.completion",
"created": 1792540800,
"model": "chat-standard",
"choices": [{"index": 0, "message": {"role": "assistant", "content": "Hello!", "refusal": null}, "logprobs": null, "finish_reason": "stop"}],
"usage": {"prompt_tokens": 12, "completion_tokens": 3, "total_tokens": 15}
}지원 매개변수
model과 비어 있지 않은 messages가 필수입니다. 선택 항목: stream(기본 false), temperature(0–2), top_p(0–1), max_tokens 또는 max_completion_tokens(정수 1–8192, 동시 사용 불가), stop(문자열 또는 1–4개 문자열), presence_penalty와 frequency_penalty(−2–2), seed(안전한 정수), n(1만 지원). 생략하면 서비스 기본값을 사용하며 샘플링 효과는 모델에 따라 다릅니다. stream_options: {"include_usage": true}는 stream: true일 때만 유효합니다. 선택 항목의 null은 기본값을 뜻합니다. JSON 본문 한도는 15 MiB이며 문맥 토큰 한도는 모델에 따라 다릅니다.
스트리밍과 사용량
SSE는 data:만 사용하며 사용자 정의 event: delta나 event: completed를 사용하지 않습니다. choices[0].delta.content를 읽고 마지막 finish_reason(stop, length, content_filter, tool_calls)과 data: [DONE]을 확인하세요. include_usage: true이면 종료 전에 choices: []와 최종 usage 청크가 추가되며 나머지 청크는 usage: null입니다. 설정하지 않으면 usage가 생략됩니다. 모든 청크는 동일한 로컬 ID, 생성 시각, 공개 모델 ID를 사용합니다.
{"model":"chat-standard","messages":[{"role":"user","content":"Hello!"}],"stream":true,"stream_options":{"include_usage":true}}data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{"content":"Hello!"},"logprobs":null,"finish_reason":null}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}],"usage":null}
data: {"id":"chatcmpl_example","object":"chat.completion.chunk","created":1792540800,"model":"chat-standard","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":3,"total_tokens":15}}
data: [DONE]오류와 지원 범위
오류 형식은 { "error": { "message": "...", "type": "invalid_request_error", "param": null, "code": "invalid_request" } }입니다. HTTP 400은 잘못되거나 지원하지 않는 입력, 401은 잘못된 키, 402는 잔액 부족, 429는 호출 제한, 503은 일시적 장애, 504는 시간 초과입니다. 오류 세부 정보는 비식별 처리됩니다. 스트림 시작 전에는 HTTP JSON 오류를 반환하고, 시작 후에는 data: {"error": ...}로 종료하며 성공 표시를 보내지 않습니다. 부분 응답을 완료로 처리하지 마세요. 첫 텍스트 제한은 90초, 텍스트 간 유휴 제한은 60초(증분마다 갱신), 비스트리밍 제한은 60초입니다.
미지원: 이미지·오디오 입력, 호스팅 검색·코드 실행, 기존 functions / function_call, 사용자 정의 도구 유형, logprobs, 복수 후보, store, Responses API 및 미기재 매개변수. 무시하지 않고 거부합니다. 음성은 /v1/chat/speech를 사용하세요.
과금과 SDK 예제
기존 잔액과 공개 요금, 입력/출력 토큰 과금이 적용됩니다. 생성 전에 크레딧을 예약하고 성공 후 실제 사용량으로 정산하며 잔여 예약액은 해제합니다. 생성 실패, 잘못된 사용량 또는 정산 전 연결 종료 시 예약액이 해제됩니다. 정산 후 취소는 청구를 취소하지 않습니다. 호출은 사용 기록과 관리자 대시보드에 표시됩니다. 표준 JSON에는 usage만 포함되며 사용자 정의 billing은 없습니다. 재전송하면 다시 과금될 수 있고 멱등성은 보장하지 않습니다.
pip install openai
npm install openaiimport os
from openai import OpenAI
client = OpenAI(api_key=os.environ["KARMAN_API_KEY"], base_url="https://api.coldstart.win/v1", max_retries=0)
print([model.id for model in client.models.list().data])
model = os.environ["KARMAN_MODEL"]
messages = [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"}]
reply = client.chat.completions.create(model=model, messages=messages, max_tokens=256)
print(reply.choices[0].message.content)
stream = client.chat.completions.create(model=model, messages=messages, max_tokens=256,
stream=True, stream_options={"include_usage": True})
for chunk in stream:
if chunk.choices:
print(chunk.choices[0].delta.content or "", end="", flush=True)
if chunk.usage:
print("\n", chunk.usage)import OpenAI from "openai";
const client = new OpenAI({ apiKey: process.env.KARMAN_API_KEY, baseURL: "https://api.coldstart.win/v1", maxRetries: 0 });
const models = await client.models.list();
console.log(models.data.map(model => model.id));
const stream = await client.chat.completions.create({
model: process.env.KARMAN_MODEL,
messages: [{ role: "user", content: "Hello!" }],
stream: true,
stream_options: { include_usage: true }
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
if (chunk.usage) console.log("\n", chunk.usage);
}에이전트 도구와 구조화 출력
/v1/chat/catalog의 models[].capabilities에서 tool_calling, parallel_tool_calls, json_mode, structured_outputs를 확인하세요. 지원 여부는 모델별로 다르며 미지원 기능은 생성 전에 HTTP 400을 반환합니다. 도구는 클라이언트 애플리케이션이 실행합니다. API는 함수를 실행하거나 에이전트 기억을 저장하지 않습니다.
tools(최대 128개 함수), tool_choice(auto, none, required 또는 함수 지정), parallel_tool_calls(불리언, tools 필요)를 지원합니다. 함수에는 name, description, JSON Schema parameters, 선택적 strict가 있습니다. message.tool_calls를 읽고 content가 null이어도 assistant 메시지를 그대로 기록하세요. 각 호출마다 해당 tool_call_id를 가진 role: "tool" 결과를 추가합니다. 실패를 포함한 모든 결과를 다음 모델 호출 전에 반환하고 ID 고유성과 메시지 순서를 유지하세요.
스트리밍에서는 choices[0].delta.tool_calls를 index별로 모으고 function.arguments 조각을 이어 붙입니다. id, type, function.name도 보존하세요. finish_reason: "tool_calls"와 정상 종료를 확인한 뒤 실행하며 length 또는 오류가 발생한 출력은 실행하지 않습니다. 도구 델타도 60초 유휴 제한을 갱신하고 첫 출력 제한은 90초입니다. 함수명, 인수, 권한을 검증하고 반복 횟수를 제한하세요.
response_format은 text, json_object, json_schema를 지원합니다. 마지막 형식은 json_schema: {name, schema, strict, description?}를 사용합니다. JSON 모드에서는 프롬프트로 JSON을 명시하세요. 엄격한 schema는 모든 속성을 required로 지정하고 additionalProperties: false를 설정합니다. 선택 값은 null 허용으로 표현합니다. JSON Schema와 parallel_tool_calls: true는 함께 사용할 수 없습니다. 파싱 전에 refusal, length, 오류를 확인하세요. 구조 제약은 사실 정확성을 보장하지 않습니다. 도구 정의, 인수, 결과가 token 과금에 포함되며 모델 호출마다 별도 과금됩니다.
전체 도구 호출 루프
import os, json
from openai import OpenAI
client = OpenAI(api_key=os.environ["KARMAN_API_KEY"],
base_url="https://api.coldstart.win/v1", max_retries=0)
model = os.environ["KARMAN_MODEL"]
tools = [{"type": "function", "function": {
"name": "lookup_memory", "description": "Read a saved preference.",
"parameters": {"type": "object", "properties": {"topic": {"type": "string"}},
"required": ["topic"], "additionalProperties": False},
"strict": True
}}]
messages = [{"role": "user", "content": "What food do I like? Use my saved memory."}]
for _ in range(4):
reply = client.chat.completions.create(
model=model, messages=messages, tools=tools,
tool_choice="auto", parallel_tool_calls=False, max_tokens=512)
choice = reply.choices[0]
message = choice.message
if message.refusal or choice.finish_reason not in ("stop", "tool_calls"):
raise RuntimeError("Incomplete or refused response")
messages.append(message.model_dump(exclude_none=True))
if not message.tool_calls:
print(message.content)
break
for call in message.tool_calls:
try:
if call.function.name != "lookup_memory":
raise ValueError("Unknown function")
args = json.loads(call.function.arguments)
if not isinstance(args, dict) or set(args) != {"topic"} or not isinstance(args["topic"], str):
raise ValueError("Invalid arguments")
result = {"topic": args["topic"], "preference": "apples"}
except (ValueError, TypeError):
result = {"error": "Invalid tool request"}
messages.append({"role": "tool", "tool_call_id": call.id,
"content": json.dumps(result)})
else:
raise RuntimeError("Agent round limit reached")구조화 출력 예제
reply = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "I like apples. Extract this preference as JSON."}],
response_format={"type": "json_schema", "json_schema": {
"name": "memory", "strict": True,
"schema": {"type": "object", "properties": {"preference": {"type": "string"}},
"required": ["preference"], "additionalProperties": False}
}}, max_tokens=256)
choice = reply.choices[0]
if choice.finish_reason != "stop" or choice.message.refusal:
raise RuntimeError("Incomplete or refused response")
memory = json.loads(choice.message.content)
print(memory)