LangChainのQuickstartを読む (2) - LLMの知識を拡張する

本シリーズでは、LangChainの Quickstart の内容を元にLangChainの使い方について紹介します。
今回は、インターネット上の情報を利用してLLMの知識を拡張する方法について見ていきます。

前回作成したコードで今回も使用する箇所を以下に整理します。

import os
from langchain_openai import ChatOpenAI

# APIキーを環境変数に設定
with open('.openai') as f:
    os.environ['OPENAI_API_KEY'] = f.read().strip()

# LLM読み込み
llm = ChatOpenAI()

これまで見てきた通り、使用していたgpt-3.5-turboでは知識が古いため、
「LangChainとは何でしょうか?」という質問に正しい回答をすることが出来ませんでした。

しかし、LangChainにはWebサイトの情報を取得して利用する仕組みがあり、
その機能を利用することで質問に正しい回答ができるようになります。

LangChainでは、テキストデータを「ドキュメント」というオブジェクトとして扱います。
本節では、Webサイトのデータをドキュメント化する方法について見ていきます。

LangChainでは、ウェブ上のデータを取得するためにBeautifulSoupを使用します。
以下のコマンドでBeautifulSoupをインストールします。

pip install beautifulsoup4

ウェブ上のコンテンツを取得するには WebBaseLoader を使用します。
以下のようにURLを引数として渡してloadメソッドを使用します。

実行するとdocsにはDocumentオブジェクトのリストが入ります。

from langchain_community.document_loaders import WebBaseLoader

loader = WebBaseLoader("https://python.langchain.com/docs/get_started/introduction")
docs = loader.load()

コンテンツが長文の場合、内容をそのままLLMに渡して処理を行うことが不可能であったり、
可能な場合でもコストがかさんでしまいます。
そのため、前処理として関連性の高い箇所を抽出し、その箇所のみを使用して回答生成を行います。
このような手法は RAG(Retrieval-Augmented Generation) と呼ばれます。

処理は以下のような流れで行われます。

  1. コンテンツをLLMが扱える長さのドキュメントに分割し、Embeddingsを使用して各ドキュメントをベクトルに変換します。
  2. これらのベクトルをベクトルストアと呼ばれるデータベースに保存し、効率的な検索基盤を構築します。
  3. ユーザの入力をベクトルに変換し、ベクトルストアの中から関連性の高いベクトルを検索します。
    これにより、ユーザの入力に関連するドキュメントのリストが得られます。
  4. ユーザの入力と抽出したドキュメントのリストを入力として、LLMによる回答を生成します。

はじめに、ドキュメントをベクトルに変換するための Embeddings を用意します。
以下のようにしてOpenAIのEmbeddingsを使用することが出来ます。
デフォルトではモデル text-embedding-ada-002 が使用されます。

from langchain_openai import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()

次に、ベクトルを保存するベクトルストアを作成します。

初めにローカルにベクトルストアを作成するために必要なfaiss-cpuライブラリをインストールします。

pip install faiss-cpu

インストール後、以下のようにしてベクトルデータを保存したベクトルストアを作成します。

from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter

# ドキュメントを分割
text_splitter = RecursiveCharacterTextSplitter()
documents = text_splitter.split_documents(docs)

# 分割したドキュメントをembeddingsを用いてベクトル化し、ベクトルストアを作成
vector = FAISS.from_documents(documents, embeddings)

次に、ユーザの入力に関連するベクトルをベクトルストアから抽出するための機構を用意します。
このような機構は retriever と呼ばれます。

retriever = vector.as_retriever()

retrieverのinvokeメソッドは、文字列を入力としてそれに関連するドキュメントのリストを返します。

