LLMアプリ開発者必読!ChatGPT/LangChainによるチャットシステム構築[実践]入門【書評】

こんにちは、GLASSテクノロジー部の森です。

2023年も終わりに近づいてきました。今年は「生成AI」が流行語大賞トップ10に入るなどAIの話題に事欠かない1年でしたね。

企業利用ではChatGPTをはじめとするLLM(Large Language Models)を使って業務効率化を試すフェーズから、自社サービスに組み込んでビジネス展開を狙うフェーズに移っている会社も多く出てきている印象です(GLASSでもAIを使って自社サービスをより魅力的にできないか模索中です!)

今回はLLMを使う側ではなくプロダクトに組み込む視点から、LLMアプリの入門書として必要十分な内容がまとめられた書籍「ChatGPT/LangChainによるチャットシステム構築[実践]入門」を読んだので、ハンズオンでコードを試しながらご紹介しようと思います。

LLMアプリ開発を効率的に行える「LangChain」

内容に入る前に書籍タイトルにあるLangChainについて簡単に説明します。

LangChainはAIの中でもLLM(大規模言語モデル)を対象にしたアプリ開発に使えるフレームワークです。LLMのアプリ開発で利用する、プロンプト関係の機能、処理内容をLLMが決定するエージェント、検索に利用できるデータのベクトル化、などなど便利なモジュールが多数用意されています。また、python版とjavascript版が提供されています(本記事ではpythonの実装例を示します)

また、書籍には未掲載ですが、LangChain実装時の新しい記法として「LCEL(LangChain Expression Language)」が公開されています。これは、LangChainの名前にもある「Chain」をより直感的に記述できる記法です。

以下の実践例では、書籍のコードをベースに一部をこのLCELで記述した例も紹介いたします。

「ChatGPT/LangChainによるチャットシステム構築[実践]入門」の章構成

書籍の章構成を大きく分けると以下の通りです。

  • 1~3章:LangChainの実装以前に必要な知識
    • LLM概要
    • プロンプトエンジニアリング
    • OpenAI APIの使い方
  • 4~5章:LangChainの基礎と活用
  • 6~8章:アプリレベルの実装例
    • Streamlitを使ったサービスの実装
    • Slackアプリの実装
  • 9章:リリースの注意点
    • ガイドライン
    • セキュリティ

この記事では、4~8章の一部の例を実際のコードで試しながらご紹介します。

LangChainによる実装例

早速書籍のコードをいくつか書いてみましょう。

なお、今回は以下環境で実行しています。

pythonv 3.11.5
langchainv 0.0.305

事前にAPIキーを環境変数

この書籍ではOpenAIと通信してLLMモデルを利用します。通信に利用するOpenAI APIのキーの取得方法はこちらのブログを参考にしてください。

取得したキーを以下<API KEY>にセットしてpythonで実行すれば環境変数OPENAI_API_KEYに値が設定されます。

import os
os.environ['OPENAI_API_KEY'] = '<API_KEY>'

モデルを指定して使ってみる

基本となる大規模言語モデル(以下モデル)をセットして動かしてみます。書籍ではgpt-3.5-turboでしたが、せっかくなのでgpt-4に変えて動かしてみます

from langchain.chat_models import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage

chat = ChatOpenAI(model_name="gpt-4", temperature=0)

messages = [
    SystemMessage(content="あなたは優秀なアシスタントです。"),
    HumanMessage(content="こんにちは私は太郎です。"),
]

result = chat(messages)
print(result.content)

モデルを定義して、初期プロンプト(SystemMessage)とユーザの入力内容(HumanMessage)を渡すだけのコードです。

これを実行すると「こんにちは、太郎さん。何かお手伝いできることがありましたら、何でもお申し付けください。」と返ってきました。

たったこれだけで、LLMを呼び出すことができました。コードもシンプルで分かりやすいですね。

Chainしてみる

ここからがlangchainの本領発揮です。LLMとのやり取りする中で必要となる複数の処理をチェインして(連続して)行わせることができます。イメージはLinuxコマンドを実行する際のパイプです。

チェインをした例は次のようになります。

from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from pydantic import BaseModel, Field


class Jorney(BaseModel):
    belongings: list[str] = Field(description="持ち物")
    route: list[str] = Field(description="ルート")

output_parser = PydanticOutputParser(pydantic_object=Jorney)

