> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yourouter.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Chat Completions

> OpenAI 호환 API로 OpenAI, Anthropic, Google 등 주요 대화 모델을 호출합니다.

YouRouter에서 채팅 모델을 사용하는 방법은 크게 두 가지입니다.

1. **OpenAI 호환 API**: 대부분의 경우에 적합하며, 동일한 인터페이스로 여러 모델을 호출합니다.
2. **제공업체 네이티브 API**: 통합 API에 노출되지 않은 상위 제공업체 전용 기능이 필요한 고급 시나리오에 적합합니다.

제공업체와 모델 선택에 대한 자세한 내용은 [라우팅 가이드](/ko/guides/router)를 참고하세요.

## OpenAI 호환 API

YouRouter를 사용하는 가장 단순하고 유연한 방법입니다. 익숙한 OpenAI SDK를 그대로 사용하면서 코드 변경을 최소화해 모델과 제공업체를 전환할 수 있습니다.

### 기본 사용법

아래 예시는 기본 chat completion 요청을 보내는 방법을 보여 줍니다. `model`과 `vendor` 요청 헤더를 바꿔 다른 모델과 상위 제공업체를 지정할 수 있습니다.

<CodeGroup>
  ```python Python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["YOUROUTER_API_KEY"],
      base_url="https://api.yourouter.ai/v1"
  )

  response = client.chat.completions.create(
      model="gpt-4o",
      messages=[
          {"role": "system", "content": "You are a helpful assistant."},
          {"role": "user", "content": "What is the capital of France?"}
      ],
      extra_headers={"vendor": "openai"}
  )

  print(response.choices[0].message.content)
  ```

  ```javascript Node.js theme={null}
  import OpenAI from 'openai';

  const openai = new OpenAI({
    apiKey: process.env.YOUROUTER_API_KEY,
    baseURL: 'https://api.yourouter.ai/v1',
  });

  const completion = await openai.chat.completions.create({
    messages: [
      { role: 'system', content: 'You are a helpful assistant.' },
      { role: 'user', content: 'What is the capital of France?' }
    ],
    model: 'claude-3-5-sonnet-20240620',
    extraHeaders: { vendor: 'anthropic' }
  });

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

  ```bash cURL theme={null}
  curl https://api.yourouter.ai/v1/chat/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $YOUROUTER_API_KEY" \
    -H "vendor: google" \
    -d '{
      "model": "gemini-1.5-pro-latest",
      "messages": [{"role": "user", "content": "What is the capital of France?"}]
    }'
  ```
</CodeGroup>

### 고급 기능

#### 다중 턴 대화

연속 대화를 유지하려면 전체 대화 기록을 `messages` 배열에 넣으면 됩니다.

<CodeGroup>
  ```python Python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["YOUROUTER_API_KEY"],
      base_url="https://api.yourouter.ai/v1"
  )

  messages = [
      {"role": "system", "content": "You are a witty assistant that tells jokes."},
      {"role": "user", "content": "Tell me a joke about computers."},
      {"role": "assistant", "content": "Why did the computer keep sneezing? It had a virus!"},
      {"role": "user", "content": "That was a good one. Tell me another."}
  ]

  response = client.chat.completions.create(
      model="gpt-4o",
      messages=messages
  )

  print(response.choices[0].message.content)
  ```
</CodeGroup>

#### 스트리밍 응답

챗봇 등 실시간 상호작용에서는 스트리밍으로 생성과 동시에 응답을 받을 수 있습니다. 요청에 `stream=True`를 전달하세요.

<CodeGroup>
  ```python Python theme={null}
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["YOUROUTER_API_KEY"],
      base_url="https://api.yourouter.ai/v1"
  )

  stream = client.chat.completions.create(
      model="claude-3-haiku-20240307",
      messages=[{"role": "user", "content": "Write a short poem about the ocean."}],
      stream=True,
      extra_headers={"vendor": "anthropic"}
  )

  for chunk in stream:
      if chunk.choices[0].delta.content is not None:
          print(chunk.choices[0].delta.content, end="")
  ```
</CodeGroup>

#### 함수 호출 / 도구 호출

모델이 도구나 함수를 호출해 외부 시스템과 상호작용하도록 할 수 있습니다. 일반적으로 다음 단계를 거칩니다.

1. 도구 정의가 포함된 요청을 보냅니다.
2. 모델이 호출하려는 도구를 반환합니다.
3. 코드에서 실제로 도구를 실행합니다.
4. 실행 결과를 모델에 다시 보내 최종 자연어 응답을 생성합니다.

<CodeGroup>
  ```python Python theme={null}
  import json
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["YOUROUTER_API_KEY"],
      base_url="https://api.yourouter.ai/v1"
  )

  def get_current_weather(location, unit="celsius"):
      """Get the current weather in a given location"""
      if "boston" in location.lower():
          return json.dumps({"location": "Boston", "temperature": "10", "unit": unit})
      else:
          return json.dumps({"location": location, "temperature": "unknown"})

  tools = [
      {
          "type": "function",
          "function": {
              "name": "get_current_weather",
              "description": "Get the current weather in a given location",
              "parameters": {
                  "type": "object",
                  "properties": {
                      "location": {
                          "type": "string",
                          "description": "The city and state, e.g. San Francisco, CA"
                      },
                      "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
                  },
                  "required": ["location"]
              }
          }
      }
  ]

  messages = [{"role": "user", "content": "What's the weather like in Boston, MA?"}]

  response = client.chat.completions.create(
      model="gpt-4o",
      messages=messages,
      tools=tools,
      tool_choice="auto"
  )

  response_message = response.choices[0].message
  tool_calls = response_message.tool_calls

  if tool_calls:
      available_functions = {
          "get_current_weather": get_current_weather,
      }
      messages.append(response_message)

      for tool_call in tool_calls:
          function_name = tool_call.function.name
          function_to_call = available_functions[function_name]
          function_args = json.loads(tool_call.function.arguments)

          function_response = function_to_call(
              location=function_args.get("location"),
              unit=function_args.get("unit"),
          )

          messages.append(
              {
                  "tool_call_id": tool_call.id,
                  "role": "tool",
                  "name": function_name,
                  "content": function_response,
              }
          )

      second_response = client.chat.completions.create(
          model="gpt-4o",
          messages=messages,
      )

      final_response = second_response.choices[0].message.content
      print(final_response)
  ```
</CodeGroup>

#### Vision(멀티모달 완성)

많은 모델이 멀티모달 입력을 지원하며 요청에 이미지를 직접 첨부할 수 있습니다. 이미지 설명, 분석, 시각 질의응답 등에 적합합니다. `gpt-4o`, `claude-3-5-sonnet-20240620`, `gemini-1.5-pro-latest` 등이 시각 기능을 지원합니다.

<CodeGroup>
  ```python Python theme={null}
  import base64
  import os
  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["YOUROUTER_API_KEY"],
      base_url="https://api.yourouter.ai/v1"
  )

  def encode_image(image_path):
    with open(image_path, "rb") as image_file:
      return base64.b64encode(image_file.read()).decode('utf-8')

  image_path = "image.jpg"
  base64_image = encode_image(image_path)

  response = client.chat.completions.create(
      model="claude-3-5-sonnet-20240620",
      messages=[
          {
              "role": "user",
              "content": [
                  {"type": "text", "text": "What’s in this image?"},
                  {
                      "type": "image_url",
                      "image_url": {
                          "url": f"data:image/jpeg;base64,{base64_image}"
                      }
                  }
              ]
          }
      ],
      max_tokens=300,
      extra_headers={"vendor": "anthropic"}
  )

  print(response.choices[0].message.content)
  ```
</CodeGroup>

### 매개변수

| 매개변수                | 타입               | 설명                                  | 기본값     |
| ------------------- | ---------------- | ----------------------------------- | ------- |
| `model`             | string           | 사용할 모델 ID.                          | 필수      |
| `messages`          | array            | 현재까지의 대화 메시지 배열.                    | 필수      |
| `max_tokens`        | integer          | 생성에 허용되는 최대 토큰 수.                   | `null`  |
| `temperature`       | number           | 샘플링 온도, 보통 0\~2.                    | `1`     |
| `top_p`             | number           | nucleus sampling 등 다른 샘플링 제어.       | `1`     |
| `n`                 | integer          | 입력 메시지당 생성할 completion 개수.          | `1`     |
| `stream`            | boolean          | true이면 ChatGPT처럼 증분 메시지로 반환.        | `false` |
| `stop`              | string or array  | 최대 4개의 중지 시퀀스, 일치 시 생성 중단.          | `null`  |
| `presence_penalty`  | number           | 토큰 출현 여부에 따라 새 토큰 확률 조정.            | `0`     |
| `frequency_penalty` | number           | 토큰 빈도에 따라 새 토큰 확률 조정.               | `0`     |
| `logit_bias`        | map              | 지정 토큰의 출현 확률 조정.                    | `null`  |
| `user`              | string           | 최종 사용자를 나타내는 고유 ID, 모니터링·오용 탐지에 사용. | `null`  |
| `tool_choice`       | string or object | 도구 호출 여부 및 방식 제어.                   | `none`  |
| `tools`             | array            | 모델이 호출할 수 있는 도구 목록.                 | `null`  |

***

## 제공업체 네이티브 API

고급 시나리오에서 OpenAI 호환 통합 API에 노출되지 않은 제공업체 전용 필드나 기능이 필요하면 해당 제공업체의 네이티브 인터페이스를 직접 호출할 수 있습니다. **이 경우 `vendor` 요청 헤더를 반드시 포함해야 합니다.**

<Note>
  YouRouter는 전체 요청 본문과 `Authorization`을 제외한 모든 요청 헤더를 상위 제공업체로 그대로 전달합니다. 자세한 내용은 [요청 전달](/ko/features/request-forwarding)을 참고하세요.
</Note>

### Gemini (Google)

#### Generate Content

**Endpoint:** `POST /v1/projects/cognition/locations/us/publishers/google/models/{model}:generateContent`

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests
  import json

  url = "https://api.yourouter.ai/v1/projects/cognition/locations/us/publishers/google/models/gemini-1.5-pro-latest:generateContent"

  headers = {
      "Authorization": f"Bearer {os.environ['YOUROUTER_API_KEY']}",
      "Content-Type": "application/json",
      "vendor": "google"
  }

  data = {
      "contents": [{
          "parts": [{"text": "Write a short story about a time-traveling historian."}]
      }]
  }

  response = requests.post(url, headers=headers, json=data)

  print(json.dumps(response.json(), indent=2))
  ```
