3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

生成AI Study - (3) RAG入門

Last updated at Posted at 2025-08-03

はじめに

LLMで生成されるコンテンツの精度を高める手法の1つとしてRAG(Retrieval-Augmented Generation)という考え方があります。
ここではRAGについて整理していきたいと思います。
実装はLangChainをベースに確認していきます。

関連記事

生成AI Study - (1) 基礎知識の整理
生成AI Study - (2) LangChain入門
生成AI Study - (3) RAG入門

RAG概要

参考:
What is RAG (retrieval augmented generation)?

RAGとは

LLMを用いることで質問や指示(プロンプト)に対して適切な情報を生成させるしくみを比較的容易に作れるようになってきました。
しかし、LLMが生成するコンテンツは事前に学習した情報をベースを基にコンテンツを生成するものであるため、生成されるコンテンツの"精度"が課題になる場合があります。
特に専門性の高い分野でLLMを利用することを考えると、以下のような課題が浮かび上がってきます。

(1) 情報のソースが不明瞭
LLMは事前に学習されたデータに基づいて確からしいコンテンツを推測して生成することになりますが、その情報源が何なのかは分からないため、生成された結果が信頼できるものかどうかを検証することが困難です。

(2) 学習データと最新情報のギャップ
LLMは事前学習データを基に回答を生成するので、LLMが提供された瞬間からそのベースとなる情報は陳腐化していきます。刻一刻と変化している世の中のあらゆる情報を逐一アップデートして新しいLLMを提供し続けていくことは困難ですし、IT業界のような変革のスピードが速い分野ではその影響は顕著です。

例えば、次のような質問をLLMに投げかけることを想定してみます。
"太陽系で最も多くの衛星を持つ惑星は?"
近年では、観測精度の進歩により木星と土星は衛星の数で競争が繰り広げされているらしく、観測された衛星の数というのは刻刻と変わっています。ある時点では木星の衛星の数が最も多いと認識されていましたが、新しく観測された衛星を加味すると最近(2025年6月時点)では土星の衛星の数がダントツで多いようです。どの時点の情報を学習しているかによってLLMが導き出す回答の精度が変わってくることは容易に想像できます。

特定の専門分野に特化した超大量のデータを追加学習させる、いわゆる"ファインチューニング"というアプローチがありますが、これを行うためには学習データの準備、実際の学習を行わせる環境整備、LLMのチューニング実施、のサイクルを回す必要があり、相当なコストがかかります。

そこで、比較的容易な方法で生成されるコンテンツの精度を上げる方法が考えられており、その1つがRAG(Retrieval Augmented Generation)という技術です。
これは、LLMにプロンプトを入力する際に、質問や指示と合わせて補足として最新情報や特定分野の専門的情報を付加することで(つまりLLMの学習データには含まれていない可能性のある情報、あるいは注目させたい情報を付加することで)、生成精度をあげようという考え方です。

image.png
image.png

考え方のベースはいたってシンプルですね。
ただ、じゃぁこの関連情報をどこからどうやって持ってくるかというところで一つ工夫が必要になります。
RAGでは一般的にはLLMを利用する前段で"関連情報"を抽出するというステップが必要になり、すなわちそのための準備として"関連情報"を蓄積して効率よく抽出するための仕組みを用意しておく必要があります。
全体像を示すと以下のようなイメージとなります。

image.png

LLMを利用する場合、入力+出力で使用されるトークン数(≒単語数)には上限があります。LLMの性能が向上していますのでトークン数の上限もどんどん増えている状況ですが、いくらでも情報を入力として与えられるわけではありません。つまり、最新の関連論文やマニュアルなどをまとめてどかっとプロンプトとして与えるということは現実的ではありません。

そこで、まず特定分野の関連情報を蓄積した"ナレッジ・ベース"を用意しておき、ユーザーからの質問に関連しそうな情報のみをナレッジ・ベースから抽出し、質問文と合わせてプロンプトを組み立てLLMに投入します。そうすることでLLMからの回答の精度が上がることが期待されます。
RAGとは、このようなシステムのアーキテクチャー・パターンを意味することもあるようです。

ここで肝になるのが、ナレッジ・ベースをどのように構築してどのように関連情報を抽出するか、ということになります。ここでいかに適切な関連情報を抽出できるかが最終的な生成コンテンツの精度に直結します。

ナレッジ・ベースについて

RAGの肝になるのは関連情報を抽出するための"ナレッジ・ベース"であると言えると思いますが、これは目的にあった情報を効果的に取得できれば実装形態はなんでもOKです。単にテキストファイルの集まりでもよいかもしれませんし、ElasticSearchのような全文検索エンジンでもよいかもしれませんし、RDBのようなものでもよいかもしれません。
ただ、LLMを使って質問→回答 のような支援システムを構築することを考えた場合、元の入力は自然言語での質問文が想定されますし、関連情報として蓄積されるソースとしては論文、Web上のコンテンツ、マニュアル、などに含まれる文章、つまり、こちらも自然言語で表記された長文テキストということになります。
元の質問文(自然言語)に関連しそうな情報をソース(自然言語)から抽出する、というのはなかなかに困難そうです。
ここで注目されているのがベクトルDBという技術です。

ベクトルDBについて

ベクトルDBとは、テキストなどの非構造化データから抽出された特徴量を"ベクトル"と呼ばれる数値の羅列に変換して保持し、それらのベクトル間の類似度(距離)に基づいて高速に検索できる仕組みを提供するデータベース・システムです。
つまり、関連情報のソースをベクトルDBに保持しておけば、元の質問文をベクトル化し、ベクトルDB上のデータのうち類似性の高いものを抽出することができる、ということになります。

事前準備としてベクトルDBにソースとなる情報を取り込む際にも工夫が必要になります。通常ベクトルDBに取り込みたいデータは論文やWeb上のコンテンツ、マニュアルなどの情報になると思いますが、これらのデータ形式は様々でしょうし(txt、HTML、PDF、...)、そのままではサイズが大きすぎる場合も多いと思います。そこで、一般的には以下のようなステップでベクトルDB化することになります。
rag_indexing-8160f90a90a33253d0154659cf7d453f.png

(1) LOAD
まずは取り込みたいデータを読み込む必要があります。
LangChainでは取り込むデータの形式に応じたDocument Loaderと呼ばれるユーティリティーが各種提供されています(PDF, HTML, csv, JSON, etc...)。

参考:
LangChain - Conceptual guide - Document Loaders
LangChain - Components - Document Loaders

(2) SPLIT
読み込んだデータはそのままでは大きすぎる場合や、意味のある単位に分ける必要がある場合があります。このステップでは、データをより小さなチャンク(塊)に分割します。例えば、長いテキストドキュメントであれば、段落ごとや、特定の文字数ごとに分割することが考えられます。この分割の仕方は、後のベクトル化の精度や検索の効率に影響するため、重要なステップです。
LangChainでは、データ形式に応じたText Splitterと呼ばれるユーティリティーが各種提供されています。

参考:
LangChain - Conceptual guide - Text Splitters
LangChain - Howto guides - Text Splitters

(3) EMBED
このステップでは、分割されたチャンク単位でテキスト情報を"ベクトル"と呼ばれる数値に変換します。この変換の際は、「埋め込みモデル(Embedding Model)」と呼ばれるAIモデルを使用します(いわゆるLLMと呼ばれるものとは違ってベクトル化専用のモデルです)。この埋め込みモデルを使用することで単語の意味や文脈を考慮したベクトル化(数値化)が行われます。このベクトルは、元のデータの意味的な特徴を多次元空間上の点として表現したものであり、似た意味を持つデータは空間上で近い位置に配置されるようになります。

埋め込みモデルは各種ベンダーが様々モデルを提供しています。例えば、IBM watsonx.ai は以下のリンク先にあるモデルを提供しています。
watsonx.aiでサポートされているエンコーダ基礎モデル - 埋め込みモデル

参考:
LangChain - Conceptual guide - Embedding models
LangChain - Components - Embedding models

(4) STORE
最後に生成されたベクトルをベクトルDBに格納します。ベクトルDBは、これらのベクトルを効率的に保存し、高速な類似度検索(最近傍探索)を可能にするためのインデックス構造を持っています。格納時には、元のデータへの参照(IDなど)も一緒に保存されることが多く、検索結果から元のデータを辿れるような仕組みを提供します。
LangChainでは、ベクトルデータを保存するためのVector Storeとよばれるユーティリティーが各種提供されています。手っ取り早く使えるVector Storeとしては、例えばInMemoryVectorStoreや、Chromaなどがあります。これらは別途データベースサーバーのようなものを構築しなくてもアプリケーションに組み込む形で利用できます。

参考:
LangChain - Conceptual guide - Vector Stores
LangChain - Components - Vector Stores

LangGraphについて

LangGraphは、LangChainが提供するライブラリの一部で、複雑なプロセスをグラフ構造で定義・実行する機能を提供するものです。
RAGの考え方に従った仕組みを作る際にLangGraphが必須という訳ではありませんが、関連情報を取得する際に複数のサービスを連携する必要がある場合など、より複雑なフローを制御したい場合にはLangGraphを使ってRAGの仕組みを実装すると効果的な場合があるようです。

参考:
LangGraph

RAGを実装してみる

いくつかのパターンでRAGベースのアプリを実装してみます。

例1: 最小構成のシンプルなRAG

ここでは、LLMにある架空の物語を生成させ、その物語に関する質問に対する回答を生成させる、ということをやってみます。
こんなイメージです。
image.png

事前準備

LLMに適当なタイトルの物語を生成させてみます。これは先に示したLangChainのようなコードで生成させてもよいですし、チャット形式のインターフェースを持つLLMであればそのUIから生成させてもよいです。
生成させた物語はテキストファイルに保存しておきます。

ここでは、存在しそうになり適当なタイトル「車の中のハエと蚊の戦い」という物語を生成させてみます。
IBM watsonx.aiではwatsonx.ai studioというWebベースのツールがあり、そこからプロンプトを入力して結果を生成させることができるので、それを使用してみます。
「車の中のハエと蚊の戦い」という日本語の物語を作成してください。結果はマークダウン形式で出力してください。 というプロンプトを与えることでマークダウン形式で短い物語が生成されました。
image.png

これを、車の中のハエと蚊の戦い.txtというファイルに保存しておきます。
これが、今回のRAGで使用する関連情報そのものです。

モデル作成

sample
import os
from dotenv import load_dotenv

