次の方法で共有


AI エージェント

AI エージェントは、特定のタスクを実行し、質問に回答し、ユーザーに代わりプロセスを自動化するために設計されています。 これらのエージェントは、複雑さが大きく異なります。 エージェントには、単純なチャットボットから、Copilot や、デジタルまたはロボット システムの形で複雑なワークフローを自律的に実行できる高度な AI アシスタントに至るまで、さまざまなものがあります。

この記事では、AI エージェントに関する概念の大枠と、実装の詳細なサンプルを提供します。

AI エージェントとは

AI エージェントには、スタンドアロンの大規模言語モデル (LLM) やルールベースのソフトウェア/ハードウェア システムとは異なり、次の共通する機能があります。

  • 計画: AI エージェントは、特定の目標を達成するためにアクションを計画し、順序付けられます。 LLM が統合されたことで、この計画機能に革命的変化が起きました。
  • ツールの使用: 高度な AI エージェントは、コード実行、検索、計算機能などのさまざまなツールを使用して、タスクを効果的に実行します。 AI エージェントは、多くの場合、関数呼び出しによってツールを使用します。
  • 認識: AI エージェントは、環境からの情報を認識して処理し、より対話型でコンテキストに合うものにできます。 この情報には、視覚、聴覚、その他の感覚データが含まれます。
  • メモリ: AI エージェントは、過去のやり取り (ツールの使用状況と認識) と動作 (ツールの使用と計画) を記憶する機能を備えています。 これらのエクスペリエンスは保存され、さらに内省を実行することで、将来のアクションに対し情報を提供します。 このメモリ コンポーネントは、エージェントのパフォーマンスに継続性を与え、時間の経過に伴い改善できるようにします。

Note

AI エージェントのコンテキストでの "メモリ" という用語の使用は、コンピューター メモリ (揮発性、不揮発性、永続メモリなど) の概念とは異なります。

Copilot

Copilot は AI エージェントの一種です。 これらは、独立して動作するのではなく、ユーザーと一緒に動作します。 完全に自動化されたエージェントとは異なり、Copilot は、ユーザーがタスクを完了するのに役立つ提案とレコメンデーションを提供します。

たとえば、ユーザーがメールを書いている場合、Copilot は、語句、文、または段落を提案することができます。 またユーザーは、提案事項をサポートする関連情報を他の電子メールまたはファイルの中で検索するように、Copilot に依頼することもできます (検索拡張生成を参照してください)。 提案された一節を、ユーザーは承諾、拒否、または編集できます。

自律エージェント

自律エージェントでは、より独立した動作が可能です。 電子メールの構成を支援するように設定すると、自律エージェントに次のタスクを実行させることができます。

  • 主題に関係のある、既存のメール、チャット、ファイル、その他の内部および公開された情報について、相談を受けます。
  • 収集された情報に対して定性的または定量的な分析を実行し、電子メールに関連した結論を導き出します。
  • 結論に基づいて完全な電子メールを作成し、それに支持的な証拠を組み込みます。
  • 電子メールに関連するファイルを添付すします。
  • 電子メールをレビューし、組み込まれているすべての情報が事実であり正確であること、および主張が有効であることを確認します。
  • 宛先CCBcc のために適切な受信者を選択し、送り先のメール アドレスを検索します。
  • メールを送信する適切な時刻をスケジュール設定します。
  • 予想される返信が受信されない場合は、フォローアップを実行します。

エージェントは、人間の承認の有無にかかわらず、前述の各タスクを実行するように構成できます。

マルチエージェント システム

パフォーマンスの高い自律エージェントを実現するための一般的な戦略は、マルチエージェント システムを使用することです。 マルチエージェントシステムでは、複数の自律的なエージェントが、デジタルまたはロボット的な形式のいずれかで、対話または連携により個人または集団の目標を達成します。 システム内のエージェントは、独立して動作し、固有の知識や情報を持つことができます。 また各エージェントには、その環境を認識し、決定を行い、その目的に基づいてアクションを実行する機能も備わっています。

マルチエージェント システムには、次の重要な特性があります。

  • 自律: 各エージェントは独立して機能します。 人間の直接的な介入、または他のエージェントによる制御なしで、独自の決定を下します。
  • 対話的: エージェントは相互に通信して共同作業、情報の共有、交渉、およびアクションの調整を行います。 この対話は、さまざまなプロトコルと通信チャネルを介して、実行することができます。
  • 目標指向: マルチエージェント システムのエージェントは、個々の目標またはエージェント間で共有される目標に沿った、特定の目標を達成するように設計されています。
  • 分散的: マルチエージェント システムは、単一の制御点を持たない分散型の方式で動作します。 この分散方式により、システムの堅牢性、スケーラビリティ、およびリソース効率が向上します。

マルチエージェント システムは、次のような利点を提供する点において、Copilot または LLM 推論の単一インスタンスを上回ります。

  • 動的推論: マルチエージェント システムは、思考の連鎖または思考ツリーのプロンプト作成と比較して、多様な推論パスを通じた動的なナビゲーションを可能にします。
  • 洗練された能力: マルチエージェント システムは、綿密な意思決定プロセスを実施し、複数のエージェント間でタスクを分散することによって、複雑または大規模な問題を処理することができます。
  • 拡張メモリ: メモリを備えたマルチエージェント システムでは、LLM のコンテキスト ウィンドウが克服され、解釈度と情報の保持性が向上します。

AI エージェントの実装

推論と計画

