LLMエージェント・オーケストレーション:LangChainとGraniteによるステップ・バイ・ステップ・ガイド

著者

Vrunda Gadesha

AI Advocate | Technical Content Author

LLMエージェント・オーケストレーションとは、AIシステム内で複雑なタスクを実行するために、大規模言語モデル(LLM)とさまざまなツール、API、またはプロセス間のやり取りを管理および調整するプロセスを指します。これには、人工知能を搭載したAIエージェントが中心的な意思決定者または推論エンジンとして機能し、外部システムからの入力、コンテキスト、出力に基づいてアクションを調整するワークフローの構築が含まれます。オーケストレーション・フレームワークを使用することで、LLMはAPI、データベース、その他のAIアプリケーションとシームレスに統合できるため、チャットボットや自動化ツールなどの機能が利用可能になります。オープンソース・エージェント・フレームワークは、これらのシステムの適応性をさらに強化し、LLMを現実世界のシナリオでより効果的にします。

多くの人が、LLM オーケストレーションとLLMエージェント・オーケストレーションの違いについて誤解しています。次の図では、主な違いを明確にしています。

LLMオーケストレーションとLLMエージェント・オーケストレーションの主な違いを示す図 LLMオーケストレーションとLLMエージェント・オーケストレーションの主な違い

このチュートリアルでは、 IBM® GraniteモデルLangChainを使用して、大規模言語モデル(LLM)を活用した自律型エージェントを構築する方法を学習します。エージェントがメモリーや計画、アクションなどの主要なコンポーネントを活用して、インテリジェントなタスクを実行する方法を説明します。また、本のテキストを処理し、動的にクエリに回答し、BLEU、精度、想起、F1スコアなどのメトリクスを使用してその性能を評価する実用的なシステムを実装します。

LLMベースの自律型エージェントのフレームワーク

図1に示すフレームワークは、プロファイル、メモリー、計画、アクションという主要なコンポーネント間の連携を重視した、大規模言語モデル(LLM)をベースとした自律型エージェントの総合的な設計を表しています。各コンポーネントは、推論、意思決定、動的な環境との対話が可能な自律型エージェントを構築する上で、重要な段階を表しています。1

LLMをベースとした自律型エージェントのフレームワーク LLMをベースとした自律型エージェントのフレームワーク

1. プロファイル:エージェントのアイデンティティーを定義する

このプロファイルには、人口統計、個性の特徴、社会的文脈などの情報を埋め込むことで、エージェントにアイデンティティーを与えます。このプロセスにより、エージェントはパーソナライズされた方法で対話できるようになります。プロファイルは手動で作成したり、IBM GraniteモデルやOpenAIのGPT(Genative Pretrained Transformer)などの生成AIモデルによって生成する、またはタスク要件を満たすために特定のデータセットに合わせて調整することもできます。プロンプト・エンジニアリングを活用することで、プロファイルを動的に調整し、応答を最適化できます。さらに、マルチエージェント・オーケストレーションでは、プロファイルはロールと動作を定義するのに役立ち、AIアルゴリズムと意思決定システム全体のシームレスな調整を確保します。

2. メモリー:コンテキストの保管と使用

メモリーは、エージェントが過去の対話を保持して取得するのに役立ち、状況に応じた応答を可能にします。これは、ユニファイド(すべてのデータを1か所に統合)またはハイブリッド(構造化および非構造化)のいずれかとなります。読み取り、書き込み、反省を含むオペレーションにより、エージェントは経験から学習し、情報に基づいた一貫性のある出力を提供できます。適切に構造化されたメモリーにより、特定のタスクのために設計された特殊エージェントを含むさまざまなエージェントが、関連データを効率的に共有および取得できるようになり、マルチエージェント・オーケストレーションが強化されます。AutoGenやCrew AIなどのフレームワークでは、メモリーは連携エージェントのエコシステム内で継続性を維持し、シームレスな調整と最適化されたタスク実行を確保する上で重要な役割を果たします。

3. 計画:アクションの戦略化

計画コンポーネントでは、エージェントは目標を達成するためのストラテジーを考案できます。エージェントは、事前定義された手順に従うことも、環境、人間、またはLLM自体からのフィードバックに基づいて動的に適応することもできます。AIアルゴリズムを統合し、ナレッジ・ベースを活用することで、計画を最適化し、推論の効率と問題解決の精度を向上させることができます。LLMアプリケーションでは、自然言語の理解と意思決定プロセスをエージェントの目的に確実に沿ったものにする上で、計画が重要な役割を果たします。さらに、検索拡張技術により、エージェントが関連情報に動的にアクセスする能力が強化され、応答の精度が向上します。この柔軟性により、エージェントは変化するシナリオ、特にマルチエージェント・オーケストレーションにおいて効果的であり続けることができます。このようなマルチエージェント オーケストレーションでは、さまざまなエージェントが複雑な目標を達成するために計画を調整し、同時に大規模で多様なタスクを処理するための拡張性を維持します。

4. アクション: 決定の実行

アクションとは、タスクの完了、情報の収集、コミュニケーションなど、エージェントが世界と対話する方法のことです。メモリーと計画を使用して実行を導き、必要に応じてツールを使用し、結果に基づいて内部状態を適応させ、継続的な改善を実現します。アクション実行アルゴリズムを最適化すると効率が向上し、特にGPTを利用した推論モデルと生成AI技術を統合してリアルタイムの意思決定を行う際は、それが顕著になります。

これらのコンポーネントを組み合わせることで、このフレームワークは、LLMを自律的に推論、学習、実行できる適応可能なエージェントに変換します。このモジュール式設計は、カスタマー・サービス、調査支援、クリエイティブな問題解決などのアプリケーションに最適です。

ユースケース: 照会可能なナレッジ・エージェントの構築

このチュートリアルでは、大規模なテキスト文書(書籍など)を処理し、ユーザーの質問に正確に答えるように設計された、クエリ可能なナレッジ・エージェントの作成について説明します。IBM GraniteモデルとLangChainを使用して、LLM ベースの自律型エージェントのフレームワークでアウトラインされている原則に従って、エージェントが構築されます。このフレームワークのコンポーネントは、エージェントのワークフローとシームレスに連携し、適応性とインテリジェントな対応を確保します。

