見出し画像

LangChainでLLMを管理しよう!

Text by 技術本部 Ichiyama


1. はじめに

最近、大規模言語モデル(LLM)がスゴイですね。 実際もう既に試行する環境という程度なら整っている印象で、APIはありますしライブラリを入れればたった数行で様々なモデルが実行できます。

# モデルllmと入力promptから回答outputを得る

from langchain.llms import OpenAI

llm = OpenAI("gpt-3.5-turbo")
prompt = "Whats up?"

output = llm(prompt)

今回は上記コードで使用しているLangChainというOSSフレームワークを用いて、LLMの使い方を紹介したいと思います。

1.1. LangChainについて

"Build context-aware, reasoning applications with LangChain’s flexible abstractions and AI-first toolkit." (公式HPより)

大規模言語モデルを利用したアプリケーション開発のためのツールキットとなっております。 大まかに以下の2つができると書いてあります。

  1. コンテキストを認識する: LLMをコンテキストのソースに接続する。 入力であるプロンプトやドキュメント、応答の根拠となるコンテンツを管理することができる。

  2. 推論する: 言語モデルごとに推論する。 得意分野の異なる各モデルを選んでLLM的な推論やアクションを出力するために必要な機能を提供している。

LangChain自体はpythonインターフェースやデプロイ機能、GUI機能(LamgSmith)までを含んだものを指しますが、今回はデプロイ機能などは手に余るため使わず、またpythonライブラリ"langchain" == LangChainと思ってください。

1.2. 補足:LangChainトレンド指数

Googleトレンドではざっくり以下のような感じです。 バズっていますね。 今後もLLM開発ツールのスタンダードになりそうな雰囲気を出しています(個人の感想)。

(googleトレンドより)

2. ブログの狙い

「LLMを(LangChainで)使ってみよう」といって使うのはとても簡単です。 事前学習済みモデルはたくさん配布されていて、呼び出して使うだけなら障壁はないです。
またアイデアを活かすためのモデリングのテンプレも用意されています。例えば、チャットボットを作ろうと思ったらAgents機能が提供されていますし、複雑な推論をさせたい場合は複数のLLMを組み合わせるChains機能があります。モデルや(独自)データを組み合わせてAIアプリケーションを作成するのは決して困難ではないでしょう。
ただ、そういった「作ってみた」系のサイト等がいくつかある中で、「どう上手く作るか」といった情報は2023年11月現在、まだまだ少ないように感じます。 そこではフレームワークの醍醐味である「開発のための様々な機能」も端折られてますし、「LLMモデルの呼び出し方」を色々紹介されたところで(自分のアイデアは形にできると思いますが)「そのアイデアを生かしての課題の解決」にはならないように思えます。
要するに「ざっと触って作るだけ作って終わり〜」とならないように、そのあとに「試行錯誤して精度向上や機能追加していこう」と自然な流れでなるような内容にしたいと思い、今回「LangChainの実験管理周りの機能」を紹介したいと思います。
そのため、アプリケーション制作の上で重要ないくつかの機能も、省略させていただいてます。
LangChainを試せる環境と、色々試すにあたっての周辺機能の紹介ができれば幸いです。

3. 構成

コードのリポジトリはこちら()です。 言語はpythonになります。 提供する環境の構成は以下のようにしました。

langchain in (docker + poetry + Jupyter)

最低限動く環境自体はミニマムです。pyproject.tomlを参考にライブラリをインストールすればOKです。 今回、環境の共有等があるのでこのような構成になっています(というかわたしの好みです)。それぞれの構成は特に凝ったことはしていないので、ご自身の好みがあればそちらを優先しても構いません。
各構成の動機は以下のようになります。

  • docker:コンテナで環境を共有。 

  • poetry:pythonライブラリ管理ツール。仮想環境をフォルダ(プロジェクト)ごとに変更できる。再現性・使いやすさ共にpipenvより断然良い(個人の感想)。poetryの公式サイトはコチラ。 

  • jupyter: python開発環境。試行錯誤しやすいように、立てておきます。

  • langchain: LLMの統一的な実験フレームワーク。今回のメイン。

4. 始めてみよう!

環境立ち上げるにあたって、こればっかりはしなければならないことが2点。

  1. APIの登録

  2. APIキーを置くための.envファイルの作成

それが終わったら、3、4回ちょっとコマンドを叩いてもらいます。

  1. 環境コンテナ立ち上げ

  2. poetryでpythonライブラリインストール

  3. jupyterカーネルにpython環境を登録

4.1. API登録

LangChainで以下のようにモデルを動かすには、APIキーとそれに伴うアカウント登録が要ります。

from langchain.llms import OpenAI

