答えは☓(バツ)
最大トークン数(max tokens)は40961ですが、プロンプトを工夫すれば30000字を超える長さであっても回答を得られます!
なお、この知見は「へぇ」レベルで、LLMを使っていく上では役に立たないと思います(ここで引き返してもええんやで)。
目次
- 答えは☓(バツ)
- 目次
- 先行研究:区切り線は2の冪乗で1トークン
- 2の12乗(4096文字)の区切り線でもいけるってこと?
- 2の12乗(4096)文字の区切り線をtiktokenで見てみる
- 2の冪乗の文字数の区切り線は64文字で1トークンと効率よくトークン化されるので、30000文字超えのプロンプトを送ることもできる
- 終わりに
- P.S. max tokensについて
先行研究:区切り線は2の冪乗で1トークン
このエントリのきっかけになったのは、はてなブックマークのテクノロジータブで見かけた以下の記事。
結論として、ChatGPT API での区切り線は、-または=を4以上の2の冪乗(4, 8, 16, 32)文字数分だけ書くのがおすすめです。
これらは1トークンとしてカウントされるため効果的です。
トークン数には上限がありますから、1トークンとしてカウントされたら節約できて便利ですよね。
2の12乗(4096文字)の区切り線でもいけるってこと?
ちょっと悪い知恵が働いて、「2の冪乗なら1024、2048、4096文字でもいけるってこと?」と思いつきました😈
2の冪乗の区切り線が1トークンならば、4096文字の区切り線も1トークンなので何も問題はないはずです。
というわけで送ってみましょう。
動作環境
- Python 3.10.9
- openai 0.27.6
- tiktoken 0.4.0
4096文字の区切り線を含んだプロンプトを送る
% python delimiter_length.py len(prompt)=4149 { "completion_tokens": 6, "prompt_tokens": 84, "total_tokens": 90 } 私は学生です。
プロンプトの文字数は4149です(4096+53)。
ですが、プロンプトのトークン数は84!
この時点で対応は見切れていませんが、4096文字の区切り線は4096トークンよりも少ないトークンにはなっていますよね。
2の12乗(4096)文字の区切り線をtiktokenで見てみる
tiktokenで見てみましょう2。
覗いて分かったこととして、2の12乗(4096)文字の区切り線は1トークンではありませんでした。
>>> import tiktoken >>> encoding = tiktoken.encoding_for_model("gpt-3.5-turbo") >>> len(f"{'='*2**12}") 4096 >>> len(encoding.encode(f"{'='*2**12}")) # 1トークンではなく、64トークン! 64 >>> encoding.encode(f"{'='*2**12}") [8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315, 8315] >>> encoding.decode([8315]) '================================================================' >>> len(encoding.decode([8315])) 64
=の代わりに-を使った場合はこちら:
>>> import tiktoken >>> encoding = tiktoken.encoding_for_model("gpt-3.5-turbo") >>> len(encoding.encode(f"{'-'*2**12}")) 64 >>> encoding.encode(f"{'-'*2**12}") [3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597, 3597] >>> encoding.decode([3597]) '----------------------------------------------------------------' >>> len(encoding.decode([3597])) 64
こちらも64文字で1トークンですね。
2の冪乗の文字数の区切り線は64文字で1トークンと効率よくトークン化されるので、30000文字超えのプロンプトを送ることもできる
2の15乗は32768です(3万字超え!)
prompt = f"""\ Translate this text into Japanese. -{'='*2**12} +{'='*2**15} I am a student."""
% python delimiter_length.py len(prompt)=32821 { "completion_tokens": 6, "prompt_tokens": 532, "total_tokens": 538 } 私は学生です。
終わりに
-または=が2の冪乗の数の区切り線は1トークンと知り、悪知恵を働かせてみました。
分かったことは以下です。
- -または=の個数が2の冪乗かつ64文字までは、1トークン
- 128以上の2の冪乗では、64文字までの1トークンに分割される
- 例:-または=が128文字なら、64文字で分かれて2トークン
- なので、(それでも効率は悪いのでオススメしないが)30000文字を超える長さの区切り線を使うこともできる
>ChatGPT API での区切り線は、-または=を4以上の2の冪乗(4, 8, 16, 32)文字数分だけ書くのがおすすめ
— nikkie にっきー (@ftnext) 2023年5月22日
区切り線を2の12乗=4096文字にしても問題なく動きました(1文字1トークンだと溢れる領域
ChatGPT API で区切り線を表現する最適な文字列を見つけた件|ざわきん/zawakin https://t.co/mMu9wj3ohu
2の冪乗の数列は無限に続きます。
それに対して、LLMsの語彙は有限と認識しています。
「2の冪乗の文字数で1トークン」だとすると、有限の語彙と矛盾しますよね。
「予め用意された語彙に対応付けているだけではなく、2の冪乗なら1トークンとする処理があるってこと?」と気になりました。
今回手を動かして分かった「最大は64文字で1トークン」で有限の語彙との折り合いは付くように思います。
P.S. max tokensについて
ドキュメントの「Managing tokens」より
max tokens 4096って、入力する(プロンプトやそれまでのChatコンテキストの)トークン数と、出力するテキストのトークン数の合計なんですね!
For example, a gpt-3.5-turbo conversation that is 4090 tokens long will have its reply cut off after just 6 tokens.
例えば、gpt-3.5-turboに4090トークン入力すると、max tokensが4096なので、出力は6トークンだけで切られるそうです。
入力するトークンが長くなると不完全な返答を受け取りやすくなる3と説明されています。
- https://platform.openai.com/docs/models/gpt-3-5↩
- TikTokデビューならぬ、tiktokenデビュー! ChatGPT APIに送らずして入力トークン長が分かるんです - nikkie-ftnextの日記↩
- Note too that very long conversations are more likely to receive incomplete replies.↩