Langchain Chain機能について
はじめに
本日はLngchainの6つの機能のうちの1つであるChainsについて解説していきます。
Langchain Chainsとは
ラングチェーンチェーンズは、複数のプロンプト入力を実行する機能で、複雑な問題を解く際に非常に有用です。中間的な回答を一度出力することでより正確な回答を得ることが可能です。このような中間的な推論ステップを踏むことで性能向上を測る手法を「CoTプロンプティング」と呼びます。
Langchain Chainsの利用例
例えば、Aというプロンプトの実行結果を次のプロンプトに引き渡す時や、Aというプロンプトの出力とBというプロンプトの出力の2つの出力内容を入力としたプロンプトを実行する時にChainsは非常に便利です。
例えば、非常に長い文章を予約したいときにそれらを10分割してそれぞれの塊に対して要約のプロンプトを実行し、出力された10個の要約を入力として最終的に長い文章を一つの文章に要約することも可能です。
Langchain Chainsの基本チェーン
Langchain Chainsには基本となるチェーンが3種類あります。
1.Simple Chain
複数のチェーンをつなげていく上で最小単位となるチェーンです。どのモデルを使ってどのようなプロンプトを実行するかを指定できます。
2.Sequential Chain
複数のチェーンをつなげたチェーンです。複数のチェーンの配列と最初のチェーンに入れる引数を指定できます。
3.Custam Chain
自由にチェーンをつなぎ合わせることができるオリジナルのチェーンです。複数のチェーンが入力された時に各チェーンの出力をどのように他のチェーンに渡していくかを設定したりすることができます。
Pythonを用いた具体的な実装方法
環境構築
ラングチェインを用いるためには、まずpip install langchainを実行してインストールします。
!pip3 install langchain openai
また、OpenAIのモデルを用いるためにはpip install openaiを実行します。ライブラリのインストールが完了したら、OpenAIのAPIキーを設定します。
import os
os.environ["OPENAI_API_KEY"] = "your openai_API_key"
1. Simple Chainの使い方
「LLMChain」というChainにLLMのモデルとプロンプトテンプレートを渡し渡します。ちなみに「LLMChain」とは、言語モデル周りにいくつかの機能を追加するシンプルな仕組みのことです。
プロンプトとしては、「(入力)に必要なことはなに?」と設定しています。
それでは、筋トレに必要なことは何かを訊いてみましょう。
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
llm = OpenAI(model_name="text-davinci-003")
prompt = PromptTemplate(
input_variables=["Subject"],
template="{Subject}に必要なことはなに??"
)
chain = LLMChain(llm=llm, prompt=prompt)
print(chain("筋トレ"))
これに対する実行結果は次の通りです。
{'Subject': '筋トレ', 'text': '\n\n・筋トレに必要なものとして、運動靴やジムウェア、安全な環境、適度な水分補給などが挙げられます。また、体重や器具を使ったトレーニングなど、適切なトレーニングを行うためのプランを立てることも大切です。さらに、筋肉の状態を見るための筋力計、温度計なども必要となります。'}
筋トレにに必要なものが答えとして帰ってきました。
2. Sequential Chainの使い方
前項では単純なChainの説明をしましたが、このChainをつなげていくことにこそ意味があります。
そこで最初に、「SimpleSequentialChain」を紹介します。「SimpleSequentialChain」は、シンプルな1つのChainの出力を「次のChainの入力」として繋げていくことができます。
各Chainの出力の変数などを設定する必要なく、神父な構造にすることができます。
次の例では、先ほどの「筋トレに必要なことはなに?」というプロンプトで返ってきた回答を入力として、「(筋トレを)のために取るべきアクションを3つ教えて。」というプロンプトに連携してみます。
それでは、実行してみましょう。
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.chains import SimpleSequentialChain
llm = OpenAI(model_name="text-davinci-003")
prompt_1 = PromptTemplate(
input_variables=["subject"],
template="{subject}に必要なことはなに?"
)
chain_1 = LLMChain(llm=llm, prompt=prompt_1)
prompt_2 = PromptTemplate(
input_variables=["programming_language"],
template="{programming_language}のために取るべきアクションを3つ教えて。",
)
chain_2 = LLMChain(llm=llm, prompt=prompt_2)
overall_chain = SimpleSequentialChain(chains=[chain_1, chain_2], verbose=True)
print(overall_chain("筋トレ"))
これに対する実行結果は次の通りです。
Entering new SimpleSequentialChain chain...
・体を温める準備運動
・体を伸ばすストレッチ
・筋力強化を目的とした運動
・運動後のストレッチ
・筋肉痛を補うためのリカバリー
・栄養補給
1.タンパク質を摂取する。
2.ビタミンとミネラルを摂取する。
3.水分補給を心がける。
> Finished chain.
{'input': '筋トレ', 'output': '\n\n1.タンパク質を摂取する。\n2.ビタミンとミネラルを摂取する。\n3.水分補給を心がける。'}
確かに大事だって感じの答えを頂きました。
次に「SequentialChain」について説明します。
先ほど説明した「SimpleSequentialChain」の引数と返り値が1つでなければならないのに対して、「SequentialChain」は複数の引数と返り値を用いることができます。
以下は「SequentialChain」ができることの例です。
input_variablesを2つ設定
先ほどの subject の前に、形容詞をおけるように変更output_keyが追加され、Chainの出力の変数名を指定
SimpleSequentialChainからSequentialChainにクラスを変えて、このインスタンスに渡す引数を辞書型のデータに変更。そして出力も、途中結果が保管された辞書型のデータとして得られる。
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.chains import SequentialChain
llm = OpenAI(model_name="text-davinci-003")
prompt_1 = PromptTemplate(
input_variables=["adjective", "subject"],
template="{adjective}{subject}に必要なことは?",
)
chain_1 = LLMChain(llm=llm, prompt=prompt_1, output_key="muscle_road")
prompt_2 = PromptTemplate(
input_variables=["muscle_road"],
template="{muscle_road}を極めるためにやるべきことを3ステップで100文字で教えて。",
)
chain_2 = LLMChain(llm=llm, prompt=prompt_2, output_key="sacrifice_for_muscle")
overall_chain = SequentialChain(
chains=[chain_1, chain_2],
input_variables=["adjective", "subject"],
output_variables=["muscle_road", "sacrifice_for_muscle"],
verbose=True,
)
output = overall_chain({
"adjective": "ゴリゴリ",
"subject": "マッチョマン",
})
print(output)
これに対する実行結果は次の通りです。
> Entering new SequentialChain chain...
> Finished chain.
{'adjective': 'ゴリゴリ', 'subject': 'マッチョマン', 'muscle_road': '\n\nゴリゴリマッチョマンに必要なものとして、まず最低限としては、健康的な食事や運動を行うことです。健康的な食事では、たんぱく質、脂肪、炭水化物をバランスよく摂ることが重要です。また、筋肉をつけるための運動を行うことも大切です。これらを継続的に行うことにより、ゴリゴリマッチョな姿が実現することができます。', 'sacrifice_for_muscle': '\n\n1. 健康的な食事:たんぱく質、脂肪、炭水化物をバランス良く摂取する。\n\n2. 運動:筋肉をつけるための運動を行う。\n\n3. ストレス管理:ストレスを和らげるために、リラックスした過ごし方を行い、バランスの取れた生活を送る。'}
実行した結果、複数の引数と返り値を用いることができました。
3. Custom Chainの使い方
Custom Chainは、ベースとなる「Chain」というクラスが既にあるため、、簡単に実装できます。
ここでは、2つのChainを入力としていて、それらの出力を結合した文字列を出力するようなChainを作っています。
from langchain.chains import LLMChain
from langchain.chains.base import Chain
from typing import Dict, List
class ConcatenateChain(Chain):
chain_1: LLMChain
chain_2: LLMChain
@property
def input_keys(self) -> List[str]:
all_input_vars = set(self.chain_1.input_keys).union(set(self.chain_2.input_keys))
return list(all_input_vars)
@property
def output_keys(self) -> List[str]:
return ['concat_output']
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
output_1 = self.chain_1.run(inputs)
output_2 = self.chain_2.run(inputs)
return {'concat_output': output_1 + "\n" + output_2}
llm = OpenAI(model_name="text-davinci-003")
prompt_1 = PromptTemplate(
input_variables=["subject"],
template="{subject}に一番オススメの道具は?:",
)
chain_1 = LLMChain(llm=llm, prompt=prompt_1)
prompt_2 = PromptTemplate(
input_variables=["subject"],
template="{subject}でやってはいけないことを教えて",
)
chain_2 = LLMChain(llm=llm, prompt=prompt_2)
concat_chain = ConcatenateChain(chain_1=chain_1, chain_2=chain_2, verbose=True)
print(concat_chain.run("筋トレ"))
これに対する実行結果は次の通りです。
Entering new ConcatenateChain chain...
> Finished chain.
ダンベル
・指示通りに行わない
・慣れるまで過度な重量を使う
・重量を押しすぎる
・飲酒しながらトレーニングする
・怪我を治すために筋トレをする
・間違った姿勢やフォームで筋トレをする
実行した結果、筋トレに必要な道具と筋トレでやってはいけないことが区別されて出力されました。
最後に
次回はMemory機能について解説しますので引き続きよろしくお願いします!