OpenAI 互換チャット
POST /v1/chat/completions と GET /v1/models は、ベース URL と API キーを変更して OpenAI Python/JavaScript SDK から利用できます。対象はテキストの 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)