load_dotenv()
myURL = os.getenv("MY_WATSONX_ENDPOINT")
myProjectID = os.getenv("MY_WATSONX_PROJECTID")
myAPIKey = os.getenv("MY_WATSONX_APIKEY")

from langchain_ibm import ChatWatsonx

model = ChatWatsonx(
    model_id = "mistralai/mistral-large", 
    url = myURL, 
    project_id = myProjectID,
    apikey = myAPIKey
)

ナレッジ・ベースの準備

今回は単なる1つのテキスト・ファイル(車の中のハエと蚊の戦い.txt)がナレッジ・ベースに相当しますが、このファイルを読み込むための関数を定義しておきます。

sample
from langchain_community.document_loaders.text import TextLoader

def retrieve():
    loader = TextLoader(file_path="./車の中のハエと蚊の戦い.txt", encoding="utf-8")
    docs = loader.load()
    return docs

関連情報取得、プロンプト作成

質問文を設定し、それに関する情報(今回は固定でLLMに生成させた物語)を合わせてプロンプトを作成します。

sample
    from langchain_core.messages import HumanMessage, SystemMessage
    
    # Question from a user
    question = "「車の中のハエと蚊の戦い」の第2章のタイトルは何ですか?"
    
    # Retrieve a related information
    docs = retrieve()
    docs_text = docs[0].page_content
    
    # Create a prompt
    system_prompt = f"""あなたは質問応答のアシスタントです。質問に答えるために、以下のコンテキストを使用してください。
    
    コンテキスト:
    ```
    {docs_text}
    ```
    """
    
    prompt = [
        SystemMessage(content=system_prompt),
        HumanMessage(content=question)
    ]

LLM呼び出し、結果の解釈

作成したプロンプトを入力にLLMを呼び出し、結果を表示させてみます。

sample
# get a response from an LLM using a prompt
output = model.invoke(prompt)
print(output.content)
結果例
「車の中のハエと蚊の戦い」の第2章のタイトルは「縄張り争い」です。

LLMが知らない(事前に学習していない)物語に関する質問に対して、適切な回答が返されました!

例2: ベクトルDBを使用したRAG

LangChain Tutorial - Build a semantic search engine

上のTutorialに沿ってベクトルDBを利用する手順を見ていきます。その後、そのベクトルDBを使用したRAGの仕組みを作って動かしてみます。

全体像としては以下のイメージです。

image.png

PDFの情報を読み込んで分割し、Embedding Modelによりベクトル化してベクトルDBに関連情報を格納しておく、ということを事前準備として実施しておきます。
その後、実際に回答を生成してもらいたい質問をした場合には、ベクトルDBから質問に関連しそうな情報をベクトルDBから抽出し、それを加えてLLMにプロンプトを投げて回答を生成させる、という流れになります。

※実際の利用を考えた場合、事前準備部分(Vector DBを作成する部分)と、RAGから利用する部分は別アプリケーションとして考えるのが自然だと思いますが、ここでは便宜上同一のアプリケーションで一気に動かしています。

事前準備フェーズ(Vector DB準備)

LOAD

特定の情報が含まれるPDFを読み込みます。今回はこのPDFに関する質問に対応することを前提としています。
今回使用するPDFは、以下に提供されているものを使用します。
https://github.com/langchain-ai/langchain/blob/master/docs/docs/example_data/nke-10k-2023.pdf
こちらはNIKE社のAnnual Reportのようです。

sample
from langchain_community.document_loaders import PyPDFLoader

file_path = "./example_data/nke-10k-2023.pdf"
loader = PyPDFLoader(file_path)

docs = loader.load()

print(len(docs))

ここではPyPDFLoaderというPDF用のLoaderを使ってファイルをロードします。このローダーは、PDFを1ページ単位でDocument型のオブジェクトにしてそのリストを返します。元のPDFファイルは107ページあるので、docsは要素数107個のリスト型オブジェクトとして生成されます。ここで生成されるdocsの中身を見るとこんな感じになっています。

docsオブジェクト
docs抜粋
[Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1'}, page_content="Table of Contents\nUNITED STATES\nSECURITIES AND EXCHANGE COMMISSION\nWashington, D.C. 20549\nFORM 10-K\n(Mark One)\n☑  ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934\nFOR THE FISCAL YEAR ENDED MAY 31, 2023\nOR\n☐  TRANSITION REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934\nFOR THE TRANSITION PERIOD FROM                         TO                         .\nCommission File No. 1-10635\nNIKE, Inc.\n(Exact name of Registrant as specified in its charter)\nOregon 93-0584541\n(State or other jurisdiction of incorporation) (IRS Employer Identification No.)\nOne Bowerman Drive, Beaverton, Oregon 97005-6453\n(Address of principal executive offices and zip code)\n(503) 671-6453\n(Registrant's telephone number, including area code)\nSECURITIES REGISTERED PURSUANT TO SECTION 12(B) OF THE ACT:\nClass B Common Stock NKE New York Stock Exchange\n(Title of each class) (Trading symbol) (Name of each exchange on which registered)\nSECURITIES REGISTERED PURSUANT TO SECTION 12(G) OF THE ACT:\nNONE\nIndicate by check mark: YES NO\n• if the registrant is a well-known seasoned issuer, as defined in Rule 405 of the Securities Act. þ ¨ \n• if the registrant is not required to file reports pursuant to Section 13 or Section 15(d) of the Act. ¨ þ \n• whether the registrant (1) has filed all reports required to be filed by Section 13 or 15(d) of the Securities Exchange Act of 1934 during the preceding\n12 months (or for such shorter period that the registrant was required to file such reports), and (2) has been subject to such filing requirements for the\npast 90 days.\nþ ¨ \n• whether the registrant has submitted electronically every Interactive Data File required to be submitted pursuant to Rule 405 of Regulation S-T\n(§232.405 of this chapter) during the preceding 12 months (or for such shorter period that the registrant was required to submit such files).\nþ ¨ \n• whether the registrant is a large accelerated filer, an accelerated filer, a non-accelerated filer, a smaller reporting company or an emerging growth company. See the definitions of “large accelerated filer,”\n“accelerated filer,” “smaller reporting company,” and “emerging growth company” in Rule 12b-2 of the Exchange Act.\nLarge accelerated filer þ Accelerated filer ☐ Non-accelerated filer ☐ Smaller reporting company ☐ Emerging growth company ☐ \n• if an emerging growth company, if the registrant has elected not to use the extended transition period for complying with any new or revised financial\naccounting standards provided pursuant to Section 13(a) of the Exchange Act.\n¨ \n• whether the registrant has filed a report on and attestation to its management's assessment of the effectiveness of its internal control over financial\nreporting under Section 404(b) of the Sarbanes-Oxley Act (15 U.S.C. 7262(b)) by the registered public accounting firm that prepared or issued its audit\nreport.\nþ \n• if securities are registered pursuant to Section 12(b) of the Act, whether the financial statements of the registrant included in the filing reflect the\ncorrection of an error to previously issued financial statements.\n¨ \n• whether any of those error corrections are restatements that required a recovery analysis of incentive-based compensation received by any of the\nregistrant's executive officers during the relevant recovery period pursuant to § 240.10D-1(b).\n¨ \n• whether the registrant is a shell company (as defined in Rule 12b-2 of the Act). ☐ þ \nAs of November 30, 2022, the aggregate market values of the Registrant's Common Stock held by non-affiliates were:\nClass A $ 7,831,564,572 \nClass B 136,467,702,472 \n$ 144,299,267,044"),
 Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 1, 'page_label': '2'}, page_content="Table of Contents\nAs of July 12, 2023, the number of shares of the Registrant's Common Stock outstanding were:\nClass A 304,897,252 \nClass B 1,225,074,356 \n1,529,971,608 \nDOCUMENTS INCORPORATED BY REFERENCE:\nParts of Registrant's Proxy Statement for the Annual Meeting of Shareholders to be held on September 12, 2023, are incorporated by reference into Part III of this report."),
 Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 2, 'page_label': '3'}, page_content="Table of Contents\nNIKE, INC.ANNUAL REPORT ON FORM 10-KTABLE OF CONTENTS\nPAGE\nPART I 1\nITEM 1. Business 1\nGeneral 1\nProducts 1\nSales and Marketing 2\nOur Markets 2\nSignificant Customer 3\nProduct Research, Design and Development 3\nManufacturing 3\nInternational Operations and Trade 4\nCompetition 5\nTrademarks and Patents 5\nHuman Capital Resources 6\nAvailable Information and Websites 7\nInformation about our Executive Officers 8\nITEM 1A.Risk Factors 9\nITEM 1B.Unresolved Staff Comments 24\nITEM 2. Properties 24\nITEM 3. Legal Proceedings 24\nITEM 4. Mine Safety Disclosures 24\nPART II 25\nITEM 5. Market for Registrant's Common Equity, Related Stockholder Matters and Issuer Purchases of Equity Securities 25\nITEM 6. Reserved 27\nITEM 7. Management's Discussion and Analysis of Financial Condition and Results of Operations 28\nITEM 7A.Quantitative and Qualitative Disclosures about Market Risk 49\nITEM 8. Financial Statements and Supplementary Data 51\nITEM 9. Changes in and Disagreements with Accountants on Accounting and Financial Disclosure 91\nITEM 9A.Controls and Procedures 91\nITEM 9B.Other Information 91\nITEM 9C.Disclosure Regarding Foreign Jurisdictions that Prevent Inspections 91\nPART III 92\n(Except for the information set forth under “Information about our Executive Officers” in Item 1 above, Part III is incorporated by reference from the ProxyStatement for the NIKE, Inc. 2023 Annual Meeting of Shareholders.)\nITEM 10.Directors, Executive Officers and Corporate Governance 92\nITEM 11. Executive Compensation 92\nITEM 12.Security Ownership of Certain Beneficial Owners and Management and Related Stockholder Matters 92\nITEM 13.Certain Relationships and Related Transactions and Director Independence 92\nITEM 14.Principal Accountant Fees and Services 92\nPART IV 93\nITEM 15.Exhibits and Financial Statement Schedules 93\nITEM 16.Form 10-K Summary 97\nSignatures 99"),
...

各ページの情報は以下の要素を含むDocument型のデータとして保持されています。

  • page_content: 当該ページに含まれる文字列情報
  • metadata: ページ番号や当該資料のタイトル、著者などの情報

読み取った1ページ目の情報の一部を出力してみると以下のようになります。

sample
print(f"{docs[0].page_content[:200]}\n")
print(docs[0].metadata)
結果例
Table of Contents
UNITED STATES
SECURITIES AND EXCHANGE COMMISSION
Washington, D.C. 20549
FORM 10-K
(Mark One)
☑  ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934
F

