OpenAI SDK

base_url 하나만 바꾸면 된다

MyIP OpenRouter 의 /api/v1 은 OpenAI Chat Completions 규격과 호환됩니다. 이미 OpenAI 공식 SDK 로 짜 둔 코드가 있다면 base URL 과 API 키만 바꾸면 그대로 동작합니다.

항목
Base URLhttps://openrouter.myip.co.kr/api/v1
인증Authorization: Bearer sk-mo-v1-… (SDK 가 api_key 로 붙입니다)
환경 변수MYIP_API_KEY
예제 모델google/gemma-4-26b-a4b, lgai/exaone-4.0-32b

키는 /settings/keys 에서 발급합니다. 추론용 키는 sk-mo-v1- 로 시작합니다.

Python

bash
pip install openai
export MYIP_API_KEY="sk-mo-v1-..."
python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.myip.co.kr/api/v1",
    api_key=os.environ["MYIP_API_KEY"],
    default_headers={
        # 선택 사항. 대시보드에서 앱별로 사용량을 구분할 때 씁니다.
        "HTTP-Referer": "https://example.com",
        "X-Title": "My Example App",
    },
)

completion = client.chat.completions.create(
    model="google/gemma-4-26b-a4b",
    messages=[
        {"role": "system", "content": "당신은 간결하게 답하는 도우미입니다."},
        {"role": "user", "content": "한국의 수도는?"},
    ],
    temperature=0.7,
    max_tokens=256,
)

print(completion.choices[0].message.content)
print(completion.usage)

TypeScript / JavaScript

bash
npm install openai
export MYIP_API_KEY="sk-mo-v1-..."
typescript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'https://openrouter.myip.co.kr/api/v1',
  apiKey: process.env.MYIP_API_KEY,
  defaultHeaders: {
    'HTTP-Referer': 'https://example.com',
    'X-Title': 'My Example App',
  },
});

const completion = await client.chat.completions.create({
  model: 'google/gemma-4-26b-a4b',
  messages: [
    { role: 'system', content: '당신은 간결하게 답하는 도우미입니다.' },
    { role: 'user', content: '한국의 수도는?' },
  ],
  temperature: 0.7,
  max_tokens: 256,
});

console.log(completion.choices[0]?.message.content);
console.log(completion.usage);

스트리밍

stream=True 만 켜면 됩니다. stream_options.include_usage우리가 항상 붙여서 업스트림에 보내므로 직접 지정할 필요가 없습니다.

python
stream = client.chat.completions.create(
    model="lgai/exaone-4.0-32b",
    messages=[{"role": "user", "content": "짧은 시를 하나 써 줘"}],
    stream=True,
)

cost_krw = None
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage is not None:
        # 마지막 usage 청크에 이 요청의 청구액(원)이 실려 옵니다.
        cost_krw = getattr(chunk.usage, "cost", None) or chunk.usage.model_extra.get("cost")

print(f"\n비용: {cost_krw} 원")
typescript
const stream = await client.chat.completions.create({
  model: 'lgai/exaone-4.0-32b',
  messages: [{ role: 'user', content: '짧은 시를 하나 써 줘' }],
  stream: true,
});

let costKrw: number | undefined;
for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? '');
  const usage = chunk.usage as { cost?: number } | undefined;
  if (usage?.cost !== undefined) costKrw = usage.cost;
}
console.log(`\n비용: ${costKrw} 원`);

비용 헤더 읽기

비스트리밍 응답에는 비용과 정산 후 잔액이 헤더로 옵니다. 금액 단위는 원(KRW) 입니다.

헤더
X-MyIP-Cost-KRW이 요청의 청구액 (비스트리밍만)
X-MyIP-Credit-Balance정산 후 잔액 (비스트리밍만)
X-MyIP-Currency항상 KRW
X-MyIP-Model실제로 응답한 모델 id
X-MyIP-Provider응답한 provider 표시명
X-MyIP-Generation-IdGET /api/v1/generation 조회용 id
python
raw = client.chat.completions.with_raw_response.create(
    model="google/gemma-4-26b-a4b",
    messages=[{"role": "user", "content": "안녕"}],
)

print(raw.headers["x-myip-cost-krw"], raw.headers["x-myip-currency"])
print(raw.headers["x-myip-generation-id"])

completion = raw.parse()
print(completion.choices[0].message.content)
typescript
const { data, response } = await client.chat.completions
  .create({
    model: 'google/gemma-4-26b-a4b',
    messages: [{ role: 'user', content: '안녕' }],
  })
  .withResponse();

console.log(response.headers.get('x-myip-cost-krw'));
console.log(response.headers.get('x-myip-generation-id'));
console.log(data.choices[0]?.message.content);

스트리밍에서는 헤더가 첫 바이트보다 먼저 나가므로 비용을 실을 수 없습니다. 위 usage 청크를 쓰거나, 끝난 뒤 GET /api/v1/generation?id=… 으로 조회하세요.

폴백 모델

우리 고유 확장으로 models 배열을 보내면 앞에서부터 시도합니다. OpenAI SDK 는 모르는 필드이므로 extra_body(Python) 로 넣습니다.

python
completion = client.chat.completions.create(
    model="lgai/exaone-4.0-32b",
    messages=[{"role": "user", "content": "안녕"}],
    extra_body={"models": ["lgai/exaone-4.0-32b", "google/gemma-4-26b-a4b"]},
)

자세한 내용은 모델 폴백 을 보세요.

동작하지 않는 것

OpenAI SDK 의 모든 기능이 우리 쪽에 있는 것은 아닙니다. 다음은 404 not_supported 를 돌려줍니다.

  • client.embeddings.*
  • client.images.*, client.audio.*
  • client.responses.* (Responses API)
  • client.batches.*, client.files.*

전체 목록과 응답 형식은 지원하지 않는 엔드포인트 에 있습니다.

client.chat.completions.*client.completions.*, 그리고 client.models.list() 는 정상 동작합니다.

관련 문서

마지막 수정 2026. 9. 5.