llm = OpenAI("gpt-3.5-turbo")
prompt = "Whats up?"

output = llm(prompt)

※ from langchain.llms import HuggingFaceHubを使いたい場合はHuggingFace、RAGでgoogle検索する場合はSerpApi、などを登録してください。 今回、OpenAIをよく使うので登録しておきます。

 4.1.1. 補足:OpenAIなどLLMのAPI使用料について

OpenAIはモデル使用料(入力した"トークン"の数だけ使用料がかかる)がありますが、初回登録時は一定のトークンを無料で使えるはずです。 使用感としては、今回のように試す分には気にしなくて良いと思いますが、 料金の確認は各自お願いします。
代表的なところだと、以下のサイトをご確認ください。

 4.1.2. 補足:動作確認用のダミーモデル

それでも「コード動かすだけで金かかるのは嫌だ」という方は、コード中の from langchain.llms import OpenAIや、from langchain.chats import ChatOpenAI といったモデル指定を以下に変更して下さい。
from langchain.llms.fake import FakeListLLM FakeListLLMオブジェクトは設定したresponseを順番に返すだけなので、料金は発生しません。
マシンスペック次第ですがローカルモデルをダウンロードして動かすのも選択肢の一つです。 .gguf形式のローカルモデルを動かすライブラリも入れています。pyproject.tomlのllama-cpp-python = "^0.2.15"がそれです。

4.2. .env作成

dockerコンテナを立ち上げる際に、APIキーを環境変数として置くため。 

langchainは環境変数OPENAI_API_KEYを見ています。
そのほか登録したいAPIキーがあれば、.envやdocker-compose.ymlのenvironmentを編集するか、コンテナ内で環境変数を設定して下さい。以下を参考に.envというファイルを作成してください。

#.env

COMPOSE_PROJECT_NAME=tech_blog
OPENAI_API_KEY=sk-XXXXXXXXXXXXXXX

4.3. 環境立ち上げ

  • docker

  • poetry

  • jupyter

 4.3.1. docker

# 立ち上げ
docker-compose up

# コンテナtech_blog-lc_tutorialの中に入る
docker exec -it tech_blog-lc_tutorial /bin/bash

 4.3.2. poetry

poetryプロジェクトはすでに立ち上げています。 デフォルトの設定で、lc_tutorial/lc_tutorialになってます。深いほうのlc_tutorialは実行ファイルを置くところとなっています。 なので、以下のコマンドでpython環境を同期するだけでOKです。poetryは設定ファイルとしてpoetry.lockかまたはpyproject.tomlを読み込みます。

# プロジェクトのフォルダ下での作業
cd lc_tutorial

# # カレントディレクトリの設定ファイルを読み込みます
poetry install

これで仮想環境が作られました。

 4.3.3. jupyter

jupyter notebookのカーネルに、今作った仮想環境を指定します。 プロジェクトフォルダ(lc_tutorial)下で実行するpoetryコマンドは作成した仮想環境と紐づいています。

# 仮想環境の有効化
poetry shell

# 仮想環境内での操作。カーネルを登録
ipython kernel install --user --name=tech_blog

あとはjupyterノートブックでカーネルを指定する際、tech_blogを指定してください。
これでLangChainを動かせます。

5. LangChainの主な機能

ここでは、LLMの実験管理に使えそうないくつかをピックアップしながら解説させていただきます。 公式サイトやjupyterノートブックを横に開いて読んでください。

5.1. Model I/O

入出力やモデル選択の機能です。 LLMs等は見ていってもキリがないので、Prompts機能(Few-shot prompt templates)、 Output persers機能を見ていきます。

 5.1.1. Few-shot prompt templates

few-shot learningをするための枠組み。このような入力も受け付けているという例で紹介します。 これは言わばLLMに「例示」するようなもので、例文(Examples)をプロンプトとして与えることで出力の精度を高める手法です。

 5.1.2. output_parsers

出力のフォーマットをリストに指定したり、日付型や列挙型(Enum)に指定したりできます。 任意型でも可能ですが、LangChain公式が"You'll have to use an LLM with sufficient capacity to generate well-formed JSON."と言うように、例えばJSON形式ならその形の出力が期待できるモデルかどうかは検討してください。 十分な能力のないLLMの場合は、OutputFixingParserで正しい結果になるまで繰り返し修正するという手法もあります。

5.2. Retrieval

Promptはモデルに与える入力の部分ですが、そのほかにも様々なデータ形式をプロンプトにするためのユーティリティが提供されています。 ローダーであるDocument loadersと、それらドキュメントを管理する仕組みを紹介します。

 5.2.1. Document loaders

