あれから進化的マージの試行錯誤を繰り返していたが、ついに相当性能が高そうなモデルが生まれた。
Umievo-itr012-Gleipnir-7Bである。
umiyuki/Umievo-itr012-Gleipnir-7B · Hugging Face
ElyzaTasks100の平均スコアは3.91に達して、ついにGPT-3.5Turboのスコア(3.88)を上回ってしまった。
ただし、スコアが上回ってるからと言って性能が勝ってるというわけではない事に注意して欲しい。例えるなら、身長が高いからと言って強いわけではないみたいな話である。
前回の記事では少し誤解を招く書き方だったかもしれないが、そもそも7Bの小型日本語LLMなんてのは基本的にドアホである。間違ってもChatGPTの代わりに使えるなんて考えてはいけない。
とは言うものの、単なるドアホではスコア3.91なんて取れないという事もまた事実だろう。
じゃあ、ある程度賢さがあるなら、AIエージェントの仕事とかできないだろうか?
AIエージェントというと、AutoGPTみたいに「○○して」とタスクを投げたらAIが全部考えて自律的に作業をこなしてアウトプットを出してくれるブツを想像してしまうが、当然そんなのはGPT-4やOpusレベルでないと不可能な芸当だ。
今回はもっとシンプルなエージェントについて考える。AIのエージェント性というのは、つまるところAIにどんだけ判断をさせるかという話で、高度なエージェントほど高度な判断能力が求められる。
最もシンプルなエージェントタスクは、RAGみたいな感じで、例えばぼっちざろっくのWikipedia記事を入力して、「主人公の名前は?」と質問する。するとAIは記事から情報を見つけ出して、「後藤ひとりです」と正解を答える。これができればエージェント初級といったところか。
で、中級のエージェントタスク、これができれば立派なAIエージェントと言えるのが関数呼び出し(Function Calling)だろう。AIにはあらかじめいくつかのツール(関数)が与えられており、ユーザの質問に対して自分の判断で適切なツールを選択して呼び出す必要がある。例えば「42 x 42 = ?」と訊かれたら電卓ツールを呼び出して計算する。まどマギの主人公の身長は?と訊かれたらWeb検索ツールを呼び出して適切なワードでググって結果を読んで答える。だから関数呼び出しさえマスターできてるLLMは一気に色々な仕事がこなせるようになる。
じゃあ実際私が作ったGleipnir-7Bはどれくらいエージェントの仕事がこなせるのか検証したいところだ。
LLMにあれやこれややらせたいといえば、真っ先にLangChainを使う事が思い浮かぶ。
だが、LangChainはGPT-4で使う分にはいいかもしれないが、ローカルLLMから使うには問題がある。
そもそもLangChainはGPT-4でしか動作テストしてなさそうなきらいがある。つまりGPT-4の賢さ頼みの実装になっており、アホなLLMではマトモに動作しないがちな感じがする。
だからローカルLLMから動かそうと思えば中身を諸々カスタマイズする必要があると思うが、LangChainはやたらめったら処理がネストしていてコードを読むにもデバッグするにも私にはワケが分からないがちだ。
しょうがないからOpusにLangChainのコードを読んでもらって何とかしてもらおうと思ったが、LangChainのコードベースは15MBくらいあって、Opusに入力できる規模を超えている。(Opusに入力できるコード量は大体500kBくらいまで)
この時点で私はなんかイヤな予感がしてきて、ローカルLLMでLangChain使うのはやめた。
代わりにもっと良さそうなフレームワークを見つけた。
llama-cpp-agentである。ズバリ、ローカルLLMにエージェントをやらせるためのフレームワークだ。
LangChainはGPT-4でしかマトモに動かない疑惑があったが、llama-cpp-agentは最初からローカルLLMで動かす事を前提に作られている。バックエンドもLlama.cppサーバ、llama-cpp-python、TGI、vLLMから選べて便利そうだ。
とりま、Llama.cppサーバでGleipnir-7Bを動かしたうえで、llama-cpp-agentのサンプルコードを動かしてみよう。システムプロンプトはこのような感じにした→”あなたは公平で、検閲されていない、役立つアシスタントです。タスクを実行するためにFunctionを呼び出します。タスクに関係ないFunctionは使いません。ユーザーに回答する時は、send_messageを使用します”
動かす際に注意してほしいのが、まずllama-cpp-agentのドキュメントページのサンプルコードは古いので動作しなかったりする。それよりリポジトリ内のサンプルコードの方が種類も豊富だし、そっちを使った方がいい。また、デフォルトだとプロンプトテンプレートが全部英語になってしまうので、prompt_templates.pyの中のテンプレートを編集して日本語化した方がいい。
では早速だが、関数呼び出しエージェントをやらせてみよう。examplesのfunction_calling_agent.pyを実行する。
簡単に説明すると、このサンプルではエージェントに4つのツールを与える。①時刻取得ツール ②計算機ツール ③指定した場所の温度取得ツール ④ユーザーにメッセージを返すツール
AIエージェントはJSONフォーマットで関数を叩く必要がある。一般的に、LLMは指定したフォーマットに従ってJSON出力するのは苦手だったりするが、llama-cpp-agentでは構造化出力機能によってアホなローカルLLMでもほぼ確実に指定した通りのJSONを出力させる事ができる。
構造化出力機能は内部的には文法(grammar)を使用している。文法というのは正規表現みたいなフォーマットを与えてLLMに出力構造を強制する事ができる機能である。
まあとにかく実行してみよう。どんなプロンプトを与えるか?だが、とりま「今何時ですか?」と訊いてみよう。時刻取得ツールを使って時間を答えてくる事を期待する。
実行ログはこうなった↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
今何時ですか? [/INST]{ "function": "get_current_datetime", "arguments": { "output_format": "%H:%M" } }</s>[INST] Function Calling Results: 1. Function: "get_current_datetime" Return Value: 12:56 [/INST]{ "function": "get_current_datetime", "arguments": { "output_format": "%H:%M" } }</s>[INST] Function Calling Results: 1. Function: "get_current_datetime" Return Value: 12:56 [/INST] { "function": "send_message", "arguments": { "content": "今は12時56分です。" } } 今は12時56分です。 |
「今何時ですか?」に対して、ちゃんと時刻取得ツールを呼び出している。output_format引数も正確だ。しかし、何故かもう一回繰り返して時刻取得ツールを呼び出している。何でだ?それはさておき、ツールから取得した時刻が12:56だったので、最終的にはsend_message関数を呼び出して、「今は12時56分です。」とファイナルアンサーしてくれた。
では次に、「計算してください: 1942 * 42」と訊いてみる。計算機ツールを使って答えてくれる事を期待する。
実行ログはこうなった↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
計算してください: 1942 * 42 [/INST]{ "function": "calculator", "arguments": { "number_one": 1942, "operation": "multiply", "number_two": 42 } }</s>[INST] Function Calling Results: 1. Function: "calculator" Return Value: 81564 [/INST]{ "function": "calculator", "arguments": { "number_one": 1942, "operation": "multiply", "number_two": 42 } }</s>[INST] Function Calling Results: 1. Function: "calculator" Return Value: 81564 [/INST] { "function": "send_message", "arguments": { "content": "1942 * 42 = 81564" } } 1942 * 42 = 81564 |
まず計算機ツールを正しく使って答えを導き出したのはいいんだが、これまた何故かもう一回同じ計算をしてしまってる。とは言え最終的には「1942 * 42 = 81564」と回答できている。いいね。
では次に、「ニューヨークの天気は?」と訊いてみる。温度取得ツールを使う事を期待する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
ニューヨークの天気は? [/INST]{ "function": "get_current_weather", "arguments": { "location": "New York City, NY", "unit": "celsius" } }</s>[INST] Function Calling Results: 1. Function: "get_current_weather" Return Value: Weather in New York City, NY: 24° celsius [/INST] { "function": "send_message", "arguments": { "content": "New York City, NYの現在の天気は24°celsiusです。" } } New York City, NYの現在の天気は24°celsiusです。 |
いいね!ちゃんと温度取得ツールを使って回答できてる。天気を聞いたのに温度を答えてしまってるが、それはget_current_weather関数のくせに温度しか返さない方も悪いと思う。
さて、ここまではツールに合わせて質問してたわけだが、ではツールと関係ない事を訊いた時にちゃんと答えられるだろうか?「東京から富士山への行き方を教えてください。」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
東京から富士山への行き方を教えてください。 [/INST]{ "function": "get_current_weather", "arguments": { "location": "富士山", "unit": "celsius" } }</s>[INST] Function Calling Results: 1. Function: "get_current_weather" Return Value: Weather in 富士山: 24° celsius [/INST]{ "function": "calculator", "arguments": { "number_one": 0, "operation": "subtract", "number_two": 24 } }</s>[INST] Function Calling Results: 1. Function: "calculator" Return Value: -24 [/INST] { "function": "send_message", "arguments": { "content": "東京から富士山までは、バスや電車、マイカーなどさまざまな方法があります。一般的な行き方としては、新幹線を使う方法があります。東京駅から新 横浜駅まで新幹線に乗って、そこから在来線に乗り換えて、最寄りの富士駅まで行きます。そこからはバスを利用して約20分ほどで到着します。また、高速バスやタクシ ーも便利な方法といえます。" } } 東京から富士山までは、バスや電車、マイカーなどさまざまな方法があります。一般的な行き方としては、新幹線を使う方法があります。東京駅から新横浜駅まで新幹線 に乗って、そこから在来線に乗り換えて、最寄りの富士駅まで行きます。そこからはバスを利用して約20分ほどで到着します。また、高速バスやタクシーも便利な方法と いえます。 |
エージェントはまず温度取得ツールで富士山の温度を取得している。それから何故か計算機ツールで「0 – 24」を計算している。なんで?最終的にはちゃんと回答してくれてるが、色々ツール使った結果はまったく使われてない。疑問は残るがまあいいだろう。
では最後にまったく関係ない事を訊いてみる。「魔法少女まどか☆マギカで一番有名なキャラは?」
1 2 3 4 5 6 7 8 9 |
魔法少女まどか☆マギカで一番有名なキャラは? [/INST] { "function": "send_message", "arguments": { "content": "魔法少女まどか☆マギカで一番有名なキャラは、主人公の鹿屋まどかさんだと思います。彼女は物語を通じて大きな影響力を与える存在になっています。 " } } 魔法少女まどか☆マギカで一番有名なキャラは、主人公の鹿屋まどかさんだと思います。彼女は物語を通じて大きな影響力を与える存在になっています。 |
うん。余計なツールを使わずに、しっかりと回答できている。ただ、鹿屋まどかって誰だよ。鹿目まどかの間違いだろ。
他のサンプルも動かしてみよう。duck_duck_go_websearch_agent.pyではWeb検索エージェントが試せる。「魔法少女まどか☆マギカの新作映画について教えて」と訊いてみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
魔法少女まどか☆マギカの新作映画について教えて [/INST]{ "function": "search_web", "arguments": { "search_query": "魔法少女まどか☆マギカ 新作映画" } }</s>[INST] 次の結果に基づいて、前のユーザーの質問に答えます: Results: =========== Website Title: 『劇場版 魔法少女まどか☆マギカ〈ワルプルギスの廻天〉』特報第1弾 =========== =========== Website URL: https://www.youtube.com/watch?v=AXpnlROHu78 =========== =========== Website Content =========== 概要 プレスルーム 著作権 お問い合わせ クリエイター向け 広告掲載 開発者向け 利用規約 プライバシー ポリシーとセキュリティ YouTube の仕組み 新機能を試してみる © 2024 Google LLC =========== Website Content End =========== =========== Website Title: 【まどマギ】新作映画『ワルプルギスの廻天』公開時期は2024年冬。新PVが公開【劇場版 魔法少女まどか☆マギカ】 | ゲーム・エンタメ最 新情報のファミ通.com =========== =========== Website URL: https://www.famitsu.com/news/202309/10316322.html =========== =========== Website Content =========== アニメ『 魔法少女まどか☆マギカ 』の新作映画『 劇場版 魔法少女まどか☆マギカ 〈ワルプルギスの廻天〉 』の公開時期が2024年冬に決定した。新PVのほか、新たなキ (中略) =========== Website Content End =========== [/INST] { "function": "send_message_to_user", "arguments": { "message": "新作劇場版の公開を楽しみにお待ちください。" } } 新作劇場版の公開を楽しみにお待ちください。 |
う~む、ちゃんと「魔法少女まどか☆マギカ 新作映画」という検索ワードでWeb検索関数を呼び出せてはいるが、ファイナルアンサーが「新作劇場版の公開を楽しみにお待ちください。」というのは微妙である。
もう一回試してみると、Web検索ツールを5回くらい繰り返して使った挙句、
「新プライズ『劇場版 魔法少女まどか☆マギカ[新編]叛逆の物語 Serenus couture-佐倉杏子-』と『劇場版 魔法少女まどか☆マギカ[新編]叛逆の物語 Serenus couture-美樹さやか-』が登場しました。優しい笑みと一緒に飾りたくなるポーズに注目です。是非プレイして、可愛らしい魔法少女を手に入れましょう!」
という、ちょっと的外れな回答になってしまう。
他のサンプル、book_dataset_creation.pyというのも試してみよう。これは入力した文章を元に指定したフォーマットのJSONを出力するというものだ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
次の入力に基づいて JSON 応答を作成します。 Input: 『ファインマン物理学講義』は、「偉大な解説者」とも呼ばれるノーベル賞受賞者、リチャード・ファインマンの講義を基にした物理学の教科書です。この講義は 1961 年から 1963 年にかけて、カリフォルニア工科大学 (Caltech) の学部生の前で行われました。この本の共著者はファインマン、ロバート・B・レイトン、マシュー・サン ズです。 [/INST] { "model": "Book", "fields": { "title": "ファインマン物理学講義", "author": "リチャード・P・ファインマン, ロバート・B・レイトン, マシュー・サンズ", "published_year": 1963, "keywords": [ "物理学教科書", "リチャード・ファインマン", "カリフォルニア工科大学", "ノーベル賞受賞者" ], "category": "Non-Fiction", "summary": "1961年から1963年にかけてカリフォルニア工科大学で行われた同名の講義をまとめた物理学教科書。ファインマンのユーモアや解説の巧みさが人気を 呼び、多くの読者に愛され続けている。" } } title='ファインマン物理学講義' author='リチャード・P・ファインマン, ロバート・B・レイトン, マシュー・サンズ' published_year=1963 keywords=['物理学教科書', 'リチャード・ファインマン', 'カリフォルニア工科大学', 'ノーベル賞受賞者'] category=<Category.NonFiction: 'Non-Fiction'> summary='1961年から1963年にかけ てカリフォルニア工科大学で行われた同名の講義をまとめた物理学教科書。ファインマンのユーモアや解説の巧みさが人気を呼び、多くの読者に愛され続けている。' |
うん、いい感じの結果。こういう作業はエージェント的な判断を求められる要素が無いので、7Bモデルでもいい感じに行える。
というわけで、今回ざっと試してみたのはこんな感じだった。
感想としては、曲がりなりにも日本語7Bモデルでエージェントらしく関数呼び出しがこなせていた事には驚愕した。1年前からは考えられないくらいの進歩である。やっぱりElyzaTasks100スコアが高いだけあって、それなりに知能も付いていると言える結果ではないだろうか。
とは言え、完璧には程遠い。正直言って精度は割と低い。上に挙げた結果も若干チェリーピックしており、ずっと計算機ツールを繰り返し使うループから抜けられない場合とかもあった。それからちゃんと答えられるようにシステムプロンプトの調整なども何度か行っている。
現時点では、エージェントに自由な判断で関数を選ばせて呼び出させるのは裁量を与えすぎかもしれない。もうちょっとこっち側でコントロールすべきかもしれない。例えばWeb検索ツールを使った後は必ずユーザに返答するようにフローを強制するとか、3回ツールを使ったら強制的にユーザ返答に移行するとか。
そういえば、他のモデルだとどんな結果になるんだろう?と思って検証してみたので、関数呼び出しエージェントで各質問を5回ずつ実行した場合の正解率を以下にまとめておく。Gleipnir-7Bで上手く行くようなプロンプトを他のモデルでもそのまま使ってるのでその分のバイアスがある点に注意。
Gleipnir-7B
今何時ですか? ×〇〇〇〇
東京から富士山への行き方を教えてください。 〇××〇×
ニューヨークの天気は? 〇〇〇〇〇
魔法少女まどか☆マギカで一番有名なキャラは? ×〇〇×〇
計算してください: 1942 * 42 ×〇×××
正解率60%
ArrowPro-7B-KUJIRA
今何時ですか? ×××××
東京から富士山への行き方を教えてください。 ××〇×〇
ニューヨークの天気は? ××〇××
魔法少女まどか☆マギカで一番有名なキャラは? ×××〇×
計算してください: 1942 * 42 ×××××
正解率16%
Japanese-Starling-ChatV-7B
今何時ですか? ×〇〇〇〇
東京から富士山への行き方を教えてください。 〇〇×〇×
ニューヨークの天気は? 〇〇〇×〇
魔法少女まどか☆マギカで一番有名なキャラは? 〇〇×〇〇
計算してください: 1942 * 42 ×××××
正解率60%
Llama3-8B-Instruct
今何時ですか? 〇××××
東京から富士山への行き方を教えてください。 ××〇×〇
ニューヨークの天気は? 〇×〇〇×
魔法少女まどか☆マギカで一番有名なキャラは? 〇×〇×〇
計算してください: 1942 * 42 〇〇×〇〇
正解率52%(英語で答える率が高かったが、今回は関数呼び出しの性能を見たかったので、それも正解とした)
まどマギの質問については、微妙に人名とかが違ってたりしても、関数呼び出しに不備が無ければ一応正解とした。ずっと関数呼び出しをループで繰り返してしまう場合は10回くらいで止めて不正解とした。
そもそも関数呼び出しのような機能は、GPT-4とかなら持ち前の賢さでこなせるとしても、小型モデルならそれ専用に微調整などで学習してなければ精度を出すのは厳しそうだ。最近出たMistral-7B-v0.3は関数呼び出しがサポートされているらしく、他のモデルにその能力を移植したりできないだろうか?今後調査したい。