GPTをドーピングする LangChain 基礎編
概要
LLM(大規模言語モデル)の統合的なライブラリである、LangChain の基本的な使い方についての解説記事です。
LangChain は、Microsoft が提供する Visual ChatGPTなどにも、内部的に使用されており、今後のLLMを使用したアプリケーション開発のデファクトスタンダードになり得るライブラリです。
LangChain は現在、Python と TypeScript(JavaScript) の環境でのみ使用可能であり、本記事は TypeScript での解説になります。
ただ、Pythonでの実装方法も殆ど変わらないため、Pythonでの実装を考えてる方にも参考程度にはなるかと思います。
この記事を読むとわかること
- LangChain とは
- LangChain の基本機能
- LangChain の使い方
- LLMs の使い方
- Template の使い方
- Memory の使い方
- Chain の使い方
- Agent の使い方
LangChain とは
LangChain の各機能を利用して、独自データを読み込んだり、Google 検索を行ったり、LLM が苦手とする計算問題を解いたりすることができるようになります。
LangChain を使ったアプリケーション開発は、高度な処理や知識の組み合わせにより、より高いパフォーマンスや複雑な処理を実現できます。
LangChain は現在 Pyhton と TypeScript の環境でのみ使用可能です。
また、Python と TypeScript においても、使える機能、LLM の種類に違いがあります。詳しくは以下の表をご覧ください。
Features
IntegrationsLangChain は様々なモジュールを提供しています。以下が主要なモジュールとその概要です。
-
LLMs
LLM(大規模言語モデル)を使い、効果的な結果を得るために複数のモデルを組み合わせるるためのモジュール -
Template
文や出力文のフォーマットを定め、効率的な文章生成や情報抽出が可能にするためのモジュール -
Memory
言語モデルに記憶を保持させ、ステートフルなやり取りを実装するためのモジュール -
Chain
複数のタスクを一連のプロセスとして連携させ、各タスクの結果を次のタスクへ引き継ぎ、より複雑な処理を行うためのモジュール -
Agent
外部の API と連携し、より複雑な処理を行うためのモジュール。
本記事では、これらの内容について、例を用いて詳しく解説していきます。
LangChain の機能・使い方
LLMs
LLMs は、大規模な言語モデルを扱うためのモジュールです。LangChain を使うことで、異なる種類の LLM を同じインターフェースで利用することができます。これにより、複数の言語モデルを簡単に切り替えたり、組み合わせたりすることができます。
始めるには、LLM の実装の call メソッドを使って文字列入力を渡すだけです。
今回の例では、OpenAI の LLM を使用して実装しました。
Example
-
入力
import { OpenAI } from "langchain/llms"; require("dotenv").config(); export const runLlm = async () => { const llm = new OpenAI(); const res = await llm.call("自己紹介してください"); console.log(res); }; runLlm();
-
出力
はじめまして、私は○○と申します。現在大学4年生で、情報システム学を専攻しています。 趣味は旅行や料理などをすることです。特に旅行が好きで、海外や国内問わず旅行を楽しんでいます。 技術的な話題で言うと、プログラミングに興味があります。 今までC、Java、PHPなどを勉強してきました。
Prompt Template
Prompt Template は、質問や指示(プロンプト)を効率的に扱うためのモジュールです。
プロンプトを共通化したり、変数を使って簡単にカスタマイズできます。これにより、同じような質問を繰り返し行う際に、手間を省くことができます。
Example
-
入力
import { PromptTemplate } from "langchain"; import { OpenAI } from "langchain/llms"; require("dotenv").config(); export const runTemplate = async () => { const template = new PromptTemplate({ inputVariables: ["menu"], template: "{menu}を作る作るために必要な材料は?", }); const llm = new OpenAI(); const res = await llm.call(await template.format({ menu: "カレー" })); console.log(res); }; runTemplate();
-
出力
・肉(牛肉、鶏肉、豚肉など) ・野菜(人参、キャベツ、トマト、にんじんなど) ・スパイス(カレー粉、唐辛子、ターメリック、クミンなど) ・油 ・水 ・醤油
Memory
LLM とのやり取りを保持するためなどに使用するモジュールです。
ChatGPT のように過去のやり取りを踏まえて回答するチャットサービスを実現するために必要な機能です。
Example
-
入力
import { ConversationChain } from "langchain/chains"; import { OpenAI } from "langchain"; require("dotenv").config(); export const runMemory = async () => { const llm = new OpenAI({ temperature: 0 }); const memoryChain = new ConversationChain({ llm }); const input1 = "あなたの座右の銘は何ですか?"; const res1 = await memoryChain.call({ input: input1 }); console.log("User: ", input1); console.log("Agent:", res1.response); const input2 = "それはどんな意味ですか?"; const res2 = await memoryChain.call({ input: input2 }); console.log("User: ", input2); console.log("Agent:", res2.response); const input3 = "なぜその言葉が好きなのですか?"; const res3 = await memoryChain.call({ input: input3 }); console.log("User: ", input3); console.log("Agent:", res3.response); }; runMemory();
-
出力
User: あなたの座右の銘は何ですか? Agent: 私の座右の銘は「知恵は力なり」です。これは、私が大切にしている考え方です。 User: それはどんな意味ですか? Agent: 「知恵は力なり」とは、知恵を持つことが力を持つことに等しいという意味です。知恵を持つことで、人々は自分自身をより良くすることができます。 User: なぜその言葉が好きなのですか? Agent: 私は、知恵を持つことが人間が成功するために必要なものだと考えています。知恵を持つことで、人々は自分自身をより良くすることができます。また、知恵を持つことで、人々は他人を理解し、他人と協力して問題を解決することができます。
Chain
Chains は、LLM を連鎖的につなげていくことのできるモジュールです。
ある LLM の出力を別の LLM の入力として使用したいときに便利です。LLM これらをつなげることで、1 つの LLM だけでは実現できない処理を行うことができます。
最も基本的な「LLMChain」は「LLM」と「プロンプトテンプレート」で構成されます。
Example
-
入力
import { LLMChain } from "langchain/chains"; import { OpenAI } from "langchain/llms"; import { PromptTemplate } from "langchain"; require("dotenv").config(); export const runChain = async () => { const llm = new OpenAI({ temperature: 1 }); const prompt = new PromptTemplate({ inputVariables: ["menu"], template: "{menu}の具材を教えて下さい。", }); const chain = new LLMChain({ llm, prompt }); const res = await chain.call({ menu: "寿司" }); console.log(res.text); }; runChain();
-
出力
いくつか例をあげます。 ・玉子 ・イカ ・たら ・サーモン ・海苔 ・たこ ・穴子 ・うなぎ ・クラゲ ・昆布 ・代々木牛蒡
Agent
Agent は LangChain の中心的な機能で、LangChain から提供されている Tools を使用して、より高度な回答を生成するためのモジュールです。
ユーザの入力に応じて、与えられたツールからどのツールを実行し、どういう順序で使用するかを決定し回答を導きます。
Agent は、LLM や Chains、Document Loaders などの機能を組み合わせて、質問や要求に対して最適な回答を生成することができます。
Tools とは、LangChain で提供される様々なユーティリティや機能をまとめたモジュールです。これらのツールを利用して、Agent や Chains をカスタマイズし、特定のタスクに適した処理を実現できます。
例えば、Google 検索ツールを使って情報を検索したり、数学の問題を解くツールを使用したりすることができます。
Agent で利用可能な Tools には、主に以下のようなものがあります。
-
BingSerpAPI
Bing Search API のラッパーです。時事問題に関する質問に答える必要があるときに便利です。入力は検索クエリである必要があります。 -
Calculator
数学式の結果を得るのに便利です。このツールへの入力は、単純な電卓で実行できる有効な数式である必要があります。 -
IFTTTWebHook
IFTTT Webhook API のラッパーです。IFTTT のアクションをトリガーするのに便利です。 -
JsonListKeys
andJsonGetValue
JSON オブジェクトからデータを抽出するのに便利です。これらのツールは、JsonToolkit としてまとめて使用することができます。 -
RequestsGet
andRequestsPost
HTTP リクエストを行う際に便利です。 -
SerpAPI
SerpAPI API のラッパーです。時事問題に関する質問に答える必要があるときに便利です。入力は検索クエリである必要があります。 -
QuerySqlTool
,InfoSqlTool
,ListTablesSqlTool
, andSqlCheckerTool
SQL データベースを操作するのに便利です。SqlToolkit で一緒に使用することができます。 -
VectorStoreQATool
ベクトルストアから関連するテキストデータを取得するのに便利です。 -
ZapierNLARunAction
Zapier NLP API のラッパーです。自然言語入力で Zapier のアクションをトリガーするのに便利です。ZapierToolkit で使用するとベストです。
上記は TypeScript 環境での tools であり、Python 環境とは異なりますので、注意してください。
より詳しく知りたい方は、以下をご覧ください。
Example
-
入力
import { initializeAgentExecutor } from "langchain/agents"; import { OpenAI, PromptTemplate } from "langchain"; import { Calculator, SerpAPI } from "langchain/tools"; require("dotenv").config(); export const runAgent = async () => { const llm = new OpenAI({ temperature: 0 }); const tools = [new SerpAPI(), new Calculator()]; const executor = await initializeAgentExecutor( tools, llm, "zero-shot-react-description", true ); // first web検索 const firstPrompt = "尾田栄一郎 ONE PIECE 最新刊の巻数"; const firstRes = await executor.call({ input: firstPrompt }); console.log("User1", firstPrompt); console.log("Agent1", firstRes.output); // second 数値取り出し const secondPrompt = new PromptTemplate({ inputVariables: ["text"], template: "「{text}」Think step-by-step only of the number of the volume from the text here, and output it precisely.", }); const secondRes = await llm.call( // firstのレスポンスをsecondのプロンプトに設定 await secondPrompt.format({ text: firstRes.output }) ); console.log("User2", secondPrompt.template); console.log("Agent2", secondRes); // third 計算 const thirdPrompt = new PromptTemplate({ inputVariables: ["volumes"], template: "{volumes}に5を掛けると?", }); const thirdRes = await executor.call({ // secondのレスポンスをthirdのプロンプトに設定 input: await thirdPrompt.format({ volumes: secondRes }), }); console.log("User3", thirdPrompt.template); console.log("Agent3", thirdRes.output); }; runAgent();
-
出力
Entering new agent_executor chain... I need to find out the latest volume of the manga Action: search Action Input: "尾田栄一郎 ONE PIECE 最新刊の巻数" 尾田栄一郎さんによる人気漫画『ONE PIECE』(ワンピース)。 最新刊となる105巻は2023年3月3日発売、次巻となる106巻は発売日未定(未発表)です。 こちらでは、『ONE PIECE』既刊から最新刊までの発売日・価格・あらすじなどの情報をご紹介しています。 Finished chain. User1 尾田栄一郎 ONE PIECE 最新刊の巻数 Agent1 尾田栄一郎 ONE PIECE 最新刊の巻数は105巻です。 User2 「{text}」Think step-by-step only of the number of the volume from the text here, and output it precisely. Agent2 105巻 Entering new agent_executor chain... I need to calculate the result of multiplying 105 by 5 Action: calculator Action Input: 105 * 5 525 Finished chain. User3 {volumes}に5を掛けると? Agent3 105を5で掛けると525になります。
最後に
今回は、LLM の統合的なフレームワークである LangChain (TypeScript 版) の基礎を解説しました。
今回は基礎編でしたが、この他にも、独自のデータセットを読み込めるDocument Loadersなどの、魅力的なモジュールがたくさんあります。
また、学習に当たり、npaka さんの記事がとても参考になりましたので、ぜひ参考にしてみてください。
最後に、間違い等ありましたら、ご指摘いただけると幸いです。
参考
Discussion
Agent の入力例の
は
の誤字でしょうか?
コメントありがとうございます。
誤字ではありませんが、
こちらでも同様のアウトプットが可能です。
なるほど、ありがとうございます!