</CodeGroup>

#### Safety Settings

요청에 `safetySettings`를 포함해 콘텐츠 안전 임계값을 설정할 수 있습니다. 전체 카테고리와 임계값 목록은 공식 [Google AI 문서](https://ai.google.dev/docs/safety_setting_gemini)를 참고하세요.

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests
  import json

  url = "https://api.yourouter.ai/v1/projects/cognition/locations/us/publishers/google/models/gemini-pro:generateContent"

  headers = {
      "Authorization": f"Bearer {os.environ['YOUROUTER_API_KEY']}",
      "Content-Type": "application/json",
      "vendor": "google"
  }

  data = {
      "contents": [{"parts": [{"text": "Tell me a potentially controversial joke."}]}],
      "safetySettings": [
          {
              "category": "HARM_CATEGORY_HATE_SPEECH",
              "threshold": "BLOCK_LOW_AND_ABOVE"
          },
          {
              "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
              "threshold": "BLOCK_MEDIUM_AND_ABOVE"
          }
      ]
  }

  response = requests.post(url, headers=headers, json=data)

  print(json.dumps(response.json(), indent=2))
  ```
</CodeGroup>

### Claude (Anthropic)

#### Messages API

**Endpoint:** `POST /v1/messages`

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests
  import json

  url = "https://api.yourouter.ai/v1/messages"

  headers = {
      "Authorization": f"Bearer {os.environ['YOUROUTER_API_KEY']}",
      "Content-Type": "application/json",
      "anthropic-version": "2023-06-01",
      "vendor": "anthropic"
  }

  data = {
      "model": "claude-3-5-sonnet-20240620",
      "max_tokens": 1024,
      "messages": [
          {"role": "user", "content": "Explain the concept of neural networks to a 5-year-old."}
      ]
  }

  response = requests.post(url, headers=headers, json=data)

  print(json.dumps(response.json(), indent=2))
  ```
</CodeGroup>

#### Claude 도구 호출

Claude에 도구 집합을 제공하면 사용자 요청에 따라 호출 시점을 결정합니다. 전체 흐름은 여전히 다단계 대화입니다. 코드에서 도구를 실행한 뒤 결과를 Claude에 다시 전달합니다.

아래는 전체 도구 호출 라이프사이클 예시입니다.

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests
  import json

  def get_weather(location):
      if "san francisco" in location.lower():
          return json.dumps({"location": "San Francisco", "temperature": "15°C", "forecast": "Cloudy"})
      else:
          return json.dumps({"location": location, "temperature": "unknown"})

  tools = [
      {
          "name": "get_weather",
          "description": "Get the current weather in a given location.",
          "input_schema": {
              "type": "object",
              "properties": {
                  "location": {
                      "type": "string",
                      "description": "The city and state, e.g. San Francisco, CA"
                  }
              },
              "required": ["location"]
          }
      }
  ]

  messages = [{"role": "user", "content": "What is the weather like in San Francisco?"}]

  initial_data = {
      "model": "claude-3-opus-20240229",
      "max_tokens": 1024,
      "tools": tools,
      "messages": messages
  }

  response = requests.post(
      "https://api.yourouter.ai/v1/messages",
      headers={
          "Authorization": f"Bearer {os.environ['YOUROUTER_API_KEY']}",
          "Content-Type": "application/json",
          "anthropic-version": "2023-06-01",
          "vendor": "anthropic"
      },
      json=initial_data
  )

  response_data = response.json()

  if response_data.get("stop_reason") == "tool_use":
      tool_use_block = next(
          (block for block in response_data["content"] if block.get("type") == "tool_use"), None
      )

      if tool_use_block:
          tool_name = tool_use_block["name"]
          tool_input = tool_use_block["input"]
          tool_use_id = tool_use_block["id"]

          if tool_name == "get_weather":
              tool_result = get_weather(tool_input.get("location", ""))

              messages.append({"role": "assistant", "content": response_data["content"]})
              messages.append({
                  "role": "user",
                  "content": [
                      {
                          "type": "tool_result",
                          "tool_use_id": tool_use_id,
                          "content": tool_result,
                      }
                  ],
              })

              final_data = {
                  "model": "claude-3-opus-20240229",
                  "max_tokens": 1024,
                  "tools": tools,
                  "messages": messages
              }

              final_response = requests.post(
                  "https://api.yourouter.ai/v1/messages",
                  headers={
                      "Authorization": f"Bearer {os.environ['YOUROUTER_API_KEY']}",
                      "Content-Type": "application/json",
                      "anthropic-version": "2023-06-01",
                      "vendor": "anthropic"
                  },
                  json=final_data
              ).json()

              final_text = next(
                  (block["text"] for block in final_response["content"] if block.get("type") == "text"),
                  "No final text response found."
              )
              print(final_text)
  ```
</CodeGroup>

***

## 모범 사례

* **라우팅**: 프로덕션에서는 `auto` 사용을 권장해 가용성을 높이세요. 모델 버전 고정이나 전용 기능이 필요할 때만 제공업체를 고정하세요. 자세한 내용은 [라우팅 가이드](/ko/guides/router)를 참고하세요.
* **오류 처리**: 네트워크 문제와 제공업체 장애는 언제든 발생할 수 있으므로, 특히 장시간 작업에서는 신뢰할 수 있는 오류 처리와 지수 백오프 재시도를 구현하세요.
* **스트리밍**: 사용자 대면 인터랙티브 앱은 스트리밍을 켜 실시간성과 경험을 개선하는 것이 좋습니다.
* **시스템 프롬프트**: 품질 높은 system prompt는 모델의 행동, 어조, 스타일에 큰 영향을 미치므로 지속적으로 테스트하고 다듬으세요.
* **토큰 관리**: 입력 컨텍스트와 출력 토큰 한계를 항상 염두에 두고, 응답의 `usage`로 비용과 잘림 위험을 추적하세요.
