Knative を使用した LLM エージェントの概要 ¶
公開日:2024-07-17
Knative を使用した LLM エージェントの概要¶
著者:Calum Murray、Red Hat のソフトウェアエンジニアリングインターン
LLM は変革的なテクノロジーであり、ユーザーとソフトウェアシステム間の新しい相互作用を可能にします。しかし、LLM がユーザーに正しい回答を与えるようにするにはどうすればよいでしょうか?LLM を単なる質問応答/要約ツール以上のものとして使用し、ユーザーに代わって行動を起こさせることはできますか?
LLM エージェントとツール呼び出しは、この分野で台頭しているパターンの一部であり、LLM が他のツールやモデルと対話し、正確性の問題の大部分を解決し、LLM にユーザーのために行動を起こす力を与えます。これらの利点すべてを考慮して、Knative コミュニティでは、LLM エージェントシステムをより簡単に、そしてシステムの残りの部分の構築方法とより一致した方法(宣言型およびクラウドネイティブ)で構築できるようにする方法を探していました。このブログ投稿では、まず LLM エージェントとは何か、そして LLM がどのようにツールを呼び出すことができるかについて説明し、次に Knative がこのパラダイムにどのように適合すると考えているかについて説明します。
エージェントとは何か¶
AI において、エージェントは、その環境に関する情報を取得し、その情報を使用して意思決定を行い、目標を達成するための行動を起こすことができるシステムとして定義されます。LLM のコンテキストでは、エージェントは、その中心に LLM を持つシステムであり、受信したプロンプトに応答するためにどのような行動をとるかを決定できます。LLM エージェントが実行できる最も一般的なアクションは、ユーザーにテキストまたはその他のメディアを送信すること、ユーザーの回答に役立つツールを呼び出すこと、およびユーザーの回答に役立つ別のエージェントを呼び出すことです。一般的に、LLM エージェントには、その役割を説明し、ツールを呼び出すタイミングやユーザーに返信するタイミングに関するいくつかのルールを与えるシステムプロンプトもあります。ほとんどのエージェントでは、制御フローを次のように示すことができます。
他の形式のエージェントと比較して LLM エージェントの重要な特性の 1 つは、より多くのツールを呼び出すか、LLM を再度呼び出すか、別のエージェントを呼び出すか、処理を終了するかについての決定が、他の形式のロジック(手動でコーディングされたものか AI/ML ベースのものか)ではなく、LLM によって行われることです。そのため、上記の図では LLM とエージェントは 2 つの別個のエンティティとして示されていますが、一般的には同じエンティティです。ツールまたはエージェントの呼び出しが完了するたびに、その情報は LLM に送信され、その情報を使用して何をすべきかを決定します。場合によっては、LLM は自身を再度呼び出すことを決定します。たとえば、LLM が他のエージェントやツールを呼び出す前にユーザーにテキストを送信したい場合に、これが発生することが確認されています。
LLM はどのようにツールを呼び出すか¶
LLM がツールを呼び出すために必要なのは、LLM が呼び出したいツールと、ツールに提供したい引数(ある場合)を伝える方法だけです。LLM の出力はトークンのシーケンスにすぎないため、この情報を出力から解析できる何らかの外部システムが必要であるため、LLM はツールをできるだけ正確に呼び出せるように、一貫した方法で構造化されたデータまたは半構造化データを出力する必要があります。これを行う方法には複数の異なる API があり、現在では使用している正確なモデルによって多少異なります(異なる方法で処理するようにトレーニングされているため)。このブログの目的では、これを行うために OpenAI チャットAPI を具体的に見ていきますが、概念は他のモデルでも一般的に同じです。
OpenAI チャットAPI では、LLM が使用できるツールのリストを渡すように求められます。提供する必要がある重要な情報は、ツールのname
と、ツールが受け入れる可能性のあるparameters
です。各パラメーターについて、パラメーターの型、その用途、およびその名前に関する情報も提供する必要があります。これにより、LLM はツールをできるだけ正確に呼び出すことができます。例として、次の JSON オブジェクトは有効なツールです。
{
"type": "function",
"function": {
"name": "get_current_weather",
"description": "Get the current weather in a given location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. San Francisco, CA",
},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["location"],
},
},
}
この JSON オブジェクトは、LLM がget_current_weather
関数を呼び出す可能性のある OpenAI チャットAPI へのすべての呼び出しに含まれます。含まれていない場合、LLM はツールを認識せず、呼び出すことができなくなります。
LLM がツールのセットで呼び出されると、ツールを呼び出すかどうか、どのツールを呼び出すか、どのパラメーターで呼び出すかを決定できます。モデルがツール呼び出しを行いたいかどうかを確認する方法は、応答メッセージのtool_calls
プロパティを確認することです。たとえば、Python では次のように行います。
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
そこから、呼び出すツールの配列と、各ツールに渡す引数が得られます。そのため、ツールを呼び出すには、LLM が提供することを選択した引数を使用して、何らかの関数またはクラスメソッドを呼び出す必要があります。
LLM ツール呼び出しに Knative を使用する¶
LLMがツールを呼び出す方法を調査している中で、多くのツールが単純なAPIラッパーであることに気づきました。これらはLLMから提供されたパラメータを受け取り、何らかの形式のAPI呼び出しにマッピングします。また、LLMはツールの名前とその受け入れるパラメータしか認識しないため、APIラッパーではないツールも非常に簡単にAPIラッパーに変換できることに気づきました(例えば、ツールのロジックをKnative Functionに配置し、LinuxコンテナとしてビルドしてKnative Serviceとしてデプロイするなど)。しかし、なぜこれが重要なのでしょうか?
すべてのツールがAPIラッパーである場合、システム内の任意のツールを定義するために必要なものは以下の通りです。
- ツールの名前
- ツールの説明
- ツールが受け入れるパラメータ
- パラメータをツールのAPIにマッピングする方法
上記のリストのすべてがツールの単なる *メタデータ* であり、これらの4つのメタデータを使用して、LLMが呼び出すことができる *任意の* ツールを定義できることに注意してください。これは非常に重要な結果であり、ツール呼び出しを一般化し、ツールを呼び出すコードからツールの定義を抽出することができます。言い換えれば、LLMメッセージに基づいてツールを呼び出すためのコードを一度記述し、システム内のツールのメタデータを使用して各ツールの詳細を処理できます。
Knativeには、このメタデータを記録するためのカスタムリソースであるEventTypeが既に存在します。EventTypeはもともと、Knative Eventingシステムに存在するCloudEventのタイプをモデル化するために作成されたため、Event Consumerに取り組んでいる開発者は、利用可能なものとその消費方法を簡単に把握できます。しかし、同じ情報を使用して、サービスが受信することを期待するもの(この場合はLLMからのツール呼び出し)を記述することもできます。EventTypeは、変更を加えることなく、LLM Agentで使用可能なツールと、それらの呼び出し方法を記述するために使用できます。
例として、特定の場所の現在の天気情報を返すサービスがあるとします。このサービスが期待する契約をEventTypeで表すことができます。
apiVersion: eventing.knative.dev/v1beta2
kind: EventType
metadata:
name: get.current.weather
spec:
reference:
apiVersion: serving.knative.dev/v1
kind: Service
name: get-current-weather
description: "Get the current weather in a given location."
schemaData: '{"location":{"type":"string","description":"The city and state, e.g. San Francisco, CA"},"unit":{"type":"string","description":"One of [celsius, farenheit]"}}'
type: "get.current.weather"
EventTypeの説明は、LLMが期待するツールの説明に直接マッピングできます。名前はEventTypeリソースの名前から取得できます(ただし、OpenAIモデルでは、ツール名はa-z、A-Z、0-9、アンダースコア、ハイフンのみを使用し、最大長は64文字である必要があるため、名前の処理を行う必要がある場合があります)。関数の場合は、EventTypeの`schemaData`を解析することで取得できます。
前述のように、EventTypeリソースには、LLMにサービスの呼び出し方を伝えるためのすべての情報が含まれています。ツール呼び出しを含むLLMからのメッセージを使用してツールを呼び出すには、EventTypeの`schemaData`と`type`フィールドを使用して、正しいデータを持つCloudEventを作成し、それを正しいサービスに送信するだけです。サービスに送信するには、以下のいずれかの方法があります。
- specからの参照をURIに解決し、直接呼び出す
- Knative Brokerを使用して、すべてのツール呼び出しを正しいKnative Serviceにディスパッチする
Brokerを使用することの多くの利点(配信の再試行、Apache Kafkaなどの永続的なメッセージテクノロジーによるBrokerのバックエンドなど)を考慮して、すべてのツール呼び出しを正しいServiceにディスパッチするためにBrokerを使用することにしました。ツール呼び出しの結果を含む応答を返すため(Brokerがイベントを受信したことを確認するだけではありません)、リクエスト・リプライのセマンティクスを提供するBrokerの前に配置されるデプロイメントを追加しました。このデプロイメントは新しいカスタムリソースを通じて追加する予定です。詳細と動作については、こちらのissueを参照してください。
このようにして、LLM Agentがサービスの呼び出し方法を学習するために必要なことは、以下の通りです。
- 特定の種類のイベントを選択するフィルタを使用して、Brokerからサービスへのトリガーを作成する
- 同じ`type`を持つEventTypeを作成し、`schemaData`を使用してサービスのAPIを記述する
まとめ¶
このブログ記事では、LLM Agentとは何か、LLMがどのようにツールを呼び出すか、そしてKnativeがメタデータを使用してツール呼び出しを簡素化する方法について説明しました。Knativeを使用してツール呼び出しと検出を簡素化するLLM Agentシステムの構築方法、そしてこのテクノロジーの今後の進化の方向性にご興味のある方は、近日公開予定のこのトピックに関する次のブログにご注目ください。このトピックに関するご質問がありましたら、CNCF SlackインスタンスのKnativeチャンネルでご連絡ください。