はじめに
ChatGPTのようなLLMにユーザが質問すると、理路整然と自然な日本語で答えてくれる。このような出力を自作アプリ内で利用するとき、特定の情報だけを出力文字列の中から抽出したいことが良くある。JSON形式での出力を要求したり正規表現を使用することもできるが、もっと便利な手法が存在するので紹介する。
Structured Outputs
任意の文字列から必要な情報だけを抽出し構造化データに変換する方法を、LLMの業界では「Structured Outputs」と呼ぶ。以下、具体的なソースコードを見ながら説明する。最初に、全ソースを以下に示す。ここではAzure OpenAIのPython SDKを利用した。
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
from openai import AzureOpenAI from pydantic import BaseModel import src.utils as utils class Output(BaseModel): """ 出力形式の定義 Attributes: persons_name (str): 抽出された人物名 datetime (str): 抽出された日時 organization_names (list[str]): 抽出された組織名のリスト """ persons_name: str datetime: str organization_names: list[str] REVIEW_TEXT = """ 小泉氏は2015年10月から自民党の農林部会長を務め、JAグループの改革に取り組んだ。 政府の規制改革会議は、競争力を強化するためにJA全農の株式会社化などの組織改革案を打ち出し、 小泉氏も支持していた。 """ def print_output(output: Output) -> None: """ 出力結果を整形して表示する関数 Args: output (Output): 抽出結果のデータ """ print(f"人物名: {output.persons_name}") print(f"日時: {output.datetime}") print(f"組織名: {', '.join(output.organization_names)}") if __name__ == "__main__": # Azure OpenAIクライアントの初期化 client = AzureOpenAI( azure_endpoint=utils.azure_openai_endpoint, api_key=utils.azure_openai_api_key, api_version=utils.azure_openai_api_version, ) # レビューのテキストから情報を抽出 response = client.beta.chat.completions.parse( model=utils.azure_openai_model_name, messages=[ { "role": "system", "content": "あなたは情報抽出の専門家です。", }, { "role": "user", "content": "以下のテキストから、人物名、日時、組織名を抽出してください。\n" f"{REVIEW_TEXT}", }, ], response_format=Output, ) # レスポンスから抽出結果を取得 output = response.choices[0].message.parsed # 出力結果を表示 if output: print_output(output) |
今回のサンプルでは以下の文章(上記コードの23行目から25行目)から人名、日時、組織名を抽出することが目的である(引用元)。
1 2 3 4 5 |
REVIEW_TEXT = """ 小泉氏は2015年10月から自民党の農林部会長を務め、JAグループの改革に取り組んだ。 政府の規制改革会議は、競争力を強化するためにJA全農の株式会社化などの組織改革案を打ち出し、 小泉氏も支持していた。 """ |
以下、必要な個所を切り出しながら順に説明する。
出力用クラスの作成
まず最初に出力用のクラスOutput
を以下のように定義する。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Output(BaseModel): """ 出力形式の定義 Attributes: persons_name (str): 抽出された人物名 datetime (str): 抽出された日時 organization_names (list[str]): 抽出された組織名のリスト """ persons_name: str datetime: str organization_names: list[str] |
メンバ変数の内訳は以下の通りである。
● persons_name
:人名
● datetime
:日時
● organization_names
:組織名
これらは今回切り出したい対象物である。
Azure OpenAIクライアントの初期化
Azure OpenAIクライアントを初期化する。
1 2 3 4 5 6 |
# Azure OpenAIクライアントの初期化 client = AzureOpenAI( azure_endpoint=utils.azure_openai_endpoint, api_key=utils.azure_openai_api_key, api_version=utils.azure_openai_api_version, ) |
引数には以下3つの情報が必要である。
● Azure OpenAIのエンドポイント
● Azure OpenAIのAPIキー
● Azure OpenAIのAPIバージョン
これら3つの情報はあらかじめ用意しておくものである。
Azure OpenAIの実行
関数parse
を呼び出し
● 最初の引数model
にAzure OpenAIのデプロイ名
● 2番目の引数messages
に入力プロンプト
● 最後の引数response_format
に上で定義した出力用クラスOutput
を渡して実行する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# レビューのテキストから情報を抽出 response = client.beta.chat.completions.parse( model=utils.azure_openai_model_name, messages=[ { "role": "system", "content": "あなたは情報抽出の専門家です。", }, { "role": "user", "content": "以下のテキストから、人物名、日時、組織名を抽出してください。\n" f"{REVIEW_TEXT}", }, ], response_format=Output, ) |
結果の出力
最後に結果を出力する。以下の関数を定義し
1 2 3 4 5 6 7 8 9 10 |
def print_output(output: Output) -> None: """ 出力結果を整形して表示する関数 Args: output (Output): 抽出結果のデータ """ print(f"人物名: {output.persons_name}") print(f"日時: {output.datetime}") print(f"組織名: {', '.join(output.organization_names)}") |
以下のように呼び出す。
1 2 3 4 5 6 |
# レスポンスから抽出結果を取得 output = response.choices[0].message.parsed # 出力結果を表示 if output: print_output(output) |
出力は以下の通り。
1 2 3 |
人物名: 小泉 日時: 2015年10月 組織名: 自民党, JAグループ, 政府の規制改革会議, JA全農 |
クラスOutput
のメンバ変数に目的の文字列が格納されていることが分かる。
まとめ
今回は、LLMの出力から特定の情報だけを抽出する便利な方法を紹介した。自作アプリ内でLLMの出力を利用する際に大いに役立つ手法である。