やりたいこと
これまでOpenAIを使っていたのを、Geminiも使えるようにしたい!!!
背景
先日Googleが、Gemini3をリリースしました。
かなりクオリティが上がったと話題になっていますね。
かくいう私も、毎日Gemini3さんとおしゃべりしています。
そのクオリティゆえか、OpenAIのサム・アルトマンCEOは非常事態を宣言したとか。
これまで、自分が作ったツールでは、OpenAIのAPIを使って、
いくつかのモデルから対話相手を選ぶ機能があるのですが、これをGeminiのモデルも選べるようにすることとなりました。
環境
- javascript(typescript)
- OpenAI SDK使用(https://github.com/openai/openai-node)
- VertexAIでサービスアカウント(キー)を発行
方針
Geminiは、OpenAI SDKから呼べます。(←!?)
以上。
リクエストの形式などはそのままで基本OK!
対応方法
概要
もともとOpenAIに対してリクエストは下記のように行えました。
const client = new OpenAI();
const response = await client.responses.create({
model: "gpt-5-nano",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{
role: "user",
content: "Explain to me how AI works",
},
],
});
これを、こう!
const openai = new OpenAI({
apiKey: "GEMINI_API_KEY",
baseURL: "https://generativelanguage.googleapis.com/v1beta/openai/"
});
const response = await openai.chat.completions.create({
model: "gemini-2.0-flash",
messages: [
{ role: "system", content: "You are a helpful assistant." },
{
role: "user",
content: "Explain to me how AI works",
},
],
});
見ての通り、apiKeyとbaseUrlを指定すれば、GeminiのModelにもchat.completions.createが行えるようになります。
ただし、今回は、VertexAIで発行したサービスアカウントを使ってGeminiAPIを使います。
VertexAIの場合も同様に互換性がありますが、指定する内容が少し違うため注意が必要です。
違いとしては、下記があります。
| gemini | Vertex AI | |
|---|---|---|
| api key | geminiのAPIキー | Google Cloud Authで取得したアクセストークン |
| base url | https://ai.google.dev/gemini-api/docs/openai | https://aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/endpoints/openapi |
| model名の指定(例) | gemini-2.5-flash | google/gemini-2.5-flash(Vertex AIの場合は、google/をつける) |
| 認証 | キーがあればOK | Google Cloud Auth認証が必要 |
| ドキュメント | https://ai.google.dev/gemini-api/docs/openai | https://docs.cloud.google.com/vertex-ai/generative-ai/docs/start/openai |
Googleの認証
VertexAI経由でGeminiを使う場合は、Google Cloud Auth認証を通す必要があります。
そのためにこれを使います。
npm install google-auth-library
その上で、下記のようにJWTでの認証をしています。
const client = new JWT({
email: process.env.GCP_OAUTH_CLIENT_EMAIL,
key: process.env.GCP_OAUTH_PRIVATE_KEY?.replace(/¥n/g, '\n'),
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
});
const apiKey = (await client.getAccessToken()).token;
下記のようにGoogleAuthで認証をするのが最初に見つかりますが、
これだと、Application Default Credentialsを使って、環境変数からキーを読み込まずに済みます。(環境変数から取得したキーをcredentialsとして渡すのは非推奨になっています。)
const auth = new GoogleAuth({
scopes: 'https://www.googleapis.com/auth/cloud-platform'
});
今回はAWSにデプロイするため、それだと都合が悪いので、上述のようにJWTで行いました。
実際の処理
あとは、よしなにModelがOpenAIかGeminiかを判定して、apiKeyとbaseUrlを分岐してあげればOK。
//modelを引数にopenAIなのか、geminiなのかを判定する関数
const modelProvider = getProviderFromModel(model);
let apiKey: string | null | undefined;
let baseUrl: string | undefined;
if (modelProvider === ModelProvider.OpenAI) {
apiKey = process.env.OPENAI_API_KEY;
} else if (modelProvider === ModelProvider.Gemini) {
const client = new JWT({
email: process.env.GCP_OAUTH_CLIENT_EMAIL,
key: process.env.GCP_OAUTH_PRIVATE_KEY?.replace(/¥n/g, '\n'),
scopes: ['https://www.googleapis.com/auth/cloud-platform'],
});
apiKey = (await client.getAccessToken()).token;
//previewモデルなどはglobalしか使えなかったりする
const location = getLocationFromModel(model);
baseUrl = `https://aiplatform.googleapis.com/v1/projects/${process.env.GCP_PROJECT_ID}/locations/${location}/endpoints/openapi`;
}
// トークン数の上限を超えないように切り詰める(モデルによって上限が異なるため、それに合わせた切り詰めをしている)
const truncatedMessages = truncateMessages(model, messages);
// OpenAIの時と基本同じパラメータでOK
// モデルによっては指定できないパラメータがある点に注意(後述)
// modelはVertexAIの場合、google/gemini-2.5-flashのように、'google/'が必要な点に注意
const params = createChatCompletionParams({ model, truncatedMessages});
// OpenAIでもGeminiでも同様
const completion = (await client.chat.completions.create({
...params,
}));
注意事項・補足
モデルによって対応していないパラメータがありそう
パラメータはそのままでOKと書きましたが、モデルによっては対応していないケースがあります。
例えば、下記のように、画像をインプットする場合です。
const messages = [
{
"role": "user",
"content": [
{
"type": "text",
"text": "What is in this image?",
},
{
"type": "image_url",
"image_url": {
"url": `data:image/jpeg;base64,${base64Image}`
},
},
],
}
];
この形式において、OpenAIの場合、detailとして画像の解像度を指定できました。
(少なくとも、gpt40やgpt5など最近のモデルでは)
{
"type": "image_url",
"image_url": {
"url": `data:image/jpeg;base64,${base64Image}`,
"detail":'high'
},
},
しかし、これをこのままGeminiの2.5flashや2.5proに上述のやり方でリクエストを送ると、エラーになります。
3pro previewならエラーにならずできたので、モデルによって対応可否が一定ありそうです。
なので、モデルによっては、detailをundefinedにする必要がありました。
もしかしたら、同様のことは他のパラメータ×モデルの組み合わせでもあるかもしれません。
とはいえ、これはOpenAIのSDKでGeminiを使うから、というよりは、複数のモデルを併用する際には、起こり得ることではあります。
(OpenAIだけの場合でも、モデルによって対応していないパラメータがあったりするので)
reasoning_effortの互換
OpenAIでは、reasoning_effortというパラメータを指定できます。
ざっくりいうと、どれくらい深く考えるか、です。
Geminiの場合は、thinking_level(gemini3)、thinking_badget(gemini2.5)と呼ぶようです。
上述のようにOpenAI SDKでGeminiを利用する際は、
reasoning_effortの指定のままで行うことができます。
その際は、下記の表のように、対応するthinking_level,thinking_badgetとして扱ってくれるようです。

