🦜

GPTをドーピングする LangChain 基礎編

2023/04/08に公開
3

概要

LLM(大規模言語モデル)の統合的なライブラリである、LangChain の基本的な使い方についての解説記事です。
LangChain は、Microsoft が提供する Visual ChatGPTなどにも、内部的に使用されており、今後のLLMを使用したアプリケーション開発のデファクトスタンダードになり得るライブラリです。

LangChain は現在、Python と TypeScript(JavaScript) の環境でのみ使用可能であり、本記事は TypeScript での解説になります。
ただ、Pythonでの実装方法も殆ど変わらないため、Pythonでの実装を考えてる方にも参考程度にはなるかと思います。

この記事を読むとわかること

  • LangChain とは
  • LangChain の基本機能
  • LangChain の使い方
    • LLMs の使い方
    • Template の使い方
    • Memory の使い方
    • Chain の使い方
    • Agent の使い方

LangChain とは

https://js.langchain.com/docs/
LangChain とは、GPT などの大規模言語モデルを使ったサービス開発に役立つ、LLM のライブラリです。
LangChain の各機能を利用して、独自データを読み込んだり、Google 検索を行ったり、LLM が苦手とする計算問題を解いたりすることができるようになります。
LangChain を使ったアプリケーション開発は、高度な処理や知識の組み合わせにより、より高いパフォーマンスや複雑な処理を実現できます。
LangChain は現在 Pyhton と TypeScript の環境でのみ使用可能です。

また、Python と TypeScript においても、使える機能、LLM の種類に違いがあります。詳しくは以下の表をご覧ください。

Features
https://langchain.com/features.html
Integrations
https://langchain.com/integrations.html

LangChain は様々なモジュールを提供しています。以下が主要なモジュールとその概要です。

  • LLMs
    LLM(大規模言語モデル)を使い、効果的な結果を得るために複数のモデルを組み合わせるるためのモジュール
  • Template
    文や出力文のフォーマットを定め、効率的な文章生成や情報抽出が可能にするためのモジュール
  • Memory
    言語モデルに記憶を保持させ、ステートフルなやり取りを実装するためのモジュール
  • Chain
    複数のタスクを一連のプロセスとして連携させ、各タスクの結果を次のタスクへ引き継ぎ、より複雑な処理を行うためのモジュール
  • Agent
    外部の API と連携し、より複雑な処理を行うためのモジュール。

本記事では、これらの内容について、例を用いて詳しく解説していきます。

LangChain の機能・使い方

LLMs

LLMs は、大規模な言語モデルを扱うためのモジュールです。LangChain を使うことで、異なる種類の LLM を同じインターフェースで利用することができます。これにより、複数の言語モデルを簡単に切り替えたり、組み合わせたりすることができます。
始めるには、LLM の実装の call メソッドを使って文字列入力を渡すだけです。
今回の例では、OpenAI の LLM を使用して実装しました。

https://js.langchain.com/docs/modules/models/llms/

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 は、質問や指示(プロンプト)を効率的に扱うためのモジュールです。
プロンプトを共通化したり、変数を使って簡単にカスタマイズできます。これにより、同じような質問を繰り返し行う際に、手間を省くことができます。

https://js.langchain.com/docs/modules/prompts/prompt_templates/

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 のように過去のやり取りを踏まえて回答するチャットサービスを実現するために必要な機能です。

https://js.langchain.com/docs/modules/memory/

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」と「プロンプトテンプレート」で構成されます。

https://js.langchain.com/docs/modules/chains/

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 and JsonGetValue
    JSON オブジェクトからデータを抽出するのに便利です。これらのツールは、JsonToolkit としてまとめて使用することができます。
  • RequestsGet and RequestsPost
    HTTP リクエストを行う際に便利です。
  • SerpAPI
    SerpAPI API のラッパーです。時事問題に関する質問に答える必要があるときに便利です。入力は検索クエリである必要があります。
  • QuerySqlToolInfoSqlToolListTablesSqlTool, and SqlCheckerTool
    SQL データベースを操作するのに便利です。SqlToolkit で一緒に使用することができます。
  • VectorStoreQATool
    ベクトルストアから関連するテキストデータを取得するのに便利です。
  • ZapierNLARunAction
    Zapier NLP API のラッパーです。自然言語入力で Zapier のアクションをトリガーするのに便利です。ZapierToolkit で使用するとベストです。

上記は TypeScript 環境での tools であり、Python 環境とは異なりますので、注意してください。
より詳しく知りたい方は、以下をご覧ください。

https://js.langchain.com/docs/modules/agents/
https://js.langchain.com/docs/modules/agents/tools/integrations/

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巻は202333日発売、次巻となる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 105Entering 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 1055で掛けると525になります。
    

最後に

今回は、LLM の統合的なフレームワークである LangChain (TypeScript 版) の基礎を解説しました。
今回は基礎編でしたが、この他にも、独自のデータセットを読み込めるDocument Loadersなどの、魅力的なモジュールがたくさんあります。
また、学習に当たり、npaka さんの記事がとても参考になりましたので、ぜひ参考にしてみてください。
最後に、間違い等ありましたら、ご指摘いただけると幸いです。

参考

https://js.langchain.com/docs/
https://langchainers.hashnode.dev/getting-started-with-langchainjs
https://book.st-hakky.com/docs/langcain-intro/
https://note.com/npaka/n/n44a5bf788a94#3cb4aa26-b795-4756-8831-1a6ccafb48a3
https://note.com/npaka/n/n6b7a07e492f1

Discussion

negibouzenegibouze

Agent の入力例の

const secondRes = await llm.call(

const secondRes = await executor.call(

の誤字でしょうか?

takigontakigon

コメントありがとうございます。
誤字ではありませんが、

const secondRes = await executor.call(

こちらでも同様のアウトプットが可能です。