「Pythonにおける構造化LLM出力の保存と解析」

「Pythonによる構造化LLM出力の保存と解析の方法」

イントロダクション

ジェネラティブAIは現在、世界中で広く使用されています。大規模言語モデルのテキスト理解能力とそれに基づいたテキスト生成能力により、チャットボットからテキスト分析まで様々なアプリケーションが生まれました。しかし、これらの大規模言語モデルは非構造化な形式でテキストを生成することが多いです。時には、LLM(大規模言語モデル)によって生成された出力を、構造化された形式、例えばJSON(JavaScript Object Notation)形式にしたいケースもあります。例えば、LLMを使用してソーシャルメディアの投稿を分析し、LLMによって生成された出力をJSON/python変数としてコード内で扱い他のタスクを実行する必要があるかもしれません。このような場合に、プロンプトエンジニアリングを使ってこれを実現することは可能ですが、プロンプトの調整には多くの時間がかかります。そこで、LangChainでは出力パースを導入しており、これによりLLMの出力を構造化された形式に変換することができます。

学習目標

  • 大規模言語モデルによって生成された出力の解釈
  • Pydanticを使用したカスタムデータ構造の作成
  • プロンプトテンプレートの重要性とLLMの出力を整形してプロンプトを生成する方法の理解
  • LangChainを使用してLLMの出力のフォーマット指示を作成する方法の学習
  • JSONデータをPydanticオブジェクトにパースする方法の理解

この記事はデータサイエンスブログマラソンの一環として掲載されました。

LangChainと出力パースとは?

LangChainは、大規模言語モデルを使用したアプリケーションを短時間で構築できるPythonライブラリです。OpenAI GPT LLM、GoogleのPaLM、そしてFalcon、LlamaなどのHugging Faceのオープンソースモデルなど、さまざまなモデルに対応しています。LangChainを使用すると、大規模言語モデルへのプロンプトのカスタマイズが容易になり、組込みのベクトルストアを提供するため、入出力の埋込みを保存することができます。そのため、数分でドキュメントをクエリできるアプリケーションを作成することができます。

LangChainは、大規模言語モデルがインターネットから情報を取得できるようにするためのエージェント機能も提供しています。また、出力パーサーも提供しており、大規模言語モデルによって生成されたデータを構造化することができます。LangChainには、リストパーサー、日時パーサー、列挙型パーサーなどさまざまな出力パーサーがあります。この記事では、LLMが生成した出力をJSON形式にパースすることができるJSONパーサーについて説明します。以下の図は、LLMの出力がPydanticオブジェクトにパースされる一般的なフローを示しており、Python変数で即座に使用できるデータが作成されます。

はじめに – モデルのセットアップ

このセクションでは、LangChainを使用してモデルをセットアップします。この記事全体を通して、PaLMをLarge Language Modelとして使用します。環境としてGoogle Colabを使用しますが、PaLMを他のどのLarge Language Modelに置き換えることもできます。まず、必要なモジュールをインポートします。

!pip install google-generativeai langchain
  • これにより、LangChainライブラリとPaLMモデルを扱うためのgoogle-generativeaiライブラリがダウンロードされます。
  • LangChainライブラリは、カスタムプロンプトの作成や大規模言語モデルによって生成された出力のパースに必要です。
  • google-generativeaiライブラリを使用すると、GoogleのPaLMモデルと対話することができます。

PaLM APIキー

PaLMを使用するには、MakerSuiteウェブサイトにサインアップしてAPIキーを取得する必要があります。次に、必要なすべてのライブラリをインポートし、APIキーを渡してPaLMモデルをインスタンス化します。

import osimport google.generativeai as palmfrom langchain.embeddings import GooglePalmEmbeddingsfrom langchain.llms import GooglePalmos.environ['GOOGLE_API_KEY']= 'YOUR API KEY'palm.configure(api_key=os.environ['GOOGLE_API_KEY'])llm = GooglePalm()llm.temperature = 0.1prompts = ["5つの惑星の名前とそれに関する一文を書いてください"]llm_result = llm._generate(prompts)print(llm_result.generations[0][0].text)
  • ここでは、まずGoogle PaLM(Pathways Language Model)のインスタンスを作成し、変数llmに割り当てました
  • 次のステップでは、モデルのtemperatureを0.1に設定しています。モデルが妄想しないように低く設定しています
  • 次に、Promptをリストとして作成し、変数promptsに渡します
  • PromptをPaLMに渡すために、._generate()メソッドを呼び出し、Promptリストを渡し、結果は変数llm_resultに格納されます
  • 最後に、.generationsを呼び出して結果を表示し、.textメソッドを呼び出してテキストに変換します

