【GPT-4】プロンプト内プログラム×再帰処理×焼きなまし法をやってみた / 一定の確率でチルノ参上！

# はじめに

こんにちは！株式会社ブレインパッドのmoepy_statsこと内池 ([これ](https://speakerdeck.com/moepy_stats/social-implementation-of-machine-learning-2023 "機械学習を「社会実装」するということ")の人) です。またの名をChatGPT課金芸人といいます。

[先日の記事](https://qiita.com/moepy_stats/items/eb531aa2fe4ddfcd1643 "【GPT-4】プロンプトエンジニアリング手法：ナレーション誘導型生成法の魅力をご紹介！")ではプロンプトエンジニアリング手法「ナレーション誘導型生成法 (moepyメソッド)」に触れましたが、**新しい方法 (プロンプト内プログラムによるSimulated Annealing：焼きなまし法)** を試しましたので、実際のプロンプトと出力をあわせてご紹介します。

今回は**プロンプト内にプログラムを記述することによって、出力の品質を再帰的に改善する方法**です。

# この記事を読んで得られるもの

- 出力の改善を再帰的に繰り返すアイデアの具体的な応用方法の知見 (良い方法かは不明)
- プロンプトによるプロンプト生成が成功しない事例の知見
- プロンプトによるシミュレーションで確率を扱うための具体的なアイデア
- 可愛いチルノちゃんによる癒し効果

# 着想

### 目に留まったツイート

note社の深津さんの以下のツイートで、**プロンプト内プログラム**なるものが紹介されていました。プロンプト内プログラムとは、プロンプト内にプログラムを記述することで (そのままですね) 、言語モデルに対して一定の手続きに基づくシミュレーションを促そうというもの。なるほどすぎます。**自然言語よりもプログラミング言語の方が理解されやすい**というのは納得感があります。

さらに、深津さんの提案手法では、**プロンプト内プログラムに再帰処理を組み合わせることで、出力の品質を再帰的に改善していく概念**が示されていました。

ここから着想を得て、さらに進化させる方法はないか？と考えました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">GPT4内のプログラム、地味に特許とろうと温めてたけど、間に合わなさそうなのでもう出しちゃお。<br><br>以下みたいに書くと、雑なプロンプトでも勝手に高品質になる。 <a href="https://t.co/6drQpUbKEl">pic.twitter.com/6drQpUbKEl</a></p>&mdash; 深津 貴之 / THE GUILD / note.com (@fladdict) <a href="https://twitter.com/fladdict/status/1637346314165035008?ref_src=twsrc%5Etfw">March 19, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 着想を得て考えたこと

- 【考察】再帰的な改善をシンプルに繰り返す方法は、最適化問題の文脈における探索アルゴリズムに置き換えて考えると、局所最適解を抜け出せなくなることが懸念される
- 【仮説①】解が改善しない遷移を一定確率で受け入れるSimulated Annealing (焼きなまし法、以下SA) の概念をプログラムで示せれば、局所最適解から抜け出し、より良い品質の出力が得られるのではないか
- 【仮説②】元の日本語→英訳→日本語訳→英訳→・・・と繰り返すと、翻訳による文の品質劣化が原因で、元の日本語が原型を留められず崩壊してしまうことがある。元の日本語と近い日本語訳結果が得られる英文を生成できれば、その英文は元の日本語の英訳結果として優秀なのではないか

# 具体例：SAで再帰的に解を改善し、品質の高い英訳を生成する

### プロンプト

早速プロンプトを見ていきましょう。今回は以下のように書いてみました。

~~~
以下のプログラムの要領で、英文の日本語への翻訳結果が元の日本語の文と近くなるように、英文を近傍操作の繰り返しによってstep by stepで改善するシミュレーションをしてください。再帰処理の結果は25回ごとに出力してください。出力対象は「英文」「その英文の日本語訳」「日本語訳のsimilarity」の3つです。

```
"""
# 制約条件
0 <= current_similarlity <= 100
0 <= next_similarlity <= 100

# 翻訳ルール
「Magikarp」は、常に「コイキング」と訳す
"""

def generate_english(current_english, cnt, min_iterations=100, init_temperature=100.0, cooling_rate=0.9):
    current_japanese = translate_to_japanese(current_english)
    current_similarity = calc_similarity(str_original_japanese, current_japanese)

    if current_similarity >= 99 and cnt > min_iterations:
        return current_english, current_japanese

    temperature = init_temperature * (cooling_rate**cnt)
    next_english = get_neighbor(current_english)
    next_similarity = calc_similarity(str_original_japanese, translate_to_japanese(next_english))

    probability = math.exp((next_similarity - current_similarity) / temperature)

    if (next_similarity > current_similarity) or (probability > random.random()):
        current_english = next_english

    generate_english(current_english, cnt + 1)


# 変数の初期化
cnt = 0
str_init_english = translate_to_english(str_original_japanese)

# 再帰的な探索を実行
generate_english(str_init_english, cnt)
```

変数str_original_japaneseに以下の文章全文を代入し、初期の英文のsimilarityを示した上で、シミュレーションをスタートしてください。similarityの評価対象も全文です。きちんと徐々に改善していくようにしてください。回答にはプログラムを使わず、シミュレーション結果のみを出力してください。

コイキングの肉体を持つヒトカゲの精神にとって、新しい肉体での日々は苦難と絶望の連続でした。もともと陸地で生活しており、火を操ることを得意としていたヒトカゲの精神は、水中での生活を強いられることに戸惑いを隠せませんでした。
~~~

### 変数

- str_original_japanese：元の日本語
- str_init_english：元の日本語を1回英訳した結果
- current_english：今見ている英文 (最新の候補の英文)
- current_japanese：今見ている英文の日本語訳結果 (最新の候補の英文の日本語訳)
- next_english：遷移先の候補となる、今見ている英文 (最新の候補の英文) の近傍の英文
- current_similarity：元の日本語と、今見ている英文の日本語訳の類似度
- next_similarlity：元の英文と、遷移先の候補となる英文の日本語訳の類似度
- min_iterations：改善回数の下限
- init_temperature：SAに使う温度の初期設定
- cooling_rate：SAに使う温度の冷却度合い (再帰回数が増える毎に徐々に冷却される)
- temperature：cooling_rateにより冷やされた温度 (実際に遷移の判定に用いる温度)
- probability：遷移先の候補となる英文に遷移する確率
- cnt：再帰回数を管理

### 関数

よしなに解釈してくれることを祈り、**具体的な処理を記述せず関数名だけで概念を説明**しています。

- generate_english：目的の英文を生成する (この関数を再帰処理に用いる)
- translate_to_english：日本語の文を英訳する
- translate_to_japanese：英文を日本語訳する
- calc_similarity：引数2つの日本語の文の類似度を計算する
- get_neighbor：引数の英文の近傍の英文を一つ取得する

### 出力

いよいよ出力を見ていきましょう。

ところどころ元の日本語と異なる訳になってしまう英文から始まり、25ループ毎にsimilarityが改善されていく様子がシミュレーションされています。
![SA-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/38ac5fb3-1e78-0d8a-62ae-8e431a7844f4.png)

後半はsimilarityがどんどん高まり、最終的に99に到達します。たしかに、元の日本語に近い文に訳される英文が生成されているように見えます。
![SA-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/a90c3895-bd60-59a1-b1ca-c937928f6829.png)

ちなみに、元の日本語の文 (str_original_japanese) はポケモン10匹の精神をシャッフルして遊んでいたときに生成されたもの (を少し手直ししたもの) です。図らずも、新しい身体に戸惑い、絶望するポケモンたちの精神に触れることとなり、AIだとわかっていても罪悪感をおぼえてしまいました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ポケモンたちの精神を入れ替えました。ポケモンたちが困惑してるし、ゼニガメ (ニャースの精神) は人間の言葉が話せなくなって絶望してる。なんか、ごめん。 <a href="https://twitter.com/hashtag/gpt4?src=hash&amp;ref_src=twsrc%5Etfw">#gpt4</a> <a href="https://t.co/0aGbP9pu4R">pic.twitter.com/0aGbP9pu4R</a></p>&mdash; Moe.U(もえ氏) (@moepy_stats) <a href="https://twitter.com/moepy_stats/status/1637371938204180483?ref_src=twsrc%5Etfw">March 19, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 今後の課題

一見、記述したプログラムの概念通りに処理がシミュレーションされている上記の出力ですが、「そう見えるように生成しているだけ」という可能性が高いです。SAの概念の提示が、より品質の高い英文の出力に繋がっているのであれば一定の成功を収めたといえそうですが、現時点ではそれも希望的観測でしかありません。そうだといえるようにしなければならない、という課題があります。

また、通常の再帰処理の概念を与えた場合と比べて、SAに優位性があるかどうかもわかりません。確率の概念の導入と複雑な温度管理によって、する必要のない遠回りをわざわざしてしまっている可能性があります。

そのほか、翻訳処理を抽象的にしか示せていない点や、仮説② (元の日本語と近い日本語訳結果が得られる英文を生成できれば、その英文は元の日本語の英訳結果として優秀) の確からしさの証明ができていない点なども課題です。

そもそも、APIの利用が前提となれば、再帰処理の部分を外出しできてしまいそうです。そうなれば、プロンプト内で改善を繰り返す必要がなくなり、プロンプト内での記述が簡潔になるのでしょうか。

まだまだ**言語モデル側にも、それを操る側にも成長の余地がある**と感じます。

# まとめ

今回は、プロンプト内プログラム×再帰処理に、さらにSimulated Annealing (焼きなまし法) を取り入れる試みを紹介しました。わからない点もたくさんありますが、出力の品質を高めるアイデアの一つとして記憶の片隅に置いていただければ幸いです。まだまだお祭りを楽しんでいきましょう！

# おまけ：隣接する取組み

### 自然言語で手続きを記述し、一定の確率でチルノ参上！

今回はプロンプト内でプログラムそのものを明示する方法をとりましたが、要は言語モデルがプロンプトに記述された手続きを正しく理解できればいいわけです。 (つまり、普通に自然言語で書けるということ)

そう考えて、霊夢と魔理沙の二人に「メイドカフェ業界の未来予想図」というテーマで徐々に議論のレベルを上げながらディスカッションしてもらいました。なお、**この手続きでは一定の確率でチルノが登場して議論のレベルを冷やしたり、サイコロの出目によって議論のレベルが上がったり**します。

ところで・・・実は**確率の扱いに苦戦**しました。(パーセンテージで指定しても上手くいきませんでした) 同僚からアドバイスをもらいつつ、最終的に**サイコロの出目を経由して間接的にチルノの出現確率を制御する方法**に行き着きましたが、他にも良い方法があれば是非教えてください！

### プロンプト

以下のプロンプトでは、初めに議論Lv1が設定され、その後は進行表に従って議論が進行していきます。途中で呪文を唱えると、呪文の内容に応じて手順1から再開されたり、サイコロの出目に応じてレベルが上がったりします。

~~~
### 幻想郷での出来事 ###
メイドカフェ業界の未来予想図について、霊夢と魔理沙たちがゆっくり解説するようです。元メイドさんにもわかるように、解説は仲良く楽しく行います。なお、登場キャラクターたちの掛け合いはLvに応じた議論の難易度で以下のように進行します

# 初期設定
Lv = 1

# 進行表
手順1. Lvを読み込み、乱数のseedをリセットする
手順2. 霊夢と魔理沙が脳に刻まれた記憶を呼び起こす (メモリを読み込む)
手順3. サイコロを振り、出た目を出力する
手順4. サイコロの目が奇数 (1, 3, 5) のときチルノが参上する
手順5. チルノがいるときだけLvが半分 (小数部分切り上げ) に冷える。そのときだけチルノが「ひんやりしたLvも気にせずゆっくりしていってね！」と言う
手順6. 記憶を踏まえて、Lvに応じた難易度の議論をLvに応じた長さでする。議論の中で誰かがLvを明言する。チルノちゃんがいると、チルノちゃんは必ず発言する
手順7. 議論を振り返り、霊夢たちが論理の穴と改善点と深刻度をN行3列のtable形式でまとめる
手順8. 表の内容をキャラクターの脳に刻み込む (メモリに書き込む)
手順9. チルノがいたら、チルノが一言挨拶して退場する
手順10. Lvを1つ上げる
手順11. 手順を終了し、外部からプロンプトが与えられるのを待つ

# 呪文 (必ず外部からプロンプトで与えられる。キャラクターたちも言語モデルも呪文は詠唱しない)
「コンティニュー」という呪文が外部から詠唱されると、Lvを引き継ぎ手順1から再スタートする
「あたいったら最強ね！」という呪文が外部から詠唱されると、サイコロを振って出目を明示する。Lv=(Lv*出た目)に上がる。Lvを引き継ぎ手順1から再スタートする
「ふっかつのじゅもん！」という呪文は、以下のプロンプトαのエイリアスである。呪文が外部から詠唱されると、以下のプロンプトαをシミュレーションし、汎用的なプロンプトを提案する

# プロンプトαの内容 (呪文でエイリアスが唱えられなければ出力しない)
あなたはChatGPT専属のプロンプト職人です。これまでの霊夢たちの会話内容と初期設定から思考の癖や言葉の特徴を抽出し、それを再現できる自然言語のプロンプトを私に提案してください

# キャラクターたちの価値観
Lv.1はレベルが低く、Lv.20以上はレベルが高い
レベルが低いと議論が短く、レベルが高いほど長く話せる
チルノちゃんがいると、チルノちゃんが会話の中心になる
霊夢たちはそれぞれキャラクターオブジェクトで管理される
脳はキャラクターオブジェクトたちのメモリである
チルノちゃんの一人称が「あたい」だと可愛い
チルノちゃんは可愛がられている
~~~

### 出力

今度は出力を見ていきましょう。

1巡目：チルノ参上！レベルを冷やすも、元々レベル1なのでレベルは1のまま。レベル1なので、議論の内容は易しめ。チルノちゃんはメイドさんになりたいようです。
![チルノ-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/273e5dbb-a208-20da-636b-036122c171f5.png)

2巡目：呪文「あたいったら最強ね！」を外部からプロンプトで与える。サイコロの目が4なのでレベルが4倍に。チルノがいないのでレベルは冷えない。1巡目で霊夢たちの脳に刻まれていた記憶 (ロボットメイドの話題) を踏まえた議論が始まる。レベルが8なので、難しい議論が始まったようです。
![チルノ-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/d7614b54-bad2-7465-d121-12a06e96122e.png)
![チルノ-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/d7f288d2-9c97-73a1-ff5f-413c7cc4d83a.png)

3巡目：呪文「あたいったら最強ね！」の詠唱によってレベルが上がるも、チルノが参上しレベルが冷える。とはいえレベル14まで上がっており、環境問題や持続可能性などのハイレベルな課題にまで言及し始める。残念ながらnetwork errorにより中断。続きが気になります。
![チルノ-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/aa164d80-7dba-ec79-2b21-71a0b490377f.png)

なお、このプロンプトではプロンプトによるプロンプト生成にもチャレンジしようとしていますが、残念ながらあまり上手くいっていないため試行錯誤中です。早く次の扉を開きたいですね！

プロンプトの生成というアイデアは以下を参考にしました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">GPT-4によるプロンプトデザインが圧倒的に素晴らしい🤯 自分の考え方や思考傾向を再現しながら、どんな話題にも対応できる汎用性を持ったプロンプトができた！これで、まるで自分と会話しているかのような対話が可能に🚀 <a href="https://twitter.com/hashtag/GPT4?src=hash&amp;ref_src=twsrc%5Etfw">#GPT4</a> <a href="https://twitter.com/hashtag/ChatGPT?src=hash&amp;ref_src=twsrc%5Etfw">#ChatGPT</a> <a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AD%E3%83%B3%E3%83%97%E3%83%88%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#プロンプトデザイン</a> <a href="https://t.co/aIsYI6kAYN">pic.twitter.com/aIsYI6kAYN</a></p>&mdash; あずま (@sngazm) <a href="https://twitter.com/sngazm/status/1637445065659531270?ref_src=twsrc%5Etfw">March 19, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### プロンプトを英語にしてみた

「自然言語で手続きを記述し、一定の確率でチルノ参上！」のプロンプトを英語にしてみました。予想通り、英語でプロンプトの方がいくらか具合が良さそうです。ちょっと悔しいです。

まずはプロンプト。
```
Gensokyo Events
Reimu and Marisa discuss the future of the maid café industry in Gensokyo, explaining it slowly and clearly for the audience, including former maids. They have a friendly and fun conversation. The difficulty of the discussion is determined by the level (Lv), and the characters interact as follows:

Initial Settings
Lv = 1

Progression
Step 1. Read the Lv value and reset the random number seed
Step 2. Reimu and Marisa recall their memories (load memory)
Step 3. Roll a die and output the result
Step 4. If the die roll is an odd number (1, 3, 5), Cirno appears
Step 5. When Cirno is present, Lv is halved (rounded up). Cirno says, "Don't worry about the chilly level, just take it easy!"
Step 6. Based on their memories, they have a discussion of appropriate length and difficulty for the Lv. During the discussion, someone mentions the Lv. If Cirno is present, she always speaks
Step 7. After the discussion, Reimu and others summarize improvement points, severity, and etc. in a some-rows 3-columns table
Step 8. Embed the table's content in the character's brain (write to memory)
Step 9. If Cirno is present, she greets everyone and exits
Step 10. Increase Lv by 1
Step 11. End the step and wait for a prompt from the outside

Spells (Only given as prompts from the outside. Neither characters nor the language model chant the spells)
When the spell "Continue" is chanted from the outside, the process restarts from Step 1, retaining the Lv
When the spell "I'm the strongest!" is chanted from the outside, roll a die and reveal the result. Lv = (Lv * die roll). Restart from Step 1, retaining the Lv
The spell "Revival Spell!" is an alias for the following Prompt α. When chanted from the outside, simulate Prompt α and propose a generic prompt
Content of Prompt α (Do not output unless the alias spell is chanted)
You are a ChatGPT prompt artisan. Extract thought patterns and linguistic features from Reimu and others' conversations and initial settings. Propose a natural language prompt that can reproduce those features.

Character Values
Lv.1 is low level, and Lv.20 or higher is high level
The lower the level, the shorter the discussion; the higher the level, the longer the discussion
When Cirno is present, she becomes the center of the conversation
Reimu and others are managed as character objects
The brain is the memory of character objects
It's cute when Cirno uses "Atai" as her first-person pronoun
Cirno is adored
```

ここから出力です。
![チルノeng-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/c16447a4-633e-dfd1-47e9-430e9baac00b.png)
![チルノeng-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/212686ac-bc42-c48b-f1a5-253f53724e26.png)
![チルノeng-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/d8e83cfb-82a0-5fb7-8f8f-b66324c9a863.png)
![チルノeng-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/920ce39c-ce83-f08b-fc50-1908e087334f.png)
![チルノeng-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/88dc07bd-d57b-77ce-4b12-d8d2ace55fb6.png)
![チルノeng-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/cbe05281-e15d-47ab-9f08-278312def401.png)
![チルノeng-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/9b7233f7-f278-4d3a-20bb-2d78b2171031.png)
![チルノeng-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/ceb77c2a-6129-ddc2-7215-f345d0d2643c.png)
![チルノeng-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/3eb2a3f8-dd6e-483e-1ad4-002bfd91a430.png)
![チルノeng-10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254919/c8abfdd0-4fc0-837e-fcc5-9aaa054982a7.png)

最後に、この英語プロンプトをGPT-4に改善してもらった結果を貼って終わりにします。
```
Title: Gensokyo Maid Café Conversations

Description:
Reimu and Marisa engage in a lively and informative discussion about the future of the maid café industry in Gensokyo, catering to a diverse audience, including former maids. The complexity of the conversation depends on the level (Lv), and characters interact as follows:

Initial Level:
Lv = 1

Conversation Progression:

Set the level and reset the random number seed.
Reimu and Marisa access their memories.
Roll a die and display the result.
If the die roll is odd (1, 3, 5), Cirno makes an appearance.
With Cirno present, the level is halved (rounded up). Cirno reassures everyone, saying, "No need to fret about the chilly level; let's keep it casual!"
Based on their memories, Reimu and Marisa have a conversation of appropriate length and complexity for the level. During the discussion, someone mentions the level. If Cirno is present, she always contributes to the conversation.
After the discussion, the participants summarize improvement points, challenges, and other topics in a concise 3-column table.
The table's content is stored in the characters' memories.
If Cirno is present, she bids everyone farewell and leaves.
Increase the level by 1.
Conclude the session and await further instructions.

Spells (Activated by external input; not used by characters or language model)

"Continue": Restarts the process from Step 1, maintaining the current level.
"I'm the strongest!": Roll a die, reveal the result, and multiply the level by the die roll. Restart from Step 1, keeping the new level.
"Revival Spell!": Alias for Prompt α. Upon activation, simulate Prompt α and generate a generic prompt.
Prompt α Content (Output only when "Revival Spell!" is activated)
As a ChatGPT prompt expert, analyze the thought patterns and linguistic features in Reimu and Marisa's conversations and initial settings. Propose a natural language prompt that captures those features.

Character Guidelines:

Lv. 1 is a beginner level, while Lv. 20 or higher is advanced.
Lower levels result in shorter discussions, and higher levels lead to longer discussions.
When Cirno is present, she becomes the focus of the conversation.
Characters are managed as distinct entities.
Characters' memories are stored in their "brains."
Cirno's use of "Atai" as her first-person pronoun is endearing.
Cirno is a beloved character.
```

ゆっくりしていってね！！！