【o3-mini-high】文字数をきっちり守って文章を生成させる
なぜこんなことを考えたか
数日前にo3-miniが公開された。Perplexityの解説を貼っておく。
STEM分野が得意だとのこと。ふと思いついて、文字数を厳密に守らせて文章を生成する方法を試してみた。
以前から言われているが、ChatGPTなど生成AIが文字を数える際、トークンという単位を利用する。トークンは文字数とは厳密にはリンクしていないため、文字数を指定しても生成AIはその指示をなかなか守ることができない。
Webの文章であれば、1文字単位で数える必要はないだろう。しかし、印刷物では、かなりしっかり数える必要がある。また、Webであっても、例えば2000文字か4000文字かは区別した方がよかろう。
文字数をしっかり守らせながら文章を生成させる方法として見かけたのは、プロンプトをいろいろと工夫するものだったと記憶している。ただ、あまり確実ではないようだった。
そこで思い出したのが、生成AIでの文章生成でPythonのプログラムを作って数えさせる方法である。かなり前に聞いたことがある程度だったが、コードを見てなかった(見てもわからん)ので、具体的な方法としては認識していなかった。
まずは文字を正しくカウントする
最初にやったのは、日本語の文章を正しくカウントするプログラムを作るところ。文章を与えて「これは何文字?」に対して正しい答えが出てくるようにする。これは難しくはない。
import unicodedata
# ユーザーから文章を入力
text = input("文章を入力してください: ")
total_count = 0
for char in text:
# 各文字の東アジア幅カテゴリを取得し、半角なら0.5、全角なら1とカウント
if unicodedata.east_asian_width(char) in ('Na', 'H'):
total_count += 0.5
else:
total_count += 1
print("文字数:", total_count)
これを実行すると「文章を入力しろ」と言ってくるので、文章をペーストしてやれば、文字数が正しくカウントされる。
ちなみに、印刷物では、全角文字1つを「1w」(wは「ワード」と読む)、半角文字1つを「0.5w」とカウントするのがお約束だが、AIへの説明が面倒なので以下は「文字」で通す。
文字数指定を守って文章を生成させる
問題はここからで、具体的な文字数を指定して「40〜60文字で書け」などと指示しても、なかなか守ってくれない。
そこで、文字数をPythonプログラムでチェックし、短ければ膨らませ、長ければ圧縮するように指示してみた。
すると、以下のようなプログラムを出力しつつ、文字数カウントを繰り返して文章を出力させることができた。なお、このプログラムを自分で実行する必要はない。
import unicodedata
def count_weighted(text):
total_count = 0
for char in text:
# 半角('Na'、'H')は0.5、全角は1としてカウント
if unicodedata.east_asian_width(char) in ('Na', 'H'):
total_count += 0.5
else:
total_count += 1
return total_count
while True:
text = input("文章を入力してください(40文字以上、50文字未満になるように): ")
total = count_weighted(text)
print("現在の文字数:", total)
if 40 <= total < 50:
print("条件を満たしました。")
break
else:
if total < 40:
print("文章が短すぎます。もう少し文章を膨らませてください。")
else:
print("文章が長すぎます。文章を圧縮してください。")
で、出力された文章が以下のものだ。
ちょうど40文字。問題ない。もう1つやってみよう。
出力は以下の通り。
223文字。全く問題ない。
長い文章を出力させたり、複雑な構造の文章を出力させようとしたりすると、なんらかの問題が起こる可能性はあるが、とりあえず200文字程度であれば、非常に正確な結果が得られたのは確かだ。
GPT-4oとo3-mini-highはかなり実力に差があるかも
チャットスレッドを新しくして、以下のプロンプトをまずo3-mini-highに与えてみた。
import unicodedata
def count_weighted(text):
total_count = 0
for char in text:
# 半角('Na'、'H')は0.5、全角は1としてカウント
if unicodedata.east_asian_width(char) in ('Na', 'H'):
total_count += 0.5
else:
total_count += 1
return total_count
while True:
text = input("文章を入力してください(40文字以上、50文字未満になるように): ")
total = count_weighted(text)
print("現在の文字数:", total)
if 40 <= total < 50:
print("条件を満たしました。")
break
else:
if total < 40:
print("文章が短すぎます。もう少し文章を膨らませてください。")
else:
print("文章が長すぎます。文章を圧縮してください。")
出力は、以下の通り。
40文字。問題ない。では、GPT-4oはどうか。同じプロンプトを与えてみた。出力は以下の通り。
237文字。パッと見て、すぐにダメだとわかるレベル。文字数を全くカウントしていない。
ということで、コーディング時には、使えるならo3-mini-highを使った方がいい結果が得られそうだ。