見出し画像

LLMの実利用をより柔軟に、簡易に行う「LangChain」とは?

こんにちは!Hi君です。
今回の記事ではLangChainと呼ばれるツールについて解説します。
少し長くなりますが、どうぞお付き合いください。

※LLMの概要についてはこちらの記事をぜひ参照して下さい。
 ▶ChatGPT・Large Language Model(LLM)概要解説【前編】
 ▶ChatGPT・Large Language Model(LLM)概要解説【後編】

LangChain


■概要

・LLMの実利用をより柔軟に、簡易に行うためのツール群です。LangChainを用いる事で例えば以下のような事が可能です。
 ▶異なる開発先(例: OpenAIのGPTとMetaのLLaMA)のLLMを使い分ける事ができます。
 ▶プロンプトフォーマットを事前に作ったりそれの中で利用される変数を事前に定義する事が出来ます。
 ▶プロンプトから出力される結果について、Google Search API検索を掛けたり、またpythonやbash等で後処理を掛けたりできます。
 └また、プロンプト応答や後処理を連鎖的に行う事が出来ます。
 ▶プロンプト応答の履歴を保存する事が出来ます。
 ▶プロンプト応答をjson等の構造化データとして出力する事が出来ます。

・概要について説明している記事: LangChainとは

・LangChainを部分的に機能拡張したLlamaIndexと呼ばれるツールもあります。これは、対話的データベース操作に特化した(操作を簡易化するための)ツールです。
 ▶faiss等のK-近傍検索ツール等とも連携可です

このようにLangChainを用いる事で、ChatGPTで利用されるLLMモデルだけでなく、ローカル環境でも動作するLLMを利用したり、また検索機能等のLLM単体では備わっていない機能を付与する事ができます。

理論上の話でも、おそらくはLLM単体よりも格段に表現能力は上がります。

準備


■APIキーについて

・OpenAI APIを用いる場合はAPI Keyが必要になります。以下の資料参考にして生成・設定して下さい。
 ▶ChatGPTみたいなアプリが簡単に作れるLangChainがすごすぎ

■ライブラリのインストールについて

・基本的にはlangchainでpipインストールを行うのみです。
 ▶LangChain で ChatGPT API を試す

機能


・npakaさんがnoteに簡潔に実行例含め色々書いています(例: LLM連携アプリの開発を支援するライブラリ LangChain の使い方 (1) - LLMとプロンプト・チェーン)

■LangChainのスクリプトの主要構成要素

LangChainのスクリプトは主に下記の要素によって構成されます。
・LLM ( + Prompt )
・PromptTemplate
・Chain
・Agent
・Memory

■LLM ( + Prompt )

・ユーザー等のプロンプト入力を受け付け、出力を行うための主体です。OpenAI API等幾つかの種類を利用できます。

・npakaさんの参考記事: LangChain の HOW-TO EXAMPLES (1) - LLM

・下にOpenAI API経由で質問の問い合わせを行った場合の実行例を示します。
 ▶temperature引数(float型)は、大きいほど出力単語の多様性が高まります。0以上の値である必要があります。
 ▶model_nameは非指定でも利用する事が出来ますが、OpenAI APIを利用する場合デフォルトでは"text-davinci-0003"(0.0300ドル/1K tokens)が選択されます。ChatGPTでも利用されている"gpt-3.5-turbo"(0.002ドル/1K tokens")を使った方が経済的ではあります。
 ▶ gpt-3.5-turboを使いたい場合はOpenAI()ではなくOpenAIChat()を使うと良さそうです

llm.py

from langchain.llms import OpenAI

# LLMの準備
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0.9)

# LLMの呼び出し
output = llm("こんにちは")
print(f"output: {output}")
 #output : こんにちは!私はAIアシスタントです。何かお手伝いできますか?

■PromptTemplate

・LLMに入力するためのプロンプトの雛形を事前に定義するためのモジュールです。