{'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1'}

metadataに含まれている要素を整理するとこんな感じです。

    metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 
              'creator': 'EDGAR Filing HTML Converter',
              'creationdate': '2023-07-20T16:22:00-04:00', 
              'title': '0000320187-23-000039', 
              'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 
              'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 
              'keywords': '0000320187-23-000039; ; 10-K', 
              'moddate': '2023-07-20T16:22:08-04:00', 
              'source': './example_data/nke-10k-2023.pdf', 
              'total_pages': 107, 
              'page': 0, 
              'page_label': '1'}

SPLIT

上で読み取った1ページごとの情報をさらに細かい単位に分割します。

sample
from langchain_text_splitters import RecursiveCharacterTextSplitter

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000, chunk_overlap=200, add_start_index=True
)
all_splits = text_splitter.split_documents(docs)

print(len(all_splits))

ここでは、RecursiveCharacterTextSplitter というsplitterを使って各ページの情報をさらに細かくchunkという単位に分割しています。分割の際に指定しているオプションを補足しておきます。

  • chunk_size=1000: 分割されるテキストの最大文字数を1000に指定しています。基本的にはこのチャンクサイズが後々LLMに投入する"関連情報"のサイズになるので、大きすぎるとLLMのトークン数上限に抵触する可能性がありますし、小さすぎると文脈が失われて意味のあるまとまった情報にならない可能性があります。
  • chunk_overlap=200: 連続するチャンク間で重複させる文字数を指定します。最初のチャンクが0~999番目の文字だとすると、次のチャンクは800~1799番目の文字列となります。チャンクの境界に重要な文章があった場合に分割によって文脈が欠落してしまう可能性を避けるためにこのようなオーバーラップを指定します。
  • add_start_index=Ture: 各チャンクに、元のテキストにおける「開始インデックス(文字位置)」をメタデータとして追加することを指定しています。

分割されたデータは、元と同じような構造で各チャンクごとにDocument型のオブジェクトとして保持され、そのリストとして保持されます。ここで生成されるall_splitsの中身を見るとこんな感じになっています。

all_splitsオブジェクト
all_splits抜粋
[Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1', 'start_index': 0}, page_content="Table of Contents\nUNITED STATES\nSECURITIES AND EXCHANGE COMMISSION\nWashington, D.C. 20549\nFORM 10-K\n(Mark One)\n☑  ANNUAL REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934\nFOR THE FISCAL YEAR ENDED MAY 31, 2023\nOR\n☐  TRANSITION REPORT PURSUANT TO SECTION 13 OR 15(D) OF THE SECURITIES EXCHANGE ACT OF 1934\nFOR THE TRANSITION PERIOD FROM                         TO                         .\nCommission File No. 1-10635\nNIKE, Inc.\n(Exact name of Registrant as specified in its charter)\nOregon 93-0584541\n(State or other jurisdiction of incorporation) (IRS Employer Identification No.)\nOne Bowerman Drive, Beaverton, Oregon 97005-6453\n(Address of principal executive offices and zip code)\n(503) 671-6453\n(Registrant's telephone number, including area code)\nSECURITIES REGISTERED PURSUANT TO SECTION 12(B) OF THE ACT:\nClass B Common Stock NKE New York Stock Exchange\n(Title of each class) (Trading symbol) (Name of each exchange on which registered)"),
 Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1', 'start_index': 781}, page_content='SECURITIES REGISTERED PURSUANT TO SECTION 12(B) OF THE ACT:\nClass B Common Stock NKE New York Stock Exchange\n(Title of each class) (Trading symbol) (Name of each exchange on which registered)\nSECURITIES REGISTERED PURSUANT TO SECTION 12(G) OF THE ACT:\nNONE\nIndicate by check mark: YES NO\n• if the registrant is a well-known seasoned issuer, as defined in Rule 405 of the Securities Act. þ ¨ \n• if the registrant is not required to file reports pursuant to Section 13 or Section 15(d) of the Act. ¨ þ \n• whether the registrant (1) has filed all reports required to be filed by Section 13 or 15(d) of the Securities Exchange Act of 1934 during the preceding\n12 months (or for such shorter period that the registrant was required to file such reports), and (2) has been subject to such filing requirements for the\npast 90 days.\nþ ¨ \n• whether the registrant has submitted electronically every Interactive Data File required to be submitted pursuant to Rule 405 of Regulation S-T'),
 Document(metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'page': 0, 'page_label': '1', 'start_index': 1592}, page_content='past 90 days.\nþ ¨ \n• whether the registrant has submitted electronically every Interactive Data File required to be submitted pursuant to Rule 405 of Regulation S-T\n(§232.405 of this chapter) during the preceding 12 months (or for such shorter period that the registrant was required to submit such files).\nþ ¨ \n• whether the registrant is a large accelerated filer, an accelerated filer, a non-accelerated filer, a smaller reporting company or an emerging growth company. See the definitions of “large accelerated filer,”\n“accelerated filer,” “smaller reporting company,” and “emerging growth company” in Rule 12b-2 of the Exchange Act.\nLarge accelerated filer þ Accelerated filer ☐ Non-accelerated filer ☐ Smaller reporting company ☐ Emerging growth company ☐ \n• if an emerging growth company, if the registrant has elected not to use the extended transition period for complying with any new or revised financial\naccounting standards provided pursuant to Section 13(a) of the Exchange Act.\n¨'),

各Document型の要素は元のdocsと同様、metadataとpage_contentから構成されます。metadataの中身の例を見てみるとこんな感じです。

    metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 
              'creator': 'EDGAR Filing HTML Converter', 
              'creationdate': '2023-07-20T16:22:00-04:00', 
              'title': '0000320187-23-000039', 
              'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 
              'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 
              'keywords': '0000320187-23-000039; ; 10-K', 
              'moddate': '2023-07-20T16:22:08-04:00', 
              'source': './example_data/nke-10k-2023.pdf', 
              'total_pages': 107, 
              'page': 0, 
              'page_label': '1', 
              'start_index': 0}

start_indexが追加されています。

今回の例では、結果的に516のチャンクに分割されました。

EMBED

Embedding Modelの設定を行います。ここでは、watsonx.aiが提供するibm/slate-125m-english-rtrvr-v2を指定しています。LLMへのアクセス同様、watsonx.aiへのアクセス情報が必要になります。

sample
from langchain_ibm import WatsonxEmbeddings

embeddings = WatsonxEmbeddings(
    model_id="ibm/slate-125m-english-rtrvr-v2",
    url = myURL, 
    project_id = myProjectID,
    apikey = myAPIKey
)

上のモデルを使用して、試しに先に分割したチャンクの文字列を2つベクトル化してみます。

sample
vector_1 = embeddings.embed_query(all_splits[0].page_content)
vector_2 = embeddings.embed_query(all_splits[1].page_content)

assert len(vector_1) == len(vector_2)
print(f"vector_1: Generated vectors of length {len(vector_1)}")
print(vector_1[:10])
結果例
vector_1: Generated vectors of length 768
[-0.006983885, -0.004521338, -0.043712303, 0.028436257, -0.0417436, -0.022272607, -0.027329985, -0.022104105, 0.016607296, 0.04549883]

embeddingsオブジェクトのembed_queryメソッドによって、特定の文字列(今回はチャンクとして分割した文字列)をベクトル化しています。結果としては数値のリストとして保持されます。ベクトルの長さ(次元数)は使用するEmbedding Modelに依存します。

※次元数が高いと単語や文章の微妙な意味合いや文脈など複数の側面詳細にとらえることができるようですが、一方で計算コストが高くなったり、データセットが小さい場合ノイズや特定パターンの影響が増えて汎用性が低下するリスクもあるようですので、一概に次元数が多ければよいという訳では無いようです。

ここでの操作はベクトル化の動作を個別に確認してみた、という位置づけのものです。後述のVector Storeの機能でベクトル化と情報の格納を一度に行えるため、実際のベクトル化は次の節で行います。

EMBED & STORE

Vector DBとして、ここではChromaというVector Storeを使用します。
ChromaはいわゆるDBMSのようなデータベースサーバーを構築する必要がなく、かつ、永続化(特定のディレクトリに情報を保持)することも容易で、ベクトル情報を保持する仕組みとしては取り扱いが容易です。

sample
from langchain_chroma import Chroma

vector_store = Chroma(
    collection_name="example_collection",
    embedding_function=embeddings,
    persist_directory="./chroma_langchain_db",  # Where to save data locally, remove if not necessary
)

ここではChromaというVector Storeをインスタンス化していますが、そこで指定しているオプションを補足します。

  • collection_name="example_collection": Chromaでは、データを「コレクション」という単位で管理します。1つのChromaインスタンス内に複数のコレクションを作成し、それぞれに異なる種類のベクトルデータを保存することができます。ここで指定された"example_collection"という名前のコレクションがChroma内に作成されるか、もし既に存在すればそのコレクションに接続します。
  • embedding_function=embeddings: テキストデータをベクトル化する際に使用するEmbedding Modelのインスタンスを指定します。ここでは先に作成したwatsonx.ai提供のEmbedding Modelを指定したインスタンスを指定しています。
  • persist_directory="./chroma_langchain_db": ChromaはデフォルトではIn-Memory DBとして動作しますが、persist_directoryを指定することで永続化することもできます。これを指定すると、内部的にはSQLiteというデータベースの仕組みが使われて指定したディレクトリ下にデータが保持されます。つまりプログラムが終了してもベクトル化されたデータが保持されます。
    ※SQLiteはサーバープロセスを必要としない軽量で自己完結型のRDBMSです。

上のコードを実行すると、chroma_langchain_dbディレクトリが無ければディレクトリを作成します。存在していればそこに含まれるベクトルデータ(SQLiteのデータとして保持しているデータ)に接続可能となります。

さて、それではいよいよデータをVector Storeに格納していきます。

sample
ids = vector_store.add_documents(documents=all_splits)

上のコードを実行することで、チャンクに分割されたデータall_splitsが、embedding(ibm/slate-125m-english-rtrvr-v2)でベクトル化され、それがvector_store(Chroma)に格納されることになります。
返される値idsは、追加された各チャンクに対応する位置のIDのリストですが、そのID自体にあまり意味はありません。

これを実行した後に、chroma_langchain_dbディレクトリ下を確認すると、以下のようになっています。

