そろそろ知っておかないとヤバい？ 話題のLangChainを30分だけ触って理解しよう！

# LangChainって何？
ChatGPTを始めとする大規模言語モデル（LLM）の流行が止まりませんが、そんなLLMを活用して日々開発するエンジニアの間で最近ずっと耳にするキーワードの一つがLangChainです。

https://github.com/hwchase17/langchain

LangChainとは、LLMを用いたアプリケーション開発を効率的に行うためのライブラリです。機械学習分野で最も人気のあるPython言語用に提供されています。


### そもそもライブラリって何？
プログラミングの文脈でよく聞く「ライブラリ」って何者なのか、初学者にはいまいちピンと来づらいですよね。
分かりやすく言うと **「特定の言語でプログラミングをする際によく使いそうな機能をあらかじめ誰かが作ってくれて、呼び出すだけでその機能を使えるようにしてくれている便利セット」** のようなものです。

例えば、よく使われるPython言語のライブラリの例として `math` があります。これは数学的な計算をするために便利な機能を多数用意してくれているライブラリです。

`math` ライブラリの中には「平方根を計算する」ための `sqrt()` という関数が用意されています。平方根とは算数で習った「ルート（√）」ですね。9の平方根は3、というやつです。
自分の作るアプリケーションの中で「9の平方根は何か？」を自力で計算したい場合、恐らくそこそこ複雑なコードをPythonで記述する必要があると思うのですが、この `math` ライブラリを取り込んで `sqrt()` 関数に「9」という引数を放り込めば「3」という回答を返してくれます。これがライブラリの利点です。


### 「外部ライブラリ」は最初にインストールが必要！

ライブラリには「標準ライブラリ」と「外部ライブラリ」があり、例えばこの `math` ライブラリは非常によく使われるためPythonランタイムに標準で同梱されている「標準ライブラリ」なのですが、今回紹介するLangChainのように日々世の中で誰かが作ってくれている「外部ライブラリ」は利用前に実行したいコンピューターにインストールする必要があります。


# 実際に触ってみよう！

### 環境準備

比較的新しい（Appleシリコン版のCPUを搭載した）Macを利用する前提とします。

- コードエディターとしてVS Codeをインストールする
- VS Codeの拡張機能「Python」をインストールする
- Pythonとpipの最新版をインストールする

https://www.python.org/downloads/macos/


### LangChainのクイックスタートをやってみよう！

何か新しいツールを勉強する際、公式サイトに「Getting started」的な入門者向けチュートリアルが用意されていることが多いので、そちらをやってみることをオススメします。

LangChainも例にもれず、英語ですがクイックスタートが用意されているので、今回のQiita記事ではクイックスタートをみなさんと一緒にやっていこうと思います。

https://python.langchain.com/docs/get_started/quickstart


### Pythonライブラリのインストール

- LangChainとOpenAIをインストールする

```zsh:ターミナル
pip install langchain
pip install openai
```

※環境によっては「pip」の代わりに「pip3」でPythonバージョン3用のコマンドを実行してみてください。

- OpenAI APIのキーを環境変数にセットする

```zsh:ターミナル
export OPENAI_API_KEY="ここにAPIキーを記載する"
```

※Mac OSの環境変数はターミナルを閉じるとクリアされてしまうので注意してください。

APIキーはコードに直接記載することも可能なのですが、APIのシークレットキーはいわばパスワードのような認証情報の一種のため、セキュリティの観点からターミナルで都度設定することは安全であると言えます。（＝他人にコードを見られても自分のOpenAIアカウントが悪用されることはない）

APIキーは以下ページから自分のOpenAIアカウントにログインして確認できます。
登録直後の3ヶ月間は18ドル分のクレジットが付与されており、無料で利用することができるので有効活用しましょう。

https://platform.openai.com/account/api-keys



### まずはLangChainを使わずにOpenAIを呼び出してみる
いきなりLangChainを使ってしまうと便利さがいまいち分からなくなるので、最初にOpenAIのAPIをPython言語で直接呼び出して「日本の総理大臣は誰？」と聞いてみることにします。

クラメソさんのブログを参考にさせていただきました。

https://dev.classmethod.jp/articles/openai-api-chat-python-first-step/

`test.py` というファイルを作って以下のコードを実行してみます。