・プロンプトを共通化したり,変数を用いることでプロンプトの取り扱いを便利にできます。

・実際にLLMに適用するためには下のChainモジュールを併用する必要があります。

・npakaさんの参考記事: LangChain の HOW-TO EXAMPLES (2) - プロンプト: 結構様々な種類があります。

例えば、以下のような形でLLMに質問するための入力変数付きプロンプトテンプレートを作成出来ます。

prompt_template.py

from langchain.prompts import PromptTemplate

prompt_template = PromptTemplate(
    input_variables=["category", "feature"],
    template="質問:次の特徴を持つ{category}を一種類挙げて下さい, 特徴:{feature}"
)
print("prompt: " + prompt_template.format(category="動物", feature="ワンワン鳴く"))

# prompt: 質問:次の特徴を持つ動物を一種類挙げて下さい, 特徴:ワンワン鳴く

■Chain

・複数のLLMの入出力を連鎖させるためのモジュールをチェーンと呼びます。

・LangChain上のユースケース上ではLLMを直接呼び出す事は少なく、以下の"チェーン"にLLMモジュールを格納する形で利用します。

・LangChain上では、LLMモジュールをチェーンモジュールに組み込んだ上で実行されます。

・プロンプトテンプレートの設計によってはLLMが複数変数の入出力になる場合がありますが、そのような場合も対応可能です。

・npakaさんの参考記事: LangChain の HOW-TO EXAMPLES (3) - チェーン

例えば、以下のようにして上のスクリプトで生成したテンプレートを利用してChatGPTに問い合わせ可能です。

llm_chain.py

from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

# LLMの準備
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0.9)

# プロンプトの作成
prompt_template = PromptTemplate(
    input_variables=["category", "feature"],
    template="質問:次の特徴を持つ{category}を一種類挙げて下さい, 特徴:{feature}"
)

# LLMChainの作成
llm_chain = LLMChain(llm=llm, prompt=prompt_template)

# 問い合わせ処理の実行
category_input = "動物"
feature_input = "ワンワン鳴く"

input_text = prompt_template.format(category=category_input, feature=feature_input)
output_text = llm_chain.predict(category=category_input, feature=feature_input)
print(f"Q: {input_text}")
print(f"A: {output_text}")

#Q: 質問:次の特徴を持つ動物を一種類挙げて下さい, 特徴:ワンワン鳴く
#A: 犬 (いぬ)

■Chainの種類

・SequentialChain: 多入力多出力なプロンプト処理連結が可能です
 ▶LLM連携アプリの開発を支援するライブラリ LangChain の使い方 (1) - LLMとプロンプト・チェーン
 └「Chain」の項を参照

PALChain
 ▶ユーザー入力 (推論の質問) を受け取り、LLMChainでそれをPython REPLで実行するPythonコードに変換し、それを結果として返すチェーンです。

・DocumentChain:
 ▶LangChain の HOW-TO EXAMPLES (3) - チェーン(DocumentChainを参照)
 └チャンク化しないドキュメント情報保持方法(Stuffing)やチャンク化し事後的にDBアクセスしやすい形で使うための方法(MapReduce)が存在する。
 ▶pdfminer(日本語のpdfも対応しているpdfリーダーライブラリ)との連携例も公式のサンプルコードにふくまれている。
 └pdf.ipynb
 └例: 小麦についてのwikipediaページを最初の方だけ要約させたもの。   
  備考: 返信が英語なのはload_summarize_chain内の指示命令が英語で始まっているため
https://github.com/hwchase17/langchain/blob/26314d7004f36ca01f2c843a3ac38b166c9d2c44/langchain/chains/combine_documents/stuff.py#L18
https://github.com/hwchase17/langchain/blob/master/langchain/chains/summarize/stuff_prompt.py

summarize_document_pdf.py

from langchain.llms import OpenAIChat
from langchain.chains.summarize import load_summarize_chain
from langchain.document_loaders import PDFMinerLoader
from langchain.schema import Document