フレームワークがこのユースケースにどのように適用されるかを理解しましょう。

フレームワークの適用 フレームワークの適用

プロフィール:このエージェントは、「知識アシスタント」プロファイルに基づいて設計されており、要約、質問応答、推論タスクに焦点を当てています。そのコンテキストは、特定のドキュメント(例:『シャーロック・ホームズの冒険』)を処理するようにパーソナライズされています。

メモリー:エージェントは、本のチャンクをFAISSベクトル・ストアに埋め込むことによって、ハイブリッド・メモリーを採用しています。この機能により、クエリー中に関連するコンテキストを動的に取得できます。読み取り(取得)や書き込み(埋め込みの更新)などのメモリ操作により、エージェントは時間の経過とともに新しいクエリに適応できるようになります。

計画:クエリの解決には単一パス推論が用いられます。エージェントは、関連するテキストのチャンクを取得し、IBMのGranite LLMを使用して回答を生成し、出力の精度を評価します。フィードバックなしで計画を立てることでシンプルさが実現し、システムのモジュール性により、フィードバック・ループを将来のイテレーションに組み込むことができます。

アクション:エージェントは、メモリの取得とLLM処理を統合してクエリーの解決を実行します。回答の生成、精度メトリクス(BLEU、精度、想起、F1スコア)の計算、ユーザー解釈のための結果の視覚化などのタスクを完了します。これらのアウトプットは、推論と計画に基づいてインテリジェントに行動するエージェントの機能を反映しています。

前提条件

watsonx.ai®プロジェクトを作成するには、IBM® Cloudのアカウントが必要です。

ステップ

ステップ1. 環境を設定する

いくつかあるツールの中から選択することもできますが、このチュートリアルでは、Jupyter Notebookを使用してIBMアカウントを設定する方法について説明します。

  1. IBM Cloudアカウントを使用してwatsonx.aiにログインします。
  2. 2. watsonx.aiプロジェクトを作成します。プロジェクトIDはプロジェクト内から取得できます。「管理」タブをクリックし、「全般」ページの「詳細」セクションからプロジェクトIDをコピーします。このチュートリアルではこのIDが必要になります。
  3. 3. Jupyter Notebookを作成します。

このステップでは、このチュートリアルのコードをコピーできるノートブック環境が開きます。あるいは、このノートブックをローカル・システムにダウンロードし、watsonx.aiプロジェクトにアセットとしてアップロードすることもできます。さらに詳しいGraniteチュートリアルを見るには、IBM Granite Communityをご覧ください。このチュートリアルはGitHubでも公開されています。

ステップ2. watsonx.aiランタイム・サービスとAPIキーを設定する

  1. watsonx.ai Runtimeサービス・インスタンスを作成します(無料インスタンスであるLiteプランを選択します)。
  2. アプリケーション・プログラミング・インターフェース(API)キーを生成します。
  3. watsonx.aiで作成したプロジェクトに watsonx.ai Runtimeサービスを関連付けます。

ステップ3. パッケージのインストール

LangChainのフレームワークを使用し、IBM® WatsonxLLMを統合するには、いくつかの必須ライブラリーをインストールする必要があります。必要なパッケージをインストールすることから始めましょう。

注: 古いバージョンのpip 次のコマンドを使用できますpip install --upgrade pip アップグレードして、古いバージョンと互換性がない可能性がある最新のパッケージを簡単にインストールできるようにしてください。ただし、すでに最新バージョンを使用している場合、または最近パッケージをアップグレードした場合は、このコマンドをスキップできます。

!pip install --upgrade pip
!pip install langchain faiss-cpu pandas sentence-transformers
%pip install langchain
!pip install langchain-ibm

前のコードセルでは、

  • LangChain 言語モデルを使用してアプリケーションを構築するための中核となるフレームワークです。
  • faiss-cpu 効率的な類似性検索のためのもので、ベクトル・インデックスの作成とクエリーに使用されます。
  • pandas データの操作と分析に使用されます。
  • sentence-transformers セマンティック検索用の埋め込みを生成します。
  • langchain-ibm IBM WatsonxLLM(このチュートリアルでは、granite-3-8b-instruct)とLangChainを統合します。

このステップにより、今後のタスクに対応できる環境の準備が整います。

ステップ4. 必要なライブラリーをインポートする

必要なライブラリーをインストールしたので、このチュートリアルに必要なモジュールをインポートしてみましょう。

import os
from langchain_ibm import WatsonxLLM
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import FAISS
from langchain.text_splitter import RecursiveCharacterTextSplitter
import pandas as pd
import getpass

前のコードセルでは、

  • OS オペレーティング・システムと対話する方法を提供します(例:環境変数へのアクセス)。
  • langchain_ibm.WatsonxLLM IBM® Watson Granite LLMをLangChainフレームワーク内でシームレスに使用できるようにします。
  • langchain.embeddings.HuggingFaceEmbeddings セマンティック検索に不可欠なHuggingFaceモデルを使用して、テキスト用の埋め込みを生成します。
  • langchain.vectorstores.FAISS 効率的なベクトル・ストレージと類似性検索のためのライブラリーであり、ベクトル・インデックスの構築とクエリーを可能にします。
  • RecursiveCharacterTextSplitter 大きなテキストブロックを小さなチャンクに分割するために役立ちます。これは、ドキュメントを効率的に処理するために重要です。
  • pandas データ分析と操作のための強力なライブラリーであり、ここでは表形式データを処理するために使用されます。
  • getpass APIキーなどの機密インプットを画面に表示せずにキャプチャーする安全な方法です。

このステップでは、テキストの処理、埋め込みの作成、ベクトル・データベースへの保管、IBMのWatsonxLLMとの対話に必要なすべてのツールとモジュールをセットアップします。

ステップ5. 認証情報を設定する

このコードは、IBM Watson Machine Learning(WML)API にアクセスするための認証情報を設定し、プロジェクトIDが正しく構成されていることを確認します。

  • 辞書認証情報 WMLサービスURLを使って作成されます およびAPIキー 。機密情報の漏洩を避けるため、APIキーは「getpass.getpass」を使用して安全に収集されます。
  • コードは、次の情報の取得を試みます。PROJECT_ID これには、次を使用しますos.environ 。もしPROJECT_ID 見つからない場合は、ユーザーはプロンプトを通じて手動で入力するように求められます。