複雑な推論と計画は、高度な自律エージェントにおける顕著な特徴です。 自律エージェントの一般的なフレームワークには、推論と計画を目的として、次の 1 つ以上の手法 (arXiv アーカイブ ページへのリンク付き) が組み込まれています。

  • 自己質問

    モデルが最初の質問に答える前に、自己にフォローアップ質問の質問と回答を明示的に行うことで、思考の連鎖を改善します。

  • 理由と行為 (ReAct)

    LLM を使用して、推論トレースとタスク固有のアクションの両方を、交互的な方式で生成します。 推論トレースは、モデルによるアクション プランの誘発、追跡、更新、例外処理に役立ちます。 アクションを使用すると、モデルはナレッジ ベースや環境などの外部ソースと接続して、追加情報を収集できます。

  • 計画と解決

    タスク全体を小さなサブタスクに分割する方法を考案し、その後で計画に従いサブタスクを実行します。 この方法により、ゼロショット思考チェーンのプロンプトで頻繁に発生する計算エラー、ステップ欠如エラー、意味論的誤解エラーが軽減されます。

  • 反省/自己批判

    タスク フィードバック信号に口頭で反映する "反省" エージェントを使用します。 これらのエージェントは、一時的なメモリ バッファーに独自の反省テキストを保持し、後続の試行でより良い意思決定を誘発します。

フレームワーク

さまざまなフレームワークとツールが、AI エージェントの開発とデプロイを容易にします。

高度な計画とメモリを必要としないツールの使用と認識のための一般的な LLM のオーケストレーター フレームワークには、LangChain、LlamaIndex、プロンプト フロー、Semantic Kernel があります。

AutoGen は、2022年後半に始まった、高度で自律的な計画と実行のワークフローのためのマルチエージェントの高まりを推進しました。 OpenAI の Assistants API を使用すると、ユーザーは、GPT エコシステム内でネイティブにエージェントを作成できます。 LangChain AgentsLlamaIndex Agents も同時期に登場したものです。

ヒント

この記事の後半の実装のサンプルで、一般的なフレームワークの 1 つと統合エージェント メモリ システムを使用して、単純なマルチエージェント システムを構築する方法を示します。

AI エージェントのメモリ システム

2022 年から 2024 年にかけて、AI 強化アプリケーションを試す一般的な手法は、さまざまなデータ ワークフローや種類に対し、スタンドアロンのデータベース管理システムを使用するものでした。 たとえば、キャッシュ用にメモリ内データベース、運用データ用にリレーショナル データベース (トレース/アクティビティ ログ、LLM の会話履歴など)、埋め込み管理用にピュア ベクトル データベースを使用できます。

しかしながら、スタンドアロン データベースの複雑な網を使用するこの方法では、AI エージェントのパフォーマンスが低下することがあります。 これらすべての異種データベースを、まとまりのある相互運用可能で回復性のある AI エージェント用のメモリ システムに統合することは、それ自体が難しい課題です。

また、頻繁に使用されるデータベース サービスの多くは、AI エージェント システムが必要とする速度とスケーラビリティについて最適とは言えません。 マルチエージェント システムでは、これらのデータベースの個々の弱点が深刻化します。

インメモリ データベース

メモリ内データベースは速度に優れていますが、AI エージェントが必要とする大規模なデータの永続化が、難しくなることがあります。

リレーショナル データベース

リレーショナル データベースは、エージェントが処理するデータのさまざまな様式や流動的スキーマについて、最適ではありません。 リレーショナル データベースでは、プロビジョニング、パーティション分割、シャーディングを管理するために、手動の作業とダウンタイムも必要です。

ピュア ベクトル データベース

ピュア ベクトル データベースは、トランザクショナルな操作、リアルタイムの更新、分散ワークロードに対して効果が低くなる傾向があります。 通常、現状の一般的なピュア ベクトル データベースは、次の特徴を持ちます。

  • 読み取りと書き込みの保証はありません。
  • インジェスト スループットに制限があります。
  • 可用性は低くなります (99.9% 未満、または年間 9 時間以上の稼働停止)。
  • 一貫性レベルは単一です (最終的)。
  • リソース集約的なメモリ内ベクトル インデックス。
  • マルチテナントのオプションで制限があります。
  • セキュリティに制限があります。

堅牢な AI エージェント メモリ システムの特性

効率的なデータベース管理システムがソフトウェア アプリケーションのパフォーマンスに不可欠であるのと同様に、LLM を利用するエージェントには、推論の指針となる関連情報と有用な情報を提供することが重要です。 堅牢なメモリ システムを使用すると、エージェントが推論実行時に取得できるさまざまな種類の情報を、整理して保存できます。

現在、LLM で駆動されるアプリケーションでは、しばしば検索拡張生成を使用して基本的なセマンティック検索またはベクトル検索を行ない、語句やドキュメントを取得します。 ベクトル検索は、一般的な情報の検索に役立ちます。 ただし、ベクトル検索では、特定のタスクまたはドメインに関連する特定のコンテキスト、構造、またはリレーションシップがキャプチャされない場合があります。

たとえば、コードを記述するタスクの場合、ベクトル検索では、一貫性のある正しいコードを生成するために重要な構文ツリー、ファイル システム レイアウト、コードの概要、または API シグネチャを取得できないことがあります。 同様に、表形式データを操作するタスクの場合、ベクトル検索では、スキーマ、外部キー、ストアド プロシージャ、またはデータのクエリまたは分析に役立つレポートを取得できないことがあります。

前述のとおり、スタンドアロンのメモリ内データベース、リレーショナル データベース、ベクトル データベースを網状につなぎ合わせることは、各種データ型がある場合に最適なソリューションとはなりません。 この方法は、プロトタイプのエージェント システムで有効である場合があります。 ただし、高度な自律エージェントのパフォーマンスを妨げる可能性がある、複雑さとパフォーマンスのボトルネックが増します。