loader = PDFMinerLoader(PDF_DATA_PATH)
data: Document = loader.load()[0]

print(data.page_content[:100])
print(data.metadata)

# コムギ
# 出典: フリー百科事典『ウィキペディア(Wikipedia)』
# コムギ(⼩⻨、英: Wheat)はイネ科コムギ属に属する⼀
# 年 草 の 植 物 。 ⼀ 般 的 に は パ ン コ ム ギ 

page_content_raw = data.page_content
docs = Document(page_content=page_content_raw.replace("\n", "")[:1000], metadata=data.metadata)

prefix_messages = [{"role": "system", "content": "あなたは日本語要約用のエージェントです。一歩一歩考えるのが得意です"}]

# LLMの準備
llm = OpenAIChat(temperature=0.5, prefix_messages=prefix_messages)

# Stuffing(チャンク化しないドキュメントデータ保持方法)による要約
chain = load_summarize_chain(llm, chain_type="stuff")
print(chain.run([docs]))

# Wheat, a type of grass in the family Poaceae, is one of the world's three major grains and is used to make flour for bread, noodles, and pastries. It is primarily grown for domestic consumption and surplus is exported, with major exporting countries including Russia, the US, Canada, Australia, Ukraine, and France. Wheat is divided into two groups based on sowing time: autumn-sown and spring-sown. It is a hard grain with an outer shell, edible endosperm, and embryo.

■Agent

・LLMにユーザーへの出力だけでなく検索機能(= Google Search APIやSerpAPI)やシェルスクリプトの実行といった追加のアクションを追加するための機能です。
 ▶厳密にはアクションはユーザーに結果を出力するか、ツールと呼ばれる機能群のどれかを使うか、の2種類にはなります。

・利用可能なツールは複数設定する事が出来、ユーザーの質問テキスト内容だけでなく、LLMChain処理内での中間処理内容に基づいて自動的にどのアクションを選択するかを自己決定されます。

・利用できるツールの種類としては例えば以下のようなものがあります。
 ▶google-search: Google検索を行い、その結果を含めた回答ができるツール
 ▶serpapi: (SerpAPIについて)[https://inaho.esa.io/posts/584/edit#SerpAPI%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6]
 ▶llm-math: 数字の足し引きや数学の問題を解くためのLLM支援ツール(正確な数字の足し引きはLLM単体だと苦手)
 ▶python_repl: pythonスクリプトを実行するためのツール
 ▶bash: bashシェルスクリプトを実行するためのツール

・npakaさんの参考記事: LangChain の HOW-TO EXAMPLES (5) - エージェント

■備考

・Agentに関連した関数だと*-react-*といった命名がされている事がありますが、これはreactライブラリとは全く関係はありません。
 ▶ReAct: Synergizing Reasoning and Acting in Language Models
 └どのような形でLLMに任意のアクションを組み込むか、また使わせるかのLLMの機能拡張について触れた論文です。

Agentは4種類ある。
 ▶その内、zero-shot-react-descriptionと conversational-react-descriptionには対話型特化のモデルが存在する(chat-zero-shot-react-description、chat-conversational-react-description)。
 └実装だったり本質的な違いは正直現状良くわかっていない。

LangChainのAgentがどのようにToolを選択しているかを確認したメモ

■例

例えば、zero-shot-react-descriptionタイプのエージェントを用いる事で、検索機能や自分で作成した関数をLLMに連携させながら対話する事ができる。

search_and_calculation.py

from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.llms import OpenAI

# エージェントの準備
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)
agent = initialize_agent(
    llm=llm,
    tools=load_tools(
            [
                "serpapi",  # 検索用のツール
                "llm-math"  # 数式計算用のツール
            ],
            llm=llm
        ),
    agent="zero-shot-react-description",  # よしなにツールを使いこなしてくれるAgentモード
    verbose=True
)