このPromptの出力は以下のようになります

見てわかるように、大規模な言語モデルはかなりの出力を生成しており、LLMもいくつかの行を追加して構造を与えようとしていることがわかります。しかし、もしLLMの出力を変数ごとに情報を保存したい場合はどうでしょうか?惑星の名前や軌道周期、太陽からの距離など、これらの情報を別々の変数に保存したい場合はどうでしょうか?モデルが生成した出力そのままでは、これを直接処理することはできません。そのため、アウトプットパーサーが必要になります。

Pydanticアウトプットパーサーとプロンプトテンプレートの作成

このセクションでは、langchainのpydanticアウトプットパーサーについて説明します。前の例では、出力は非構造化の形式でした。大規模な言語モデルが生成した情報を構造化された形式で保存する方法について見てみましょう。

コードの実装

まず、次のコードを見てみましょう:

from pydantic import BaseModel, Field, validatorfrom langchain.output_parsers import PydanticOutputParserclass PlanetData(BaseModel):    planet: str = Field(description="これは惑星の名前です")    orbital_period: float = Field(description="これは軌道周期で、地球の日数です")    distance_from_sun: float = Field(description="これは惑星から太陽までの距離を示す浮動小数点数です")    interesting_fact: str = Field(description="これは惑星に関する興味深い事実です")
  • ここでは、Pydanticパッケージをインポートしてデータ構造を作成します。このデータ構造には、LLMからの出力を解析して格納します。
  • ここでは、Pydanticを使用してPlanetDataという名前のデータ構造を作成しました。このデータ構造には、次のデータが格納されます
  • Planet: モデルへの入力として使用する惑星の名前です
  • Orbit Period: 特定の惑星の地球の日数での軌道周期を示す浮動小数点数です
  • Distance from Sun: 惑星から太陽までの距離を示す浮動小数点数です
  • Interesting Fact: その惑星に関する興味深い事実が含まれる文字列です

さて、惑星に関する情報を大規模な言語モデルにクエリし、このデータをLLMの出力を解析してPlanetDataデータ構造に保存することを目指します。LLMの出力をPydanticデータ構造に解析するために、LangChainではPydanticOutputParserというパーサーを提供しています。次のようにPlanetDataクラスをこのパーサーに渡します:

planet_parser = PydanticOutputParser(pydantic_object=PlanetData)

parserオブジェクトをplanet_parserという変数に保存します。parserオブジェクトには、LLMが出力を生成する方法を示すget_format_instructions()というメソッドがあります。それを印刷してみましょう。

from pprint import pppp(planet_parser.get_format_instructions())

上記の例では、フォーマットの指示には、LLMによって生成された出力をどのように整形するかの情報が含まれています。それはLLMに出力をJSONスキーマで出力するよう指示し、そのJSONをPydanticデータ構造に解析できるようにします。出力スキーマの例も提供されています。次に、プロンプトテンプレートを作成します。

プロンプトテンプレート

from langchain import PromptTemplate, LLMChaintemplate_string = """あなたは惑星に関する質問に答えるのは得意です。惑星名が与えられ、惑星の名前、軌道周期(日)、太陽からの距離(百万キロメートル)、興味深い事実が出力されます。```{planet_name}```{format_instructions}"""planet_prompt = PromptTemplate(    template=template_string,    input_variables=["planet_name"],    partial_variables={"format_instructions": planet_parser.get_format_instructions()})
  • プロンプトテンプレートでは、惑星の名前が入力として与えられ、LLMが惑星の軌道周期、太陽からの距離、および惑星に関する興味深い事実などの情報を含む出力を生成することを指定しています。
  • 次に、このテンプレートをPrompTemplate()に割り当て、input_variablesパラメータに入力変数名を指定します。この場合はplanet_nameです。
  • また、以前に見たフォーマット指示も提供します。これにより、LLMがJSON形式で出力を生成する方法が指定されます。

惑星名を指定してプロンプトを入力し、大規模な言語モデルに送信する前のプロンプトの表示方法を試してみましょう。

input_prompt = planet_prompt.format_prompt(planet_name='mercury')pp(input_prompt.to_string())

出力では、定義したテンプレートが最初に現れ、入力「mercury」が続きます。それに続いて、フォーマットの指示が表示されます。これらのフォーマット指示には、LLMがJSONデータを生成するために使用できる指示が含まれています。

大規模言語モデルのテスト

このセクションでは、入力をLLMに送信し、生成されたデータを観察します。前のセクションで、LLMに送信される入力文字列はどのようになりますか。

input_prompt = planet_prompt.format_prompt(planet_name='mercury')output = llm(input_prompt.to_string())pp(output)

