# OpenAI SDK

> base_url 만 바꾸면 돼요.

> 원문: https://oneport.kr/docs/guides/openai-sdk

OpenAI SDK 로 GPT 는 물론 Claude·Gemini·Grok·DeepSeek 모델까지 부를 수 있어요. 게이트웨이가 형식을 번역해요.

```python
from openai import OpenAI

client = OpenAI(
    api_key="sk-so-...",
    base_url="https://oneport.kr/v1",
)

response = client.chat.completions.create(
    model="claude-sonnet-5",       # OpenAI SDK 로 Claude 를 불러도 돼요
    messages=[{"role": "user", "content": "안녕하세요"}],
)
print(response.choices[0].message.content)
```

**TypeScript / JavaScript**

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.ONEPORT_API_KEY,
  baseURL: "https://oneport.kr/v1",
});

const stream = await client.chat.completions.create({
  model: "gpt-5.6-terra",
  messages: [{ role: "user", content: "안녕하세요" }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```

## 스트리밍

**받는 대로 흘려받기**

```python
stream = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "분수 단원 수업 계획을 써줘"}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)
```

> **Claude 도 이 코드 그대로예요**
>
> model 자리에 claude-opus-5 를 넣으셔도 같은 코드가 돌아요. 저희가 Anthropic 형식으로 번역해 넘기고 답을 다시 OpenAI 모양으로 돌려드리거든요. 도구 호출(tools)도 같아요.

**JavaScript · TypeScript 에서 스트리밍**

```typescript
const stream = await client.chat.completions.create({
  model: "claude-sonnet-5",
  messages: [{ role: "user", content: "분수 단원 수업 계획을 써줘" }],
  stream: true,
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
```

## 도구 호출

**tools 는 벤더가 달라도 같은 모양이에요**

```python
resp = client.chat.completions.create(
    model="claude-sonnet-5",
    messages=[{"role": "user", "content": "서울 날씨 알려줘"}],
    tools=[{
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "도시의 지금 날씨",
            "parameters": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
            },
        },
    }],
)
call = resp.choices[0].message.tool_calls[0]
print(call.function.name, call.function.arguments)
```

## 안 될 때

- 404 가 난다 — base_url 에 /v1 이 빠졌는지 보세요. OpenAI SDK 는 /v1 이 필요해요(Anthropic SDK 는 반대로 붙이면 안 돼요).
- 401 이 난다 — 키가 폐기됐거나 오타예요. 대시보드에서 키 상태를 보시고 값 앞뒤 공백도 확인해주세요.
- 402 가 난다 — 잔액이 이 요청의 예상 최대 금액보다 적어요. 부르기 전에 나오니 요금은 안 붙었어요. max_tokens 를 줄이시면 통과하기도 해요.
- 403 이 난다 — 클로드·GPT 팩 크레딧으로 제미나이를 부른 경우예요. 오류 문장의 모델 이름으로 바꾸시면 돼요.
- 429 가 난다 — 그 키의 이번 달 한도예요. 분당 제한은 저희가 안 걸어요.
- temperature 때문에 400 이 난다 — Claude 5 세대로 갈 때는 저희가 빼고 넘겨서 이 문으로는 안 나요. /v1/messages 로 직접 부르실 때만 나요.

## 원래대로 되돌리기

base_url 한 줄을 지우시면 OpenAI 직접 연결로 돌아가요. 코드에 남는 우리 흔적이 그 줄 하나뿐이라 언제든 되돌리실 수 있어요.

