はじめに
シリーズ2回目です。前回はさくらのAI Engine用アカウントトークン(APIキー)を発行して、curlコマンドで最初の1リクエストを成功させました。
| 各回のタイトル | 内容 |
|---|---|
| ①セットアップ編 | 無償プラン契約〜アカウントトークン(APIキー)発行〜最初の1リクエスト |
| ②全機能ためす編(本記事) | チャット生成/ベクトル埋め込み/音声の文字起こし/音声の読み上げ |
| ③つまずき解決編 | 実際に遭遇したエラーと解決法FAQ |
| ④まとめ編 | 30分で作るミニアプリ+無償枠の賢い使い方(予定) |
今回はさくらのAI Engine公式ドキュメント に沿って、無償枠で使える機能を一通り体験します。読み終わる頃には「さくらのAI Engineで何ができるのか?」の全体図がイメージできる状態を目指します。
この記事の内容と消費リクエスト目標
| 機能 | 無償枠 | 消費リクエスト目標 |
|---|---|---|
| Chat 生成(通常) | 月3,000 リクエスト | 5回程度 |
| Chat 生成(ストリーミング) | 〃 | 2回 |
| ベクトル埋め込み | 月10,000 リクエスト | 3回 |
| 音声の文字起こし | 月50 リクエスト | 2回だけ |
| 音声の読み上げ | 月50 リクエスト | 2回だけ |
準備: PHP環境を作る(入っていない人向け)
今回からcurlコマンドに代えてPHPを使います。理由は2つ。1つ目はJSONの組み立て・解析の処理をコマンドラインでやるのは大変になってくること、そして2つ目はWordPressなどでおなじみのPHPなら、レンタルサーバやVPSに最初から入っていることが多いことです。Pythonが入っていないサーバでも、PHPなら動く環境は意外と多いはずです。
ライブラリ管理ツール(Composer)は使いません。PHP標準のcURL拡張だけで全機能を試します。追加インストールが最小で済み、書いたコードはそのままWordPressのプラグインや自作ツールに流用できます。
すでに php -v と php -m | grep curl が通る人は、この章は読み飛ばして次章へ進んでください。
A: Linux環境(WSLのUbuntuを含む)
Ubuntu / Debian系(WSLのUbuntuはこちら):
sudo apt update
sudo apt install -y php-cli php-curl
AlmaLinux / Rocky Linux / RHEL系:
sudo dnf install -y php-cli php-common
確認(バージョンとcurl拡張の有無):
php -v
php -m | grep curl
実行結果:(Almalinux9の場合)
php -m | grep curl で「curl」と1行出ればOK
$ php -v
PHP 8.3.32 (cli) (built: Jul 1 2026 08:57:05) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.3.32, Copyright (c) Zend Technologies
$ php -m | grep curl
curl
B: Windows環境
B-1. 公式スクリプトでPHPをインストールする
PHP公式サイト(php.netのダウンロードページのWindows向け案内)が提供しているインストールスクリプトを使います。かつては「ZIPをダウンロード→展開→PATHを手動編集」という手順が必要でしたが、いまはコマンド1つで済みます。
PowerShellで次を実行(Linux環境にあわせるため、PHP8.3を指定)
※通常のPowerShell(非管理者)で実行すること
# Download and install PHP.
powershell -c "& ([ScriptBlock]::Create((irm 'https://www.php.net/include/download-instructions/windows.ps1'))) -Version 8.3"
実行すると、いくつか対話形式で質問されます。基本はEnterキーで既定値のままでOKですが、timezoneだけ入力します。
| 質問 | 入力 | 意味 |
|---|---|---|
| architecture [x64/x86] | Enter(既定: x64) | 64bit版 |
| ThreadSafe [true/false] | Enter(既定: false) | コマンドライン用途はNTS(Non Thread Safe)でOK |
| timezone |
Asia/Tokyo と入力 |
php.iniの日時設定。UTCのままだと日時が9時間ずれる |
| install for [1-3] | Enter(既定: 1) | 通常は現在のユーザー向けにインストールされる |
実行結果:
PS C:\> powershell -c "& ([ScriptBlock]::Create((irm 'https://www.php.net/include/download-instructions/windows.ps1'))) -Version 8.3"
What architecture would you like to install?
Enter x64 for 64-bit
Enter x86 for 32-bit
Press Enter to use default (x64)
Please enter [x64/x86]:
What ThreadSafe option would you like to use?
Enter true for ThreadSafe
Enter false for Non-ThreadSafe
Press Enter to use default (False)
Please enter [true/false]:
What timezone would you like to set in php.ini?
Press Enter to use default (UTC)
Please enter timezone: Asia/Tokyo
Would you like to install PHP for:
Enter 1 for Current user
Enter 2 for All users (requires admin elevation)
Enter 3 to install PHP at a custom path
Press Enter to choose automatically
Please enter [1-3]:
Downloading PHP 8.3.33 (x64, nts) -> C:\Users\hoge\AppData\Local\Programs\PHP\8.3.33\nts\x64
Installed PHP 8.3.33: C:\Users\hoge\AppData\Local\Programs\PHP\8.3.33\nts\x64
It has been linked to C:\Users\hoge\AppData\Local\Programs\PHP\current and added to PATH.
Please restart any open Command Prompt/PowerShell windows or IDEs to pick up the new PATH.
You can run 'php -v' to verify the installation in the new window.
このスクリプトは、指定したPHP8.3の最新版のダウンロード・展開・PATHへの登録・php.iniの作成まで自動でやってくれます。完了したら、開いているターミナルを一度閉じて開き直してから(PATHの反映に必要)、確認します。
php -v
実行結果:
PS C:\> php -v
PHP 8.3.33 (cli) (built: Jul 28 2026 18:10:26) (NTS Visual C++ 2019 x64)
Copyright (c) The PHP Group
Zend Engine v4.3.33, Copyright (c) Zend Technologies
B-2. php.ini の拡張有効化とエラー表示設定
スクリプトはphp.iniを自動作成してくれますが、今回使う拡張の有効化までは行われないため、ここだけ手動編集が必要です。
php.ini ファイルの場所を確認する
PS C:\> php --ini
Configuration File (php.ini) Path:
Loaded Configuration File: C:\Users\hoge\AppData\Local\Programs\PHP\current\php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)
php --ini で表示された「Loaded Configuration File」のphp.iniをメモ帳などで開き、次の3行の行頭のセミコロン(;)を外して有効化します。
extension=curl
extension=mbstring
extension=openssl
あわせて、もう1箇所。自動作成されるphp.iniは本番サーバ向けの雛形(php.ini-production)がベースのため、エラーが画面に表示されない設定(display_errors = Off)になっています。このままだと、書いたコードにミスがあっても「何も表示されず終わる」という初心者に一番つらい挙動になるので、学習用では表示をOnにします。
display_errors = On
B-3. HTTPS通信のための証明書設定(Windows最大の罠)
拡張を有効化してもまだ足りません。このままAPIを叩くと、高確率で次のようなエラーになります。
実際のエラーメッセージ:
> php chat_basic.php
通信エラー: SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
LinuxはOSが持つCA証明書ストアをPHPが参照しますが、Windows版PHPは参照先が未設定のため、HTTPS接続の相手(さくらのAPIサーバ)を検証できずにエラーになります。これはさくら側の問題ではなく、手元のPHPの設定不足で、公式インストールスクリプトもここまでは設定してくれません。
まず、curl公式のcacert.pem からcacert.pemファイルをダウンロードします。
そして、php.iniと同じフォルダ(php --ini で表示された場所)に置き、php.iniに次の1行を追加します。(実際の環境を確認して、フルパスを置き換えること)
curl.cainfo = "C:\Users\<ユーザー名>\AppData\Local\Programs\PHP\current\cacert.pem"
最終確認:
下記のコマンドを実行します。
php -v
php -m
実行結果:
php -m の一覧にcurl, mbstring, opensslが表示されればOK
PS C:\> php -v
PHP 8.3.33 (cli) (built: Jul 28 2026 18:10:26) (NTS Visual C++ 2019 x64)
Copyright (c) The PHP Group
Zend Engine v4.3.33, Copyright (c) Zend Technologies
PS C:\> php -m
[PHP Modules]
…
curl
…
mbstring
…
openssl
…
共通の準備: アカウントトークンを設定ファイルに保存する(全環境共通)
①セットアップ編ではアカウントトークンを環境変数に設定しましたが、今回からは設定ファイル方式に切り替えます。理由は3つあります。
- 環境変数はターミナルを閉じると消える(特にコマンドプロンプトの
setはそのセッション限り)ので、毎回設定し直すのが地味に面倒 - 環境変数の設定方法・挙動がOSやシェルごとに微妙に違う(①セットアップ編のcmd/PowerShell/bashの書き分けがまさにそれ)のに対し、ファイル読み込みは全環境で同じコードになる
- 将来レンタルサーバやcronで動かすときも、ファイルごと持っていけばそのまま動く
作業ディレクトリに config.php として保存します(<アカウントトークン>は ①セットアップ編で発行したものに差し替え):
config.php:
<?php
// このファイルは秘密情報。取り扱い注意
return [
'api_key' => '<アカウントトークン>',
'base_url' => 'https://api.ai.sakura.ad.jp/v1',
];
各プログラムからは、冒頭の2行で読み込んで使います。
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
<アカウントトークン>を正しく読めるか、check_config.php で確認します。<アカウントトークン>本体は画面に出さず、文字数と前後1文字だけ表示する作りにしています。
check_config.php:
<?php
$configPath = __DIR__ . '/config.php';
if (!is_file($configPath)) {
exit("config.php が見つかりません。作業ディレクトリに作成してください\n");
}
$config = require $configPath;
$key = $config['api_key'] ?? '';
if ($key === '' || $key === '<アカウントトークン>') {
exit("config.php の api_key に発行したアカウントトークンを設定してください\n");
}
printf("読み込みOK: %d文字 [%s ... %s]\n", strlen($key), $key[0], substr($key, -1));
php check_config.php
実行結果:
//失敗
PS C:\sakura-ai-engine> php check_config.php
config.php の api_key に発行したアカウントトークンを設定してください
//成功
PS C:\sakura-ai-engine> php check_config.php
読み込みOK: 77文字 [3 ... F]
1. チャット生成(基本)
1-1. まずは基本形
chat_basic.php:
<?php
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
$payload = [
'model' => 'gpt-oss-120b',
'messages' => [
['role' => 'system', 'content' => 'あなたは簡潔に答えるアシスタントです。'],
['role' => 'user', 'content' => 'HTTPとHTTPSの違いを2文で教えてください。'],
],
'max_tokens' => 300,
];
$ch = curl_init($config['base_url'] . '/chat/completions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
]);
$response = curl_exec($ch);
if ($response === false) {
exit('通信エラー: ' . curl_error($ch) . "\n");
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($status !== 200) {
exit("APIエラー (HTTP {$status}): " . $response . "\n");
}
echo $data['choices'][0]['message']['content'] . "\n";
php chat_basic.php
実行結果:
PS C:\sakura-ai-engine> php chat_basic.php
HTTPはデータを暗号化せずに送信する通信プロトコルで、通信内容が第三者に盗聴や改ざんされやすいです。HTTPSはHTTPにTLS/SSLによる暗号化を加えたもので、データの機密性と完全性が保護されます。
1-2. 会話の継続(過去やり取りの持たせ方)
ChatGPTのWebと違い、APIは毎回まっさらです。会話を続けるには過去のやり取りをmessagesに全部まとめて送り直す必要があります。chat_basic.phpのmessages部分を下記のように変更して、再度実行してみましょう。
$payload = [
'model' => 'gpt-oss-120b',
'messages' => [
['role' => 'user', 'content' => '私の趣味はフライトシューティングゲームです'],
['role' => 'assistant', 'content' => 'いいですね!空戦の緊張感は格別ですよね。'],
['role' => 'user', 'content' => '私の趣味は何だったでしょう?'],
],
'max_tokens' => 300,
];
実行結果:
PS C:\sakura-ai-engine> php chat_basic.php
あなたの趣味は **フライトシューティングゲーム** です 🚀✨
他にも好きなゲームや、特にハマっている作品があればぜひ教えてください!
2. ストリーミング応答
ChatGPTのWebのように「文字がパラパラ出てくる」やつです。PHPでは CURLOPT_WRITEFUNCTION で受信データを逐次処理します。中身はSSE(Server-Sent Events)という形式で、data: {JSON} という行が流れてきます。
……と、さらっと書きましたが、実はここでこの連載最大のつまずきに遭遇しました。最初に書いた単純な実装(delta.contentだけを拾って表示する20行ほどのコード)を実行したところ、エラーも出ず、出力も一切ないまま終了したのです。
PS C:\sakura-ai-engine> php chat_stream.php
PS C:\sakura-ai-engine>
原因は ①セットアップ編の実行結果で見つけた、あのreasoningフィールドでした。gpt-oss-120bは回答の前に 「思考」を行うモデル で、ストリーミングでは思考トークンがdelta.contentではなく別フィールドで流れてきます。
つまり:
- 思考中は
contentが空 → 画面に何も出ない - さらに思考もmax_tokensを消費する →
max_tokens: 300程度だと思考だけで枠を使い切り、本文が1文字も生成されないまま終了
「エラーがない=成功」ではなく「エラーがない+出力もない」という初心者に一番厳しい形で現れます。対策は、・思考の進行を可視化すること・max_tokensを多めに確保すること・本文ゼロのときに理由を表示することの3点です。下のコードでは対策しています。
chat_stream.php(対策込みの完成版):
<?php
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
$payload = [
'model' => 'gpt-oss-120b',
'messages' => [['role' => 'user', 'content' => '生成AIの歴史を200字で']],
'max_tokens' => 2000, // 思考型モデルは「思考」にもこの枠を使うため多めに確保
'stream' => true,
];
$buffer = ''; // 受信データの行組み立て用
$nonSse = ''; // 「data:」形式でない受信内容(=エラー本文の可能性)を溜める
$reasoningShown = false;
$gotContent = false;
$finishReason = null;
$ch = curl_init($config['base_url'] . '/chat/completions');
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
CURLOPT_WRITEFUNCTION => function ($ch, $chunk) use (
&$buffer, &$nonSse, &$reasoningShown, &$gotContent, &$finishReason
) {
$buffer .= $chunk;
while (($pos = strpos($buffer, "\n")) !== false) {
$line = trim(substr($buffer, 0, $pos));
$buffer = substr($buffer, $pos + 1);
if ($line === '') continue;
// 「data:」で始まらない行はエラー本文の可能性が高いので保管しておく
if (!str_starts_with($line, 'data: ')) {
$nonSse .= $line . "\n";
continue;
}
$json = substr($line, 6);
if ($json === '[DONE]') continue;
$data = json_decode($json, true);
$delta = $data['choices'][0]['delta'] ?? [];
$finishReason = $data['choices'][0]['finish_reason'] ?? $finishReason;
// 思考型モデルの思考トークン(フィールド名はモデルにより異なる)
$reasoning = $delta['reasoning'] ?? $delta['reasoning_content'] ?? '';
if ($reasoning !== '' && !$gotContent) {
if (!$reasoningShown) {
echo '(思考中';
$reasoningShown = true;
}
echo '.'; // 思考の進行をドットで表示
flush();
}
// 本文
$content = $delta['content'] ?? '';
if ($content !== '') {
if ($reasoningShown && !$gotContent) {
echo ")\n"; // 思考表示を閉じて本文へ
}
$gotContent = true;
echo $content;
flush();
}
}
return strlen($chunk);
},
]);
$ok = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
$curlErr = curl_error($ch);
curl_close($ch);
echo "\n";
// ---- 本文が届かなかった場合の診断表示 ----
if ($ok === false) {
exit("通信エラー: {$curlErr}\n");
}
if ($status !== 200) {
exit("APIエラー (HTTP {$status}):\n{$nonSse}\n");
}
if (!$gotContent) {
echo "[要確認] 本文が1文字も届きませんでした。finish_reason: " . ($finishReason ?? '不明') . "\n";
if ($finishReason === 'length') {
echo "→ max_tokensを「思考」で使い切った可能性が高いです。max_tokensを増やしてください。\n";
}
}
実行結果:成功(わかりやすいようにアニメーションGIFにしています)
「思考中」のドットが伸びていく間、モデルは裏で回答を組み立てています。旧実装ではこの間ずっと無言だったわけで、ストリーミングを自前でパースすると、裏で隠れている挙動がわかるのがPHP直叩きの醍醐味です。
【補足】実行結果:max_tokens が足りない場合
PS C:\sakura-ai-engine> php chat_stream.php
(思考中...................................................................................................................................................................................................
)
[要確認] 本文が1文字も届きませんでした。
finish_reason: length
→ max_tokensを「思考」で使い切った可能性が高いです。max_tokensを増やしてください。
3. ベクトル埋め込み(Embeddings)
「文章を数値の並びに変換する」機能です。一番ピンとこない機能だと思うので、 「意味が近い文章を探せる」 という一点だけ体験します。
embeddings.php:
<?php
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
$texts = [
'サーバが応答しません',
'Webサイトが落ちています',
'今日の昼ごはんはカレーでした',
];
$ch = curl_init($config['base_url'] . '/embeddings');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'model' => 'multilingual-e5-large',
'input' => $texts,
], JSON_UNESCAPED_UNICODE),
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
$vecs = array_map(fn($d) => $d['embedding'], $data['data']);
// コサイン類似度: 2つのベクトルの「向きの近さ」= 意味の近さ
function cosine(array $a, array $b): float {
$dot = $na = $nb = 0.0;
foreach ($a as $i => $v) {
$dot += $v * $b[$i];
$na += $v * $v;
$nb += $b[$i] * $b[$i];
}
return $dot / (sqrt($na) * sqrt($nb));
}
printf("「%s」×「%s」: %.4f\n", $texts[0], $texts[1], cosine($vecs[0], $vecs[1]));
printf("「%s」×「%s」: %.4f\n", $texts[0], $texts[2], cosine($vecs[0], $vecs[2]));
実行結果:
PS C:\sakura-ai-engine> php embeddings.php
「サーバが応答しません」×「Webサイトが落ちています」: 0.8838
「サーバが応答しません」×「今日の昼ごはんはカレーでした」: 0.7992
※e5系モデルは類似度が全体的に高めに圧縮されて出る特性があるので、絶対値ではなく相対比較で見る(0.88 > 0.80 の差が意味の差)こと
4. 音声認識(文字起こし)— 慎重に最大2回だけ
ここから無償枠が月50リクエストの世界です。 音声はスマホのボイスレコーダーを使い、自分の声を録音した5秒程度の短い音声ファイルを使います。ファイル送信はJSONではなくmultipart形式なので、PHPの CURLFile を使って実装しました。
※音声ファイルは30分、もしくは30MBの制限あり
※対応拡張子は、aac, m4a, mp3, mp4, ogg, wav などの一般的な音声・動画フォーマットに対応
transcribe.php:
<?php
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
$ch = curl_init($config['base_url'] . '/audio/transcriptions');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
CURLOPT_POSTFIELDS => [
'file' => new CURLFile('20260802_natsume.m4a'),
'model' => 'whisper-large-v3-turbo',
],
]);
echo curl_exec($ch) . "\n";
curl_close($ch);
実行結果:
PS C:\sakura-ai-engine> php transcribe.php
{"text":"我輩は猫である。名前はまだない。","model":"whisper-large-v3-turbo"}
5. 読み上げ(TTS)— こちらも最大2回だけ
利用する前に、さくらのAI Engine コントロールパネルで 音声モデルの利用規約 に同意する必要があります。また、公式ドキュメントの音声合成モデルのライセンス表示もあわせて確認しないと、同意しますのチェックボックスが選択できないようになっています。
今度は逆に、返ってくるのがJSONではなく音声データそのものなので、ファイルに書き出します。
※文字数には1000文字程度の制限あり
tts.php:
<?php
$config = require __DIR__ . '/config.php';
$apiKey = $config['api_key'];
$ch = curl_init($config['base_url'] . '/audio/speech');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'accept: audio/wav',
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'model' => 'meimeihimari',
'input' => 'はじめまして、冥鳴ひまりです。さくらのAIエンジンを学び始めた初心者です。よろしくお願いします。',
'voice' => 'normal',
'response_format' => 'wav',
], JSON_UNESCAPED_UNICODE),
]);
file_put_contents('hello.wav', curl_exec($ch));
curl_close($ch);
echo "hello.wav に保存しました\n";
実行結果:
PS C:\sakura-ai-engine> php tts.php
hello.wav に保存しました
Qiitaは音声ファイルを直接埋め込めないので、実際の音声を確認してもらえないのは残念です。保存された音声ファイルを手元の環境で確認してみてください。
まとめ: 今回の消費リクエストと全体図
今回体験した機能と、消費したリクエスト数の実績です。
| 機能 | やったこと | 消費リクエスト |
|---|---|---|
| チャット生成(通常) | 基本形+会話の継続 | 4回 |
| チャット生成(ストリーミング) | 失敗版+完成版+max_tokens不足の再現 | 10回 |
| ベクトル埋め込み | 3つの文の類似度比較 | 4回 |
| 音声の文字起こし | 5秒の録音音声(枠は月50) | 1回 |
| 音声の読み上げ | 冥鳴ひまりさんに自己紹介してもらう(枠は月50) | 1回 |
※チャット生成(ストリーミング)について、試行錯誤とGIF撮影で予定の5倍使ったが、それでも誤差のレベル
無償枠で使える主要機能を全部体験しても、チャット系の消費は20回未満。月3,000リクエストの枠は、まだ99%以上残っています。「とりあえず全部触ってみる」のに、残量を気にする必要はまったくありませんでした。
今回わかったこと
- APIの正体はただのHTTPS通信。PHP標準のcURL拡張だけで、チャットもベクトル埋め込みも音声も全機能呼び出せた。SDKやComposerは(少なくとも入門段階では)必須ではない
- 思考型モデルは「思考」にもmax_tokensを消費する。「エラーなし・出力なし」で終わったら、まずトークン切れ(finish_reason: length)を疑う
- 会話の記憶は自分で持たせる。APIは毎回まっさらなので、過去のやり取りをmessagesにまとめて送り直す
- ベクトル埋め込みは「意味の近さ」を数値にする機能。値は高めに出る傾向があるので、絶対値ではなく相対比較で見る
- 音声系は別枠(月50回)+利用規約への同意が必要。読み上げモデルはキャラクターごとにライセンス表示があるので、使う前に必ず確認する
次回予告: ③つまずき解決編
ここまでの2記事、順調に進んだように見えて、裏では結構つまずいています。次回は実際に遭遇したエラーを「エラーメッセージ → 原因 → 解決」のFAQ形式でまとめる保存版です。
予定している内容:
-
SSL certificate problem: unable to get local issuer certificate— Windows PHP最大の罠 - ストリーミングが無言で正常終了する — 思考型モデルとmax_tokensの深い関係
- コマンドプロンプトの
setで設定したトークンが、curlでは動くのにPHPだと401になる — 引用符の怪 -
php.iniを編集したのに反映されない/エラーが何も表示されない — production雛形の落とし穴 - モデル名の指定ミスで404 — 正式名の調べ方
同じエラーで検索して来た方が、そのまま解決して帰れる記事を目指します。