大規模言語モデルによって生成された出力が表示されます。出力は実際にJSON形式で生成されています。このJSONデータには、PlanetDataデータ構造で定義したすべてのキーが含まれています。そして、各キーには、それが持つと予想される値が含まれています。

これで、このJSONデータを行ったようにデータ構造にパースする必要があります。これは以前に定義したPydanticOutputParserで簡単に行うことができます。そのコードを見てみましょう:

parsed_output = planet_parser.parse(output)print("Planet: ",parsed_output.planet)print("Orbital period: ",parsed_output.orbital_period)print("Distance From the Sun(in Million KM): ",parsed_output.distance_from_sun)print("Interesting Fact: ",parsed_output.interesting_fact)

planet_parserのparse()メソッドを呼び出すと、出力が解析され、Pydanticオブジェクト(この場合はPlanetDataのオブジェクト)にパースおよび変換されます。つまり、大規模な言語モデルによって生成された出力、つまりJSONはPlannetDataデータ構造にパースされ、個々のデータにアクセスすることができます。上記の出力は次のとおりです。

JSONデータから抽出されたキーと値のペアがPydanticデータに正しくパースされたことがわかります。別の惑星で試して、出力を観察してみましょう。

input_prompt = planet_prompt.format_prompt(planet_name='venus')output = llm(input_prompt.to_string())parsed_output = planet_parser.parse(output)print("惑星: ",parsed_output.planet)print("公転周期: ",parsed_output.orbital_period)print("太陽からの距離: ",parsed_output.distance_from_sun)print("興味深い事実: ",parsed_output.interesting_fact)

入力「Venus」について、LLMは出力としてJSONを生成し、これがPydanticデータに正常にパースされました。このように、出力のパースを介して、Large Language Modelsによって生成された情報を直接利用することができます。

潜在的な応用と使用例

このセクションでは、これらの出力パース技術を利用できる潜在的な現実世界の応用/使用例について説明します。抽出/抽出後のパースを使用すると、あらゆるタイプのデータを抽出する場合に、抽出された情報を他のアプリケーションで利用できるようにします。いくつかの応用例は次のようなものがあります:

  • 製品クレームの抽出と分析:新しいブランドが市場に登場し、新製品をリリースする際に、まずやるべきことは製品のパフォーマンスをチェックすることです。これを評価する最良の方法の1つは、消費者がこれらの製品を使用するため、消費者のソーシャルメディア投稿を分析することです。出力パーサーとLLMは、消費者のソーシャルメディアの投稿からブランド名や製品名、クレームまでの情報を抽出することができます。これらのLarge Language Modelsは、出力のパースによってこのデータをPythonicな変数に保存し、データの可視化に活用することができます。
  • カスタマーサポート:顧客サポート用のLLMを使用してチャットボットを作成する場合、重要なタスクの1つは顧客のチャット履歴から情報を抽出することです。この情報には、製品/サービスに関する消費者が直面する問題など、重要な詳細が含まれています。カスタムコードではなく、LangChain出力パーサーを使用して、この情報を簡単に抽出できます。
  • 求人情報:IndeedやLinkedInなどの求人検索プラットフォームを開発する際には、求人情報から求人タイトル、企業名、経験年数、求人の説明などの詳細を抽出するためにLLMsを使用することができます。出力パージングを使用すると、求人のマッチングやおすすめのための構造化されたJSONデータとしてこの情報を保存できます。LangChain Output Parsersを介してLLMの出力から直接この情報をパースすることで、この別個のパース処理のために必要な冗長なコードを削減することができます。

結論

Large Language Modelsは、その非凡なテキスト生成能力のため、実質的にすべてのユースケースに適合する優れたものです。しかし、実際に生成された出力を使用する場合、出力のパースにかなりの時間を費やす必要があります。この記事では、この問題と、特にJSONパーサーを使用してLLMから生成されたJSONデータをPydanticオブジェクトに変換する方法について見てきました。

キーポイント

この記事からのいくつかのキーポイントは次のとおりです:

  • LangChainはPythonライブラリであり、既存のLarge Language Modelsを使用したアプリケーションを作成することができます。
  • LangChainは、Large Language Modelsによって生成された出力をパースできるOutput Parsersを提供します。
  • Pydanticを使用すると、LLMからの出力をパースする際に使用できるカスタムデータ構造を定義できます。
  • PydanticのJSONパーサー以外にも、LangChainはリストパーサーや日付時刻パーサー、列挙型パーサーなど、さまざまな出力パーサーを提供しています。

よくある質問

この記事に表示されるメディアはAnalytics Vidhyaの所有ではなく、著者の裁量で使用されています。

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more