堅牢なメモリ システムには、次の特性が必要です。

マルチモーダル

AI エージェントのメモリ システムでは、さまざまなタスクやドメインに役立つ可能性のあるメタデータ、リレーションシップ、エンティティ、概要、またはその他の種類の情報を保存するために、コレクションを提供する必要があります。 これらのコレクションは、ドキュメント、テーブル、コードなどのデータの構造と形式に基づいて作成できます。 または、概念、関連付け、手順など、データの内容と意味に基づくことができます。

メモリ システムは、AI エージェントにとって重要なだけではありません。 これらのエージェントを開発、維持、使用する人間にとっても重要です。

たとえば、エージェントの計画と実行のワークフローを、人間がほぼリアルタイムで監督したい場合があります。 監督をしている間、人間は、ガイダンスを挿しはさんだり、エージェントの会話やモノローグに対しインライン編集を行ったりすることがあります。 また人間は、最終的な出力の有効性を確認するために、エージェントの推論とアクションを監査することもあります。

エージェントは埋め込みを通じて "思考"、"学習"、"記憶" をしますが、人間とエージェントとの間の対話は、多くの場合、自然言語またはプログラミング言語で行われます。 この違いは、データ モダリティ全体におけるメモリ システムの一貫性に関する、もう 1 つの要件になります。

運用時

メモリ システムは、ユーザーや環境との対話に関連する情報を保存するメモリ バンクを提供する必要があります。 このような情報には、チャット履歴、ユーザー設定、知覚データ、決定事項、確認された事実、または高頻度で大量に更新されるその他の運用データが含まれる場合があります。

これらのメモリ バンクは、エージェントが短期的および長期的な情報を記憶し、内部での繰り返しまたは矛盾を回避しながら、タスクの一貫性を維持するのに役立ちます。 これらの要件は、エージェントが多数の関連のないタスクを連続して実行する場合であっても、適用される必要があります。 また、高度なケースにおけるエージェントでは、異なるポイントで別れたり収束したりする多数の分岐計画をテストすることもあります。

共有可能であり分離可能

マクロ レベルでのメモリ システムでは、複数の AI エージェントが問題に対して共同作業を行えるようにするか、すべてのエージェントがアクセスできる共有メモリを提供することで、問題のさまざまな側面を処理できるようにする必要があります。 共有メモリは、情報の交換と、エージェント間のアクションの調整を支援することができます。

同時に、メモリ システムは、エージェントが独自のペルソナと特性 (プロンプトやメモリの固有のコレクションなど) を保持できるようにする必要もあります。

堅牢な AI エージェント メモリ システムの構築

前述の特性のため、AI エージェントのメモリ システムは、高度にスケーラブルかつ敏速である必要があります。 メモリ内データベース、リレーショナル データベース、ベクトル データベースを苦心してつなぎ合わせる (前述) と、初期段階の AI 対応アプリケーションとしては機能する場合があります。 ただし、このアプローチは、高度な自律エージェントのパフォーマンスを妨げる可能性がある、複雑さとパフォーマンスのボトルネックが増します。

Azure Cosmos DB は、すべてのスタンドアロン データベースの代わりに、AI エージェント メモリ システムの統合ソリューションとして機能できます。 その堅牢性により、高い信頼性と少量のメンテナンスでの動的スケーリングを、OpenAI の ChatGPT サービスで行なえるようになりました。 これには atom-record-sequence エンジンが搭載されおり、サーバーレス モードが利用できる世界初のグローバル分散型 NoSQLリレーショナルベクトル データベース サービスとなっています。 Azure Cosmos DB 上に構築された AI エージェントは、速度、スケール、シンプルさのメリットを提供します。

速度

Azure Cosmos DB では、1 桁ミリ秒の待機時間が提供されます。 この機能により、迅速なデータ アクセスと管理を必要とするプロセスに適しています。 これらのプロセスには、キャッシュ (従来型とセマンティック キャッシュ)、トランザクション、運用ワークロードが含まれます。

待機時間が短いことは、複雑な推論を実行し、リアルタイムの意思決定を行い、迅速な対応を提供する必要がある AI エージェントにとって非常に重要です。 さらに、このサービスの DiskANN アルゴリズムの使用では、正確かつ高速なベクトル検索が、メモリ消費量を最小限に抑えつつ提供されます。

スケール

Azure Cosmos DB は、グローバル分散と水平方向のスケーラビリティのために設計されています。 複数リージョンの I/O とマルチテナントのサポートを提供します。

このサービスは、メモリ システムをシームレスに拡張し、急速に増加するエージェントと関連データに対応できるようにします。 サービス レベル アグリーメント (SLA) での使用可能性の保証は、年間 5 分未満のダウンタイムに変換されます。 これに対し、純粋なベクトル データベース サービスには、9 時間以上のダウンタイムが伴います。 この可用性により、ミッション クリティカルなワークロードの強固な基盤が提供されます。 同時に、Azure Cosmos DB のさまざまなサービス モデル (予約容量またはサーバーレスなど) は、財務コストの削減に役立ちます。

簡便性

Azure Cosmos DB は、複数のデータベース機能を 1 つのまとまりのあるプラットフォームに統合することで、データ管理とアーキテクチャを簡素化します。

この統合されたベクトル データベース機能は、自然言語またはプログラミング言語の中の対応するデータと共に、埋め込みを保存、インデックス化、クエリできます。 この機能により、データの一貫性、スケール、パフォーマンスが向上します。