# Set up credentials
credentials = {
      "url": "https://us-south.ml.cloud.ibm.com", # Replace with the correct region if needed
      "apikey": getpass.getpass("Please enter your WML API key (hit enter): ")
     }
# Set up project_id
try:
     project_id = os.environ["PROJECT_ID"]
except KeyError:
     project_id = input("Please enter your project_id (hit enter): ")

ステップ6. 大規模言語モデルを初期化する

このコードは、アプリケーションで使用するためにIBM WatsonxLLMを初期化します。

  1. このコードにより、次のインスタンスが作成されます。WatsonxLLM これには、次のモデルを使用します。ibm/granite-3-8b-instruct このモデルは、指示ベースの生成AIタスク用に設計されています。
  2. URLAPIキーproject_id 以前に設定した認証情報からの値が、認証のために渡され、IBM WatsonxLLMサービスに接続されます。
  3. 次のパラメーターを構成します。max_new_tokens このパラメーターは、各応答でモデルが生成するトークンの数(この場合は150トークン)を制限します。

このステップでは、WatsonxLLMがワークフローで応答を生成できるように準備します。

# Initialize the IBM Granite LLM
llm = WatsonxLLM(
      model_id="ibm/granite-3-8b-instruct",
      url=credentials["url"],
      apikey=credentials["apikey"],
      project_id=project_id,
      params={
           "max_new_tokens": 150
      }
)

ステップ7. ファイルからテキストを抽出する関数を定義する

文書からテキストを処理するには、その内容を読み取り、抽出する関数が必要です。次の関数は、プレーン・テキスト・ファイルを処理するために設計されています。

def extract_text_from_txt(file_path):
      """Extracts text from a plain text file."""
           with open(file_path, "r", encoding="utf-8") as file:
           text = file.read()
return text

次の関数extract_text_from_txt は、プレーン・テキスト・ファイルの内容を読み取り、抽出するように設計されています。ファイル・パスを引数として受け入れ、ファイルを読み取りモードで開きます。エンコーディングはUTF-8で 、特殊文字が正しく処理されるようにします。

ファイルの内容全体が次の変数に読み込まれます。テキスト 、その後これが返されます。この関数は、文書から生のテキストを抽出してインプットを準備し、チャンク化、埋め込み、クエリーなどの後続のオペレーションの準備を整える上で重要な役割を果たします。プレーン・テキスト・ファイルからテキスト・データを処理するためのシンプルかつ効率的な方法が提供されます。

この関数により、入力ファイル(シャーロック・ホームズの冒険)を処理し、その内容を抽出して、テキストのチャンク化や埋め込みなどのさらなる操作を行うことができます。これにより、生のテキストを分析する準備が整います。

ステップ8. テキストをチャンクに分割する

大きなテキストブロックを効率的に処理してインデックスを付けるには、テキストをより小さく管理しやすいチャンクに分割する必要があります。このタスクは次の関数で処理します。

def split_text_into_chunks(text, chunk_size=500, chunk_overlap=50):
           """Splits text into smaller chunks for indexing."""
           splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)
return splitter.split_text(text)

split_text_into_chunks 関数は、効率的な処理とインデックス作成を行えるように、大きなテキストブロックをより小さな管理しやすいチャンクに分割するように設計されています。生のテキストをインプットとして受け取り、次の2つのオプションのパラメーターとともに使用します。chunk_size 各チャンクの最大サイズを定義します(デフォルトは500文字)。また、chunk_overlap これは、連続するチャンク間の重複する文字の数を指定します(デフォルトは50文字)

この関数により、チャンク全体でコンテキスト上の継続性が確保されます。この機能はRecursiveCharacterTextSplitter fromLangChain 、これは、コンテキストを維持しながらテキストをインテリジェントに分割します。この関数は、より小さいテキスト・チャンクのリストを返すことで、埋め込みやインデックス作成など、さらなる操作のための入力を準備します。

多くの場合、言語モデルにはトークンの制限があり、長いテキストを直接処理できないため、これは大規模な文書を扱う場合不可欠です。

ステップ9. ベクトル・インデックスを作成する

効率的なセマンティック検索を可能にするには、テキストのチャンクをベクトル埋め込みに変換し、検索可能なインデックスに保管する必要があります。このステップでは、FAISSとHuggingFaceの埋め込みを使用してベクトルインデックスを作成し、クエリに基づいて関連情報を取得するための基盤を形成します。

def create_vector_index(chunks):
           """Creates a FAISS vector index from text chunks."""
               embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2")
               vector_store = FAISS.from_texts(chunks, embeddings)
return vector_store

create_vector_index 関数が構築するのは前ステップで生成されたテキスト・チャンクからFAISSベクトル・インデックスを 構築します。この関数は、埋め込みを使用して各チャンクを高次元ベクトル空間にマッピングすることにより、セマンティック検索を可能にする上で不可欠です。

まず、HuggingFaceEmbeddingsモデルを初期化します。sentence-transformers/all-MiniLM-L6-v2 は、テキスト・チャンクのベクトル埋め込みを生成します。これらの埋め込みは、各チャンクの意味を捉えます。

その後 関数は次を使用します。FAISS これは、これらの埋め込みにインデックスを付けることでベクトル・ストアを作成し、後で効率的な類似性検索を可能にします。

結果として得られるベクトル・ストアは返され、ユーザーのクエリーに基づいて関連するチャンクを見つけるために使用され、エージェントの検索および取得プロセスのバックボーンを形成します。

ステップ10. Graniteでベクトル・インデックスを照会する

このステップでは、ベクトル・インデックスを照会して関連情報を取得し、IBMのGranite LLMを使用して改善された応答を生成します。この機能は、類似性検索とLLM推論を統合することで、動的でインテリジェントなクエリー解決プロセスを提供します。

