独自データやGoogle検索と連携が可能なLangChainを試す

## LangChainとは
自然言語処理を中心にしたアプリケーション開発用のフレームワークになります。、LangChainを使用することで、データソースや言語処理系などの外部リソースを組み合わせて、LLM（Language Model）を使用したアプリケーションを開発することが可能です。LangChainの良いところとして、OpenAIなどのメジャーなLLMだけでなく様々なものに組み合わせて使用する事ができるといった点が挙げられます。

## LangChainのモジュール一覧
LangChainが提供する様々なモジュールを組み合わせる事で、応用的なアプリケーション開発をサポートします。モジュールを活用することで、例えばGoogle検索と連携することで最新の情報を参照させた応答を返す事も出来るようになります。

|モジュール|説明|
|---|---|
|Models|LangChainがサポートするさまざまなモデルタイプとモデル統合|
|Prompts|プロンプトの管理、プロンプトの最適化、プロンプトのシリアル化|
|LLMs|全てのLLMsに対する汎用インターフェースと、LLMsで作業するための共通ユーティリティ|
|Indexes|独自テキストデータを言語モデルと対話できるように構造化するためのパターンと機能（埋め込み、ベクターストア、テキストスプリッター、リトリーバーなど）を提供|
|Memory|Memoryは、チェーン/エージェントの呼び出し間で状態を永続化する概念で、メモリの標準インターフェース、メモリ実装のコレクション、メモリを使用するチェーン/エージェントの例を提供|
|Chains|単一のLLMの呼び出しではなく、シーケンシャルな呼び出し（LLMまたは別のユーティリティへの呼び出し）です。チェーンの標準インターフェース、他のツールとの多数の統合、および一般的なアプリケーションのエンドツーエンドチェーンを提供|
|Agents|LLMがどのアクションをとるかを決め、実行、観察、完了するまで繰り返す。エージェントの標準インターフェース、選択できるエージェントのコレクション、およびエンドツーエンドエージェントの例を提供|
|Document Loaders|独自のテキストデータをLLMと連携をサポートするモジュール|

## LangChainを使ったLLMアプリケーションを試す
### セットアップ
```
pip install langchain
```

```
export OPENAI_API_KEY="..."
```

### LLMｓ
これはChatGPTなどOpenAIを用いたText completionと同様
```llm-sample.py
from langchain.llms import OpenAI

llm = OpenAI(temperature=0.9)

text = "新規事業開発支援会社のいい名前を考えて"
print(llm(text))
```

■ 結果
```
・ブレイズスタートアップ
・スタートトゥシューティング
・インサイトサイレンス
・アバンチュール・アート
・イノベーションスクエア
・クリエイティブスパーク
・ファイブスタービジネス
・ジェットセット・インキュベーション
・プログレス・ファクター
・グローバルブレイクスルー
・ステージワンエンタープライズ
```

### Prompt
これ単体では分かりづらいですが、プロンプトは言語モデルを起動する際に与えられる入力のことで、言語モデルに何を尋ねるかを指定するために使われます。

LangChainのプロンプトは、プロンプトを作成するためのテンプレートを提供してくれるPromptTemplateモジュールで管理が可能になります。これにより予めテンプレート化したプロンプトを加えた上でOpenAIに指示をすると言ったことが出来るようになるわけです。

```prompts-sample.py
from langchain.prompts import PromptTemplate

prompt = PromptTemplate(
    input_variables=["product"],
    template="{product}の新しいキャッチコピーを考えて",
)

print(prompt.format(product="生成AI"))
```

■ 結果
```
生成AIの新しいキャッチコピーを考えて
```

### Chains
LangChainのチェーンは、複数の言語モデルを組み合わせて複雑なタスクを解決するための仕組みです。以下ではチェーン内でllmとプロンプトの複数処理を同時に実行させています。

```chains-sample.py
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI
from langchain.chains import LLMChain

llm = OpenAI(temperature=0.9)
prompt = PromptTemplate(
    input_variables=["product"],
    template="{product}の新しいキャッチコピーを考えて複数パターン考えて",
)

chain = LLMChain(llm=llm, prompt=prompt)

print(chain.run("生成AI"))
```