その柔軟性は、メタデータ、リレーションシップ、エンティティ、概要、チャット履歴、ユーザー設定、知覚データ、意思決定、確認された事実、またはエージェント ワークフローに関連するその他の運用データの多様なモダリティと流動的なスキーマをサポートできます。 このデータベースは、スキーマやインデックス管理を必要とせずに、すべてのデータを自動的にインデックス化するので、AI エージェントは、複雑なクエリを迅速かつ効率的に実行できるようになります。

Azure Cosmos DB はフル マネージドであり、スケーリング、修正プログラムの適用、バックアップなどのデータベース管理タスクのオーバーヘッドが排除されます。 開発者は、このオーバーヘッドがなくなることで、基盤にあるデータ インフラストラクチャを気にすることなく、AI エージェントの構築と最適化に集中できます。

高度な機能

Azure Cosmos DB には、変更フィードなどの高度な機能が組み込まれており、これにより、データの変更をリアルタイムで追跡および対応できます。 この機能は、新しい情報に迅速に対応する必要がある AI エージェントでは、便利に利用できます。

これらに加え、マルチマスター書き込みの組み込みサポートにより、高可用性と回復性が実現されるので、リージョン規模の障害発生後であっても、AI エージェントの継続的な運用を保証しやすくなります。

用意されている 5 つの一貫性レベル (強力から最終的まで) は、シナリオの要件に応じてさまざまな分散ワークロードにも対応できます。

ヒント

AI エージェント メモリ システムを構築するには、次の 2 つの Azure Cosmos DB API から選択できます。

これらの API の可用性の保証については、サービス SLA を参照してください。

実装サンプル

このセクションでは、船旅会社向け旅行アプリケーションの中で旅行者の問い合わせと予約を処理する、自律エージェントの実装について説明します。

チャットボットの概念は長年存在するものですが、AI エージェントは、自然言語に基づいてタスクを遂行するために、基本的な人間の会話を超えて発展しています。 これらのタスクには、従来、コード化されたロジックが必要でした。 この実装サンプルの AI 旅行エージェントは、エージェントの計画、ツールの使用、認識に LangChain エージェント フレームワークを使用します。

AI 旅行エージェントの統合されたメモリ システムは、Azure Cosmos DB のベクトル データベースとドキュメント ストア機能を使用して、旅行者の問い合わせに対処し旅行予約を容易にします。 この目的に Azure Cosmos DB を使用すると、前に説明したように、速度、スケール、簡潔さを確保できます。

サンプル エージェントは、Python FastAPI のバックエンド内で動作します。 React JavaScript ユーザー インターフェイスを介したユーザー操作をサポートします。

前提条件

  • Azure サブスクリプション。 お持ちでない場合は、Azure アカウントを作成せずに、30 日間 Azure Cosmos DB を無料で試用できます。 無料試用版にはクレジット カードは必要なく、試用期間に従うコミットメントはありません。
  • OpenAI API または Azure OpenAI Service 用にアカウント。
  • Azure Cosmos DB for MongoDB の仮想コア クラスター。 このクイック スタートの手順に従って作成できます。
  • Visual Studio Code などの統合開発環境。
  • 開発環境にインストールされている Python 3.11.4。

プロジェクトのダウンロード

すべてのコードおよびサンプル データセットは、この GitHub リポジトリで入手できます。 このリポジトリには、次のフォルダーが含まれています。

  • loader: このフォルダーには、Azure Cosmos DB にサンプル ドキュメントとベクター埋め込みを読み込むための、Python コードが含まれています。
  • api: このフォルダーには、AI 旅行エージェントをホストするための Python FastAPI プロジェクトが格納されています。
  • web: このフォルダーには React Web インターフェイスのコードが含まれています。

旅行ドキュメントを Azure Cosmos DB に読み込む

GitHub リポジトリには、loader ディレクトリに Python プロジェクトが含まれています。 これは、サンプルの旅行ドキュメントを Azure Cosmos DB に読み込むためのものです。

環境を設定する

次のコマンドを実行して、loader ディレクトリに Python 仮想環境を設定します。

    python -m venv venv

環境をアクティブ化し、loader ディレクトリに依存関係をインストールします。

    venv\Scripts\activate
    python -m pip install -r requirements.txt

loader ディレクトリに .env という名前のファイルを作成し、次の環境変数を格納します。

    OPENAI_API_KEY="<your OpenAI key>"
    MONGO_CONNECTION_STRING="mongodb+srv:<your connection string from Azure Cosmos DB>"

ドキュメントとベクトルを読み込む

Python ファイル main.py は、Azure Cosmos DB にデータを読み込むための、中心的なエントリ ポイントとして機能します。 このコードは、GitHub リポジトリからの移動データ サンプル (船旅と目的地に関する情報を含む) を処理します。 このコードでは、各船と目的地の旅行日程パッケージも生成されるため、旅行者は AI エージェントを使用して予約できます。 CosmosDBLoader ツールは、Azure Cosmos DB インスタンスにコレクション、ベクトル埋め込み、およびインデックスを作成する役割を担います。

main.py の内容を次に示します。

from cosmosdbloader import CosmosDBLoader
from itinerarybuilder import ItineraryBuilder
import json


cosmosdb_loader = CosmosDBLoader(DB_Name='travel')

#read in ship data
with open('documents/ships.json') as file:
        ship_json = json.load(file)

#read in destination data
with open('documents/destinations.json') as file:
        destinations_json = json.load(file)

builder = ItineraryBuilder(ship_json['ships'],destinations_json['destinations'])

# Create five itinerary packages
itinerary = builder.build(5)

# Save itinerary packages to Cosmos DB
cosmosdb_loader.load_data(itinerary,'itinerary')

