GeminiのInteractions APIをPHPで実装:previous_interaction_idで会話を継続する
作成日:2026.08.01
Gemini Developer APIのInteractions APIを、PHPのcURLから呼び出す方法を解説します。PHP用の公式SDKがないためREST APIを利用し、APIキーの設定、リクエストとレスポンスの処理、previous_interaction_idを使った会話継続まで、実際のコード例とともに紹介します。
目次
Gemini API にはGoogle が提供している SDKがありますが、公式の対応言語一覧に PHP は含まれていません。そのため、PHP から利用する場合は REST API を cURL から呼び出します。
今回は、Gemini Developer API の Interactions API を PHP から呼び出してみます。単発のテキスト生成だけでなく、レスポンスに含まれる interaction の ID を次のリクエストへ渡すことで、会話を継続するところまで実装します。
OpenAI の Responses API で previous_response_id を使って会話を継続する記事を書きましたが、今回は Gemini の Interactions API で同じようなことをやってみます。
Interactions API とは
Gemini API には、従来からある generateContent のほかに、Interactions API があります。
Interactions API は、モデルとの1回のやり取りを Interaction という単位で扱います。レスポンスには、最終的なテキストだけでなく、モデルの出力やツール呼び出しなどの処理を steps として含めることができます。
公式ドキュメントでは、Interactions API はマルチターンの会話やエージェント的な処理に適した API と説明されています。詳しくは、Interactions API の公式ドキュメントを参照してください。
generateContent API との違い
generateContent は、入力に対する生成結果を受け取る、比較的シンプルな API です。
一方、Interactions API では、1回のやり取りに ID が割り当てられます。その ID を次のリクエストで previous_interaction_id として指定すると、過去の会話を Gemini 側で参照した上で回答を生成できます。
アプリケーション側で毎回すべての会話履歴を組み立てて送信しなくてもよい点が、Interactions API の便利なところです。
前提
今回の動作確認では、以下の環境を想定します。
- PHP 8.2 以降
- PHP の cURL 拡張が有効
- Gemini Developer API の API キーを取得済み
- API キーを環境変数
GEMINI_API_KEYに設定済み
Gemini Developer API の API キーは、Google AI Studio の API keys ページから作成できます。
API キーは PHP のソースコードに直接記述せず、環境変数などから読み込むようにします。
Interactions API にリクエストを送信する
Interactions API のエンドポイントは、以下の URL です。
https://generativelanguage.googleapis.com/v1beta/interactions
HTTP の POST メソッドで、API キーを x-goog-api-key ヘッダーに指定します。
まずは、テキストを1件送信するだけの JSON を確認してみます。
{
"model": "gemini-3.6-flash",
"input": "PHP から Gemini API を呼び出しています。"
}
model には利用するモデルの ID を、input にはモデルへ渡すテキストを指定します。
上記のモデル ID は、今回公式ドキュメントの例で使用されていたものです。利用可能なモデルやモデル ID は変更される可能性があるため、実際に利用する際は公式のモデル一覧を確認してください。
PHP から API を呼び出す
PHP の cURL 拡張を使って、Interactions API を呼び出す関数を作成します。
<?php
const GEMINI_API_URL = 'https://generativelanguage.googleapis.com/v1beta/interactions';
const GEMINI_MODEL = 'gemini-3.6-flash';
/**
* Interactions API を実行する。
*/
function createInteraction(string $input, ?string $previousInteractionId = null): array
{
$apiKey = getenv('GEMINI_API_KEY');
if ($apiKey === false || $apiKey === '') {
throw new RuntimeException('GEMINI_API_KEY が設定されていません。');
}
$requestData = [
'model' => GEMINI_MODEL,
'input' => $input,
'system_instruction' => 'あなたは親切なアシスタントです。',
];
if ($previousInteractionId !== null) {
$requestData['previous_interaction_id'] = $previousInteractionId;
}
$requestBody = json_encode(
$requestData,
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
);
$curl = curl_init(GEMINI_API_URL);
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-goog-api-key: ' . $apiKey,
],
CURLOPT_POSTFIELDS => $requestBody,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 60,
]);
$apiResponse = curl_exec($curl);
if ($apiResponse === false) {
$errorMessage = curl_error($curl);
curl_close($curl);
throw new RuntimeException('cURL の実行に失敗しました: ' . $errorMessage);
}
$httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
try {
$responseData = json_decode(
$apiResponse,
true,
512,
JSON_THROW_ON_ERROR
);
} catch (JsonException $e) {
throw new RuntimeException(
'API レスポンスの JSON 解析に失敗しました。',
0,
$e
);
}
if ($httpStatus < 200 || $httpStatus >= 300) {
$error = $responseData['error'] ?? [];
$errorCode = $error['code'] ?? 'unknown';
$errorMessage = $error['message'] ?? '詳細不明の API エラーです。';
throw new RuntimeException(
"Gemini API error ({$httpStatus}): {$errorCode} - {$errorMessage}"
);
}
return $responseData;
}
/**
* Interaction からテキストのモデル出力を取り出す。
*/
function getModelOutputText(array $interaction): string
{
foreach ($interaction['steps'] ?? [] as $step) {
if (($step['type'] ?? null) !== 'model_output') {
continue;
}
foreach ($step['content'] ?? [] as $content) {
if (($content['type'] ?? null) === 'text') {
return $content['text'] ?? '';
}
}
}
throw new RuntimeException('テキスト形式のモデル出力が見つかりません。');
}
try {
$interaction = createInteraction('PHP から Gemini API を呼び出しています。');
echo getModelOutputText($interaction);
} catch (Throwable $e) {
error_log($e->getMessage());
echo 'API の呼び出しに失敗しました。';
}
createInteraction では、API キーを環境変数から取得してリクエストを作成しています。
API が正常な HTTP ステータスを返した場合は配列としてレスポンスを返し、通信エラーや JSON の解析エラー、4xx/5xx のレスポンスの場合は例外を投げます。
レスポンスのテキストを取り出す
Interactions API のレスポンスには、概ね以下のような情報が含まれます。
{
"id": "v1_...",
"status": "completed",
"steps": [
{
"type": "thought"
},
{
"type": "model_output",
"content": [
{
"type": "text",
"text": "回答本文"
}
]
}
],
"usage": {
"total_tokens": 197
}
}
最終的なテキストは、steps 内の type が model_output の要素に含まれています。
常に steps[0] がテキスト出力になるとは限らないため、上のコードでは model_output を検索してからテキストを取り出しています。
previous_interaction_id で会話を継続する
Interactions API で会話を継続するには、1回目のレスポンスに含まれる id を保存しておきます。
2回目のリクエストで、その値を previous_interaction_id として送信すると、Gemini は前回の interaction を参照して回答します。
例えば、1回目に以下の質問を送ります。
私はハエトリグモを2匹飼っています。
このときのレスポンスから、以下のような ID を取得したとします。
v1_abc123...
続いて、同じ ID を指定して次の質問を送ります。
{
"model": "gemini-3.6-flash",
"input": "私の家にハエトリグモの足は何本ありますか?",
"previous_interaction_id": "v1_abc123..."
}
2回目の入力だけを見るとハエトリグモの数は分かりませんが、前回の interaction を参照することで、ハエトリグモ2匹を前提に回答できます。
PHP のセッションに ID を保存する
Web アプリケーションから利用する場合は、簡単な動作確認であれば PHP のセッションに interaction ID を保存できます。
<?php
session_start();
$message = trim($_POST['message'] ?? '');
if ($message === '') {
exit('メッセージを入力してください。');
}
$previousInteractionId = $_SESSION['previous_interaction_id'] ?? null;
try {
$interaction = createInteraction($message, $previousInteractionId);
if (!isset($interaction['id'])) {
throw new RuntimeException('レスポンスに interaction ID が含まれていません。');
}
$_SESSION['previous_interaction_id'] = $interaction['id'];
echo htmlspecialchars(
getModelOutputText($interaction),
ENT_QUOTES,
'UTF-8'
);
} catch (Throwable $e) {
error_log($e->getMessage());
echo '回答の取得に失敗しました。';
}
先ほどの createInteraction は、第2引数に interaction ID が渡された場合だけ、リクエストへ previous_interaction_id を追加します。
初回のリクエストでは ID がないため新しい interaction が作成され、2回目以降はセッションに保存された ID を使って同じ会話を継続します。
会話ごとに ID を管理する
実際のアプリケーションでセッションを使う場合でも、interaction ID を単純にユーザー単位で1件だけ持つのではなく、ユーザーと会話の組み合わせで管理する必要があります。
例えば、同じユーザーが複数のチャットを作成できる場合は、以下のような情報をデータベースに保存する構成が考えられます。
- ユーザー ID
- アプリケーション側の会話 ID
- 直前の interaction ID
- 最終利用日時
クライアントから interaction ID を直接受け取る設計にする場合は、その ID が現在のユーザーと会話に属しているかを確認してください。別ユーザーの ID をそのまま受け付けると、意図しない会話を参照する原因になります。
system_instruction などの設定について
previous_interaction_id で引き継がれるのは、過去の入力と出力による会話履歴です。
system_instruction、tools、generation_config などは interaction 単位の設定なので、次のリクエストでも使いたい場合は、その都度指定します。
先ほどの createInteraction では、毎回同じ system_instruction を送信しています。会話を継続できるからといって、初回の設定が自動的にすべて引き継がれるわけではない点に注意が必要です。
store とステートレスな会話
Interactions API は、デフォルトでは interaction を保存します。保存された interaction は、previous_interaction_id を使った会話継続や、ログの確認などに利用できます。
一方、リクエストに store: false を指定すると、interaction を保存しないステートレスな動作にできます。
{
"model": "gemini-3.6-flash",
"input": "この質問には保存しない設定で回答してください。",
"store": false
}
ただし、store: false の場合は、後続のリクエストで previous_interaction_id を使えません。
この場合は、アプリケーション側でユーザー入力とモデルから返された steps を保存し、次のリクエストへ会話履歴として再送する必要があります。保存しないことと、会話履歴をアプリケーション側で管理しなくてよいことは別なので注意してください。
保存期間や削除方法は契約しているティアなどによって変わる可能性があります。2026年7月時点の公式ドキュメントでは、無料ティアは1日、有料ティアは55日が保存期間として説明されています。最新の情報はInteractions API のデータ保存に関する説明で確認してください。
エラー処理
Interactions API からエラーが返る場合、HTTP ステータスに加えて、JSON の error オブジェクトに code と message が含まれます。
例えば、公式ドキュメントでは以下のようなエラーコードが説明されています。
authentication- API キーが未指定、または無効な場合
model_not_found- 指定したモデルが存在しない場合
rate_limit_exceeded- 短時間に大量のリクエストを送信した場合
quota_exceeded- 利用可能なクォータを超えた場合
service_unavailable- サービスが一時的に利用できない場合
今回のコードでは、HTTP ステータスが 2xx 以外の場合にエラーの内容をログへ出しています。実際の運用では、429 や一時的な 5xx に対するリトライ、タイムアウト時の扱い、ユーザーへ表示するメッセージなども検討します。
エラーの種類やレスポンス形式については、Gemini API の API errorsを参照してください。
API キーと会話データの扱い
- API キーは PHP のソースコードや公開リポジトリへ含めない。
- API キーをブラウザへ渡さず、サーバー側の PHP から API を呼び出す。
- interaction ID は会話の参照に使う値なので、ユーザーや会話との対応をサーバー側で管理する。
- 個人情報や機密情報を送信する場合は、保存設定、利用規約、社内のデータ取り扱いルールを確認する。
- 入力内容や API レスポンスをログへ残す場合は、ログに機密情報が含まれないようにする。
まとめ
今回は、Gemini Developer API の Interactions API を PHP の cURL から呼び出してみました。
Interactions API の基本的なリクエストは、以下のような流れです。
- API キーを
x-goog-api-keyヘッダーへ設定する modelとinputを JSON で送信する- レスポンスの
stepsからmodel_outputを取り出す - レスポンスの
idを保存し、次回のprevious_interaction_idへ指定する
previous_interaction_id を使うことで、PHP 側で会話履歴を毎回組み立てなくても、Gemini 側で会話を継続できます。
ただし、interaction の保存や API キーの管理には注意が必要です。まずは今回のような単純なテキスト生成で仕組みを確認し、必要に応じてストリーミング、画像入力、Function calling などを追加していくのがよいかと思います。
奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。
これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。
【制作会社・企業様向けサポート】
Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。
ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。
Google OAuth 2.0で実装するPHP SSO入門:Google Cloud 設定と実装コード例
2025.11.24
Google OAuth 2.0 を利用した Google アカウントによる SSO を PHP で実装する手順を解説します。Google Cloud Console での OAuth 同意画面とクライアント作成、必要なスコープ設定から、Composer の導入、GSI(Google Sign‑In)ボタンの設置、ログインスクリプトの実装例までを一貫して扱います。
漏洩パスワードとの照合:Pwned Passwords APIの仕組みと実運用での注意点
2025.11.06
Pwned Passwords API(Have I Been Pwned)が採用する k‑Anonymity の仕組みを分かりやすく解説し、PHPによる実装例を通して漏洩パスワードチェックの具体手順を示します。さらに、ユーザー通知文面の注意点など、実運用で押さえるべきセキュリティと運用上の留意点をまとめています。
Composerオートローダーでの「Class not found」エラー対処法
2025.10.18
Composerを利用してPHPライブラリをインストールした後に発生する「Class not found」エラーの原因と、その対処法について解説しています。特に、オートローダーの設定が正しく機能していない場合の具体的なエラー例を基に手順を紹介。
PHPで実現するCloud Vision API OCR入門:画像からテキスト抽出の基本
2025.09.30
Google Cloud Vision API を利用して、PHP で画像からテキストを抽出する OCR 処理の基本的な実装方法を解説します。API の有効化や認証情報の取得、PHP クライアントライブラリのインストール手順から、実際のコード例に基づいた OCR 処理の流れを紹介。