```py:test.py
import os
import OpenAI

openai.api_key = os.environ["OPENAI_API_KEY"]

response = openai.ChatCompletion.create(
    model="gpt-3.5-turbo",
    messages=[
        {"role": "user", "content": "日本の総理大臣は誰ですか？"},
    ],
)
print(response.choices[0]["message"]["content"].strip())
```

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
私には日本の総理大臣の最新情報がありません。2021年7月現在、日本の総理大臣は菅義偉氏ですが、この情報は常に更新され、正確であるとは限りません。正確な情報を確認するには、公式のニュースソースや政府のウェブサイトを参照してください。
```


### 主要機能その①「LLM」
LangChainの中でも「言語モデルを呼び出す」という最も基本的な機能を実現してくれるのが「LLM」という機能です。そのままですね。

具体的にはOpenAIなどの言語モデルを指定し、Temperature（回答のブレ具合）やプロンプト（入力テキスト）などのパラメーターを付与してLLMのAPIへリクエストを送信するといった形で、LLMのAPIをプログラムから便利に呼び出すためのラッパーとしての機能を提供してくれます。

試しに `llms.py` というファイルを作って以下のコードを書いてみましょう。

```py:llms.py
from langchain.llms import OpenAI

llm = OpenAI(temperature=0.9)
output = llm.predict("日本の総理大臣は誰ですか？")

print(output)
```

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
安倍晋三が現在の日本の総理大臣です。
```

これでOpenAIのAPIに対して、Temperatureや入力テキストを渡して回答文を生成することができました。
LangChainを使わないときよりも少ないコード量で似たような処理を実装することができましたね。


### 主要機能その②「チャットモデル」
Chat modelsは雑に言うとLLMの亜種です。テキスト生成のなかでもチャット対話に特化しており、前述のLLMsとは入出力パラメーターの仕様が少し異なっています。

試しに `chat_models.py` というファイルを作って以下のコードを書いてみましょう。

```py:chat_models.py
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

chat = ChatOpenAI(temperature=0)
output = chat.predict_messages([HumanMessage(content="日本の総理大臣は誰ですか？")])

print(output)
```

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
content='2021年現在の日本の総理大臣は菅義偉（すが・よしひで）です。' additional_kwargs={} example=False
```

先ほどとは出力形式が変わりましたね。総理大臣の最新情報も微妙に違っているので、バックエンドで利用される言語モデルが変わったことも影響していそうです。

ちなみにこのChat modelsを前述のLLMsと同じフォーマットで利用できるインターフェースもあります。
`predict_messages` メソッドの代わりに `predict` メソッドを使えばいいようです。

```py:chat_models.py
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
    AIMessage,
    HumanMessage,
    SystemMessage
)

chat = ChatOpenAI(temperature=0)
output = chat.predict("日本の総理大臣は誰ですか？") #ここが少し変わった

print(output)
```

出力フォーマットもLLMsと同様、テキストのみになりました。

```zsh:ターミナル
2021年現在、日本の総理大臣は菅義偉（すが・よしひで）です。
```


### 主要機能その③「プロンプトテンプレート」
テキスト生成AIを使ってアプリケーションを開発する際、LLMに渡すプロンプト（入力テキスト）をテンプレート化して、その中の一部のキーワードのみ毎回変えられるようにする…といった使い方ができると便利です。
これを実現するLangChainの機能がPrompt templatesです。

試しに `prompts.py` というファイルを作って以下のコードを書いてみましょう。

```py:prompts.py
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate

template = PromptTemplate.from_template("{keyword}を解説するQiita記事のタイトル案は?")
prompt = template.format(keyword="Python")

chat = ChatOpenAI(temperature=0)
output = chat.predict(prompt)

print(output)
```
サンプルコードを見ると、 `{keyword}` 部分を後から指定できるような形でまとまった文をテンプレートとして設定していることが分かります。

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
1. Python入門者必見！基本的な文法から応用まで解説
2. Pythonでプログラミングを始めよう！初心者向けの解説記事
3. Pythonの基礎から応用まで徹底解説！初心者でもわかるように説明します
4. Pythonの使い方をマスターしよう！初心者向けの解説記事
5. Pythonの基本的な文法を理解しよう！初心者でもわかりやすい解説記事
```

試しに `{keyword}` を "AWS" に変えて再実行してみましょう。

```zsh:ターミナル
1. AWSとは？クラウドコンピューティングの基礎知識から解説
2. AWSの魅力とは？ビジネスにおける活用方法を解説
3. AWSの主要サービスを徹底解説！初心者でもわかる使い方と活用法
4. AWSのセキュリティ対策について解説！安全なクラウド環境を構築する方法
5. AWSの料金体系を理解しよう！コスト削減のためのノウハウを紹介
6. AWSのデータベースサービスを解説！RDSやDynamoDBの使い方と特徴
7. AWSのマネージドサービスを解説！LambdaやS3などの活用方法を紹介
8. AWSのアーキテクチャ設計について解説！スケーラビリティや可用性の向上方法
9. AWSのIoTサービスを解説！デバイス管理やデータ収集の方法を紹介
10. AWSの機械学習サービスを解説！SageMakerやRekognitionの活用方法
```

めっちゃ例出てきましたｗ


### 主要機能その④「チェーン」
Chainsは、LangChainというソフトウェア名にもなっているように中心的な機能です。
その名の通り、LangChainが持つ様々な機能を「連結」して組み合わせることができます。

