ChatGPTの限界を超えろ LangChain【概要編】
🦜

ChatGPTの限界を超えろ LangChain【概要編】

Tags
AI
Software Development
Published
May 5, 2023
Author
heyhey1028

現状のChatGPT の限界

チャット GPT は非常に便利ですが主に2つの課題があります。
1つめは学習されたデータが最新でない事です。2021年9月までのデータで学習しているため それ以降のデータについては 回答することができません。
2つめはプロンプトに含められるトークン数の制限です。GPT3.5では4,096トークンまで、GPT4は8,192トークンまでとなっています。ざっくりと日本語1文字で1トークンとなります。これよりも文字数の多い論文などについて要約したくてもプロンプトに含めることはできません。
このようなChatGPTが抱える課題を乗り越えるために開発されたライブラリが今回ご紹介するLangChainです。

LangChainとは

LangChainとは大規模言語モデルを効果的に使う為のライブラリです。現在、PythonTypescriptに対応しています。(こちらの記事ではPythonを紹介)
このライブラリを使用することで 先ほどあげた ChatGPTの課題を克服することが可能になります。
つまり最新の情報をもとにGPTモデルと対話することやまた論文など文字数の多い資料をもとにGPTモデルと対話することも可能になります。

どのようなモジュールがあるのか?

LangChainはModelsPromptsMemoryIndexesChainsAgentsの6つのカテゴリに分かれ、それぞれに複数のモジュールが属しています。
  • Models
    • LLMsChat ModelsText Embeddings Models
  • Prompts
    • Prompt TemplatesChat Prompt TemplateExample SelectorsOutput Parsers
  • Memory
  • Indexes
    • Document LoadersText SplittersVectorstoresRetrievers
  • Chains
  • Agents
    • ToolsAgentsToolkitsAgent Executors
それぞれ 概要を見ていきましょう。

Models

Modelsのカテゴリでは、LLMsChat ModelsText Embeddings Modelsというモジュールが用意されています。Text completion(単発のやり取り)やChat completion、EmbeddingsなどLLMのAPIを叩くのに便利なインターフェースを提供しています。
下記のように連携可能なLLMをシンプルな記法で呼び出すことができます。
from langchain.llms import OpenAI llm = OpenAI(model_name="text-ada-001", n=2, best_of=2)
llm("Tell me a joke")
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'

Prompts

PromptsのカテゴリではPrompt TemplatesChat Prompt TemplateExample SelectorsOutput Parsers というモジュールが用意されています。これらはプロンプトをデザインする上で便利な機能を提供しています。
Prompt Template, Chat Prompt Templateではそれぞれプロンプトを共通化したり、変数を使って簡単にカスタマイズできるインターフェースを提供しています。同じような質問を繰り返し行う際に、手間を省くことができます。
例えば以下の例ではプロンプトにproductという変数を持ったテンプレートを用意し、実行時に変数を代入できるようにしています。
from langchain import PromptTemplate template = """ I want you to act as a naming consultant for new companies. What is a good name for a company that makes {product}? """ prompt = PromptTemplate( input_variables=["product"], template=template, ) prompt.format(product="colorful socks") # -> I want you to act as a naming consultant for new companies. # -> What is a good name for a company that makes colorful socks?
これを後述するChains を使って、Modelsで定義したLLMと組み合わせることでLLMへカスタマイズしたプロンプトを投げることが出来ます。
他にもFew shot Promptsなどのテクニックを実装する為のExample Selectorsや出力結果のフォーマットを定義するOutput Parsersなどが用意されています。

Memory

LLM とのやり取りを保持するために使用するモジュールです。
ChatGPT のように過去のやり取りを踏まえて回答するチャットサービスを実現するために必要な機能です。
以下の例ではChatMessageHistoryクラスにユーザーとAIからのメッセージをそれぞれ格納している様子が分かるかと思います。
from langchain.memory import ChatMessageHistory history = ChatMessageHistory() history.add_user_message("hi!") history.add_ai_message("whats up?")
history.messages
[HumanMessage(content='hi!', additional_kwargs={}), AIMessage(content='whats up?', additional_kwargs={})]