# 質問応答の実行
response = agent({"input": "ChatGPTが登場してから今年は何年目?"})

# > Entering new AgentExecutor chain...
# I don't know what ChatGPT is or when it was introduced, so I need to search for it.
# Action: Search
# Action Input: "ChatGPT introduction year"
# Observation: ChatGPT was launched on November 30, 2022, by San Francisco–based OpenAI, also the creator of DALL·E 2 and Whisper AI. The service was initially free to the public, the company having plans to monetize the service later. By December 4, 2022, ChatGPT had over one million users.
# Thought:Now that I know when ChatGPT was introduced, I can calculate how many years it has been since then.
# Action: Calculator
# Action Input: 2022 - 2021
# Observation: Answer: 1

# Thought:So the answer to the original question is that this year is the second year since ChatGPT was introduced.
# Final Answer: 2

# > Finished chain.

■Memory

・過去のやり取りを記憶・保存・読み込みするためのモジュールです。

・LLMは入力トークンの幅はあれど(ChatGPTだったら4096tokensなど)、人間の長期記憶に相当する機能は構造上基本的には持ちません。ですので、必要に応じて会話内容についての記憶を呼び出し、LLMChainに追加する等の処理が必要になります。

・Memoryは以下の種類があります。
 ▶Conversational Memory
 └チャット内容を記憶するための機能です。例えば以下のような種類があります。
  ▷ConversationBufferMemory: 指定した回数の受け答え内容を記憶するための機能
  ▷ConversationalBufferWindowMemory: 指定した回数の受け答え内容について、トークン数の意味で制約を付けながら記憶するための機能
  ▷ConversationSummaryMemory: 指定した回数の受け答え内容を、要約しながら記憶するための機能

 ▶Entity Memory
 └会話内の特定の事柄だけ抽出・記憶するための機能です。
 └例えば、チャット内容内で特定人物に対応するトピックが出てきた場合は、関連事項を要約しながら記憶するような事が可能になります。

・npakaさんの参考記事:
 ▶LangChain の HOW-TO EXAMPLES (6) - メモリ
 ▶LangChainのエンティティメモリを試す

・メガゴリラさんの参考記事: LangChainのメモリについてのメモ

■その他の構成要素 (利用できる機能)

LangChain のトークン使用状況の追跡
LangChain で GPT Index をツールとして利用する
GPT Index でのHuggingFaceの埋め込みモデルの利用
LangChain の評価機能を試す
LangChain のデバッグツール Tracing を試す

事例集


ChatGPT APIを使ってAIキャラクターを作ってみる!
 ▶使い方を言い換えれば、chat agentにどのように事前設定をインストールするかの方法論について述べている
 ▶sakasegawaさんは割とlangchainを使いこなしている + NoteやQiitaやTwitterに色々情報を投稿している人の一人

LangChain の モデレーションチェーン による問題発言の検出
 ▶npakaさんは割とlangchainを使いこなしている + Noteに積極的に情報を投稿している人の一人

AI を用いた情報抽出システムの試作 #00

最新の論文をChatGPTで要約して毎朝Slackに共有してくれるbotを作る!

GPT-3を使って根拠付きで正確に質問応答してくれるシステムを作ってみる
オープンソース【LangChain/OpenAI/Gradio】を使ったChatGPTライクな会話チャットボットの作成

LangChainで文書データを読み込んだQ&Abotの評価を行う

LangChain Agentsを使ってテストコードから「テストの通るコード」を自動生成するプログラムを書いてみた
 ▶下のような難しさは語られている(ただし、これらについては個人的にはやりようがある話の範疇だと思う。)
 └テストコードは通ったものの、生成されたコード自体は綺麗なものとは言えないし脆弱である。
 └大きめのテストコードを与えると最大トークン数をすぐオーバーしてしまうので実用性は良くない。
 └運が悪いと延々とテストの通らないコードを生成し続けてしまう(最大トークン数制限オーバーで強制終了する)。

