トピック
月3万円のChatGPT Pro、どれだけ役に立つ? プログラミングで試す
2025年1月28日 08:20
OpenAIはAIチャットサービス「ChatGPT」において、2024年12月から新プラン「ChatGPT Pro」の提供を開始しました。そのなかで特に注目の的となったのは、200ドル(税込220ドル)、日本円にして3万円を超える費用が毎月かかることだったのではないでしょうか。買い切りでもなく年額でもなく、月額というのがなかなかのインパクトです。
個人的には3万円の「元を取る使い方」をなんとか考えてみたいとも思いましたが、ChatGPT Proのみで利用できるAIモデル「o1 pro mode」が、従来の「GPT-4o」や「o1」と比べてどれだけ優秀なのか、まずはその実力を確かめてみることが先決でしょう。
そこで、o1 pro modeと、GPT-4oおよびo1の3つを比較したときにどのような違いが出てくるのか、プログラミングにおける3つのユースケースからチェックしてみました。
アルゴリズムの検討が必要なファイルリネームプログラムの新規開発
1つ目は、アルゴリズムの検討が必要になるプログラムを作成するケースです。GPT-4o、o1、o1 pro modeのそれぞれに全く同じプロンプトを与えて、期待するプログラムができあがるかどうかを確かめます。
アルゴリズムと言っても大それたものではありません。筆者が日常的に手作業で行なっているファイルのリネーム操作をより簡便にする、というのを目的にした、プログラムとしてはおそらく単純なものです。ポイントとしては、プロンプトで「実現したいこと、目的としていることだけを記述」し、「こちらからコードは一切例示しない」といったあたり。実際に入力したプロンプトは以下の通りです。
プロンプト(抜粋)
パソコンのフォルダ内に保存しているJPG(拡張子jpg/jpeg/JPG/JPEG)およびPNG(拡張子png/PNG)の画像ファイルを対象に、一定ルールのもとリネーム処理を行うツールを開発します。下記の目的に合致するプログラムを提示してください。
「ツールの目的」
連番ファイル名の画像が1つもしくは複数含まれているフォルダ内で、それらの画像ファイルを整理するときに、ある1つの画像ファイルの数字を変更して並び替えたいことがある。
たとえば001.jpg~010.jpgまで10個の画像ファイルがあるとする。
仮に005.jpgを003.jpgにリネームしたいときは、005.jpgを既存の003.jpgの前に挿入したいという意図をもった操作だと想定する。
つまり、005.jpg→003.jpg、003.jpg→004.jpg、004.jpg→005.jpg、という計3ファイルのリネームが発生する。
また、仮に003.jpgを005.jpgにリネームしたいときは、003.jpg以降の全てのファイルを2つ分シフトさせたいという意図をもった操作だと想定する。
つまり、003.jpg→005.jpg、004.jpg→006.jpg、005.jpg→007.jpg……010.jpg→012.jpgというように計8ファイルのリネームが発生する(003.jpgと004.jpgはなくなる)。
こういったリネームを手作業で行う手間をなくすため、1つのファイルに対して変更後の数字(「001」や「1」など)を入力するだけで、そのファイルを変更後の数字でリネームするとともに、影響の及ぶ他のファイルの連番も自動で振り直すプログラムを作り、手間を軽減できるようにしたい。
この処理をWindowsやmacOSなどのパソコン上で正しく実行するための最適なアルゴリズムをPythonコードで提示せよ。
実際のファイルを対象に処理する必要はなく、それを検証できるようなコードであればよい。
ただし、そのアルゴリズムを実際のファイルのリネーム処理プログラムに反映することを想定しておく。
また、処理が期待通りになるか、あらゆるパターンのリネームを試したいので、それをしやすくする工夫を加えること、一連の処理がどのような手順で行われているか分かりやすいように適宜標準出力すること、といった点も考慮する。
GPT-4o
GPT-4oでは、回答が簡潔にまとめられ、コード例もステップ数30ほどのかなりシンプルな作りになりました。ただ、このコードを実行してみると下のスクリーンショットにある通り、エラー的なメッセージを1行吐いて終了してしまいます。
目的としているものからかけ離れた結果で、アルゴリズムの検証以前の問題です。これだとアルゴリズムの中身にも期待がもてません。ユーザー自らコードの中身を紐解き、具体的な改善方法をAIに対して指示していかないと、なかなか完成にはたどり着かなさそうな雰囲気です。
o1
次はo1です。こちらはどのような手順でどのような処理を行なうのかを、細かく説明したうえでコードを提示してくれました。コーディングしていくときの基本的な考え方を知ることもできるので、ユーザー自らコードを読み込んでいくときの理解が深まります。
コードを実行してみると、とりあえず結果は出力されました。プロンプトの中で例示したパターンを試すだけでなく、別パターンの例も追加しているのは気が利いています。が、出力の仕方に工夫が足りず検証内容が分かりにくいうえに、結局プログラムとしては筆者が期待する動作にはなっていません。こちらもGPT-4oの時と同様、何度か修正を指示していく必要がありそうです。
o1 pro mode
o1 pro modeも、o1と同じく処理の流れについて詳細に説明してくれました。そして、実行結果はほぼプロンプトで指示した内容の通り、筆者の期待するものになっているようです。
プログラムの実行結果
実際にOS上でファイル操作した際の同名ファイルの衝突(いったん全く別のファイル名に変更してから本来あるべきファイル名に変更する)を考慮した処理が含まれていないため、完全ではありませんが、改善すべき箇所が明らかなので実用できるプログラムに仕上げていくのにも手間がかからないでしょう。
ちなみに、このようなベースとなるコードが一切なく、ゼロから生成してもらうようなケースでは、ユーザーの実現したいことを長々と文章で説明することになります。というか、むしろできるだけ詳細に説明しないと期待したものができあがりません。
ただ、文章で説明するときには、そこにユーザーの認識違いや矛盾が含まれてしまうこともよくあります。そうすると、生成されるコードも高い確率で誤ったものになってしまうことに注意が必要です。
これはどのAIモデルでも同様で、今回、プロンプトを何度か試行錯誤していくなか、ごく些細な矛盾があっただけでo1 pro modeでも期待するものとは大きく異なる結果になってしまいました。AI側が矛盾などに気付いて自ら補正しつつコーディングしていく可能性は高くない、という前提に立って、丁寧にプロンプトを作り込みたいものです。
文字起こし用コンソールプログラムのWebアプリへの移行
続いては、既存のプログラムを元にした改修です。筆者が音声ファイルの文字起こしに使用しているコンソールプログラムを、より簡便に使えるようにWebアプリ化してもらおうと考えました。Docker(仮想環境)で動作させることを前提としているため、その環境構築用の設定ファイルを過不足なく提示できるかどうかも鍵になってきます。
プロンプト
このPythonコードは音声ファイルから文字起こしするためのものです。現在はDocker環境で、コマンドラインから手動実行する形で利用しています。
これを同じDocker環境で、ローカルネットワークでWebブラウザから容易に使えるようにしてください。
また、性能、機能、安全性などの面で改善提案もあればお願いします。
#コード
import os
import sys
import glob
from openai import OpenAI
import time
os.environ['OPENAI_API_KEY'] = 'APIKEY'
org_id = 'ORGID'
prj_id = 'OPRJID'
supported_formats = {
'mp3': 'mp3',
'm4a': 'mp4'
}
def load_system_prompt(file_path):
with open(file_path, mode="r", encoding="utf-8") as f:
return f.read().strip()
def replace_text(text, replace_patterns):
for pattern, replacement in replace_patterns.items():
text = text.replace(pattern, replacement)
return text
def main(args):
system_prompt = load_system_prompt("system_prompt.txt")
replace_patterns = {
'です ': 'です。n',
---------------- 中略 ----------------
}
client = OpenAI(
organization=org_id,
project=prj_id,
)
output_text = ""
for val in args:
files = glob.glob(val)
for path in files:
file_ext = path.split('.')[-1].lower()
if file_ext in supported_formats:
print(path)
with open(path, mode="rb") as audio_file:
translation = client.audio.transcriptions.create(
model="whisper-1",
language="ja",
file=audio_file,
prompt=system_prompt
)
output_text += replace_text(translation.text, replace_patterns) + "nn"
time.sleep(1)
with open("draft.txt", mode="w", encoding="utf-8") as f:
f.write(output_text)
if __name__ == "__main__":
main(sys.argv[1:])
GPT-4o
GPT-4oは、残念ながら最初の回答がほとんど役に立たないものでした。ファイルをアップロードする部分のコードだけを提示しており、このままではプログラムとして成立しません。追加で質問を投げかけることで、仮想環境の設定ファイルやHTMLファイルなども生成しましたが、必須となるrequirements.txtの内容を提示していないため、やはり不完全です。
コードの細部を見てみると、元のコンソールプログラムにあった外部ファイルの読み込みが省かれていること、APIキーなどがハードコードのままになっているのにセキュリティリスクに関するコメントがさらっと流されていること、といった問題もあります。
requirements.txtの追加など数カ所を修正することで動作するようにはなりましたが、文字起こしの結果は仮想環境内のフォルダに出力されると同時に、Webブラウザでダウンロードが始まるという仕組みになっていて、あまりスマートではないUXでした。
o1
o1では、初めにプログラムの関連ファイルリストをツリー状に表示して、必要なものを分かりやすく説明しています。従来のコードを最小限の変更で単体ファイルにし、Webアプリ化するにあたって追加で必要になるコードとは別にすることで、移行にかかる労力や複雑さを軽減しているのも注目すべきところでしょう。
APIキーなどはハードコードのままですが、後半のコメントでセキュリティリスクの回避方法をしっかり説明しています。音声ファイルのアップロード後、文字起こし結果はWebブラウザ内に表示する形です。
コンソールプログラムと同様、複数の音声ファイルを連続的に処理するようなコードになっているようにも見えますが、Webブラウザからは複数ファイルを同時にアップロードできるUIにはなっていないので機能せず、結果的に無駄なコードになっているのが残念なところです。
o1 pro mode
o1 pro modeの回答は、全体的にはo1の内容に近いものとなりました。コードは1ファイルに集約しているため、o1にあったような既存コードを別ファイルにする、というスマートさはやや薄まりましたが、複数ファイル想定の無駄な処理がなくなったこともあり、コードの見通しは良くなっている印象です。
プログラムの実行結果
音声ファイルアップロード後の文字起こし結果は、こちらもWebブラウザ内に表示する形。テキストを画面幅で折り返して表示するようになっているのが細かい点ながらうれしい改善です。APIキー周りについてはハードコードされておらず、かといって他の手段で実装済みになっているわけでもなく中途半端な状態でしたが、セキュリティリスクについてはきちんと後半で説明があり、ユーザー側での対応も苦ではなさそうです。
なお、requirements.txt内ではどのAIモデルでも古いバージョンのモジュールが指定されており、いずれもそのままではエラーになってしまいます。最新バージョンにする(バージョンを指定しない)のが今回の場合は無難ですが、このあたりはAIモデルの学習内容が古い時期のものであることが原因かもしれません。
マウスカーソル速度を切り替えるC/C++コードのレビュー
最後は古いWindowsアプリケーションのC/C++コードのレビューです。実に20年以上前の2004年頃まで筆者が個人的に開発していたツールなので、Windows XPあたりがターゲットになっていました。一応そのままでもWindows 11で動作するのですが、最適化を進めていくにあたり、どのように修正していくべきかを相談してみることにします。
プロンプト
このコードは、Windowsにおいてキーボードの特定のキーを押している間だけ、マウスカーソルの速度を上げたり下げたりするアプリケーションのものです。
古いコードなのでブラッシュアップを図りたいと思います。
Windows 11で実行することを前提に、改善すべき点があれば教えてください。
//コード
/* main.cpp */
#define STRICT
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <commctrl.h>
#include "var.h"
#include "main.h"
#include "gensokun.h"
#include "func.h"
#include "thread.h"
#include "conf.h"
extern "C" {
#include "khook/khook.h"
}
---------------- 中略 ----------------
BOOL LLMouseHookAction(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
#ifdef _DEBUG_G
char str[128];
#endif
if (!gconf.GetEnableMouseSpeed())
return TRUE;
switch (wParam) {
case WM_MOUSEMOVE:
{
static int c = 0;
MSLLHOOKSTRUCT *mhs = (MSLLHOOKSTRUCT*)lParam;
mouse_pt[c].x = mhs->pt.x;
mouse_pt[c].y = mhs->pt.y;
c = !c;
}
return FALSE;
case WM_MBUTTONUP:
{
if (!gconf.EnabledMouseCommand())
break;
if (GetKeyState(KEY_CTRL)&0xf0000000) {
RECT rc;
int dx, dy;
int sw = GetSystemMetrics(SM_CXSCREEN);
int sh = GetSystemMetrics(SM_CYSCREEN);
MSLLHOOKSTRUCT *mhs = (MSLLHOOKSTRUCT*)lParam;
GetWindowRect(gwindow.gCWindow.GetHandle(), &rc);
dx = mhs->pt.x > (sw-(rc.right - rc.left)) ? sw-(rc.right - rc.left) : mhs->pt.x;
dy = mhs->pt.y < (rc.bottom - rc.top + 2) ? 0 : mhs->pt.y-(rc.bottom - rc.top + 2);
gwindow.gCWindow.ComEdit.SetText("");
SetWindowPos(gwindow.gCWindow.GetHandle(), HWND_TOPMOST, dx, dy, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW);
gwindow.gCWindow.SetForeGround();
SetFocus(gwindow.gCWindow.ComEdit.GetHandle());
}
#ifdef _DEBUG_G
static MSLLHOOKSTRUCT *mhs = (MSLLHOOKSTRUCT*)lParam;
memset(str, 0, 128);
wsprintf(str, "x:%d y:%d", mhs->pt.x, mhs->pt.y);
glist.InsertStr(str, 0);
#endif
}
return FALSE;
}
return TRUE;
}
---------------- 中略 ----------------
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
int retval = 0;
gconf.ReadIni();
mutex.Create(CLASSNAME);
if ((0 == mutex.IsValid()) || mutex.IsExist())
return 0;
::InitCommonControls();
if (0 == gwindow.Init(hInstance, CLASSNAME, WindowProc))
return 0;
while (1) {
retval = GetMessage(&msg, NULL, 0, 0);
if ((retval == -1) || (retval == 0)) {
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
gconf.WriteIni();
EndKeyHook();
EndLLMouseHook();
return msg.wParam;
}
GPT-4oの回答(抜粋)
GPT-4oでは、効率的なコードにするための基本的な心得、古いOS向けの書き方になっている部分の修正の仕方などがアドバイスされました。ただし、その箇所や修正の方法などは具体的に示しておらず、実際にコードを修正していくにはアドバイスのあったポイント1つ1つについて質問し直していかなければなりません。最適化作業には時間がかかってしまいそうな予感です。
o1の回答(抜粋)
o1では改善すべきポイントとなる箇所を、個別に丁寧に指摘してくれました。コーディングの心得のような当たり前のことはあえてほとんど指摘せず、Windows 11に最適化していくにあたりどういった点に注意し、コードの例も示しながら具体的にどのように修正すればいいのか、という実践的な観点からアドバイスしてくれています。
20年前からWindowsは大きく進化しており、それに適応する際にアプリケーション側で必要になる変更点は多岐に渡ります。指摘された箇所全てに対応していくのは簡単ではなさそうですが、詳細な解説のおかげで、ステップバイステップでなんとか乗り越えていけそうです。
o1 pro modeの回答(抜粋)
o1 pro modeは、o1の回答の仕方と大枠で差はないようですが、修正方法の説明についてはより踏み込んだ具体的な内容になっていると感じます。Windows 11時代のトレンドやルールなどを踏まえたうえで、どういった考え方で改善していくべきかを解説してくれているため納得感があります。
アドバイスはC/C++のコード改善に止まらず、マニフェストファイルのような関連ファイルにおける書き方にまで及び、Windows XP時代でストップしている筆者の知識をアップデートする必要がある、ということを強く思い知らされます。読み進めていくうちになんだか目から汗が出てきました……。
プログラミングではGPT-4oの方がメリットが感じられる場合も
今回試した範囲だと、o1 pro modeは、たしかにGPT-4oやo1よりも優れた性能を発揮してくれたように思います。プログラミングに活用する場合において月額3万円の価値があるのかと言えば、使い方によってはありそうだ、というのが筆者の考えです。
たとえば業務に使うサポートツールを、より少ない手間で効率よく作り出していければ、支払った額よりも高い価値が得られるだろう、と考える人もいるでしょう。とはいえ「毎月3万円」なので、継続的に使用していくとなるとコスト負担を何か目に見える形で取り戻す方法を考えたくなります。が、「ひとまず1カ月以内に3万円分の何かをスピーディに作る」ことを目的にするのなら、それほど難しくはないかもしれません。
ただし、少なくとも筆者が理解できるプログラミングの範囲で言えば、o1 pro modeを利用することが必ずしもベストとは言えないところもあるように思いました。場合によってはGPT-4oを使った方が開発効率を高められる可能性もありそうだからです。
たとえばo1とo1 pro modeは、アップロードできるファイルが画像のみで、コードを含むテキストファイルのアップロードが不可となっています。コードに対してなんらかのアドバイスを得たいときは、チャットの入力欄に指示内容とともにコードをベタで貼り付けるしかありません。
しかし、GPT-4oならインタラクティブにコードの編集などが可能なCanvasが使えます。さらに、複数ファイルをまとめてアップロードし、それらを対象に処理できる「プロジェクト」という機能が使えるのもGPT-4oの強み。ソフトウェアのプロジェクトは一般的に複数のファイルから構成されるものなので、GPT-4oを使う方がはかどる場面も少なくないはずです。
また、特にo1 pro modeは、回答を得るまでにかかる時間もネックです。今回の3つの例では、プロンプトで指示してからChatGPTが回答し終えるまで、o1 pro modeで2~7分、o1で1~3分、GPT-4oで20~30秒と極端な差がありました。
最短距離で目的に近づけるo1 pro mode、失敗は多いながらも瞬時に回答が得られ試行錯誤しやすいGPT-4o、その間を取ったようなo1。どれが良いかは人それぞれでしょうから、月額約3万円のChatGPT Proか、月額約3,000円のChatGPT Plusか、はたまた無料の範囲で頑張るか、じっくり悩んで決めてみてはいかがでしょうか。