試しに `chains.py` というファイルを作って以下のコードを書いてみましょう。

```py:chains.py
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain

chat = ChatOpenAI(temperature=0)
template = PromptTemplate.from_template("{keyword}を解説するQiita記事のタイトル案は?")

chain = LLMChain(llm=chat, prompt=template)
output = chain.run("LangChain")

print(output)
```

サンプルコードを見ると、先に登場した「チャットモデル」と「プロンプトテンプレート」をLLMChainというオブジェクトに放り込み、 `run` メソッドで連結動作させていることが分かります。

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
「LangChainとは？ブロックチェーン技術を活用した言語学習プラットフォームの魅力」
```

ちなみにLangChainは新しいソフトウェアなので、この言語モデルでは名前をもとに誤った推測がされているようです。笑



### 主要機能その⑤「エージェント」
Agents はかなり面白い機能です。入力テキストに基づいて、何をすべきか自動で判断したうえで複数のツールを使い分け、ワークフローのような形で仕事を順番に実行して目的を達成してくれます。

今回はLLMに加えて、以下のツールを利用してみます。

- SerpAPI：Google検索結果を取得してくれるAPIツール
- LLM Math：算術計算をしてくれるLangChainのツール

事前にSerpAPIをpipでインストールし、APIキーを環境変数にセットする必要があります。

```zsh:ターミナル
pip install google-search-results
export SERPAPI_API_KEY="ここにAPIキーを記載します"
```

SerpAPIにサインアップすれば無料で一定利用できるAPIキーを取得することができます。

https://serpapi.com/

試しに `agents.py` というファイルを作って以下のコードを書いてみましょう。

```py:agents.py
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)

agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
output = agent.run("今日の新宿区の最高気温の摂氏温度の平方根はいくつ？")

print(output)
```

最後にAgentsに渡しているプロンプトを見ると、「今日の新宿区の最高気温」というWeb検索が必要な情報を取得したうえで、平方根を求めるという算術計算が必要なことが分かります。

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
> Entering new AgentExecutor chain...
 I need to find out the highest temperature in Shinjuku today and then calculate its square root.
Action: Search
Action Input: "Today's highest temperature in Shinjuku"
Observation: Today, in Shinjuku, cloudy weather is expected. The temperature will vary between a minimum of 22°C (71.6°F) and a maximum of 31°C (87.8°F).
Thought: I now need to calculate the square root of the maximum temperature.
Action: Calculator
Action Input: 31°C
Observation: Answer: 304.15
Thought: I now know the final answer.
Final Answer: 5.5°C

> Finished chain.
5.5°C
```

せっかくなので処理過程をChatGPTさんに日本語訳してもらったものが以下です。

```zsh:ターミナル
> 新たなAgentExecutorチェーンを開始...
 今日の新宿の最高気温を調べ、その平方根を計算する必要があります。

アクション：検索
アクション入力："今日の新宿の最高気温"
観察：今日、新宿では曇りの天気が予想されています。気温は最低22°C（71.6°F）から最高31°C（87.8°F）の間で変動します。
思考：次に、最高気温の平方根を計算する必要があります。

アクション：計算機
アクション入力：31°C
観察：答え：304.15
思考：最終的な答えを知りました。

最終答え：5.5°C

> チェーン終了。
5.5°C
```

これは凄いですね！ 自分でもGoogle検索してみましたが、確かに今日の新宿の最高気温は31℃程度（30℃）でした。平方根の計算結果も合っていそうです。


### 主要機能その⑥「メモリー」
最後に紹介するMemoryは分かりやすい機能で、ChatGPTのWeb UIのように過去の対話内容を保持して次回の入力を補正してくれます。

試しに `memory.py` というファイルを作って以下のコードを書いてみましょう。

```py:memory.py
from langchain import OpenAI, ConversationChain

llm = OpenAI(temperature=0)
conversation = ConversationChain(llm=llm, verbose=True)

output = conversation.run("私は日本人です。何を聞いても日本語で答えてください。")
output = conversation.run("Who is the prime minister of Japan?")

print(output)
```

VS Codeのデバッグ機能を使って実行すると、ターミナルで以下のように結果が出力されます。

```zsh:ターミナル
> Entering new ConversationChain chain...
Prompt after formatting:
The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.

Current conversation:
Human: 私は日本人です。何を聞いても日本語で答えてください。
AI:  はい、わかりました。私はあなたの日本語を理解します。どうぞ、どうぞ、質問をしてください。
Human: Who is the prime minister of Japan?
AI:

> Finished chain.
 日本の現在の首相は安倍晋三さんです。
```

※会話を2回連続で行っているので、実際には一部冗長な形でターミナルに結果が出力されます。

このAIの最終回答を見ると、1回目の会話で入力された内容が文脈として引き継がれ、2回目の入力を補正してくれていることが推測できます。