出典:https://ai.google.dev/gemini-api/docs/openai より
thinking_level,thinking_badgetで指定したい場合は、下記のように指定することも可能です。
const response = await openai.chat.completions.create({
model: "gemini-2.5-flash",
messages: [{role: "user", content: "Explain to me how AI works",}],
extra_body: {
"google": {
"thinking_config": {
"thinking_budget": "low",
"include_thoughts": true
}
}
}
});
まとめ
今回はOpenAIのSDKでGeminiのAPIを使う方法をまとめました。
GeminiのAPIをフル活用するのであれば、上述のようにreasoning_effortで指定するより、thinking_levelで指定した方が細かく指定可能です。
また、今回は使っていないので確認していないですが、音声のインプットや画像生成、embeddingなどを行う際も互換性はあるようですが、reasoning_effort同様、限界はあるかもしれません。
とはいえ、モデルの違いを試すには便利で良いなと感じました。
ところで、
なんでOpenAIのSDKなのに、ライバルのGeminiのAPIが使えてしまうのだろう・・・
と私は疑問に感じましたが、それをGeminiに聞いたところ下記のように返ってきました。
OpenAIのSDKでGeminiが動く理由は、以下の力学によるものです。
- ライバルの追随: Googleなどが、開発者を取り込むためにOpenAIの仕様に合わせた(OpenAI互換エンドポイントを作った)。
- 標準化の勝利: OpenAIの書き方が、事実上の「AI開発の世界標準」になった。
- 流動性の確保: 簡単に乗り換えられる環境を作ることで、逆に「いつでもOpenAIに戻れる」安心感を与えている。
なるほど。
後発の戦略として、勉強になります。