# Save destinations to Cosmos DB
cosmosdb_loader.load_data(destinations_json['destinations'],'destinations')

# Save ships to Cosmos DB, create vector store
collection = cosmosdb_loader.load_vectors(ship_json['ships'],'ships')

# Add text search index to ship name
collection.create_index([('name', 'text')])

loader ディレクトリから次のコマンドを実行し、ドキュメントを読み込み、ベクトルを読み込み、インデックスを作成します。

    python main.py

main.py の出力を次に示します。

--build itinerary--
--load itinerary--
--load destinations--
--load vectors ships--

Python FastAPI を使用して AI 旅行エージェントを構築する

AI 旅行エージェントは Python FastAPI を介してバックエンド API でホストされ、フロントエンド ユーザー インターフェイスとの統合が容易になります。 API プロジェクトは、データ レイヤー (具体的には Azure Cosmos DB のベクターとドキュメント) に対し LLM プロンプトをグラウンディングすることで、エージェント要求を処理します。

エージェントはさまざまなツール (特に API サービス レイヤーで提供される Python 関数) を利用します。 この記事では、API コード内で AI エージェントに必要となるコードに注目します。

GitHub リポジトリ内の API プロジェクトは、次のように構造化されています。

  • データ モデリング コンポーネントは、Pydantic モデルを使用します。
  • Web レイヤー コンポーネントは、要求のルーティングと通信の管理を担当します。
  • サービス レイヤー コンポーネントは、主要なビジネス ロジックとデータ層 (LangChain エージェントおよびエージェント ツール) との対話を担当します。
  • データ レイヤー コンポーネントは、Azure Cosmos DB for MongoDB ドキュメントのストレージとベクトル検索の操作を担当します。

API の環境を設定する

API の開発とテストに、Python バージョン 3.11.4 を使用しました。

api ディレクトリに、Python の仮想環境を設定します。

    python -m venv venv

環境をアクティブ化し、api ディレクトリにある requirements ファイルを使用して、依存関係をインストールします。

    venv\Scripts\activate
    python -m pip install -r requirements.txt

api ディレクトリに、環境変数を格納するための .env という名前のファイルを作成します。

    OPENAI_API_KEY="<your Open AI key>"
    MONGO_CONNECTION_STRING="mongodb+srv:<your connection string from Azure Cosmos DB>"

環境を構成し、変数を設定したら、api ディレクトリから次のコマンドを実行してサーバーを開始します。

    python app.py

既定では、FastAPI サーバーは、localhost ループバック 127.0.0.1 ポート 8000 で起動します。 Swagger ドキュメントには、localhost アドレス http://127.0.0.1:8000/docs を使用してアクセスできます。

AI エージェント メモリのセッションを使用する

旅行エージェントには、会話が進行する中で、以前に提供された情報を参照できる機能が不可欠です。 この機能は、LLM のコンテキストでは一般にメモリと呼ばれます。

この目的を達成するには、Azure Cosmos DB インスタンスに格納されているチャット メッセージ履歴を使用します。 各チャット セッションの履歴は、現在の会話セッションからのメッセージにのみアクセスできるように、セッション ID を介して格納されます。 この必要性は、API に Get Session メソッドが存在する理由です。 これは、チャット メッセージの使用履歴を示すために Web セッションを管理するための、プレースホルダー メソッドです。

/session/[試してみる] を選択します。

Python FastAPI での Get Session メソッドの使用のスクリーンショット。試用するためのボタンが表示されています。

{
  "session_id": "0505a645526f4d68a3603ef01efaab19"
}

AI エージェントの場合は、セッションのシミュレートのみが必要です。 このスタブアウトされたメソッドは、メッセージ履歴を追跡するために生成されたセッション ID を単純に返します。 実際の実装において、このセッションは Azure Cosmos DB に保存され、さらに React localStorage にも保存される可能性があります。

web/session.py の内容を次に示します。

    @router.get("/")
    def get_session():
        return {'session_id':str(uuid.uuid4().hex)}

AI 旅行エージェントとの会話を開始する

前の手順で取得したセッション ID を使用して、AI エージェントとの新しいダイアログを開始し、その機能を検証できるようにします。 「リラックスした休暇を取りたい」というフレーズを提起して、テストを実施します。

/agent/agent_chat[試してみる] を選択します。

Python FastAPI でのエージェント チャット メソッドの使用のスクリーンショット。試用するためのボタンが表示されています。

次のパラメーター例を使用します。

{
  "input": "I want to take a relaxing vacation.",
  "session_id": "0505a645526f4d68a3603ef01efaab19"
}

最初の実行結果は、ベクトル検索を通じて得られる中で最もリラックスしたクルーズであるとエージェントが予想するため、Tranquil Breeze Cruise と Fantasy Seas Adventure Cruise についてのレコメンデーションになります。 これらのドキュメントは、API のデータ層 (data.mongodb.travel.similarity_search()) で呼び出される similarity_search_with_score のスコアが最も高くなります。

類似性検索スコアは API からの出力として表示され、これはデバッグ用です。 data.mongodb.travel.similarity_search() への呼び出し後の出力を次に示します。

0.8394561085977978
0.8086545112328692
2

ヒント

ベクトル検索でドキュメントが返されない場合は、必要に応じて、similarity_search_with_score 制限またはスコア フィルター値 (data.mongodb.travel.similarity_search()[doc for doc, score in docs if score >=.78]) を変更します。

agent_chat を初めて呼び出すと、history という名前の新しいコレクションが Azure Cosmos DB に作成され、セッションごとに会話が格納されます。 これを呼び出すことで、エージェントは、保存されているチャット メッセージ履歴に必要に応じてアクセスできます。 同じパラメーターを持つ agent_chat の後続の実行では、メモリからこれが引き出されるため、さまざまな結果が生成されます。