■ 結果
プロンプトの通り、`生成AI`のキャッチコピーが複数生成されました。

```
1. AIであなたの未来を開く
2. AIがあなたの世界を変える
3. AIがあなたの生活を劇的に変える
4. AIがあなたの成功を見据える
5. AIが未来をつくり出す
6. AIがあなたの夢を叶える
7. AIがあなたの未来を変える
8. AIと一緒に未来をつくる
```

### Agent
エージェントはLLMを用いて実行するアクションとその順序を決定します。以下の例は外部ツールであるGoogle検索を用いて

■ google-search-resultsインストール
```
pip install google-search-results
```

■ APIKey取得
以下へアクセス

https://serpapi.com/

フリープランでSign up

![スクリーンショット 2023-04-05 2.59.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/068dd061-e017-23a5-20d9-d7affe19688c.png)

API Keyをコピー

![スクリーンショット_2023-04-05_3_00_09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354022/579ab487-1a97-9f36-7d79-851191976bc6.png)

■ 環境変数へセット

```
export SERPAPI_API_KEY="..."
```

```agent-sample.py
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.llms import OpenAI

llm = OpenAI(temperature=0)

tools = load_tools(["serpapi", "llm-math"], llm=llm)
agent = initialize_agent(tools, llm, agent="zero-shot-react-description", verbose=True)
agent.run("株式会社Relic本社の住所を教えて下さい")
```

■ 結果
```sh
> Entering new AgentExecutor chain...
 I need to find the address of the company
Action: Search
Action Input: "株式会社Relic本社の住所"
Observation: 商号: 株式会社Relic (Relic Inc.) 所在地. 【本社】 〒150-6008 東京都渋谷区恵比寿4-20-3 恵比寿ガーデンプレイスタワー8F.
Thought: I now know the final answer
Final Answer: 〒150-6008 東京都渋谷区恵比寿4-20-3 恵比寿ガーデンプレイスタワー8F

> Finished chain.
```

### Memory
以下の例ではinputの最初で、私の名前はKumadaだとAIに教えて後からそれを覚えているか確認する例になります。今回はScript内に会話が一見成立しているような感じに、こちら側の応答を予め記述してなってますが、メモリーとChatModelを組み合わせれば実際にリアルタイムに対話した上で会話内容が保持されている事が確認できます。

```memory-sample.py
from langchain import OpenAI, ConversationChain

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

conversation.predict(input="私の名前はKumadaです")

conversation.predict(input="私は宇宙から来ました。因みにあなたの名前はJarvisです")

conversation.predict(input="私はあなたとの会話を楽しむためです。ところで私の名前を覚えていますか？")

conversation.predict(input="あなたと会話するためです。ありがとう")
```

■ 結果
```sh
> 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: 私の名前はKumadaです
AI:  こんにちは、Kumadaさん！私の名前はAIです。あなたはどこから来ましたか？
Human: 私は宇宙から来ました。因みにあなたの名前はJarvisです
AI:  はい、私の名前はJarvisです。宇宙から来たんですね！それはとても面白いですね！あなたが宇宙から来た理由は何ですか？
Human: 私はあなたとの会話を楽しんでます。ところで私の名前を覚えていますか？
AI:  はい、Kumadaさんという名前を覚えています！あなたが宇宙から来た理由は何ですか？
Human: あなたと会話するためです。ありがとう
AI:
> Finished chain.
```

## 終わりに
自然言語モデルの応用的なアプリケーション開発をサポートするライブラリであるLangChainの一端に触れてみた感想としてはそれぞれが中々に強力的で独自にChatGPTライクなものを作りたいとなった際には色々とお世話になりそうという印象でした。LangChainには今回試したModel以外にもChatModelが提供されていたり、LlamaIndex同様にドキュメントローダーが備わっているため独自データを交えたやり取りも可能であるなど幅広い使い道がありそうです。今後もアップデートをWatchしていきたいと思います。

## 参照

https://python.langchain.com/en/latest/index.html

https://book.st-hakky.com/docs/langcain-intro/