retriever.invoke("LangChainとは何でしょうか?")
  • 実行結果

    [Document(page_content='Introduction | 🦜️🔗 LangChain', metadata={'source': 'https://python.langchain.com/docs/get_started/introduction', 'title': 'Introduction | 🦜️🔗 LangChain', 'description': 'LangChain is a framework for developing applications powered by large language models (LLMs).', 'language': 'en'}),
     Document(page_content="Skip to main contentComponentsIntegrationsGuidesAPI ReferenceMorePeopleVersioningContributingTemplatesCookbooksTutorialsYouTube🦜️🔗LangSmithLangSmith DocsLangServe GitHubTemplates GitHubTemplates HubLangChain HubJS/TS Docs💬SearchGet startedIntroductionQuickstartInstallationUse casesQ&A with RAGExtracting structured outputChatbotsTool use and agentsQuery analysisQ&A over SQL + CSVMoreExpression LanguageGet startedRunnable interfacePrimitivesAdvantages of LCELStreamingAdd message history (memory)MoreEcosystem🦜🛠️ LangSmith🦜🕸️LangGraph🦜️🏓 LangServeSecurityGet startedOn this pageIntroductionLangChain is a framework for developing applications powered by large language models (LLMs).LangChain simplifies every stage of the LLM application lifecycle:Development: Build your applications using LangChain's open-source building blocks and components. Hit the ground running using third-party integrations and Templates.Productionization: Use LangSmith to inspect, monitor and evaluate your chains, so that you can continuously optimize and deploy with confidence.Deployment: Turn any chain into an API with LangServe.Concretely, the framework consists of the following open-source libraries:langchain-core: Base abstractions and LangChain Expression Language.langchain-community: Third party integrations.Partner packages (e.g. langchain-openai, langchain-anthropic, etc.): Some integrations have been further split into their own lightweight packages that only depend on langchain-core.langchain: Chains, agents, and retrieval strategies that make up an application's cognitive architecture.langgraph: Build robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph.langserve: Deploy LangChain chains as REST APIs.The broader ecosystem includes:LangSmith: A developer platform that lets you debug, test, evaluate, and monitor LLM applications and seamlessly integrates with LangChain.Get started\u200bWe recommend following our Quickstart guide to familiarize yourself with the framework by building your first LangChain application.See here for instructions on how to install LangChain, set up your environment, and start building.noteThese docs focus on the Python LangChain library. Head here for docs on the JavaScript LangChain library.Use cases\u200bIf you're looking to build something specific or are more of a hands-on learner, check out our use-cases.", metadata={'source': 'https://python.langchain.com/docs/get_started/introduction', 'title': 'Introduction | 🦜️🔗 LangChain', 'description': 'LangChain is a framework for developing applications powered by large language models (LLMs).', 'language': 'en'}),
     Document(page_content="They're walkthroughs and techniques for common end-to-end tasks, such as:Question answering with RAGExtracting structured outputChatbotsand more!Expression Language\u200bLangChain Expression Language (LCEL) is the foundation of many of LangChain's components, and is a declarative way to compose chains. LCEL was designed from day 1 to support putting prototypes in production, with no code changes, from the simplest “prompt + LLM” chain to the most complex chains.Get started: LCEL and its benefitsRunnable interface: The standard interface for LCEL objectsPrimitives: More on the primitives LCEL includesand more!Ecosystem\u200b🦜🛠️ LangSmith\u200bTrace and evaluate your language model applications and intelligent agents to help you move from prototype to production.🦜🕸️ LangGraph\u200bBuild stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain primitives.🦜🏓 LangServe\u200bDeploy LangChain runnables and chains as REST APIs.Security\u200bRead up on our Security best practices to make sure you're developing safely with LangChain.Additional resources\u200bComponents\u200bLangChain provides standard, extendable interfaces and integrations for many different components, including:Integrations\u200bLangChain is part of a rich ecosystem of tools that integrate with our framework and build on top of it. Check out our growing list of integrations.Guides\u200bBest practices for developing with LangChain.API reference\u200bHead to the reference section for full documentation of all classes and methods in the LangChain and LangChain Experimental Python packages.Contributing\u200bCheck out the developer's guide for guidelines on contributing and help getting your dev environment set up.Help us out by providing feedback on this documentation page:NextIntroductionGet startedUse casesExpression LanguageEcosystem🦜🛠️ LangSmith🦜🕸️ LangGraph🦜🏓 LangServeSecurityAdditional resourcesComponentsIntegrationsGuidesAPI referenceContributingCommunityDiscordTwitterGitHubPythonJS/TSMoreHomepageBlogYouTubeCopyright © 2024 LangChain, Inc.", metadata={'source': 'https://python.langchain.com/docs/get_started/introduction', 'title': 'Introduction | 🦜️🔗 LangChain', 'description': 'LangChain is a framework for developing applications powered by large language models (LLMs).', 'language': 'en'})]
    

次に、回答情報の含まれているドキュメントのリストが既に得られているものとして、
ドキュメントのリストとユーザの入力から回答を生成するためのチェインを作成します。

初めに、プロンプトテンプレートを作成します。
4. プロンプトのテンプレートを使用するで設定したように、ユーザの入力を挿入する箇所には{input}
ドキュメントのリストを挿入する箇所には{context}と記載します。

from langchain_core.prompts import ChatPromptTemplate


template = ChatPromptTemplate.from_template("""与えられたContextのみから次の質問に回答してください:

<context>
{context}
</context>

Question: {input}""")

