TadaoYamaokaの開発日記

個人開発しているスマホアプリや将棋AIの開発ネタを中心に書いていきます。

【LLM】guidanceを使ってみる

LLMをプロンプトやチェーンよりも効果的に制御することができるguidanceを試してみた。

LangChainを使うと、複数のプロンプトを組み合わせて、前のプロンプトの回答を次のプロンプトに渡すような処理ができる。
そのような処理をするには、Pythonでプログラミングが必要なため、ユーザ側で簡単に試すことができない。

guidanceを使うと、テキストに記述することで、プロンプトの組み合わせを制御できる。

以下、公式のノートブックのチャットの例を実行してみた結果である。日本語で出力するように一部修正している。
guidance/chat.ipynb at main · microsoft/guidance · GitHub

例1:ゴールを与えて計画を立案する

ゴールだけ与えて、プランのオプションを生成して、その中からベストなプランを選択して、それを基に方法を回答する。
プランのオプションを生成して、その中からベストなプランを選択する部分は、内部で自動的にプロンプトを生成して実行して、ユーザからは見えない。

ガイダンス:

{{#system~}}
You are a helpful assistant.
{{~/system}}
{{#block hidden=True}}
{{#user~}}
I want to {{goal}}.
{{~! generate potential options ~}}
Can you please generate one option for how to accomplish this?
Please make the option very short, at most one line.
{{~/user}}
{{#assistant~}}
{{gen 'options' n=5 temperature=1.0 max_tokens=600}}
{{~/assistant}}
{{/block}}
{{~! generate pros and cons and select the best option ~}}
{{#block hidden=True}}
{{#user~}}
I want to {{goal}}.

Can you please comment on the pros and cons of each of the following options, and then pick the best option?
---{{#each options}}
Option {{@index}}: {{this}}{{/each}}
---
Please discuss each option very briefly (one line for pros, one for cons), and end by saying Best=X, where X is the best option.
{{~/user}}
{{#assistant~}}
{{gen 'prosandcons' temperature=0.0 max_tokens=600}}
{{~/assistant}}
{{/block}}
{{#user~}}
I want to {{goal}}.
{{~! Create a plan }}
Here is my plan:
{{parse_best prosandcons options}}
Please elaborate on this plan, and tell me how to best accomplish it.
Please output in Japanese.
{{~/user}}
{{#assistant~}}
{{gen 'plan' max_tokens=500}}
{{~/assistant}}

ゴール=「読書量を増やす」とした場合の回答:

読書量を増やすための計画を作成します。まず、毎日のルーティンに30分の読書時間をスケジュールすることが重要です。これを実現するためには、以下のような方法があります。

1.スケジュールを作成する:毎日のスケジュールに、30分の読書時間を割り当てることが大切です。スケジュールを作成することで、読書時間を忘れることがなくなります。

2.読書スペースを作る:読書スペースを作ることで、読書に集中しやすくなります。静かな場所や、好きな音楽を聴きながら読書する場所を作ると良いでしょう。

3.本を選ぶ:自分が興味を持つ本を選ぶことが大切です。読みやすい本や、自分の専門分野に関する本を選ぶと、読書に取り組みやすくなります。

4.読書の習慣を身につける:毎日同じ時間に読書することで、読書の習慣を身につけることができます。習慣化することで、読書が自然な行動になります。

以上の方法を実践することで、読書量を増やすことができます。毎日30分の読書時間を確保し、読書の習慣を身につけることが大切です。

「毎日のルーティンに30分の読書時間をスケジュール」の部分は、5つのプランを生成した中から選択した内容になっている。
5つのプランを生成する部分は、ガイダンスで、

{{gen 'options' n=5 temperature=1.0 max_tokens=600}}

のように記述されており、ChatGPTに温度パラメータ=1で、5つの候補を生成させている。

{{parse_best prosandcons options}}

の部分で、ベストな回答を文字列から抽出するためPythonの関数を呼び出している。

def parse_best(prosandcons, options):
    best = re.search(r'Best=(\d+)', prosandcons)
    if not best:
        best =  re.search(r'Best.*?(\d+)', 'Best= option is 3')
    if best:
        best = int(best.group(1))
    else:
        best = 0
    return options[best]

例2:複数の専門家の意見

質問を答えるのに適した専門家を3人挙げさせて、それぞれの専門家が共同で書いたかのように回答をさせる。

ガイダンス:

{{#system~}}
You are a helpful assistant.
{{~/system}}
{{#user~}}
I want a response to the following question:
{{query}}
Who are 3 world-class experts (past or present) who would be great at answering this?
Please don't answer the question or comment on it yet.
{{~/user}}
{{#assistant~}}
{{gen 'experts' temperature=0 max_tokens=300}}
{{~/assistant}}
{{#user~}}
Great, now please answer the question as if these experts had collaborated in writing a joint anonymous answer.
In other words, their identity is not revealed, nor is the fact that there is a panel of experts answering the question.
If the experts would disagree, just present their different positions as alternatives in the answer itself (e.g. 'some might argue... others might argue...').
Please output in Japanese.
Please start your answer with ANSWER:
{{~/user}}
{{#assistant~}}
{{gen 'answer' temperature=0 max_tokens=1500}}
{{~/assistant}}

質問「人生の意味とは?」に対する回答:

人生の意味とは何でしょうか?この問いに対する答えは、多くの哲学者や思想家が長年にわたって探求してきました。私たちのパネルに参加した3人の世界的な専門家たちは、それぞれ異なる観点からこの問いに答えます。

一人目の専門家は、ビクトール・フランクルです。彼は、ホロコーストを生き延びたオーストリアの神経学者であり精神科医です。彼は、自分自身の経験から、人生に意味を見出すことの重要性を説いた『夜と霧』や『意味のある人生』などの著書を執筆しました。フランクルは、人生の意味は、自分自身の内面にあるものであり、自分自身の選択によって見出されるものだと主張しています。

二人目の専門家は、ダライ・ラマです。彼は、チベット仏教の精神的指導者であり、幸福や思いやり、そして人生の目的について広く著作を残しています。彼は、人生の意味は、他者に奉仕することや、自己超越によって見出されるものだと考えています。

三人目の専門家は、アリストテレスです。彼は、古代ギリシャの哲学者であり、倫理学や人間の繁栄の本質について多くの著作を残しました。彼は、人生の究極の目的は、ユダイモニア(繁栄や幸福の状態)を達成することだと主張しています。

これらの専門家たちは、それぞれ異なる観点から人生の意味について語っています。フランクルは、自分自身の内面にある意味を見出すことが重要だと主張し、ダライ・ラマは、他者に奉仕することや自己超越によって意味を見出すことができると考えています。一方、アリストテレスは、繁栄や幸福を追求することが人生の意味だと考えています。これらの異なる観点から、人生の意味について考えることができます。

例3:検索して回答

Bingで検索した結果を基に回答する。

ガイダンス:

{{#system~}}
You are a helpful assistant.
{{~/system}}
{{#user~}}
From now on, whenever your response depends on any factual information, please search the web by using the function <search>query</search> before responding. I will then paste web results in, and you can respond.
{{~/user}}
{{#assistant~}}
Ok, I will do that. Let's do a practice round
{{~/assistant}}
{{>practice_round}}
{{#user~}}
That was great, now let's do another one.
{{~/user}}
{{#assistant~}}
Ok, I'm ready.
{{~/assistant}}
{{#user~}}
{{user_query}}
{{~/user}}
{{#assistant~}}
{{gen "query" stop="</search>"}}{{#if (is_search query)}}</search>{{/if}}
{{~/assistant}}
{{#if (is_search query)}}
{{#user~}}
Search results: {{#each (search query)}}
<result>
{{this.title}}
{{this.snippet}}
</result>{{/each}}
{{~/user}}
{{#assistant~}}
{{gen "answer"}}
{{~/assistant}}
{{/if}}

まず、質問文に対して検索クエリを生成して、
「Search results: {{#each (search query)}}」の部分で、検索する処理を呼び出している。
検索処理は、Pythonの関数としてbingを検索する処理を実装している。

def is_search(completion):
    return '<search>' in completion
def search(query):
    return top_snippets(query, n=3) # bingを検索する処理

質問「What is Microsoft's stock price right now?」に対する回答:

Microsoft's stock price is currently $288.37. Please note that stock prices are constantly changing, so it's best to check an updated source for the most accurate information.

まとめ

LangChainよりも手軽に制御ができるので使いやすいと思う。
LangChainで標準にない処理を実装しようとすると、Chainのクラスを自作する必要があって面倒なのに比べて、ガイダンス言語からPythonの関数を呼び出せるのでより手軽に試せるようになっている。
#ifや#eachで制御構文も使えるので、複雑な処理も実装できる。
なお、オープンソースのLLMを使用する場合は、推論の途中に介入して出力を制御することもできるようだがそちらは試していない。

今のところLangChainの方がベクトルDBへの対応などが標準で用意されているため分がありそうだが、今後guidanceが主流になってくるかもしれない。