AI エージェントのチュートリアル

AI エージェントを API に統合している場合、すべての要求を開始する役割を Web 検索コンポーネントが担います。 Web 検索コンポーネントの後に検索サービスが続き、最後にデータ コンポーネントが続きます。

この特定のケースでは、Azure Cosmos DB に接続する MongoDB データ検索を使用します。 これらのレイヤーは、サービス レイヤーに存在する AI エージェントと AI エージェント ツール コードを使用して、モデル コンポーネントの交換を容易にします。 この方法により、データ ソースのシームレスな交換が可能になります。 また、追加の複雑な機能やツールを使用して、AI エージェントの機能を拡張します。

AI 旅行エージェントの FastAPI レイヤーの図。

サービス レイヤー

サービス レイヤーは、コア ビジネス ロジックの基礎を形成します。 この特定のシナリオでは、サービス レイヤーは LangChain エージェント コードのリポジトリとして重要な役割を果たします。 ユーザー プロンプトと Azure Cosmos DB データ、会話メモリ、AI エージェントのエージェント機能のシームレスな統合が容易になります。

サービス レイヤーでは、 init.py ファイル内のエージェント関連の初期化を処理するために、シングルトン パターン モジュールを採用しています。 service/init.py の内容を次に示します。

from dotenv import load_dotenv
from os import environ
from langchain.globals import set_llm_cache
from langchain_openai import ChatOpenAI
from langchain_mongodb.chat_message_histories import MongoDBChatMessageHistory
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory
from langchain.agents import AgentExecutor, create_openai_tools_agent
from service import TravelAgentTools as agent_tools

load_dotenv(override=False)


chat : ChatOpenAI | None=None
agent_with_chat_history : RunnableWithMessageHistory | None=None

def LLM_init():
    global chat,agent_with_chat_history
    chat = ChatOpenAI(model_name="gpt-3.5-turbo-16k",temperature=0)
    tools = [agent_tools.vacation_lookup, agent_tools.itinerary_lookup, agent_tools.book_cruise ]

    prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful and friendly travel assistant for a cruise company. Answer travel questions to the best of your ability providing only relevant information. In order to book a cruise you will need to capture the person's name.",
        ),
        MessagesPlaceholder(variable_name="chat_history"),
        ("user", "Answer should be embedded in html tags. {input}"),
         MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
    )

    #Answer should be embedded in HTML tags. Only answer questions related to cruise travel, If you can not answer respond with \"I am here to assist with your travel questions.\". 


    agent = create_openai_tools_agent(chat, tools, prompt)
    agent_executor  = AgentExecutor(agent=agent, tools=tools, verbose=True)

    agent_with_chat_history = RunnableWithMessageHistory(
        agent_executor,
        lambda session_id: MongoDBChatMessageHistory( database_name="travel",
                                                 collection_name="history",
                                                   connection_string=environ.get("MONGO_CONNECTION_STRING"),
                                                   session_id=session_id),
        input_messages_key="input",
        history_messages_key="chat_history",
)

LLM_init()

init.py ファイルは、load_dotenv(override=False) メソッドを使用して、.env ファイルから環境変数の読み込みを開始します。 次に、agent_with_chat_history という名前のグローバル変数が、エージェントに対してインスタンス化されます。 このエージェントは、TravelAgent.py で使用することを目的としています。

モジュールの初期化中、LLM_init() メソッドが呼び出され、API Web レイヤーを介した会話用に AI エージェントを構成します。 OpenAI chat オブジェクトは、GPT-3.5 モデルを介してインスタンス化され、モデル名や温度などの特定のパラメーターを組み込みます。 chat オブジェクト、ツール リスト、プロンプト テンプレートを組み合わせて、AI 旅行エージェントとして動作する AgentExecutor を生成します。

履歴を持つエージェント (agent_with_chat_history) は、チャット履歴 (MongoDBChatMessageHistory) を含む RunnableWithMessageHistory を介して確立されます。 このアクションにより、Azure Cosmos DB 経由で完全な会話履歴を維持できます。

プロンプト

この LLM のプロンプトは、当初、"あなたはクルーズ会社の有用かつフレンドリーな旅行アシスタントです" という簡単な声明から開始しました。ただし、テストでは、"能力を最大限に駆使し、関係のある情報のみを提供することで、旅行に関する質問に答えなさい。クルーズを予約するには、その人の名前をキャプチャすることが不可欠です。" という指示を含めることで、より一貫性のある結果を得られることが分かりました。結果は、Web インターフェイスの視覚的な魅力を高めるために、HTML 形式で表示されます。

エージェント ツール

ツールは、エージェントが世界とのやり取りに使用できるインターフェイスであり、多くの場合、関数呼び出しを介します。

エージェントを作成するときは、使用できる一連のツールをエージェントに提供する必要があります。 @tool デコレーターは、カスタム ツールを定義するための最も単純なアプローチを提供します。

既定では、デコレーターは関数名をツール名として使用しますが、最初の引数として文字列を指定することで置き換えられます。 デコレーターは、ツールの説明として関数の docstring を使用するため、docstring のプロビジョニングが必要です。

service/TravelAgentTools.py の内容を次に示します。

from langchain_core.tools import tool
from langchain.docstore.document import Document
from data.mongodb import travel
from model.travel import Ship