PDF、csv、PowerPoint、Word、HTML、メールなど。またそれらを含むディレクトリも対象にできます。 その他もGoogle Drive、 Slack、 YouTubeといった形式にも対応しているようです。 また、これらのデータは形式を問わず「ドキュメント」と呼ばれます。

 5.2.2. Indexing

LLMに必要な、大量のドキュメントを管理する機能です。

5.3. More

More(その他)と言われても大雑把な気がしますが、Chains(モデル同士の連結)とMemory(モデルの状態を保存)とCallback(ロギングやイベント処理など)を含んでいます。 そのうち気になった点をピックアップして紹介します。

 5.3.1. Memory.ChatMessageMemory

これ自体はただの独自型で、HumanMessage型とAIMessage型で入出力を包んでいるだけです。 保存や再利用のために用います。 再利用の際は、後述のBufferMemoryに入れると良いと思います。

 5.3.2. Memory.ConversationBufferMemory

バッファとして記憶を外部化し、モデルの状態を保存します。

 5.3.3. Callback.使用料の確認

色々あるとは思うのですが、コールバック情報の中にトークン使用料のデータがあったので紹介します。 ついでに料金の話なのでFakeLLMも紹介します。

6. 注意

今回私が出会ったエラーなどを記載します。 必要ないかもしれませんが何かありましたら見て下さい。

6.1. openaiライブラリのversion

openai = "^1.2.4"(最新) -> openai = "0.28.1"(0.系の最新)
自分の構成で最新verを入れると、以下のようなエラーが出てlangchain.llms.OpenAI()などが使えませんでした。 AttributeError: module 'openai' has no attribute 'error'  
このリンクを参考にver指定openai = "0.28.1"で解決。
2023/11/15現在、llamaindexを使う場合は注意。 openai = ">=1.1.0"に依存しているので、バッティングしてます。poetryを使うならプロジェクトを分けるなどして対応して下さい。

6.2. llama-cpp-pythonのインストールがうまくいかなかった。

llama-cpp-pythonはローカルLLM(ggufファイル)を動かすためのライブラリ。

Note: This error originates from the build backend, and is 
likely not a problem with poetry but with llama-cpp-python 
(0.2.15) not supporting PEP 517 builds. You can verify this by 
running 'pip wheel --no-cache-dir --use-pep517 
"llama-cpp-python (==0.2.15)"'.

llama-cpp-pythonのver指定や書いてある通りの方法ではうまくいかず。私のケースですと、FROM python:3.9だとうまくいっていましたが、FROM python:3.9.7-busterに変更するとうまくいかなくなります。 結局Dockerfileを変更したら解決する問題でしたので、どこが悪いのかはよく分かりません。

7. おわりに

LangChainの使用感は最近のライブラリの例にもれず「使いやすいな」といったところです。モジュールも結構良い感じに分類されていますし、公式も分かりやすいです。
しかしまだ新しいフレームワークなので仕様変更は続くでしょう。更に、常用しているわけではないので、使うにつれて問題が生じるかもしれません。この内容に不備があればその時は申し訳ございません。
また今回はAgentやChatsといったアプリケーションの部分には触れませんでした。ここを作ることが本筋ですので、色々試行錯誤すると良いと思います。
最後になりますがここまで読んで下さってありがとうございました。

8. Future Work

今回は調べられませんでしたが、考えられる周辺・発展技術を挙げます。

  • 入力プロンプトの管理(llamaIndex)

  • 様々なデータ形式への対応(llamahub)

  • 本番環境デプロイ(langsmith)

  • やはり気になるインジェクション対策(Prompt engineering)

  • モデルの再学習(fine-tuning)

  • ローカルLLMs(LangChain公式のruns LLMs locally)

  • モデル評価(OpenAI Evals)

  • GUI操作(LangFlow)

  • キリがないですね。

中でも気になる(であろう)点は、fine-tuningですかね。モデルの学習方法を知らないと中々応用できないような気もしますが、それっぽい結果を出すにもデータが要るでしょうし、割愛しました。 あとはLangFlowによるGUIですね。「Agentノードをエッジで繋げてAI作成」などができるようです。今回話していない部分のLLMアプリケーション製作で、モックを作成するにあたって便利でしょうか。

9. 参考

最後に参考サイトです。
 と言っても、何より公式サイトが一番です。

 LangChainは新しいので、既存の技術ブログ等には変更に伴って非推奨となったやり方が散見されます(from langchain import OpenAIとか)。なので、最終的には公式サイトでファクトチェックした方が良いです。 
またLangChainは公式の検索機能にAIを使ってます。日本語でも会話可能。これのおかげで下手な解説ブログを見るより、公式サイトに行った方がいいです。以上、下手なブログからでした。


■ 第3回 顔認証と画像品質について