Indexes

Indexesのカテゴリでは、Document LoadersText SplittersVectorstoresRetrieversというモジュールが用意されています。このカテゴリはEmbeddingsというLLMに任意の情報を追加する手法で用いられます
Embeddingsの手法は主に
  1. テキストデータの読み込み
  1. テキストデータの分割
  1. 分割されたチャンクのベクトル化
  1. ベクトル化したデータの保存
  1. 保存したデータの取得
というステップで行われます。このステップの1,2,4,5に対応したモジュールが用意されているわけです。
テキストデータの読み込み: Document loader テキストデータの分割: Text Splitters ベクトル化データの保存: Vectorstores 保存したデータの取得: Retrievers
 
例えば以下のようにドキュメントを読み込み、TextSplitterというクラスを使ってそのドキュメントを指定したチャンクサイズに分割することができます。
from langchain.text_splitter import CharacterTextSplitter documents = loader.load() text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0) texts = text_splitter.split_documents(documents)

Chains

Chains は、LLM を連鎖的につなげていくことのできるモジュールです。前述のModelsPromptsを組み合わせて、鎖を作り、それを繋げていく様なイメージです。それを応用することで、ある LLM の出力を別の LLM の入力として使用することなども可能になります。
最もシンプルなChainは以下の様にModelsPromptTemplateを組み合わせて作ります。
from langchain.prompts import PromptTemplate from langchain.llms import OpenAI llm = OpenAI(temperature=0.9) prompt = PromptTemplate( input_variables=["product"], template="What is a good name for a company that makes {product}?", )
from langchain.chains import LLMChain chain = LLMChain(llm=llm, prompt=prompt) # Run the chain only specifying the input variable. print(chain.run("colorful socks"))
またSimpleSequentialChain というクラスでChainを複数繋げることもできます。
from langchain.chains import SimpleSequentialChain overall_chain = SimpleSequentialChain(chains=[chain, chain_two], verbose=True) # Run the chain specifying only the input variable for the first chain. catchphrase = overall_chain.run("colorful socks") print(catchphrase)

Agents

Agentsカテゴリでは、ToolsAgentsToolkitsAgent Executorというモジュールがあります。これらはAutoGPTBabyAGIといった最近話題となっている自律駆動型AIエージェントを作るベースとなっています。
ToolsはLLMを使ってインターネット検索やZapierの操作など実際のアクションを実行するモジュールです。これをChainと組み合わせることで一連の流れの中でLLMからの応答に応じて、ネット検索を行ったり、APIを実行したり実際のアクションを実行させることが出来ます。
例えば以下の様な流れでGoogle検索を実行することが出来ます。
from langchain.tools import Tool from langchain.utilities import GoogleSearchAPIWrapper search = GoogleSearchAPIWrapper() tool = Tool( name = "Google Search", description="Search Google for recent results.", func=search.run )
tool.run("Obama's first name?")
そして中でも強力な機能がAgentsモジュールです。このモジュールではユーザーの指示に基づいて、何をどのステップで行うかを自身で判断し、実行まで行ってくれるAgentを定義することができます。
# Construct the agent. We will use the default agent type here agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
ここまででは凄さが伝わらないかと思いますが、詳細は別記事にて深堀りたいと思います。

まとめ

現在、LLMを使った様々なサービスがカンブリア爆発よろしく、日々大量に誕生していますが、その多くはGPTの様なLLM x LangChainの組み合わせで作られています。また今後も話題に登ってくるであろう自立駆動型AIエージェントでもLangChainが広く使われています。
この2点からもLLMを使ったアプリケーションを作る際には必ずと言って良いほど使われるライブラリとなっているので、各モジュールの中身を知ってアイデアを形にしていきましょう。
各カテゴリのより詳細な説明や使い方は別の記事で見ていきたいと思います。
今日はここまで!!👋