メインコンテンツへスキップ
YouRouter でチャットモデルを使う主な方法は次の 2 つです。
  1. OpenAI 互換 API:ほとんどの用途で推奨。統一インターフェースで多モデルを扱えます。
  2. プロバイダー固有 API:統一 API に無い上流固有機能が必要な上級用途向け。
モデルとプロバイダーの選び方は ルーティング を参照してください。

OpenAI 互換 API

最もシンプルで柔軟な方法です。慣れた OpenAI SDK を使いつつ、モデルや上流を最小限の変更で切り替えられます。

基本的な使い方

modelvendor を変えることで、別モデルや別上流を指定できます。
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key-here",
    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)

高度な機能

マルチターン会話

会話履歴を messages にそのまま積み上げます。
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key-here",
    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)

ストリーミング

チャット UI などでは stream=True で逐次出力します。
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key-here",
    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="")

関数呼び出し / ツール利用

ツールを使う場合は多段になります。
  1. ツール定義を付けてリクエスト
  2. モデルがツール呼び出しを返す
  3. アプリ側でツールを実行
  4. 実行結果をモデルへ返し、最終回答を生成
import json
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key-here",
    base_url="https://api.yourouter.ai/v1"
)

def get_current_weather(location, unit="celsius"):
    if "boston" in location.lower():
        return json.dumps({"location": "Boston", "temperature": "10", "unit": unit})
    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,
    )

    print(second_response.choices[0].message.content)

ビジョン(マルチモーダル)

多くのモデルは画像入力に対応します。gpt-4oclaude-3-5-sonnet-20240620gemini-1.5-pro-latest などが例です。
import base64
from openai import OpenAI

client = OpenAI(
    api_key="your-api-key-here",
    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)

パラメータ(代表)

パラメータ説明既定値
modelstringモデル ID必須
messagesarray会話メッセージ配列必須
max_tokensinteger生成上限null
temperaturenumberサンプリング温度1
top_pnumbernucleus sampling1
ninteger生成候補数1
streambooleanストリーミングfalse
stopstring or array停止シーケンスnull
presence_penaltynumberpresence ペナルティ0
frequency_penaltynumberfrequency ペナルティ0
logit_biasmapトークン確率の調整null
userstringエンドユーザー識別子null
tool_choicestring or objectツール利用の制御none
toolsarrayツール定義null

プロバイダー固有 API

統一 API に無いパラメータや挙動が必要な場合、上流のネイティブエンドポイントへ直接リクエストできます。この場合は vendor ヘッダーが必須です。
YouRouter は Authorization 以外のヘッダーとリクエストボディを可能な限りそのまま上流へ転送します。詳細は リクエスト転送 を参照してください。

Gemini(Google)

Generate Content

Endpoint: POST /v1/projects/cognition/locations/us/publishers/google/models/{model}:generateContent
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": "Bearer YOUR_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))

Safety Settings

Google AI の公式ドキュメントに沿って safetySettings を設定できます(カテゴリと閾値の一覧は公式参照)。
import requests
import json

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

headers = {
    "Authorization": "Bearer YOUR_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))

Claude(Anthropic)

Messages API

Endpoint: POST /v1/messages
import requests
import json

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

headers = {
    "Authorization": "Bearer YOUR_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))

Claude のツール利用

Claude のツール利用は複数ステップになります。以下はライフサイクル例です。
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"})
    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": "Bearer YOUR_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": "Bearer YOUR_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)

ベストプラクティス

  • ルーティング:本番はまず auto を推奨。特定バージョンや固有機能が必要なときだけ固定します(ルーティング)。
  • エラー処理:ネットワーク断や上流障害に備え、指数バックオフ付きの再試行を実装します。
  • UX:ユーザー向け UI ではストリーミングを検討します。
  • システムプロンプト:品質に直結するため継続的に改善します。
  • トークン管理:入力コンテキストと出力上限に注意し、レスポンスの usage でコストと切り詰めを監視します。