def query_index_with_granite_dynamic(vector_store, query, llm):
         """Searches the vector index, uses Granite to refine the response, and returns all components."""
             # Perform similarity search
             print("\n> Entering new AgentExecutor chain...")
             thought = f"The query '{query}' requires context from the book to provide an accurate response."
             print(f" Thought: {thought}")
             action = "Search FAISS Vector Store"
             print(f" Action: {action}")
             action_input = query
             print(f" Action Input: \"{action_input}\"")
             # Retrieve context
             results = vector_store.similarity_search(query, k=3)
             observation = "\n".join([result.page_content for result in results])
             print(f" Observation:\n{observation}\n")
            # Generate response with Granite
            prompt = f"Context:\n{observation}\n\nQuestion: {query}\nAnswer:"
            print(f" Thought: Combining retrieved context with the query to generate a detailed answer.")
            final_answer = llm(prompt)
            print(f" Final Answer: {final_answer.strip()}")
            print("\n> Finished chain.")
            # Return all components as a dictionary
            return {
                    "Thought": thought,
                     "Action": action,
                     "Action Input": action_input,
                     "Observation": observation,
                     "Final Answer": final_answer.strip()
                     }

query_index_with_granite_dynamic 関数は3つのインプットを受け取ります。1つ目は、ベクトル・ストア(vector_store )、2つ目は、ユーザーのクエリー(query )、3つ目はGranite LLMインスタンス(LLM

まず、ベクトル・インデックスに対して類似性検索を実行して、最も関連性の高いテキストのチャンクを取得します。これらのチャンクは、observation として参照され、1つのコンテキストブロックに結合されます。

この関数は、クエリーと取得したコンテキストを組み合わせてプロンプトを構築します。このプロンプトは、Granite LLM に渡され、詳細かつ文脈に沿った、正確な応答を生成します(final_answer

プロセス全体を通して、エージェントによる次の中間的なステップがあります。thoughtアクションaction input これらは、透明性を確保するために表示されます。

最後に、この関数は、思考プロセス、実行されたアクション、取得された観察、最終的な答えを含むすべてのコンポーネントを含む辞書を返します。

このステップは、LLMの推論機能を使用して、未加工データの取得を実行可能なかつ意味を持つ洞察に変換する上で重要です。

ステップ11. クエリー結果の「DataFrame」を生成する

このステップでは、複数のクエリーを動的に処理し、関連情報を取得し、分析のために構造化された形式で結果を保存します。この機能は、クエリーの実行、データ構造化、エクスポート機能を統合します。

def dynamic_output_to_dataframe(vector_store, queries, llm, csv_filename="output.csv"):
           """Generates a DataFrame dynamically for multiple queries and saves it as a CSV file."""
           # List to store all query outputs
           output_data = []
           # Process each query
           for query in queries:
           # Capture the output dynamically
           output = query_index_with_granite_dynamic(vector_store, query, llm)
           output_data.append(output)
           # Convert the list of dictionaries into a DataFrame
           df = pd.DataFrame(output_data)
           # Display the DataFrame
           print("\nFinal DataFrame:")
           print(df)
           # Save the DataFrame as a CSV file
           df.to_csv(csv_filename, index=False)
           print(f"\nOutput saved to {csv_filename}")

dynamic_output_to_dataframe 関数は次の4つの入力を受け付けます:ベクトル・ストア(vector_store )、クエリのリスト(queries )、Granite LLMインスタンス(LLM )、およびオプションのCSVファイル名(csv_filename があり、デフォルトは以下になります。output.csv

クエリーごとに関数を使用し、query_index_with_granite_dynamic LLMによって関連するコンテキストを取得し、応答を生成します。結果には、次のような中間コンポーネントが含まれます。ThoughtObservationFinal Answer これらは、リストに格納されています。

すべてのクエリーが処理されると、結果のリストがpandas DataFrameに変換されます。この表形式により、クエリーの結果を簡単に分析し、視覚化できます。DataFrameはレビュー用にプリントされ、将来的な使用のためにCSVファイルとして保存されます。

このステップは、出力をユーザーフレンドリーな形式に整理し、精度評価や視覚化などの下流タスクを可能にするために不可欠です。

ステップ12. メイン・ワークフローを実行する

このステップでは、上述されたすべてのステップを単一のワークフローにまとめて、テキスト・ファイルを処理し、ユーザーのクエリーに回答し、結果を構造化された形式で保存します。関数main_workflow が、チュートリアルの中心的なオーケストレーターとして機能します。

def main_workflow():
           # Replace with your text file
           file_path = "aosh.txt"
           # Extract text from the text file
           text = extract_text_from_txt(file_path)
           # Split the text into chunks
           chunks = split_text_into_chunks(text)
           # Create a vector index
           vector_store = create_vector_index(chunks)
           # Define queries
           queries = [
                     "What is the plot of 'A Scandal in Bohemia'?",
                     "Who is Dr. Watson, and what role does he play in the stories?",
                     "Describe the relationship between Sherlock Holmes and Irene Adler.",
                     "What methods does Sherlock Holmes use to solve cases?"
                     ]
           # Generate and save output dynamically
          dynamic_output_to_dataframe(vector_store, queries, llm)

このワークフローがどのように実行されるのか理解しましょう。

テキスト・ファイルの入力:file_path この変数は、処理されるテキスト・ファイルを指定します。このチュートリアルでは、インプットファイルは"aosh.txt" であり、『シャーロック・ホームズの冒険』のテキストが含まれています。

テキストの抽出:extract_text_from_txt この関数は、入力テキスト・ファイルの内容を読み取って抽出するために呼び出されます。

テキストのチャンキング:抽出されたテキストは、関数を使用してより小さなチャンクに分割され、split_text_into_chunks 埋め込みとインデックス作成を容易にします。

ベクトル・インデックスを作成する:テキストのチャンクは埋め込みに変換され、前ステップで生成されたテキスト・チャンクからFAISSベクトル・インデックスを 以下を使用してインデックスに保存されます。create_vector_index 集めています。

クエリの定義:それぞれがテキストから特定の情報を取得するように設計された、サンプルクエリーのリストが提供されています。これらのクエリーには、エージェントが回答します。

クエリーの処理:dynamic_output_to_dataframe この関数は、ベクトル・インデックスとIBMのGranite LLMを使用してクエリを処理します。関連するコンテキストを取得し、回答を生成し、さらなる分析のために結果をCSVファイルとして保存します。

このステップでは、チュートリアルのすべてのコンポーネントを一貫性のあるワークフローに統合します。テキストの抽出からクエリの解決までのプロセスが自動化されるため、エージェントの機能をテストし、結果を構造化された形式で調べることができます。

ワークフローを実行するには、次の関数を呼び出します。main_workflow() これにより、パイプライン全体がシームレスに実行されます

# Run the workflow
main_workflow()

アウトプット


 

> Entering new AgentExecutor chain...
 Thought: The query 'What is the plot of 'A Scandal in Bohemia'?' requires context from the book to provide an accurate response.
 Action: Search FAISS Vector Store
 Action Input: "What is the plot of 'A Scandal in Bohemia'?"
 Observation:
I. A SCANDAL IN BOHEMIA


I.
“I was aware of it,” said Holmes dryly.

“The circumstances are of great delicacy, and every precaution has to
be taken to quench what might grow to be an immense scandal and
seriously compromise one of the reigning families of Europe. To speak
plainly, the matter implicates the great House of Ormstein, hereditary
kings of Bohemia.”

“I was also aware of that,” murmured Holmes, settling himself down in
his armchair and closing his eyes.
Contents

   I.     A Scandal in Bohemia
   II.    The Red-Headed League
   III.   A Case of Identity
   IV.    The Boscombe Valley Mystery
   V.     The Five Orange Pips
   VI.    The Man with the Twisted Lip
   VII.   The Adventure of the Blue Carbuncle
   VIII.  The Adventure of the Speckled Band
   IX.    The Adventure of the Engineer’s Thumb
   X.     The Adventure of the Noble Bachelor
   XI.    The Adventure of the Beryl Coronet
   XII.   The Adventure of the Copper Beeches

 Thought: Combining retrieved context with the query to generate a detailed answer.
/var/folders/4w/smh16qdx6l98q0534hr9v52r0000gn/T/ipykernel_2648/234523588.py:23: LangChainDeprecationWarning: The method `BaseLLM.__call__` was deprecated in langchain-core 0.1.7 and will be removed in 1.0. Use :meth:`~invoke` instead.
  final_answer = llm(prompt)
 Final Answer: Step 1: Identify the main characters and their roles.
- Sherlock Holmes: The detective who is approached by a client with a delicate matter.
- An unnamed client: A representative of the great House of Ormstein, hereditary kings of Bohemia, who seeks Holmes' help to prevent a potential scandal.

Step 2: Understand the main issue or conflict.
- The main issue is a delicate matter that, if exposed, could lead to a massive scandal and compromise one of the reigning families of Europe, specifically the House of Ormstein.

Step 3: Ident

> Finished chain.

> Entering new AgentExecutor chain...
 Thought: The query 'Who is Dr. Watson, and what role does he play in the stories?' requires context from the book to provide an accurate response.
 Action: Search FAISS Vector Store
 Action Input: "Who is Dr. Watson, and what role does he play in the stories?"
 Observation:
“Sarasate plays at the St. James’s Hall this afternoon,” he remarked.
“What do you think, Watson? Could your patients spare you for a few
hours?”

“I have nothing to do to-day. My practice is never very absorbing.”
“Try the settee,” said Holmes, relapsing into his armchair and putting
his fingertips together, as was his custom when in judicial moods. “I
know, my dear Watson, that you share my love of all that is bizarre and
outside the conventions and humdrum routine of everyday life. You have
shown your relish for it by the enthusiasm which has prompted you to
chronicle, and, if you will excuse my saying so, somewhat to embellish
so many of my own little adventures.”
“My God! It’s Watson,” said he. He was in a pitiable state of reaction,
with every nerve in a twitter. “I say, Watson, what o’clock is it?”

“Nearly eleven.”

“Of what day?”

“Of Friday, June 19th.”

“Good heavens! I thought it was Wednesday. It is Wednesday. What d’you
want to frighten a chap for?” He sank his face onto his arms and began
to sob in a high treble key.

“I tell you that it is Friday, man. Your wife has been waiting this two
days for you. You should be ashamed of yourself!”

 Thought: Combining retrieved context with the query to generate a detailed answer.
 Final Answer: Dr. Watson is a character in the Sherlock Holmes stories, written by Sir Arthur Conan Doyle. He is a former military surgeon who becomes the narrator and chronicler of Holmes' adventures. Watson is a close friend and confidant of Holmes, often accompanying him on cases and providing a more human perspective to the stories. He is known for his enthusiasm for the bizarre and unconventional, as well as his skill in recording the details of their investigations. Watson's role is crucial in presenting the narrative and offering insights into Holmes' character and methods.

> Finished chain.


Final DataFrame:
                                             Thought  \
0  The query 'What is the plot of 'A Scandal in B...   
1  The query 'Who is Dr. Watson, and what role do...   
2  The query 'Describe the relationship between S...   
3  The query 'What methods does Sherlock Holmes u...   

                      Action  \
0  Search FAISS Vector Store   
1  Search FAISS Vector Store   
2  Search FAISS Vector Store   
3  Search FAISS Vector Store   

                                        Action Input  \
0        What is the plot of 'A Scandal in Bohemia'?   
1  Who is Dr. Watson, and what role does he play ...   
2  Describe the relationship between Sherlock Hol...   
3  What methods does Sherlock Holmes use to solve...   

                                         Observation  \
0  I. A SCANDAL IN BOHEMIA\n\n\nI.\n“I was aware ...   
1  “Sarasate plays at the St. James’s Hall this a...   
2  “You have really got it!” he cried, grasping S...   
3  to learn of the case was told me by Sherlock H...   

                                        Final Answer  
0  Step 1: Identify the main characters and their...  
1  Dr. Watson is a character in the Sherlock Holm...  
2  Sherlock Holmes and Irene Adler have a profess...  
3  Sherlock Holmes uses a variety of methods to s...  

Output saved to output.csv

 

関数を実行後main_workflow() 、テキストファイル(aosh.txt)を処理し、『シャーロック・ホームズの冒険』に関する4つのユーザー定義クエリーを実行しました。出力には、各クエリーがどのように処理されたのか、詳細な内訳が表示されます。

  • Thoughtは、クエリーの背後にある論理的思考プロセスと、正確な回答を得るために必要な文脈を説明します。
  • Actionは実行されたステップを示し、この場合はFAISSベクトル・インデックスを使用して類似性検索を実行する操作を指します。
  • Action Inputは、1つのイテレーションで処理される特定のクエリーです。
  • Observationは、クエリに関連するベクトル・インデックスから取得されたテキストのチャンクです。
  • Final Answerは、取得したコンテキストを使用してIBMのGranite LLMが生成する詳細な回答です。

さらに、すべてのクエリーの結果はDataFrameに構造化され、として保存されますoutput.csv 。このファイルには、さらなる分析や共有のため、上記のコンポーネントがすべて含まれています。

このプロセスでは、テキスト検索とLLM推論を組み合わせて、書籍に関する複雑なクエリに回答しました。エージェントは関連情報を動的に取得し、文脈を使用して正確な回答を生成し、分析を容易にするために構造化された形式に出力を整理しました。

結果を視覚化する

output.csvファイルが作成されたので、クエリ結果とその関連する精度メトリクスを視覚化することで、エージェントの性能についてより深い洞察を獲得できます。

次のコードセルでは、保存されたクエリーの結果をoutput.csv ファイルからpandas DataFrameに読み込み、視覚化と分析に備えます。DataFrameを使用すると、構造化された形式でデータを操作および調査できます。

# Load the output.csv file into a DataFrame
df = pd.read_csv("output.csv")
print(df.head()) # Display the first few rows

出力


Thought  \
0  The query 'What is the plot of 'A Scandal in B...   
1  The query 'Who is Dr. Watson, and what role do...   
2  The query 'Describe the relationship between S...   
3  The query 'What methods does Sherlock Holmes u...   

                      Action  \
0  Search FAISS Vector Store   
1  Search FAISS Vector Store   
2  Search FAISS Vector Store   
3  Search FAISS Vector Store   

                                        Action Input  \
0        What is the plot of 'A Scandal in Bohemia'?   
1  Who is Dr. Watson, and what role does he play ...   
2  Describe the relationship between Sherlock Hol...   
3  What methods does Sherlock Holmes use to solve...   

                                         Observation  \
0  I. A SCANDAL IN BOHEMIA\n\n\nI.\n“I was aware ...   
1  “Sarasate plays at the St. James’s Hall this a...   
2  “You have really got it!” he cried, grasping S...   
3  to learn of the case was told me by Sherlock H...   

                                        Final Answer  
0  Step 1: Identify the main characters and their...  
1  Dr. Watson is a character in the Sherlock Holm...  
2  Sherlock Holmes and Irene Adler have a profess...  
3  Sherlock Holmes uses a variety of methods to s...

このコードでは、DataFrameには次のような主要なコンポーネントが含まれています。Thought行動ObservationFinal Answer 各クエリーに対して。以下を使用して、最初の数行を表示します。df.head() これにより、データが正しくフォーマットされ、次の段階である意味のある視覚化に対応できるようにします。

視覚化ライブラリーをインポートする

クエリーの結果を視覚化するために、必要なライブラリーをインポートします。

import matplotlib.pyplot as plt
from wordcloud import WordCloud

 

matplotlib.pyplot これは、Pythonで静的、対話的かつ動的な視覚化を作成するために広く使用されているライブラリーです。棒グラフ、円グラフ、その他の視覚化の生成に使用されます。

wordcloud ワードクラウドを作成するためのライブラリーです。ワードクラウドは、データ内で最も頻繁に使用される単語を視覚的に強調表示します。このステップは、テキストから取得した文脈を要約し、調査する際に役立ちます。

重要な注記: エラーが発生した場合は「WordCloudが見つかりません」 この場合、次のコマンドを使用してライブラリをインストールすることで問題を解決できますpip install wordcloud

観察と回答の長さを視覚化する

このコードは、水平棒グラフを作成し、各クエリーのObservation(取得された文脈)Answer(生成された応答)の長さを比較します。この視覚化により、生成された回答の長さに対して、エージェントが使用する文脈の量についての洞察が得られます。

def visualize_lengths_with_queries(df):
"""Visualizes the lengths of observations and answers with queries on the y-axis."""
df["Observation Length"] = df["Observation"].apply(len)
df["Answer Length"] = df["Final Answer"].apply(len)
# Extract relevant data
queries = df["Action Input"]
observation_lengths = df["Observation Length"]
answer_lengths = df["Answer Length"]
# Create a horizontal bar chart
plt.figure(figsize=(10, 6))
bar_width = 0.4
y_pos = range(len(queries))
plt.barh(y_pos, observation_lengths, bar_width, label="Observation Length", color="skyblue", edgecolor="black")
plt.barh([y + bar_width for y in y_pos], answer_lengths, bar_width, label="Answer Length", color="lightgreen", edgecolor="black")
plt.yticks([y + bar_width / 2 for y in y_pos], queries, fontsize=10)
plt.xlabel("Length (characters)", fontsize=14)
plt.ylabel("Queries", fontsize=14)
plt.title("Observation and Answer Lengths by Query", fontsize=16)
plt.legend(fontsize=12)
plt.tight_layout()
plt.show()
# Call the visualization function
visualize_lengths_with_queries(df)
 
クエリー別のObservationとAnswerの長さ

次の関数visualize_lengths_with_queries このコードは、水平棒グラフを作成し、各クエリーのObservation(取得された文脈)Answer(生成された応答)の長さを比較します。

ObservationとAnswerの両方の文字長を計算し、それらを新しい列(Observation LengthAnswer Length )としてDataFrameに追加します。次を使用します。Matplotlib 次に、各クエリーについてこれらの長さをプロットします。クエリーはy軸に表示されるため、読みやすくなります。

棒グラフは、ObservationとAnswerの長さを区別するために色分けされており、わかりやすくするためにラベル、凡例、タイトルが含まれています。

この視覚化は、取得した文脈のサイズと生成された応答における詳細との間のバランスを分析する上で役立ち、エージェントがクエリーをどのように処理し、応答するのかについて洞察を提供します。

観察で使用されるテキストの割合を視覚化する

このステップでは、エージェントによって処理されたテキスト全体のうち、Observation(取得された文脈)で使用されているテキストの量とそれ以外のテキストの量を視覚化します。円グラフが、比率を直感的に表現するために作成されます。

def visualize_text_proportion(df):
     """Visualizes the proportion of text used in observations."""
     total_text_length = sum(df["Observation"].apply(len)) + sum(df["Final Answer"].apply(len))
     observation_text_length = sum(df["Observation"].apply(len))
     sizes = [observation_text_length, total_text_length - observation_text_length]
     labels = ["Observation Text", "Remaining Text"]
     colors = ["#66b3ff", "#99ff99"]
     plt.figure(figsize=(4, 4))
     plt.pie(sizes, labels=labels, colors=colors, autopct="%1.1f%%", startangle=140)
     plt.title("Proportion of Text Used in Observations", fontsize=16)
     plt.show()
# Call the visualization function
visualize_text_proportion(df)
Observationに使用されるテキストの比率の図

visualize_text_proportion この関数は、Observation(取得された文脈)で使用されるテキストとそれ以外のテキストの比率を示す円グラフを作成します。すべてのObservationとAnswerの文字長を合計することでテキスト全体の長さを計算し、Observationが占める割合を決定します。

このデータは円グラフで視覚化され、次のように明確なラベルが付けられています。"Observationによるテキスト" および"残りのテキスト" また、可読性を高めるはっきりとした色が特徴です。グラフには、比率を簡単に解釈できるようにパーセンテージ値が含まれています。

この視覚化により、エージェントがクエリー処理中に文脈として使用するテキストの量に関する概要が得られるため、取得プロセスの効率性と焦点についての洞察が得られます。

観察と最終的な回答のためのワード・クラウドを生成する

このコードは、テキスト内で最も頻繁に出現する単語を視覚的に表すために、2つのワードクラウドを Observation および Final Answer 生成します。

def generate_wordclouds_side_by_side(df):
      """Generates and displays word clouds for Observations and Final Answers side by side."""
      # Combine text for Observations and Final Answers
      observation_text = " ".join(df["Observation"])
      final_answer_text = " ".join(df["Final Answer"])
      # Create word clouds
      observation_wordcloud = WordCloud(width=800, height=400, background_color="white").generate(observation_text)
      final_answer_wordcloud = WordCloud(width=800, height=400, background_color="white").generate(final_answer_text)
      # Create a side-by-side visualization
      plt.figure(figsize=(16, 8))
      # Plot the Observation word cloud
      plt.subplot(1, 2, 1)
      plt.imshow(observation_wordcloud, interpolation="bilinear")
      plt.axis("off")
      plt.title("Word Cloud of Observations", fontsize=16)
      # Plot the Final Answer word cloud
      plt.subplot(1, 2, 2)
      plt.imshow(final_answer_wordcloud, interpolation="bilinear")
      plt.axis("off")
      plt.title("Word Cloud of Final Answers", fontsize=16)
      plt.tight_layout()
      plt.show()
# Call the function to generate and display the word clouds
generate_wordclouds_side_by_side(df)
 
Observationのワードクラウド

このコードは、テキスト内で最も頻繁に出現する単語を視覚的に表すために、2つのワードクラウドをObservation およびFinal Answer テキストを並べて表示し、簡単に比較できるようにします。以下のコードを使い、ObservationFinal Answer テキストをまず2つの別々の文字列に連結します。" ".join() これにより、それぞれの列のすべての行を結合します。次に、WordCloud のライブラリーを使用して、特定の構成でテキストごとにワードクラウドを生成します。

並べて表示するには、サブプロットを使用します。最初のサブプロットには、Observation のワードクラウドが表示され、2番目にはFinal Answertight_layout() この関数により、プロット間の間隔が整理されます。これらのワードクラウドを使用すると、次の文脈から取得した重要な用語を強調することで、エージェントの性能を直感的に分析できます(Observation )また、応答では次の用語が強調表示されます(Final Answer

エージェントの精度をテストする

このセクションでは、次の複数の精度メトリクスを使用してエージェントの性能を評価します。キーワード・マッチングBLEUスコア精度/再現率F1スコア 。これらのメトリクスは、エージェントがユーザーのクエリーに基づいて正確で関連性の高い応答をどの程度生成できるかについて、包括的なビューを提供します。

必要なライブラリーをインポートする

テストを開始する前に、精度評価のために必要なライブラリーをインポートします。

from sklearn.feature_extraction.text import CountVectorizer
from nltk.translate.bleu_score import sentence_bleu
from sklearn.metrics import precision_score, recall_score

これらのライブラリーには、キーワード・マッチング、BLEUスコア計算、精度および再現率評価のためのツールが含まれています。インポート・エラーを避けるため、これらのライブラリーが環境にインストールされていることを確認してください。

キーワードのマッチング精度

このテストでは、生成された回答にクエリーのキーワードがどの程度含まれているかを評価します。テストでは、以下の関数を使用します。CountVectorizer これにより、クエリーと回答からキーワードをトークン化して抽出します。この関数は、生成された回答に存在するクエリー・キーワードの比率を計算し、この比率がしきい値(デフォルトでは0.5)を超える場合、その応答が正確であるとしてマークされます。結果は、次のDataFrameに追加されます。Keyword Match Score およびIs Accurate列 .

def keyword_matching_accuracy(df):
      """Checks if key phrases from the query are present in the final answer."""
      vectorizer = CountVectorizer(stop_words='english')
      def check_keywords(query, answer):
      query_keywords = set(vectorizer.build_tokenizer()(query.lower()))
      answer_keywords = set(vectorizer.build_tokenizer()(answer.lower()))
      common_keywords = query_keywords & answer_keywords
      return len(common_keywords) / len(query_keywords) # Proportion of matched keywords
      df["Keyword Match Score"] = df.apply(lambda row: check_keywords(row["Action Input"], row["Final Answer"]), axis=1)
      df["Is Accurate"] = df["Keyword Match Score"] >= 0.5 # Set a threshold for accuracy
      return df
# Apply keyword matching
df = keyword_matching_accuracy(df)
df.to_csv("output_with_accuracy.csv", index=False)
df
これは、Thinkページのチュートリアルのコード・セルの出力です。

BLEUスコアの計算

このテストは、生成された回答が取得されたObservationとどの程度一致しているかを測定します。BLEU(バイリンガル評価アンダースタディ) 以下に基づいてテキストの類似性を評価するための一般的な指標です。n-gram 重複。この関数は、BLEUスコア クエリと回答のペアごとに計算し、BLEUスコア列の下にあるDataFrameに追加します。

def calculate_bleu_scores(df):
    """Calculates BLEU scores for answers against observations."""
    df["BLEU Score"] = df.apply(
       lambda row: sentence_bleu([row["Observation"].split()], row["Final Answer"].split()),
       axis=1
       )
    return df
# Apply BLEU score calculation
df = calculate_bleu_scores(df)
df.to_csv("output_with_bleu.csv", index=False)
Thinkページでチュートリアル用に作成された図。

精度と再現率

回答の関連性と完全性を評価するために、精度と再現率が計算されます。精度は、回答内で取得された単語の中で関連する単語の割合を測定します。一方、再現率は、Answerに表示されるObservation内の関連単語の割合を測定します。

これらのメトリクスは、DataFrameの 精度 および 再現率 列に追加されます。

def calculate_precision_recall(df):
     """Calculates precision and recall for extractive answers."""
         def precision_recall(observation, answer):
                observation_set = set(observation.lower().split())
                answer_set = set(answer.lower().split())
                precision = len(observation_set & answer_set) / len(answer_set) if answer_set else 0
                recall = len(observation_set & answer_set) / len(observation_set) if observation_set else 0
         return precision, recall
        df[["Precision", "Recall"]] = df.apply(
        lambda row: pd.Series(precision_recall(row["Observation"], row["Final Answer"])),
        axis=1
        )
return df
# Apply precision/recall
df = calculate_precision_recall(df)
df.to_csv("output_with_precision_recall.csv", index=False)
df
Thinkページにあるチュートリアルのコード・セルの出力

F1スコアの計算

F1スコアは、精度と再現率を1つのメトリクスにまとめたもので、関連性と完全性のバランスが取れた評価を提供します。F1スコアの計算式は次のとおりです:F1 Score = 2 * (Precision * Recall) / (Precision + Recall)

計算されたF1スコアは F1スコア列の下のDataFrameに追加されます。

def calculate_f1(df):
      """Calculates F1 scores based on precision and recall."""
          df["F1 Score"] = 2 * (df["Precision"] * df["Recall"]) / (df["Precision"] + df["Recall"])
          df["F1 Score"].fillna(0, inplace=True) # Handle divide by zero
          return df
# Apply F1 calculation
df = calculate_f1(df)
df.to_csv("output_with_f1.csv", index=False)
df
Thinkページにあるチュートリアルのコード・セルの出力

精度のメトリクスを要約する

最後に、サマリー機能によってすべてのメトリクスを統合し、エージェントの性能の概要を提供します。クエリーの総数、正確な応答の数と割合、BLEUとF1の平均スコアを計算します。

def summarize_accuracy_metrics(df):
      """Summarizes overall accuracy metrics."""
          total_entries = len(df)
          accurate_entries = df["Is Accurate"].sum()
          average_bleu = df["BLEU Score"].mean()
          average_f1 = df["F1 Score"].mean()
          print(f"Total Entries: {total_entries}")
          print(f"Accurate Entries: {accurate_entries} ({accurate_entries / total_entries * 100:.2f}%)")
          print(f"Average BLEU Score: {average_bleu:.2f}")
          print(f"Average F1 Score: {average_f1:.2f}")
# Call summary function
summarize_accuracy_metrics(df)

出力


 

Total Entries: 4
Accurate Entries: 4 (100.00%)
Average BLEU Score: 0.04
Average F1 Score: 0.24

これらの精度テストは、関連性のある正確な応答を生成するエージェントの能力を詳細に評価します。各テストは、含まれるキーワードからテキストの類似性、回答の完全性まで、特定の側面に焦点を当てています。サマリーでは、これらのメトリクスを統合して、全体的な性能のスナップショットを提供します。

概要

このチュートリアルでは、IBMのGranite LLMとLangChainを活用した自律型エージェントの構築について説明します。テキスト抽出からベクトル化、クエリー解決まで、機能的なLLMベース・エージェントの設計と実装のプロセス全体をカバーしました。主なステップには、ベクトル・ストアによるメモリー管理、クエリー処理、Graniteを使用した応答の生成が含まれます。

キーワード・マッチング、BLEUスコア、精度、再現率、F1スコアなどのメトリクスを使用してエージェントの性能を評価しました。棒グラフ、円グラフ、ワードクラウドなどの視覚化により、エージェントの行動と有効性についての追加の洞察が得られました。

このチュートリアルを完了することで、LLMエージェントの性能を設計、テスト、視覚化する方法を学べます。この基礎を応用することで、より複雑なデータセットに取り組み、精度を向上させ、マルチエージェント・システムなどの高度な機能を利用できるようになります。

関連ソリューション
ビジネス向けAIエージェント

生成AIを使用してワークフローとプロセスを自動化する強力なAIアシスタントとエージェントを構築、デプロイ、管理しましょう。

    watsonx Orchestrateの詳細はこちら
    IBM AIエージェント・ソリューション

    信頼できるAIソリューションでビジネスの未来を構築します。

    AIエージェント・ソリューションの詳細はこちら
    IBM®コンサルティング AIサービス

    IBMコンサルティングAIサービスは、企業がAIをトランスフォーメーションに活用する方法を再考するのに役立ちます。

    人工知能サービスの詳細はこちら
    次のステップ

    事前構築済みのアプリケーションとスキルをカスタマイズする場合でも、AIスタジオを使用してカスタム・エージェント・サービスを構築し、デプロイする場合でも、IBM watsonxプラットフォームが対応します。

    watsonx Orchestrateの詳細はこちら watsonx.aiの詳細はこちら