create_stuff_documents_chainを使用すると、上記プロンプトテンプレートを使用して、
ドキュメントのリストとユーザの入力を元に回答を生成するチェインが作成できます。

from langchain.chains.combine_documents import create_stuff_documents_chain


document_chain = create_stuff_documents_chain(llm, template)

作成したチェインのinvokeメソッドは以下のように使用します。

from langchain_core.documents import Document

document_chain.invoke({
    "input": "LangChainとは何でしょうか?",
    "context": [Document(page_content="LangChainは`pip install langchain`でインストールします。")]
})
  • 実行結果

    LangChainはPythonのパッケージであり、`pip install langchain`でインストールすることができます。LangChainは何かしらの自然言語処理(NLP)の機能を提供している可能性があります。
    

先ほど作成した retriever と組み合わせることで、Webサイトの情報を参照した回答を生成することが出来ます。

user_input = "LangChainとは何でしょうか?"
context = retriever.invoke(user_input)
document_chain.invoke({
    "input": user_input,
    "context": context
})
  • 実行結果

    'LangChainは、大規模言語モデル(LLM)を活用するアプリケーションを開発するためのフレームワークです。LangChainは、LLMアプリケーションライフサイクルの各段階を簡素化します。開発段階では、LangChainのオープンソースのビルディングブロックやコンポーネントを使用してアプリケーションを構築し、本格的に始動します。製品化段階では、LangSmithを使用してチェーンを調査し、監視し、評価して、継続的に最適化して自信を持って展開します。展開段階では、LangServeを使用して任意のチェーンをAPIに変換します。LangChainには、langchain-core、langchain-community、パートナーパッケージ(langchain-openai、langchain-anthropicなど)などのオープンソースライブラリが含まれています。LangChainは、アプリケーションの認知アーキテクチャを構成するチェーン、エージェント、およびリトリーバル戦略から成り立っています。LangChainの広範なエコシステムには、LangSmith、LangGraph、LangServeなどが含まれています。LangChainは、LangChainライブラリおよびJavaScript LangChainライブラリに関するドキュメントに焦点を当てています。LangChainは、言語モデルアプリケーションとシームレスに統合されるLangSmithを使用してデバッグ、テスト、評価、モニタリングを行う開発者プラットフォームです。LangGraphを使用して、LLMを使用した堅牢で状態を持ったマルチアクターアプリケーションを構築できます。LangServeを使用して、LangChainチェーンをREST APIとして展開できます。LangChainは、多くの異なるコンポーネントに対する標準的で拡張可能なインターフェースや統合を提供します。LangChainは、フレームワークと統合し、それに基づいて構築されたさまざまなツールの豊富なエコシステムの一部です。LangChainとLangChain Experimental Pythonパッケージのすべてのクラスとメソッドの完全なドキュメントのために、リファレンスセクションに向かってください。LangChain, Inc.による著作権©2024。'
    

これまでに、以下の2つを作成して使用方法について見てきました。

  • retriever: 入力された文字列に対し、関連するドキュメントのリストを返すretriever。
  • document_chain: ユーザの質問とドキュメントのリストを元に、LLMの回答を生成するチェイン。

最後に、この2つを自動的に組み合わせて、ユーザの質問にドキュメントを参照して回答するチェインを作成します。
これは、create_retrieval_chainを使用して以下のように簡単に作成できます。

from langchain.chains import create_retrieval_chain

retrieval_chain = create_retrieval_chain(retriever, document_chain)

作成したチェインを使用してみましょう。
ドキュメントを参照して回答が生成されていることが確認できます。

response = retrieval_chain.invoke({"input": "LangChainとは何でしょうか?"})
print(response["answer"])
  • 実行結果

    LangChainは大規模言語モデル(LLMs)を活用したアプリケーションを開発するためのフレームワークです。LangChainはLLMアプリケーションライフサイクルの各段階を簡素化します。開発段階では、LangChainのオープンソースのビルディングブロックやコンポーネントを使用してアプリケーションを構築します。本番環境への展開では、LangSmithを使用してチェーンを検査し、監視し、評価することで、継続的に最適化して自信を持って展開します。展開段階では、LangServeを使用して任意のチェーンをAPIに変換します。LangChainは、langchain-core、langchain-community、さまざまなパートナーパッケージ(例:langchain-openai、langchain-anthropicなど)など、さまざまなオープンソースライブラリで構成されています。LangChainの広範なエコシステムにはLangSmith、LangGraph、LangServeなどが含まれています。
    

関連記事