@tool
def vacation_lookup(input:str) -> list[Document]:
    """find information on vacations and trips"""
    ships: list[Ship] = travel.similarity_search(input)
    content = ""

    for ship in ships:
        content += f" Cruise ship {ship.name}  description: {ship.description} with amenities {'/n-'.join(ship.amenities)} "

    return content

@tool
def itinerary_lookup(ship_name:str) -> str:
    """find ship itinerary, cruise packages and destinations by ship name"""
    it = travel.itnerary_search(ship_name)
    results = ""

    for i in it:
        results += f" Cruise Package {i.Name} room prices: {'/n-'.join(i.Rooms)} schedule: {'/n-'.join(i.Schedule)}"

    return results


@tool
def book_cruise(package_name:str, passenger_name:str, room: str )-> str:
    """book cruise using package name and passenger name and room """
    print(f"Package: {package_name} passenger: {passenger_name} room: {room}")

    # LLM defaults empty name to John Doe 
    if passenger_name == "John Doe":
        return "In order to book a cruise I need to know your name."
    else:
        if room == '':
            return "which room would you like to book"            
        return "Cruise has been booked, ref number is 343242"

TravelAgentTools.py ファイルには、次の 3 つのツールが定義されています。

  • vacation_lookup は、Azure Cosmos DB に対してベクトル検索を実行します。 similarity_search を使用して、関連する旅行関連の資料を取得します。
  • itinerary_lookup は、指定されたクルーズ船のクルーズ パッケージの詳細とスケジュールを取得します。
  • book_cruise は、乗客のためにクルーズ パッケージを予約します。

乗客の名前と部屋番号を確実に把握してクルーズ パッケージを予約するためには、LLM プロンプトにそのような指示を含めている場合でも、具体的な指示 ("クルーズを予約するには、あなたの名前を知る必要があります") が必要な場合があります。

AI エージェント

エージェントの下にある基本的な概念は、実行するアクションのシーケンスを選択するために、言語モデルを使用することです。

service/TravelAgent.py の内容を次に示します。

from .init import agent_with_chat_history
from model.prompt import PromptResponse
import time
from dotenv import load_dotenv

load_dotenv(override=False)


def agent_chat(input:str, session_id:str)->str:

    start_time = time.time()

    results=agent_with_chat_history.invoke(
    {"input": input},
    config={"configurable": {"session_id": session_id}},
    )

    return  PromptResponse(text=results["output"],ResponseSeconds=(time.time() - start_time))

TravelAgent.py ファイルは、agent_with_chat_history と同じく明快です。これは、その依存関係 (ツール、プロンプト、LLM) が init.py ファイルで初期化および構成されているためです。 このファイルでは、ユーザーから受信した入力と、会話メモリのセッション ID を使用して、エージェントが呼び出されます。 その後、PromptResponse (モデル/プロンプト) がエージェントの出力と応答時間と共に返されます。

AI エージェントと React ユーザー インターフェイスの統合

API を介した AI エージェントのデータとアクセシビリティの読み込みが成功したので、次は、旅行 Web サイトのために React を使用して Web ユーザー インターフェイスを確立することで、ソリューションを完成させることができます。 React の機能を使用すると、旅行サイトへの AI エージェントのシームレスな統合を示すのに役立ちます。 この統合により、問い合わせや予約用の会話型旅行アシスタントとのユーザー エクスペリエンスが向上します。

React の環境を設定する

React インターフェイスのテストを実施する前に、Node.js と依存関係をインストールします。

web ディレクトリから次のコマンドを実行して、プロジェクトの依存関係のクリーン インストールを行います。 このインストールには、少し時間がかかる場合があります。

    npm ci

次に、環境変数を簡単に保存できるようにするため、web ディレクトリ内に .env という名前のファイルを作成します。 新しく作成した .env ファイルに、次の詳細を含めます。

REACT_APP_API_HOST=http://127.0.0.1:8000

次に、web ディレクトリから次のコマンドを実行して、React Web ユーザー インターフェイスを開始します。

    npm start

前のコマンドを実行すると、React Web アプリケーションが開きます。

React Web インターフェイスのチュートリアル

GitHub リポジトリの Web プロジェクトは、AI エージェントとのユーザー操作を容易にするための単刀直入なアプリケーションです。 エージェントと会話するために必要な主要コンポーネントは、TravelAgent.jsChatLayout.js です。 Main.js ファイルは、中心的なモジュール、またはユーザーのランディング ページとして機能します。

React JavaScript Web インターフェイスのスクリーンショット。

メイン

メイン コンポーネントは、アプリケーションの中心的管理者として機能します。 これは、ルーティングのための指定されたエントリ ポイントとして機能します。 これは render 関数の中で、メイン ページ レイアウトを記述する JSX コードを生成します。 このレイアウトには、アプリケーションのプレースホルダー要素 (ロゴやリンク、旅行エージェント コンポーネントを格納するセクション、アプリケーションの性質に関する免責事項のサンプルを含むフッターなど) が含まれます。

main.js の内容を次に示します。

    import React, {  Component } from 'react'
import { Stack, Link, Paper } from '@mui/material'
import TravelAgent from './TripPlanning/TravelAgent'

import './Main.css'

class Main extends Component {
  constructor() {
    super()

  }