(venv312_test01) ...> dir /s chroma_langchain_db   
 ドライブ C のボリューム ラベルは Windows です
 ボリューム シリアル番号は 7E75-9120 です

 C:\...\chroma_langchain_db のディレクトリ

2025/07/19  14:04    <DIR>          .
2025/07/19  13:42    <DIR>          ..
2025/07/19  14:04    <DIR>          13711aac-21a8-4cad-8152-a505a0d0602f
2025/07/19  14:04         7,364,608 chroma.sqlite3
               1 個のファイル           7,364,608 バイト

 C:\...\chroma_langchain_db\13711aac-21a8-4cad-8152-a505a0d0602f のディレクトリ

2025/07/19  14:04    <DIR>          .
2025/07/19  14:04    <DIR>          ..
2025/07/19  14:04        32,120,000 data_level0.bin
2025/07/19  14:04               100 header.bin
2025/07/19  14:04            40,000 length.bin
2025/07/19  14:04                 0 link_lists.bin
               4 個のファイル          32,160,100 バイト

     ファイルの総数:
               5 個のファイル          39,524,708 バイト
               5 個のディレクトリ  304,452,894,720 バイトの空き領域

このような形でベクトル情報が永続化されます。

ここまでの操作で、ようやく事前準備としてのナレッジ・ベースの準備(PDFデータをベクトルDBとして取り込み)が完了しました。

ベクトルDB利用方法の確認

本番のRAGの実装に行く前に、ベクトルDBから情報抽出方法を確認しておきます。

similarity_search

ベクトルDBを利用する目的の1つに"意味的に近い情報を検索する"ということがあります。今回は、取り込んだPDFに関する質問を受け付けるRAGの仕組みを想定しているので、まずユーザーから質問を受けた場合にそれに関連しそうな情報を含むチャンクをベクトルDBから検索する必要があります。

この"類似検索"を試してみます。

ベースにしているPDFの情報が英語なので、質問もTutorialそのまま英文で試します。ここでは、ユーザーから以下の質問がされた場合を想定し、この内容の意味に近い情報を含むチャンクをベクトルDBから検索してみます。
"How many distribution centers does Nike have in the US?"

sample
results = vector_store.similarity_search(
    "How many distribution centers does Nike have in the US?"
)

print(results[0])
結果例
page_content='direct to consumer operations sell products through the following number of retail stores in the United States:
U.S. RETAIL STORES NUMBER
NIKE Brand factory stores 213 
NIKE Brand in-line stores (including employee-only stores) 74 
Converse stores (including factory stores) 82 
TOTAL 369 
In the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.
2023 FORM 10-K 2' metadata={'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'total_pages': 107, 'creator': 'EDGAR Filing HTML Converter', 'page': 4, 'start_index': 3125, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'source': './example_data/nke-10k-2023.pdf', 'page_label': '5', 'moddate': '2023-07-20T16:22:08-04:00', 'creationdate': '2023-07-20T16:22:00-04:00', 'keywords': '0000320187-23-000039; ; 10-K'}

質問文の意味が近い文章を含むチャンク(≒質問文の答えを生成するのに参考になる関連情報)が抽出されたことになります。

vector_storeオブジェクトに対するsimilarity_searchメソッドにより類似検索を行うことになりますが、ここをもう少し詳細に見てみます。

similarity_searchは、引数で指定した文字列をベクトル化し、vector_storeに格納されているベクトルと距離が近いもの(類似度が高いと判断されるもの)を、類似度が高い順にいくつか抽出してリストとして返します。デフォルトでは上位4件が返されます。件数は引数で制御可能です(例:k=4)。

参考: langchain_chroma.vectorstores.Chroma.similarity_search

results全体としては以下のような情報が返されています。

