[Guidance#1]GPT-4による多段階の推論を試す
Microsoft社が出したGuidanceについて、利用方法をまとめます。
今回はGPT-4を利用した、多段階の推論をしたいというケースを取り上げてみたいと思います。
以下のColabで試せます。
プログラムを定義
全体のコードはこちらになります。guidance('''…''')部分で、まとめて他段階の推論を行なっています。
import os
os.environ['OPENAI_API_KEY'] = "your-openai-api-key"
!pip install guidance
import guidance
import re
# ここでは GPT-4 を使用しますが、gpt-3.5-turbo も利用可能です
guidance.llm = guidance.llms.OpenAI("gpt-4")
# Best=Xを抽出しそのオプション内容を返す関数(Guidance Program内で呼び出す)
def parse_best(prosandcons, options):
best = int(re.findall(r'Best=(\d+)', prosandcons)[0])
return options[best]
create_plan = guidance('''
{{#system~}}
あなたは料理のエキスパートです。
{{~/system}}
{{! 五つの改良案を生成します }}
{{#block hidden=True}}
{{#user~}}
私は{{goal}}です。
改良案を一つ提案してもらえますか?
提案は非常に短く、最大でも一行です。
{{~/user}}
{{#assistant~}}
{{gen 'options' n=5 temperature=1.0 max_tokens=500}}
{{~/assistant}}
{{/block}}
{{! 各改良案の利点と欠点を生成し、最良の改良案を選びます }}
{{#block hidden=True}}
{{#user~}}
私は{{goal}}です。
以下の各改良案の利点と欠点についてコメントし、最良の改良案を選んでいただけますか?
---{{#each options}}
改良案{{@index}}: {{this}}{{/each}}
---
各改良案について非常に簡潔に説明してください(利点は一行、欠点は一行)、そしてBest=Xという形で最良の改良案を教えてください、Xは最良の改良案の番号です。
{{~/user}}
{{#assistant~}}
{{gen 'prosandcons' temperature=0.0 max_tokens=500}}
{{~/assistant}}
{{/block}}
{{! 選択された改良案を達成するための計画を生成します }}
{{#user~}}
私は{{goal}}です。
以下が私の計画です:
{{parse_best prosandcons options}}
この計画について詳しく説明して、最良の達成方法を教えてください。
{{~/user}}
{{#assistant~}}
{{gen 'plan' max_tokens=500}}
{{~/assistant}}''')
out = create_plan(
goal='チキンカレーのレシピを改良したい',
parse_best=parse_best,
echo=True
)
guidance programの文法
guidanceの見通しをよくするため、文法について簡単に解説していきます。
{{ }}を使って変数の呼び出しや関数の実行、論理制御などを行います
{{#role_tag~}} {{~/role_tag}}
これで囲われている部分が指定したロールのメッセージ部分になります。Chat.Completion型のAPIを利用する場合、このロールタグを用いる必要があります
{{#system~}} {{~/system}}
{{#user~}} {{~/user}}
{{#assistant~}} {{~/assistant}}
{{! xxxxx }}
コメントを意味します。プロンプトとしては含まれず実行時に除外されていそうです。
{{~! xxxx }}という形でもコメントは書けるようです。違いはよく分かりません。
{{gen 'xxx' n=5 temperature=1.0 max_tokens=500}}
LLMへの推論部分となります。この{{gen …}}の箇所に該当する生成文字列が'xxx'という変数に格納されます。
`n=`で何回生成するかを指定できます。複数生成した文字列は配列のように呼び出すことができます。今回のユースケースではoptionsで5つ選択肢を指定して、それを後続部分のeachでそれぞれ呼び出しています。
Chat.Completion型の場合は、ロールタグの中に単独で{{gen …}}を指定しないとエラーが出てしまいます。{{#assistant~}} {{gen 'xxx' n=5 temperature=1.0 max_tokens=500}} {{~/assistant}}のように利用します。
{{#block hidden=True}} {{/block}}
このブロックで囲われた部分は、後続の推論時にプロンプトとして含まれない(隠される)ようになっています。前準備のプロセスを含ませたくない場合などに有用なイメージです。
今回のユースケースでは、複数生成した選択肢を全て前提情報として含ませるのではなく、最良の選択肢のみを抽出して利用するようにしています。
Colabで実際に動かしてライブストリーミングの挙動を見ると理解ができると思います。
{{parse_best prosandcons options}}
カスタム関数parse_bestを呼び出すこともできます。以降に続くprosandcons optionsは引数です。
{{parse_best}}で指定した部分は、戻り値に差し変わった形でプロンプトが作成されます。
出力結果
ライブストリーミングで見ると、以下のような3段階の出力結果が出てきます。各ステップはいきなり出力内容が書き変わるので、最初は少し混乱しますが、正常です。
また生成した各種変数はKey-Valueのように呼び出すことが可能です。
# 生成された変数はこのように呼び出すことができます
print(f"Goal: {out['goal']}")
print("\n----------\n")
print(f"Options: {out['options']}")
print("\n----------\n")
print(f"Pros and Cons: {out['prosandcons']}")
print("\n----------\n")
print(f"Plan: {out['plan']}")
ぜひ試してみて下さい!