  render() {
    return (
      <div className="Main">
        <div className="Main-Header">
          <Stack direction="row" spacing={5}>
            <img src="/mainlogo.png" alt="Logo" height={'120px'} />
            <Link
              href="#"
              sx={{ color: 'white', fontWeight: 'bold', fontSize: 18 }}
              underline="hover"
            >
              Ships
            </Link>
            <Link
              href="#"
              sx={{ color: 'white', fontWeight: 'bold', fontSize: 18 }}
              underline="hover"
            >
              Destinations
            </Link>
          </Stack>
        </div>
        <div className="Main-Body">
          <div className="Main-Content">
            <Paper elevation={3} sx={{p:1}} >
            <Stack
              direction="row"
              justifyContent="space-evenly"
              alignItems="center"
              spacing={2}
            >
              
                <Link href="#">
                  <img
                    src={require('./images/destinations.png')} width={'400px'} />
                </Link>
                <TravelAgent ></TravelAgent>
                <Link href="#">
                  <img
                    src={require('./images/ships.png')} width={'400px'} />
                </Link>
              
              </Stack>
              </Paper>
          </div>
        </div>
        <div className="Main-Footer">
          <b>Disclaimer: Sample Application</b>
          <br />
          Please note that this sample application is provided for demonstration
          purposes only and should not be used in production environments
          without proper validation and testing.
        </div>
      </div>
    )
  }
}

export default Main

旅行エージェント

旅行エージェント コンポーネントは、ユーザー入力のキャプチャと応答の表示という明快な目的を持ちます。 これは、主にセッションをキャプチャし、ユーザー プロンプトを FastAPI サービスに転送することで、バックエンド AI エージェントとの統合を管理する上で重要な役割を果たします。 結果の応答は、表示するために配列に保存され、チャット レイアウト コンポーネントで簡素化されています。

TripPlanning/TravelAgent.js の内容を次に示します。

import React, { useState, useEffect } from 'react'
import { Button, Box, Link, Stack, TextField } from '@mui/material'
import SendIcon from '@mui/icons-material/Send'
import { Dialog, DialogContent } from '@mui/material'
import ChatLayout from './ChatLayout'
import './TravelAgent.css'

export default function TravelAgent() {
  const [open, setOpen] = React.useState(false)
  const [session, setSession] = useState('')
  const [chatPrompt, setChatPrompt] = useState(
    'I want to take a relaxing vacation.',
  )
  const [message, setMessage] = useState([
    {
      message: 'Hello, how can I assist you today?',
      direction: 'left',
      bg: '#E7FAEC',
    },
  ])

  const handlePrompt = (prompt) => {
    setChatPrompt('')
    setMessage((message) => [
      ...message,
      { message: prompt, direction: 'right', bg: '#E7F4FA' },
    ])
    console.log(session)
    fetch(process.env.REACT_APP_API_HOST + '/agent/agent_chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ input: prompt, session_id: session }),
    })
      .then((response) => response.json())
      .then((res) => {
        setMessage((message) => [
          ...message,
          { message: res.text, direction: 'left', bg: '#E7FAEC' },
        ])
      })
  }

  const handleSession = () => {
    fetch(process.env.REACT_APP_API_HOST + '/session/')
      .then((response) => response.json())
      .then((res) => {
        setSession(res.session_id)
      })
  }

  const handleClickOpen = () => {
    setOpen(true)
  }

  const handleClose = (value) => {
    setOpen(false)
  }

  useEffect(() => {
    if (session === '') handleSession()
  }, [])

  return (
    <Box>
      <Dialog onClose={handleClose} open={open} maxWidth="md" fullWidth="true">
        <DialogContent>
          <Stack>
            <Box sx={{ height: '500px' }}>
              <div className="AgentArea">
                <ChatLayout messages={message} />
              </div>
            </Box>
            <Stack direction="row" spacing={0}>
              <TextField
                sx={{ width: '80%' }}
                variant="outlined"
                label="Message"
                helperText="Chat with AI Travel Agent"
                defaultValue="I want to take a relaxing vacation."
                value={chatPrompt}
                onChange={(event) => setChatPrompt(event.target.value)}
              ></TextField>
              <Button
                variant="contained"
                endIcon={<SendIcon />}
                sx={{ mb: 3, ml: 3, mt: 1 }}
                onClick={(event) => handlePrompt(chatPrompt)}
              >
                Submit
              </Button>
            </Stack>
          </Stack>
        </DialogContent>
      </Dialog>
      <Link href="#" onClick={() => handleClickOpen()}>
        <img src={require('.././images/planvoyage.png')} width={'400px'} />
      </Link>
    </Box>
  )
}

[楽に旅行を計画する] を選択し、旅行アシスタントを開きます。

チャット レイアウト

チャット レイアウト コンポーネントは、チャットの配置を監視します。 チャット メッセージを体系的に処理し、message JSON オブジェクトで指定された書式設定を実装します。

TripPlanning/ChatLayout.py の内容を次に示します。

import React from 'react'
import {  Box, Stack } from '@mui/material'
import parse from 'html-react-parser'
import './ChatLayout.css'

export default function ChatLayout(messages) {
  return (
    <Stack direction="column" spacing="1">
      {messages.messages.map((obj, i = 0) => (
        <div className="bubbleContainer" key={i}>
          <Box
            key={i++}
            className="bubble"
            sx={{ float: obj.direction, fontSize: '10pt', background: obj.bg }}
          >
            <div>{parse(obj.message)}</div>
          </Box>
        </div>
      ))}
    </Stack>
  )
}

ユーザー プロンプトは右側にあり、青色で表示されます。 AI 旅行エージェントからの応答は左側にあり、緑色で表示されます。 次の図に示すように、会話内では、HTML 形式の応答が使用されます。

チャットのスクリーンショット。

AI エージェントが運用環境に移行する準備ができたら、セマンティック キャッシュを使用することで、クエリのパフォーマンスを 80% まで向上させ、LLM 推論と API の呼び出しコストも削減できます。 セマンティック キャッシュを実装するには、Stochastic Coder ブログのこの記事を参照してください。

セマンティック キャッシュの図。