関連記事


LangChainによる質問応答データセットの自動生成を試す

【LangChain】Agentの仕組みを理解して, 任意のLLMを使用する

LLamaIndexのチュートリアルをやってみる

Langchainで記憶を実装したGoogle検索を使うChatGPTを作る【agentの利用】

大規模言語モデルと外部リソースとを融合させたアプリケーションを作ろう-langchainのご紹介-
 ▶langchainの機能構成要素についての記述あり

ChatGPTの機能構成要素を拡張するLangChainを試してみた
 ▶langchainの構成要素等についての記述あり

備考


・TransformerベースのLLMにMemoryを備えた場合、そのシステムは理論上はチューリング完全です。つまり上手くやれば理屈上は任意の操作が実行可能です。
 ▶Memory Augmented Large Language Models are Computationally Universal
 ▶当然理論と実際は乖離する部分がありますが、その程度の表現力はあるという意味です。
 ▶langchainを使う本質的な意義の一つはここにもあると思います。

補足


■SerpAPIについて

・Google等様々な検索エンジンについて、スクレイピング結果を提供するAPI。

・無料版・有料版がある。
 ▶無料版 : 1ヶ月に100クエリ
 ▶有料版 : 5000クエリで50ドル

・GithubアカウントやGoogleアカウントでユーザー登録可能。

・メールアドレス・電話番号の登録が必要。

・取得される情報は表層的(スニペットのみ?)
 ▶詳細やBing AI的なモノを自作したい場合は下のtwitterツリーを参照
https://twitter.com/ono_shunsuke/status/1629416694694412289

・LangChainとの連携の際にはgoogle-search-resultsライブラリも必要なのでpipでインストールする必要がある。

・実行例:
lanchain_with_serpapi.py

from langchain.utilities import SerpAPIWrapper

search = SerpAPIWrapper()
search.run("2023/04/05現在、日本の首相は誰?")

# '令和 · 第100代. 岸田 文雄. 在職日数38日. 令和3年10月4日~令和3年11月10日. 岸田内閣. 顔写真:岸田 文雄 · 第99代. 菅 義偉. 在職日数384日. 令和2年9月16日~令和3年10 ...'

■ユースケースによっては関連しそうなものなど

オープンソースのベクトル検索エンジンWeaviateが、Generativeサーチモジュールをリリース

misc


■Chatbot UI(ChatGPTライクなUIを提供するOSS)について

ChatGPT風の画面を表示できるChatbot UIをFastAPIで作成した自作LangChainサーバに接続させる方法
 ▶ChatGPTライクなUIを提供するChatbot UIについても紹介している

■OpenAIのEmbedding APIについて

・text-embedding-ada-002が最新モデル
 ▶text-embedding-ada-002 の概要

・embedding model自体はInstructGPTの(古い?)davinciバージョンと同程度のモデルサイズ(+ 性能)でAPI利用料もかなり安め。入力可能な最大トークン数も結構大きい(8K、日本語文で4000字程度)
 ▶https://openai.com/blog/new-and-improved-embedding-model
 ▶https://platform.openai.com/docs/guides/embeddings/what-are-embeddings

■OpenAI APIのモデル毎の価格等

https://openai.com/pricing

■より実践的な開発手法

6/2 より実践的なLangchainを使ったアプリケーション開発手法が
openAIとAndrew教授により、無料動画として公開されています。
こちらも合わせてご覧ください。
https://www.deeplearning.ai/short-courses/

以上です!
色々調べて、色々試して…とやっておりますが、この辺り弄ってるととても時間が足りないので、やはりSD系にもう少し絞ってみようと思います。
ということで次回はStable Diffusion周辺の理論・内部実装について調べてみたことを投稿しようと思います!

文:Hi君
協力:inaho株式会社

この記事が気に入ったらサポートをしてみませんか?