results
[Document(id='150e2336-cf56-41d1-bbef-e4ec7c3efd22', metadata={'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'total_pages': 107, 'creator': 'EDGAR Filing HTML Converter', 'page': 4, 'start_index': 3125, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'source': './example_data/nke-10k-2023.pdf', 'page_label': '5', 'moddate': '2023-07-20T16:22:08-04:00', 'creationdate': '2023-07-20T16:22:00-04:00', 'keywords': '0000320187-23-000039; ; 10-K'}, page_content='direct to consumer operations sell products through the following number of retail stores in the United States:\nU.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 213 \nNIKE Brand in-line stores (including employee-only stores) 74 \nConverse stores (including factory stores) 82 \nTOTAL 369 \nIn the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.\n2023 FORM 10-K 2'),
 Document(id='508b1d59-be14-42db-b1cc-4745e467cf54', metadata={'source': './example_data/nke-10k-2023.pdf', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'title': '0000320187-23-000039', 'page': 26, 'start_index': 804, 'total_pages': 107, 'page_label': '27', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'creator': 'EDGAR Filing HTML Converter', 'moddate': '2023-07-20T16:22:08-04:00', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'keywords': '0000320187-23-000039; ; 10-K', 'creationdate': '2023-07-20T16:22:00-04:00'}, page_content='operations. We also lease an office complex in Shanghai, China, our headquarters for our Greater China geography, occupied by employees focused on implementing our\nwholesale, NIKE Direct and merchandising strategies in the region, among other functions.\nIn the United States, NIKE has eight significant distribution centers. Five are located in or near Memphis, Tennessee, two of which are owned and three of which are\nleased. Two other distribution centers, one located in Indianapolis, Indiana and one located in Dayton, Tennessee, are leased and operated by third-party logistics\nproviders. One distribution center for Converse is located in Ontario, California, which is leased. NIKE has a number of distribution facilities outside the United States,\nsome of which are leased and operated by third-party logistics providers. The most significant distribution facilities outside the United States are located in Laakdal,'),
 Document(id='c197f7a2-4937-4bdf-87cc-c1e4391111a3', metadata={'start_index': 922, 'keywords': '0000320187-23-000039; ; 10-K', 'creator': 'EDGAR Filing HTML Converter', 'title': '0000320187-23-000039', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'source': './example_data/nke-10k-2023.pdf', 'creationdate': '2023-07-20T16:22:00-04:00', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'moddate': '2023-07-20T16:22:08-04:00', 'page_label': '6', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'total_pages': 107, 'page': 5}, page_content='the following number of retail stores outside the United States:\nNON-U.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 560 \nNIKE Brand in-line stores (including employee-only stores) 49 \nConverse stores (including factory stores) 54 \nTOTAL 663 \nSIGNIFICANT CUSTOMER\nNo customer accounted for 10% or more of our consolidated net Revenues during fiscal 2023.\nPRODUCT RESEARCH, DESIGN AND DEVELOPMENT\nWe believe our research, design and development efforts are key factors in our success. Technical innovation in the design and manufacturing process of footwear,\napparel and athletic equipment receives continued emphasis as we strive to produce products that help to enhance athletic performance, reduce injury and maximize\ncomfort, while decreasing our environmental impact.\nIn addition to our own staff of specialists in the areas of biomechanics, chemistry, exercise physiology, engineering, digital technologies, industrial design, sustainability'),
 Document(id='91a2a3e7-4ca5-4f53-8c10-7056e7b7ce8b', metadata={'keywords': '0000320187-23-000039; ; 10-K', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'moddate': '2023-07-20T16:22:08-04:00', 'title': '0000320187-23-000039', 'creationdate': '2023-07-20T16:22:00-04:00', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'source': './example_data/nke-10k-2023.pdf', 'page_label': '5', 'start_index': 2311, 'creator': 'EDGAR Filing HTML Converter', 'page': 4, 'total_pages': 107, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0'}, page_content='UNITED STATES MARKET\nFor fiscal 2023, NIKE Brand and Converse sales in the United States accounted for approximately 43% of total revenues, compared to 40% and 39% for fiscal 2022 and\nfiscal 2021, respectively. We sell our products to thousands of retail accounts in the United States, including a mix of footwear stores, sporting goods stores, athletic\nspecialty stores, department stores, skate, tennis and golf shops and other retail accounts. In the United States, we utilize NIKE sales offices to solicit such sales. During\nfiscal 2023, our three largest United States customers accounted for approximately 22% of sales in the United States.\nOur NIKE Direct and Converse direct to consumer operations sell our products to consumers through various digital platforms. In addition, our NIKE Direct and Converse\ndirect to consumer operations sell products through the following number of retail stores in the United States:\nU.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 213')]

similarity_search_with_score

similarity_search_with_scoreメソッドを使用すると、検索結果に加えてスコア(類似度)を取得することができます。スコアはベクトル間の距離を表すものなので数値が小さいほうが類似度が高いということを意味します。

sample
results = vector_store.similarity_search_with_score("What was Nike's revenue in 2023?")
doc, score = results[0]
print(f"Score: {score}\n")
print(doc)
結果例
Score: 0.2825096845626831

page_content='Table of Contents
FISCAL 2023 NIKE BRAND REVENUE HIGHLIGHTSThe following tables present NIKE Brand revenues disaggregated by reportable operating segment, distribution channel and major product line:
FISCAL 2023 COMPARED TO FISCAL 2022
• NIKE, Inc. Revenues were $51.2 billion in fiscal 2023, which increased 10% and 16% compared to fiscal 2022 on a reported and currency-neutral basis, respectively.
The increase was due to higher revenues in North America, Europe, Middle East & Africa ("EMEA"), APLA and Greater China, which contributed approximately 7, 6,
2 and 1 percentage points to NIKE, Inc. Revenues, respectively.
• NIKE Brand revenues, which represented over 90% of NIKE, Inc. Revenues, increased 10% and 16% on a reported and currency-neutral basis, respectively. This
increase was primarily due to higher revenues in Men's, the Jordan Brand, Women's and Kids' which grew 17%, 35%,11% and 10%, respectively, on a wholesale
equivalent basis.' metadata={'page': 35, 'total_pages': 107, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'page_label': '36', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'creationdate': '2023-07-20T16:22:00-04:00', 'creator': 'EDGAR Filing HTML Converter', 'title': '0000320187-23-000039', 'keywords': '0000320187-23-000039; ; 10-K', 'start_index': 0, 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31'}

results全体の中身はこちら

results
[(Document(id='d8f0ad53-d29a-46e5-876f-767eb05068ef', metadata={'page': 35, 'total_pages': 107, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'page_label': '36', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'creationdate': '2023-07-20T16:22:00-04:00', 'creator': 'EDGAR Filing HTML Converter', 'title': '0000320187-23-000039', 'keywords': '0000320187-23-000039; ; 10-K', 'start_index': 0, 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31'}, page_content='Table of Contents\nFISCAL 2023 NIKE BRAND REVENUE HIGHLIGHTSThe following tables present NIKE Brand revenues disaggregated by reportable operating segment, distribution channel and major product line:\nFISCAL 2023 COMPARED TO FISCAL 2022\n• NIKE, Inc. Revenues were $51.2 billion in fiscal 2023, which increased 10% and 16% compared to fiscal 2022 on a reported and currency-neutral basis, respectively.\nThe increase was due to higher revenues in North America, Europe, Middle East & Africa ("EMEA"), APLA and Greater China, which contributed approximately 7, 6,\n2 and 1 percentage points to NIKE, Inc. Revenues, respectively.\n• NIKE Brand revenues, which represented over 90% of NIKE, Inc. Revenues, increased 10% and 16% on a reported and currency-neutral basis, respectively. This\nincrease was primarily due to higher revenues in Men\'s, the Jordan Brand, Women\'s and Kids\' which grew 17%, 35%,11% and 10%, respectively, on a wholesale\nequivalent basis.'),
  0.2825096845626831),
 (Document(id='268e5b92-9806-4b7a-9751-6e4960862d13', metadata={'total_pages': 107, 'start_index': 1454, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'keywords': '0000320187-23-000039; ; 10-K', 'page_label': '37', 'creator': 'EDGAR Filing HTML Converter', 'page': 36, 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'source': './example_data/nke-10k-2023.pdf', 'creationdate': '2023-07-20T16:22:00-04:00', 'moddate': '2023-07-20T16:22:08-04:00', 'title': '0000320187-23-000039'}, page_content='Operating overhead expense 12,317 10,954 12 % 9,911 11 %\nTotal selling and administrative expense $ 16,377 $ 14,804 11 % $ 13,025 14 %\n% of revenues 32.0 % 31.7 % 30  bps 29.2 % 250  bps\n(1) Demand creation expense consists of advertising and promotion costs, including costs of endorsement contracts, complimentary product, television, digital and print advertising and media costs, brandevents and retail brand presentation.\nFISCAL 2023 COMPARED TO FISCAL 2022\nDemand creation expense increased 5% for fiscal 2023, primarily due to higher advertising and marketing expense and higher sports marketing expense. Changes in\nforeign currency exchange rates decreased Demand creation expense by approximately 4 percentage points.\nOperating overhead expense increased 12%, primarily due to higher wage-related expenses, NIKE Direct variable costs, strategic technology enterprise investments and'),
  0.35101863741874695),
 (Document(id='79cd2d08-5474-40ae-9e3d-36c2f1280c46', metadata={'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'page': 88, 'creationdate': '2023-07-20T16:22:00-04:00', 'creator': 'EDGAR Filing HTML Converter', 'title': '0000320187-23-000039', 'moddate': '2023-07-20T16:22:08-04:00', 'start_index': 0, 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'total_pages': 107, 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'keywords': '0000320187-23-000039; ; 10-K', 'page_label': '89', 'source': './example_data/nke-10k-2023.pdf'}, page_content='Table of Contents\nYEAR ENDED MAY 31,\n(Dollars in millions) 2023 2022 2021\nREVENUES\nNorth America $ 21,608 $ 18,353 $ 17,179 \nEurope, Middle East & Africa 13,418 12,479 11,456 \nGreater China 7,248 7,547 8,290 \nAsia Pacific & Latin America 6,431 5,955 5,343 \nGlobal Brand Divisions 58 102 25 \nTotal NIKE Brand 48,763 44,436 42,293 \nConverse 2,427 2,346 2,205 \nCorporate 27 (72) 40 \nTOTAL NIKE, INC. REVENUES $ 51,217 $ 46,710 $ 44,538 \nEARNINGS BEFORE INTEREST AND TAXES\nNorth America $ 5,454 $ 5,114 $ 5,089 \nEurope, Middle East & Africa 3,531 3,293 2,435 \nGreater China 2,283 2,365 3,243 \nAsia Pacific & Latin America 1,932 1,896 1,530 \nGlobal Brand Divisions (4,841) (4,262) (3,656)\nConverse 676 669 543 \nCorporate (2,840) (2,219) (2,261)\nInterest expense (income), net (6) 205 262 \nTOTAL NIKE, INC. INCOME BEFORE INCOME TAXES $ 6,201 $ 6,651 $ 6,661 \nADDITIONS TO PROPERTY, PLANT AND EQUIPMENT\nNorth America $ 283 $ 146 $ 98 \nEurope, Middle East & Africa 215 197 153 \nGreater China 56 78 94'),
  0.35981690883636475),
 (Document(id='095e95d6-473b-4ba0-ae45-43d67049f065', metadata={'title': '0000320187-23-000039', 'creator': 'EDGAR Filing HTML Converter', 'start_index': 0, 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'page': 89, 'total_pages': 107, 'page_label': '90', 'moddate': '2023-07-20T16:22:08-04:00', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'creationdate': '2023-07-20T16:22:00-04:00', 'source': './example_data/nke-10k-2023.pdf', 'keywords': '0000320187-23-000039; ; 10-K', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0'}, page_content='Table of Contents\nAS OF MAY 31,\n(Dollars in millions) 2023 2022\nACCOUNTS RECEIVABLE, NET\nNorth America $ 1,653 $ 1,850 \nEurope, Middle East & Africa 1,197 1,351 \nGreater China 162 406 \nAsia Pacific & Latin America 700 664 \nGlobal Brand Divisions 96 113 \nTotal NIKE Brand 3,808 4,384 \nConverse 235 230 \nCorporate 88 53 \nTOTAL ACCOUNTS RECEIVABLE, NET $ 4,131 $ 4,667 \nINVENTORIES\nNorth America $ 3,806 $ 4,098 \nEurope, Middle East & Africa 2,167 1,887 \nGreater China 973 1,044 \nAsia Pacific & Latin America 894 686 \nGlobal Brand Divisions 232 197 \nTotal NIKE Brand 8,072 7,912 \nConverse 305 279 \nCorporate 77 229 \nTOTAL INVENTORIES $ 8,454 $ 8,420 \nPROPERTY, PLANT AND EQUIPMENT, NET\nNorth America $ 794 $ 639 \nEurope, Middle East & Africa 1,009 920 \nGreater China 292 303 \nAsia Pacific & Latin America 279 274 \nGlobal Brand Divisions 840 789 \nTotal NIKE Brand 3,214 2,925 \nConverse 38 49 \nCorporate 1,829 1,817 \nTOTAL PROPERTY, PLANT AND EQUIPMENT, NET $ 5,081 $ 4,791'),
  0.3652665317058563)]

Retriever

Vector Storeのメソッド、'similarity_search'、'similarity_search_with_score' の利用は、そのままだとLCELのRunnableを継承していないため、LangChainのchainに組み込んで実行することができません。そこで、chainに組み込めるようRunnableのオブジェクトとして類似検索の機能をretrieverとして定義します。

sample
from typing import List

from langchain_core.documents import Document
from langchain_core.runnables import chain


@chain
def retriever(query: str) -> List[Document]:
    return vector_store.similarity_search(query, k=1)


retriever.batch(
    [
        "How many distribution centers does Nike have in the US?",
        "When was Nike incorporated?",
    ],
)

@chainにて、Pythonのデコレーターという機能を使ってretriever関数をLangChainのRunnableオブジェクトとして登録しています。
このようにすることで、LCEL Runnableのbatchメソッドで複数の類似検索をまとめて実行できるようになっています。
ここではsimilarity_searchの引数としてk=1を指定しているので、最上位の類似の候補1つのみを返すようにしています。

結果例
[[Document(id='150e2336-cf56-41d1-bbef-e4ec7c3efd22', metadata={'start_index': 3125, 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'creator': 'EDGAR Filing HTML Converter', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'moddate': '2023-07-20T16:22:08-04:00', 'title': '0000320187-23-000039', 'page': 4, 'keywords': '0000320187-23-000039; ; 10-K', 'page_label': '5', 'creationdate': '2023-07-20T16:22:00-04:00'}, page_content='direct to consumer operations sell products through the following number of retail stores in the United States:\nU.S. RETAIL STORES NUMBER\nNIKE Brand factory stores 213 \nNIKE Brand in-line stores (including employee-only stores) 74 \nConverse stores (including factory stores) 82 \nTOTAL 369 \nIn the United States, NIKE has eight significant distribution centers. Refer to Item 2. Properties for further information.\n2023 FORM 10-K 2')],
 [Document(id='e816712d-195e-4853-ba17-3d1b2ac6fa3c', metadata={'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'page_label': '10', 'page': 9, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'moddate': '2023-07-20T16:22:08-04:00', 'keywords': '0000320187-23-000039; ; 10-K', 'title': '0000320187-23-000039', 'creator': 'EDGAR Filing HTML Converter', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'total_pages': 107, 'creationdate': '2023-07-20T16:22:00-04:00', 'start_index': 3254, 'source': './example_data/nke-10k-2023.pdf'}, page_content='about.nike.com. Information contained on or accessible through our websites is not incorporated into, and does not form a part of, this Annual Report or any other report\nor document we file with the SEC, and any references to our websites are intended to be inactive textual references only.\nAVAILABLE INFORMATION AND WEBSITES\nOur NIKE digital commerce website is located at www.nike.com. On our NIKE corporate website, located at investors.nike.com, we post the following filings as soon as\nreasonably practicable after they are electronically filed with, or furnished to, the United States Securities and Exchange Commission (the "SEC"): our annual report on\nForm 10-K, our quarterly reports on Form 10-Q, our current reports on Form 8-K and any amendments to those reports filed or furnished pursuant to Section 13(a) or\n15(d) of the Securities and Exchange Act of 1934, as amended. Our proxy statements are also posted on our corporate website. All such filings on our corporate website')]]

実行結果としては、2つの質問文に対して、それぞれ類似度が最も高いチャンクの情報が返されています。
さて、

実行フェーズ(RAGアプリ本体のフロー)

ここからが本丸です。
事前に準備したベクトルDBを活用したRAGのフローを見ていきます。

ユーザーからPDF内容(NIKE Annual Report)に関する質問を受け付け、LLMにより回答を生成させるシステムを想定します。PDF内容は、これまでの手順でベクトルDB化されている状態です。

RAG システムの構築

ここではLangChainのLCELを使った実装を試してみます。

質問文 + 関連情報を生成する関数

プロンプトを生成する元になる情報として、以下の2つの情報が必要になります。

  • question: ユーザーからの質問文
  • context: 質問文に関連する情報(Vector Storeから抽出した質問文の関連情報)

まずは、これらの情報を生成するためのRunnableの関数を定義します。

sample
from typing import List
from langchain_core.documents import Document
from langchain_core.runnables import chain

@chain
def retriever(query: str) -> List[Document]:
    return vector_store.similarity_search(query, k=3)

from langchain_core.runnables import RunnableParallel, RunnablePassthrough
retriever_and_passthrough = RunnableParallel(
    {"context": retriever, "question": RunnablePassthrough()}
)

@chainデコレーターを使ってretrieverを定義します。
これを使ってretriever_and_passthroughというRunnableParallelの新たなインスタンスを作成しています。RunnableParallelは引数に指定したDocument型オブジェクトに含まれるキーを、並列に生成します。
retriever_and_passthroughに質問文の文字列を渡して実行することで、以下の処理が並列に行われることになります。

  • retriever関数に質問文の文字列を渡して実行し、結果をcontextに格納する
  • RunnablePassthrough()関数に質問文の文字列を渡して実行し、結果をquestionに格納する

RunnablePassthrough()は、受け取ったデータを何も処理せずにそのまま返すだけのダミーのような関数です。つまり、これにより、質問文(question)と、それに類似するVector Store上の関連情報(context)が生成されるということになります。

Runnableのオブジェクトとして作成することで、後続のプロンプト・テンプレート生成にchainでつなげることができるようになります。このような質問文と関連情報の組み立て方はRAGのchainを構築する際によく使われるパターンのようです。

プロンプト・テンプレート

使用しているサンプルが英語ベースなので、プロンプトも英語で与えることにします。
前段で、プロンプト生成に必要な質問文、関連情報をそれぞれquestion, context という変数で準備することにしているので、これらの変数をテンプレートに組み込む形で作成しています。

sample
    from langchain_core.prompts import ChatPromptTemplate
    
    system_prompt_template = """You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. 
    
    context:
    ```
    {context}
    ```
    
    Please output in json format including the following fields. Output only json data.
    - question
    - answer
    - page_label (page_label of the documentation containing the information on which the answer originated)
    
    
    """
    user_prompt_template = "{question}"
    
    prompt_template = ChatPromptTemplate([
        ("system", system_prompt_template),
        ("user", user_prompt_template)
    ])

システム・プロンプトとして、ここでは結果に、question, answer, page_labelを含み、かつ、JSON形式で出力するよう指示しています。

Chat Model

プロンプトを投げるLLMをインスタンス化します。

sample
from langchain_ibm import ChatWatsonx

model = ChatWatsonx(
    model_id = "mistralai/mistral-medium-2505", 
    url = myURL, 
    project_id = myProjectID,
    apikey = myAPIKey
)
Output Parser

LLMによる生成結果からテキスト情報のみ抽出するためのOutput Parserを定義します。

sample
from langchain_core.output_parsers import StrOutputParser
output_parser = StrOutputParser()
chain作成
sample
rag_chain = retriever_and_passthrough | prompt_template | model | output_parser

これまでの要素をつなぎ合わせてRAGチェーンを作成します。

RAGシステムの実行

ここまでで、一通りRAGに必要な要素は組み立てられました。後はこれらを使用して実行すればよいです。

ユーザーからの質問入力

以下のような10件の質問があるものとします。

sample
questions = [
    "When was Nike incorporated?",
    "How many distribution centers does Nike have in the US?",
    "How many shares did Nike repurchase under the $15 billion share repurchase program before it was terminated in August 2022?",
    "How many shares did Nike repurchase under the new $18 billion share repurchase program as of May 31, 2023?",
    "What were Nike's total revenues in fiscal year 2023?",
    "Why did Nike's gross margin decline in fiscal year 2023?",
    "What was Nike's net income for fiscal year 2023?",
    "What drove the high currency-neutral revenue growth in Asia Pacific & Latin America for fiscal 2023?",
    "How do foreign currency fluctuations affect Nike’s consolidated earnings?",
    "What happens if actual losses exceed Nike’s recorded liability for legal claims?",
]
chain実行

リスト形式になっている複数の質問文をまとめて実行するにはinvokeではなくbatchが使えます。

sample
answers = rag_chain.batch(questions)
print(answers)

ここで、chainとして作成したフロー(Vector Storeから関連情報抽出、プロンプト生成、LLMに対するリクエスト発行、結果のパース)が、各質問に対して行われることになります。

結果が見にくいので、少し加工して出力させてみます。

sample
for answer in answers:
    print(answer.replace('```json\n', '', 1).removesuffix('```'))
結果例
{
  "question": "When was Nike incorporated?",
  "answer": "NIKE, Inc. was incorporated in 1967",
  "page_label": "4"
}

{
  "question": "How many distribution centers does Nike have in the US?",
  "answer": "Nike has eight significant distribution centers in the United States.",
  "page_label": "5"
}

{
    "question": "How many shares did Nike repurchase under the $15 billion share repurchase program before it was terminated in August 2022?",
    "answer": "Nike repurchased 83.8 million shares under the $15 billion share repurchase program before it was terminated in August 2022.",
    "page_label": "28"
}

{
  "question": "How many shares did Nike repurchase under the new $18 billion share repurchase program as of May 31, 2023?",
  "answer": "As of May 31, 2023, Nike had repurchased 43.5 million shares under the new $18 billion share repurchase program.",
  "page_label": "28"
}

{
    "question": "What were Nike's total revenues in fiscal year 2023?",
    "answer": "Nike's total revenues in fiscal year 2023 were $51.2 billion",
    "page_label": "36"
}

{
  "question": "Why did Nike's gross margin decline in fiscal year 2023?",
  "answer": "Nike's gross margin decline in fiscal year 2023 was primarily due to higher product costs, lower margin in the NIKE Direct business driven by higher promotional activity, unfavorable changes in net foreign currency exchange rates including hedges, as well as lower off-price margin.",
  "page_label": "\"37\""
}

{
  "question": "What was Nike's net income for fiscal year 2023?",
  "answer": "Nike's net income for fiscal year 2023 was $5,070 million.",
  "page_label": "32"
}

{
  "question": "What drove the high currency-neutral revenue growth in Asia Pacific & Latin America for fiscal 2023?",
  "answer": "APLA revenues increased 17% on a currency-neutral basis due to higher revenues across nearly all territories, led by Southeast Asia and India, Korea and Japan. The increase was partially offset by a decline in our CASA territory. Within our CASA territory, the transition of our Chile, Argentina and Uruguay entities to a third-party distributor operating model reduced APLA revenue growth by approximately 5 percentage points. Revenues increased primarily due to growth in Men's, Women's and the Jordan Brand.",
  "page_label": "43"
}

{
  "question": "How do foreign currency fluctuations affect Nike’s consolidated earnings?",
  "answer": "Foreign currency fluctuations affect Nike's consolidated earnings in several ways. First, the company's international revenues and expenses are impacted because they are generally derived from sales and operations in foreign currencies, which are then translated into U.S. Dollars for financial reporting. Weakening of foreign currencies against the U.S. Dollar adversely affects the U.S. Dollar value of the company's foreign currency-denominated sales and earnings. Additionally, fluctuations in currency exchange rates can lead to increased costs, including higher wage and other professional services expenses, and affect the difference between actual and standard foreign currency exchange rates assigned to various operating segments, impacting the consolidated gross margin.",
  "page_label": "45"
}

{
  "question": "What happens if actual losses exceed Nike’s recorded liability for legal claims?",
  "answer": "If actual losses exceed the recorded liability, Nike's results of operations and financial condition could be negatively impacted.",
  "page_label": "12"
}

なんとなく各質問に対してそれっぽい回答が生成されましたね。
これで、特定のPDFの内容(LLMが学習データとして持っていない可能性のある情報)に特化した質問に対し、それなりの精度の回答を返せることが示せたと思います。

おまけ: step by stepでの実行

chainを一気に実行してエラーになると、どこで何が悪かったか問題判別がしにくいので、個別に実行するやり方も見ておきます。

1件ずつの処理確認(invoke)
sample
question_and_context = retriever_and_passthrough.invoke(questions[0])
print(question_and_context)
print("-----------------")

prompt = prompt_template.invoke(question_and_context)
print(prompt)
print("-----------------")

output = model.invoke(prompt)
print(output)
print("-----------------")

answer = output_parser.invoke(output)
print(answer)
print("-----------------")
結果例
    {'context': [Document(id='e816712d-195e-4853-ba17-3d1b2ac6fa3c', metadata={'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'moddate': '2023-07-20T16:22:08-04:00', 'source': './example_data/nke-10k-2023.pdf', 'keywords': '0000320187-23-000039; ; 10-K', 'total_pages': 107, 'page_label': '10', 'page': 9, 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'title': '0000320187-23-000039', 'start_index': 3254, 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31'}, page_content='about.nike.com. Information contained on or accessible through our websites is not incorporated into, and does not form a part of, this Annual Report or any other report\nor document we file with the SEC, and any references to our websites are intended to be inactive textual references only.\nAVAILABLE INFORMATION AND WEBSITES\nOur NIKE digital commerce website is located at www.nike.com. On our NIKE corporate website, located at investors.nike.com, we post the following filings as soon as\nreasonably practicable after they are electronically filed with, or furnished to, the United States Securities and Exchange Commission (the "SEC"): our annual report on\nForm 10-K, our quarterly reports on Form 10-Q, our current reports on Form 8-K and any amendments to those reports filed or furnished pursuant to Section 13(a) or\n15(d) of the Securities and Exchange Act of 1934, as amended. Our proxy statements are also posted on our corporate website. All such filings on our corporate website'), Document(id='6b129b62-1939-4dae-b4ef-7033ce5c8e06', metadata={'title': '0000320187-23-000039', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'keywords': '0000320187-23-000039; ; 10-K', 'page': 53, 'source': './example_data/nke-10k-2023.pdf', 'page_label': '54', 'total_pages': 107, 'moddate': '2023-07-20T16:22:08-04:00', 'creationdate': '2023-07-20T16:22:00-04:00', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'start_index': 0, 'creator': 'EDGAR Filing HTML Converter'}, page_content='Table of Contents\nITEM 8. FINANCIAL STATEMENTS AND SUPPLEMENTARYDATA\nManagement of NIKE, Inc. is responsible for the information and representations contained in this Annual Report. The financial statements have been prepared in\nconformity with accounting principles generally accepted in the United States of America ("U.S. GAAP") and include certain amounts based on our best estimates and\njudgments. Other financial information in this Annual Report is consistent with these financial statements.\nOur accounting systems include controls designed to reasonably assure assets are safeguarded from unauthorized use or disposition and provide for the preparation of\nfinancial statements in conformity with U.S. GAAP. These systems are supplemented by the selection and training of qualified financial personnel and an organizational\nstructure providing for appropriate segregation of duties.'), Document(id='205a2dd9-24b6-4ce2-b076-4990d40f57bb', metadata={'page': 12, 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'source': './example_data/nke-10k-2023.pdf', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'start_index': 3011, 'creationdate': '2023-07-20T16:22:00-04:00', 'total_pages': 107, 'creator': 'EDGAR Filing HTML Converter', 'moddate': '2023-07-20T16:22:08-04:00', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'page_label': '13', 'title': '0000320187-23-000039', 'keywords': '0000320187-23-000039; ; 10-K'}, page_content='NIKE is a consumer products company and the relative popularity of various sports and fitness activities and changing design trends affect the demand for our products,\nservices and experiences. The athletic footwear, apparel and equipment industry is highly competitive both in the United States and worldwide. We compete\ninternationally with a significant number of athletic and leisure footwear companies, athletic and leisure apparel companies, sports equipment companies, private labels\nand large companies that have diversified lines of athletic and leisure footwear, apparel and equipment. We also compete with other companies for the production\ncapacity of contract manufacturers that produce our products. In addition, we and our contract manufacturers compete with other companies and industries for raw\nmaterials used in our products. Our NIKE Direct operations, both through our digital commerce operations and retail stores, also compete with multi-brand retailers, which'), Document(id='3d5e29dc-d3b8-487b-964a-73f1c51f53c0', metadata={'source': './example_data/nke-10k-2023.pdf', 'keywords': '0000320187-23-000039; ; 10-K', 'page_label': '4', 'page': 3, 'moddate': '2023-07-20T16:22:08-04:00', 'total_pages': 107, 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'creator': 'EDGAR Filing HTML Converter', 'start_index': 0, 'creationdate': '2023-07-20T16:22:00-04:00', 'title': '0000320187-23-000039', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions'}, page_content='Table of Contents\nPART I\nITEM 1. BUSINESS\nGENERAL\nNIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"\n"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.\nOur principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is\nthe largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores\nand sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales'), Document(id='1e098fe8-35f6-4ab3-a3ed-0f647f942b87', metadata={'moddate': '2023-07-20T16:22:08-04:00', 'creator': 'EDGAR Filing HTML Converter', 'creationdate': '2023-07-20T16:22:00-04:00', 'producer': 'EDGRpdf Service w/ EO.Pdf 22.0.40.0', 'keywords': '0000320187-23-000039; ; 10-K', 'title': '0000320187-23-000039', 'subject': 'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31', 'page': 34, 'start_index': 0, 'page_label': '35', 'author': 'EDGAR Online, a division of Donnelley Financial Solutions', 'source': './example_data/nke-10k-2023.pdf', 'total_pages': 107}, page_content='Table of Contents\nCONSOLIDATED OPERATING RESULTS\nREVENUES\n(Dollars in millions) FISCAL2023 FISCAL2022 % CHANGE\n% CHANGEEXCLUDINGCURRENCYCHANGES FISCAL2021 % CHANGE\n% CHANGEEXCLUDINGCURRENCYCHANGES\nNIKE, Inc. Revenues:\nNIKE Brand Revenues by:\nFootwear $ 33,135 $ 29,143 14 % 20 %$ 28,021 4 % 4 %\nApparel 13,843 13,567 2 % 8 % 12,865 5 % 6 %\nEquipment 1,727 1,624 6 % 13 % 1,382 18 % 18 %\nGlobal Brand Divisions 58 102 -43 % -43 % 25 308 % 302 %\nTotal NIKE Brand Revenues $ 48,763 $ 44,436 10 % 16 %$ 42,293 5 % 6 %\nConverse 2,427 2,346 3 % 8 % 2,205 6 % 7 %\nCorporate 27 (72) — — 40 — — \nTOTAL NIKE, INC. REVENUES $ 51,217 $ 46,710 10 % 16 %$ 44,538 5 % 6 %\nSupplemental NIKE Brand Revenues Details:\nNIKE Brand Revenues by:\nSales to Wholesale Customers $ 27,397 $ 25,608 7 % 14 %$ 25,898 -1 % -1 %\nSales through NIKE Direct 21,308 18,726 14 % 20 % 16,370 14 % 15 %\nGlobal Brand Divisions 58 102 -43 % -43 % 25 308 % 302 %\nTOTAL NIKE BRAND REVENUES $ 48,763 $ 44,436 10 % 16 %$ 42,293 5 % 6 %')], 'question': 'When was Nike incorporated?'}
    -----------------
    messages=[SystemMessage(content='You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. \n\ncontext:\n```\n[Document(id=\'e816712d-195e-4853-ba17-3d1b2ac6fa3c\', metadata={\'author\': \'EDGAR Online, a division of Donnelley Financial Solutions\', \'moddate\': \'2023-07-20T16:22:08-04:00\', \'source\': \'./example_data/nke-10k-2023.pdf\', \'keywords\': \'0000320187-23-000039; ; 10-K\', \'total_pages\': 107, \'page_label\': \'10\', \'page\': 9, \'creator\': \'EDGAR Filing HTML Converter\', \'creationdate\': \'2023-07-20T16:22:00-04:00\', \'producer\': \'EDGRpdf Service w/ EO.Pdf 22.0.40.0\', \'title\': \'0000320187-23-000039\', \'start_index\': 3254, \'subject\': \'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31\'}, page_content=\'about.nike.com. Information contained on or accessible through our websites is not incorporated into, and does not form a part of, this Annual Report or any other report\\nor document we file with the SEC, and any references to our websites are intended to be inactive textual references only.\\nAVAILABLE INFORMATION AND WEBSITES\\nOur NIKE digital commerce website is located at www.nike.com. On our NIKE corporate website, located at investors.nike.com, we post the following filings as soon as\\nreasonably practicable after they are electronically filed with, or furnished to, the United States Securities and Exchange Commission (the "SEC"): our annual report on\\nForm 10-K, our quarterly reports on Form 10-Q, our current reports on Form 8-K and any amendments to those reports filed or furnished pursuant to Section 13(a) or\\n15(d) of the Securities and Exchange Act of 1934, as amended. Our proxy statements are also posted on our corporate website. All such filings on our corporate website\'), Document(id=\'6b129b62-1939-4dae-b4ef-7033ce5c8e06\', metadata={\'title\': \'0000320187-23-000039\', \'subject\': \'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31\', \'producer\': \'EDGRpdf Service w/ EO.Pdf 22.0.40.0\', \'keywords\': \'0000320187-23-000039; ; 10-K\', \'page\': 53, \'source\': \'./example_data/nke-10k-2023.pdf\', \'page_label\': \'54\', \'total_pages\': 107, \'moddate\': \'2023-07-20T16:22:08-04:00\', \'creationdate\': \'2023-07-20T16:22:00-04:00\', \'author\': \'EDGAR Online, a division of Donnelley Financial Solutions\', \'start_index\': 0, \'creator\': \'EDGAR Filing HTML Converter\'}, page_content=\'Table of Contents\\nITEM 8. FINANCIAL STATEMENTS AND SUPPLEMENTARYDATA\\nManagement of NIKE, Inc. is responsible for the information and representations contained in this Annual Report. The financial statements have been prepared in\\nconformity with accounting principles generally accepted in the United States of America ("U.S. GAAP") and include certain amounts based on our best estimates and\\njudgments. Other financial information in this Annual Report is consistent with these financial statements.\\nOur accounting systems include controls designed to reasonably assure assets are safeguarded from unauthorized use or disposition and provide for the preparation of\\nfinancial statements in conformity with U.S. GAAP. These systems are supplemented by the selection and training of qualified financial personnel and an organizational\\nstructure providing for appropriate segregation of duties.\'), Document(id=\'205a2dd9-24b6-4ce2-b076-4990d40f57bb\', metadata={\'page\': 12, \'author\': \'EDGAR Online, a division of Donnelley Financial Solutions\', \'source\': \'./example_data/nke-10k-2023.pdf\', \'producer\': \'EDGRpdf Service w/ EO.Pdf 22.0.40.0\', \'start_index\': 3011, \'creationdate\': \'2023-07-20T16:22:00-04:00\', \'total_pages\': 107, \'creator\': \'EDGAR Filing HTML Converter\', \'moddate\': \'2023-07-20T16:22:08-04:00\', \'subject\': \'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31\', \'page_label\': \'13\', \'title\': \'0000320187-23-000039\', \'keywords\': \'0000320187-23-000039; ; 10-K\'}, page_content=\'NIKE is a consumer products company and the relative popularity of various sports and fitness activities and changing design trends affect the demand for our products,\\nservices and experiences. The athletic footwear, apparel and equipment industry is highly competitive both in the United States and worldwide. We compete\\ninternationally with a significant number of athletic and leisure footwear companies, athletic and leisure apparel companies, sports equipment companies, private labels\\nand large companies that have diversified lines of athletic and leisure footwear, apparel and equipment. We also compete with other companies for the production\\ncapacity of contract manufacturers that produce our products. In addition, we and our contract manufacturers compete with other companies and industries for raw\\nmaterials used in our products. Our NIKE Direct operations, both through our digital commerce operations and retail stores, also compete with multi-brand retailers, which\'), Document(id=\'3d5e29dc-d3b8-487b-964a-73f1c51f53c0\', metadata={\'source\': \'./example_data/nke-10k-2023.pdf\', \'keywords\': \'0000320187-23-000039; ; 10-K\', \'page_label\': \'4\', \'page\': 3, \'moddate\': \'2023-07-20T16:22:08-04:00\', \'total_pages\': 107, \'producer\': \'EDGRpdf Service w/ EO.Pdf 22.0.40.0\', \'subject\': \'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31\', \'creator\': \'EDGAR Filing HTML Converter\', \'start_index\': 0, \'creationdate\': \'2023-07-20T16:22:00-04:00\', \'title\': \'0000320187-23-000039\', \'author\': \'EDGAR Online, a division of Donnelley Financial Solutions\'}, page_content=\'Table of Contents\\nPART I\\nITEM 1. BUSINESS\\nGENERAL\\nNIKE, Inc. was incorporated in 1967 under the laws of the State of Oregon. As used in this Annual Report on Form 10-K (this "Annual Report"), the terms "we," "us," "our,"\\n"NIKE" and the "Company" refer to NIKE, Inc. and its predecessors, subsidiaries and affiliates, collectively, unless the context indicates otherwise.\\nOur principal business activity is the design, development and worldwide marketing and selling of athletic footwear, apparel, equipment, accessories and services. NIKE is\\nthe largest seller of athletic footwear and apparel in the world. We sell our products through NIKE Direct operations, which are comprised of both NIKE-owned retail stores\\nand sales through our digital platforms (also referred to as "NIKE Brand Digital"), to retail accounts and to a mix of independent distributors, licensees and sales\'), Document(id=\'1e098fe8-35f6-4ab3-a3ed-0f647f942b87\', metadata={\'moddate\': \'2023-07-20T16:22:08-04:00\', \'creator\': \'EDGAR Filing HTML Converter\', \'creationdate\': \'2023-07-20T16:22:00-04:00\', \'producer\': \'EDGRpdf Service w/ EO.Pdf 22.0.40.0\', \'keywords\': \'0000320187-23-000039; ; 10-K\', \'title\': \'0000320187-23-000039\', \'subject\': \'Form 10-K filed on 2023-07-20 for the period ending 2023-05-31\', \'page\': 34, \'start_index\': 0, \'page_label\': \'35\', \'author\': \'EDGAR Online, a division of Donnelley Financial Solutions\', \'source\': \'./example_data/nke-10k-2023.pdf\', \'total_pages\': 107}, page_content=\'Table of Contents\\nCONSOLIDATED OPERATING RESULTS\\nREVENUES\\n(Dollars in millions) FISCAL2023 FISCAL2022 % CHANGE\\n% CHANGEEXCLUDINGCURRENCYCHANGES FISCAL2021 % CHANGE\\n% CHANGEEXCLUDINGCURRENCYCHANGES\\nNIKE, Inc. Revenues:\\nNIKE Brand Revenues by:\\nFootwear $ 33,135 $ 29,143 14 % 20 %$ 28,021 4 % 4 %\\nApparel 13,843 13,567 2 % 8 % 12,865 5 % 6 %\\nEquipment 1,727 1,624 6 % 13 % 1,382 18 % 18 %\\nGlobal Brand Divisions 58 102 -43 % -43 % 25 308 % 302 %\\nTotal NIKE Brand Revenues $ 48,763 $ 44,436 10 % 16 %$ 42,293 5 % 6 %\\nConverse 2,427 2,346 3 % 8 % 2,205 6 % 7 %\\nCorporate 27 (72) — — 40 — — \\nTOTAL NIKE, INC. REVENUES $ 51,217 $ 46,710 10 % 16 %$ 44,538 5 % 6 %\\nSupplemental NIKE Brand Revenues Details:\\nNIKE Brand Revenues by:\\nSales to Wholesale Customers $ 27,397 $ 25,608 7 % 14 %$ 25,898 -1 % -1 %\\nSales through NIKE Direct 21,308 18,726 14 % 20 % 16,370 14 % 15 %\\nGlobal Brand Divisions 58 102 -43 % -43 % 25 308 % 302 %\\nTOTAL NIKE BRAND REVENUES $ 48,763 $ 44,436 10 % 16 %$ 42,293 5 % 6 %\')]\n```\n\nPlease output in json format including the following fields. Output only json data.\n- question\n- answer\n- page_label (page_label of the documentation containing the information on which the answer originated)\n\n\n', additional_kwargs={}, response_metadata={}), HumanMessage(content='When was Nike incorporated?', additional_kwargs={}, response_metadata={})]
    -----------------
    content='```json\n{\n  "question": "When was Nike incorporated?",\n  "answer": "NIKE, Inc. was incorporated in 1967",\n  "page_label": "4"\n}\n```' additional_kwargs={} response_metadata={'token_usage': {'completion_tokens': 44, 'prompt_tokens': 2960, 'total_tokens': 3004}, 'model_name': 'mistralai/mistral-medium-2505', 'system_fingerprint': '', 'finish_reason': 'stop'} id='chatcmpl-2f98d3bf-a1a9-441d-b12c-21890a524fdc---05fea021a87d0d1d58640519ee59c0cd---dc46e642-6f46-4c9a-8f8a-2f3436e7fea9' usage_metadata={'input_tokens': 2960, 'output_tokens': 44, 'total_tokens': 3004}
    -----------------
    ```json
    {
      "question": "When was Nike incorporated?",
      "answer": "NIKE, Inc. was incorporated in 1967",
      "page_label": "4"
    }
    ```
    -----------------
複数件まとめて実行(batch)
sample
questions_and_contexts = retriever_and_passthrough.batch(questions)
print(questions_and_contexts)
print("-----------------")

prompts = prompt_template.batch(questions_and_contexts)
print(prompts)
print("-----------------")

outputs = model.batch(prompts)
print(outputs)
print("-----------------")

answers = output_parser.batch(outputs)
print(answers)
print("-----------------")

結果例は省略。

※LangChainのLCEL/Runnableだと、invoke(), batch() の使い分けで1つずつの処理、一括処理が簡単に実行できるのは便利ですね。

例3: LangGraphを使用したRAG

LangChain - Build a Retrieval Augmented Generation (RAG) App: Part 1

上のTutorialに沿ってLangGraphを使ったRAGを実装してみます。

全体像としては以下のイメージです。
image.png

前の例とやっていることはほぼ一緒です。今回は、取り込むデータがWeb上のBlog情報であること、使用するVector DBとしてIn-Memory DBを使っていること、RAGのフローの実装としてLangGraphを使っていること、が主な相違点です。

事前準備フェーズ(Vector DB準備)

前回の例と少しずつ使っている技術要素が違いますが、本質的なところは変わらないので詳細の説明は割愛します。

Load

sample
import bs4
from langchain import hub
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langgraph.graph import START, StateGraph
from typing_extensions import List, TypedDict

# Load and chunk contents of the blog
loader = WebBaseLoader(
    web_paths=("https://lilianweng.github.io/posts/2023-06-23-agent/",),
    bs_kwargs=dict(
        parse_only=bs4.SoupStrainer(
            class_=("post-content", "post-title", "post-header")
        )
    ),
)
docs = loader.load()

split

sample
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
all_splits = text_splitter.split_documents(docs)

vector store

sample
from langchain_ibm import WatsonxEmbeddings
embeddings = WatsonxEmbeddings(
    # model_id="ibm/slate-125m-english-rtrvr",
    model_id="ibm/slate-125m-english-rtrvr-v2",
    url = myURL, 
    project_id = myProjectID,
    apikey = myAPIKey
)

from langchain_core.vectorstores import InMemoryVectorStore
vector_store = InMemoryVectorStore(embeddings)

Embed & Store

# Index chunks
_ = vector_store.add_documents(documents=all_splits)

実行フェーズ(RAGアプリ本体のフロー)

RAGシステムの構築

プロンプト・テンプレート
sample
# Define prompt for question-answering
# N.B. for non-US LangSmith endpoints, you may need to specify
# api_url="https://api.smith.langchain.com" in hub.pull.
prompt = hub.pull("rlm/rag-prompt")

Web上でよく使われるprompt templateが公開されていてそれをそのまま利用できる仕組みが提供されているようです。ここではLangChain Hubで提供されているrlm/rag-promptを利用しています。
参考: https://smith.langchain.com/hub/rlm/rag-prompt

State, Node

LangGraphの考え方としては、処理フローをグラフ構造のように扱うことを想定しているようです。フローチャートのイメージをそのままコードに落とし込むイメージでしょうか。主要な要素としてステート、ノード、エッジという考え方があります。

  • ステート: グラフの実行中に共有され、変更されるデータ構造です。各ノードは現在のステートを受け取り、それを更新して次のノードに渡します。グラフ全体で情報を受け渡し、処理の進行状況を追跡するための「グローバル変数」のようなものです。
  • ノード: グラフ内で実行される個々の処理単位です。一般的にはPythonの関数として定義され、ステートを受け取って何らかの処理を行い、ステートの一部を更新して返します。
  • エッジ: グラフ内のノード間の接続を表します。あるノードから別のノードへの「流れ」や「遷移」を定義し、どのノードが次に実行されるかを決定します。
sample
# Define state for application
class State(TypedDict):
    question: str
    context: List[Document]
    answer: str


# Define application steps
def retrieve(state: State):
    retrieved_docs = vector_store.similarity_search(state["question"])
    return {"context": retrieved_docs}


def generate(state: State):
    docs_content = "\n\n".join(doc.page_content for doc in state["context"])
    messages = prompt.invoke({"question": state["question"], "context": docs_content})
    response = llm.invoke(messages)
    return {"answer": response.content}

ここでは、"ステート"としてStateクラス、"ノード"として retrievegenerate関数を定義しています。

retrieve関数は、Statequestionを基にVector Storeから類似検索を行ってStatecontextを更新します。
generate関数は、Statequestion, contextからプロンプトを作成し、llmに投げ、結果をStateanswerに格納します。

グラフ作成

上で定義したステートとノードを組み合わせてグラフを構築します。

sample
# Compile application and test
graph_builder = StateGraph(State).add_sequence([retrieve, generate])
graph_builder.add_edge(START, "retrieve")
graph = graph_builder.compile()

まず、StateGraph(State)で新しいLangGraphグラフビルダーを初期化し、Stateクラスを渡すことで、グラフが管理する状態のスキーマを定義します。
.add_sequence([retrieve, generate])で、retrieve関数とgenerate関数を連続して実行されるシーケンスとしてグラフに追加します。
graph_builder.add_edge(START, "retrieve")で、グラフの開始位置からretrieveノードへのエッジが作成されます。これにより、このグラフが開始されると最初にretrieveが実行されることになります。
最後に、graph = graph_builder.compile()によってコンパイルすることで、実行可能なグラフがgraphオブジェクトとして生成されます。

RAGシステムの実行

ここまでで、一通りRAGに必要な要素は組み立てられました。後はこれらを使用して実行すればよいです。

sample
response = graph.invoke({"question": "What is Task Decomposition?"})
print(response["answer"])

ナレッジベースとして用意している情報が英語のブログ記事なので、英語で質問投げています。
先に作成したgraphinvoke()メソッドを実行することでグラフが実行されます。引数として{"question": "xxx"}というDocument型のデータとして質問を与えています。
結果はステートのanswerとして返されるのでそれを出力しています。

結果例
Task decomposition is the process of breaking down a complex task into smaller, more manageable sub-tasks. This approach helps simplify problem-solving and improves efficiency by allowing focus on individual components. It is commonly used in project management, software development, and AI planning.

それっぽい結果が返されました!

3
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?