template = """旅行プランを考えて下さい。

{format_instructions}

旅行先:{destination}
"""

prompt = PromptTemplate(
    template=template,
    input_variables=["destination"],
    partial_variables={"format_instructions": output_parser.get_format_instructions()}
)

model = ChatOpenAI(model_name="gpt-4", temperature=0)
chain = prompt | model | output_parser
jorney = chain.invoke({"destination": "沖縄"})
print(jorney)

これは旅行の目的地(例えば「沖縄」)の入力に対して、持ち物と旅行ルートを考えてくれて、結果をJSON形式で返す処理です。

templateの箇所がLLMに渡されるテキストです。destinationには入力された目的地(ここでは沖縄)が渡されます。format_instructionsには、特定のJSON形式で返すように指示する内容が入ります(ここではJorneyクラスのbelogings(持ちもの)リストとroute(ルート)リストの形式に合うように返すよう指示が入る)

このtemplateをgpt-4を指定したmodelに渡し、出力はoutput_parserによってJSON形式だけを返します。これらのtemplate → model → output parser の処理を連続して指定するのがチェインです。

今回のコードではchainの箇所をLCELで書きました。書籍とは主に最後のchainの箇所が違います。

chain = prompt | model | output_parser

書籍では以下のように引数の形でプロンプトやモデル、パーサーを渡します。

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

LCELでは|を使ってパイプの形で直感的に記述できてわかりやすいです。

なお、結果は以下のようになりました。

belongings=['スーツケース', 'パスポート', '日焼け止め', '水着', 'サングラス', 'ビーチサンダル', 'カメラ', 'スマートフォ ン', '充電器']
route=['那覇空港', '首里城', '美ら海水族館', '青の洞窟', '沖縄美ら海ビーチ', '那覇市内観光', '那覇空港']

ルートを考えさせるとちゃんと那覇空港に戻ってくるんですね。面白い。

Agentを使ってみる

上記の例ではモデル単体に回答をさせました。モデル単体では学習時点で得られた知識しかもっていないので、最新の情報に答えることができない場合があります。

しかし、LangChainではToolsと呼ばれる機能を使って、インターネット上の情報を使って回答させることなどが可能です。例えば天気予報のAPIにアクセスして明日の天気を回答させたり、最新のニュースについて回答させることができます。

Toolsは便利ですが、ユーザーのあらゆる質問に答えるためには、質問に合わせてToolを切り替える必要があります(天気を聞かれたら天気用のToolを使う、など)。

そこで活躍するのがAgentです。Agentはユーザの質問に対して最適なToolを判断して回答を作ってくれます

以下は書籍で紹介されている例で、DuckDuckGoというWeb検索サービスのToolとWikipediaから回答を作るToolを使って、Agentが最適な回答を行うようにするものです。

※書籍ではWebアプリのUIとしてStreamlitを使った例で紹介されていますが、ここではAgentだけの説明にするため、書き換えています。

        (...略...)
        tools = load_tools(["ddg-search", "wikipedia"])
        model = ChatOpenAI(model_name="gpt-4",temperature=0.5)
        agent = initialize_agent(tools, model, agent=AgentType.OPENAI_FUNCTIONS)
        response = agent.run(prompt)
        print(response)

とても素直なコードですね。DuckDuckGoとWikipediaのToolを読み込み、それらのツールを扱るAgentを初期化。Agentにプロンプトを渡して回答を表示しています。

ちなみに、上記の例をStreamlitを使って実装すると以下のような利用イメージになりました(Streamlitを使った実装の詳細は書籍をご確認ください)

まとめ

今回は書籍「ChatGPT/LangChainによるチャットシステム構築[実践]入門」の一部を紹介しました。本書はプロンプトエンジニアリングなどLLM全般の話から、LangChainを使った具体的なWebアプリやSlackアプリの実装まで掲載されており、LLMアプリの実装を包括的に学べる良書だと思います。LLMアプリを実装してみたいと思った人が最初に手に取る書籍としてオススメです。

さらに今回は、実装例の一部にLangChainの新しい記法であるLCMLを使ってみました。LangChainはまだまだ黎明期で新機能が増えたり、内部構造が変わったりと変化も大きいです。しかし、少しの記述量でLLMアプリを試行できる便利なフレームワークです。GLASSでも引き続き追いかけていきたいと思います。

カテゴリー: AI
タグ: LangChain , LLM
GLASSで一緒に働いてみませんか?