🌴

【LangChain】複数処理をつなげる「Chains」読解メモ

2024/02/12に公開

LangChainでLLMやツール使用、データの前処理など、さまざまな処理をラクにつなげることができる「Chains」のドキュメントを読み解いたメモです。

https://python.langchain.com/docs/modules/chains
https://api.python.langchain.com/en/stable/langchain_api_reference.html#module-langchain.chains

pip install -U openai langchain langchain-openai

「Chains」とは

LLM、ツール、データ前処理ステップなどへの一連の呼び出しを簡単に行うためのLangChainのモジュールの一つです。これによって特定タスクを効率的に実行できるようになります。

現在「LCEL Chains」と「Legacy Chains」の2種類のチェーンがサポートされています。(2024年2月12日時点)

1. LCEL Chains

LCEL(LangChain Composition Expression Language)を用いて構築された、よりモダンで柔軟性の高いチェーン。

「独自の処理フローを持つチェーンを構築したい場合」や「特定のタスクに合わせて細かいカスタマイズが必要な場合」に適しています。

1-1. create_stuff_documents_chain (GitHub

  • 「Documentオブジェクトのリスト」を一つのプロンプトにまとめてLLMに渡すチェーン。
コード例&出力プロンプト
  • コード例
from langchain_openai import ChatOpenAI
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain


prompt = ChatPromptTemplate.from_messages(
    [("system", "みんなの好きな色は何ですか?:\n\n{context}")]
)
llm = ChatOpenAI(model_name="gpt-4-0125-preview")
chain = create_stuff_documents_chain(llm, prompt)

docs = [
    Document(page_content="ジェシーは赤が好きだけど黄色は好きではない"),
    Document(page_content="ジャマールは緑が好きだけど、オレンジの方がもっと好き")
]

res = chain.invoke({"context": docs})
res

# ジェシーの好きな色は赤で、ジャマールの好きな色はオレンジです。
  • 生成されるプロンプト
# SYSTEM PROMPT
みんなの好きな色は何ですか?:

ジェシーは赤が好きだけど黄色は好きではない

ジャマールは緑が好きだけど、オレンジの方がもっと好き

1-2. create_openai_fn_runnable (GitHub

  • OpenAIのFunction Callingを使用して、「構造化された出力応答を生成したい場合」に使用。
  • 複数の関数を渡せるけれど、必ずしもそれらを呼び出す必要はない。
コード例&出力プロンプト
  • コード例
from langchain_openai import ChatOpenAI
from langchain.chains.openai_functions import create_openai_fn_runnable
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Optional


class RecordPerson(BaseModel):
    """ある人物の識別情報を記録する。"""

    name: str = Field(..., description="名前")
    age: int = Field(..., description="年齢")
    fav_food: Optional[str] = Field(None, description="好きな食べ物")

class RecordDog(BaseModel):
    """ある犬の識別情報を記録する。"""

    name: str = Field(..., description="犬の名前")
    color: str = Field(..., description="犬の色")
    fav_food: Optional[str] = Field(None, description="犬の好きな食べ物")


llm = ChatOpenAI(model="gpt-4-0125-preview")
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "エンティティを記録するための世界クラスのアルゴリズムです。"),
        ("human", "以下の入力にあるエンティティを記録するために、関連する関数を呼び出してください: {input}"),
        ("human", "ヒント: 正しいフォーマットで回答してください"),
    ]
)
chain = create_openai_fn_runnable([RecordPerson, RecordDog], llm, prompt)
res = chain.invoke({"input": "ハリーはチキンが大好きなふくよかな茶色のビーグル犬でした"})
res

# RecordDog(name='ハリー', color='茶色', fav_food='チキン')
  • 生成されるプロンプト
# SYSTEM PROMPT
エンティティを記録するための世界クラスのアルゴリズムです。

# HUMAN PROMPT
以下の入力にあるエンティティを記録するために、関連する関数を呼び出してください: ハリーはチキンが大好きなふくよかな茶色のビーグル犬でした

# HUMAN PROMPT
ヒント: 正しいフォーマットで回答してください

1-3. create_structured_output_runnable (GitHub

  • OpenAIのFunction Callingを使用して、「LLMに特定の関数で応答させることを強制したい場合」に使用。
  • 一つの関数のみを渡し、常にこの応答を返します。
コード例&出力プロンプト
  • コード例
from langchain_openai import ChatOpenAI
from langchain.chains.openai_functions import create_structured_output_runnable
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
from typing import Optional

class Dog(BaseModel):
    """犬に関する識別情報。"""

    name: str = Field(..., description="犬の名前")
    color: str = Field(..., description="犬の色")
    fav_food: Optional[str] = Field(None, description="犬の好きな食べ物")


llm = ChatOpenAI(model="gpt-4-0125-preview")
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "構造化されたフォーマットで情報を抽出するための世界クラスのアルゴリズムです。"),
        ("human", "与えられたフォーマットを使用して、以下の入力から情報を抽出してください: {input}"),
        ("human", "ヒント: 正しいフォーマットで回答してください"),
    ]
)
chain = create_structured_output_runnable(Dog, llm, prompt)
res = chain.invoke({"input": "ハリーはチキンが大好きなふくよかな茶色のビーグル犬でした"})
res

# Dog(name='Harry', color='茶色', fav_food='チキン')
  • 生成されるプロンプト
# SYSTEM PROMPT
エンティティを記録するための世界クラスのアルゴリズムです。

# HUMAN PROMPT
以下の入力にあるエンティティを記録するために、関連する関数を呼び出してください: ハリーはチキンが大好きなふくよかな茶色のビーグル犬でした

# HUMAN PROMPT
ヒント: 正しいフォーマットで回答してください

1-4. load_query_constructor_runnable (GitHub

  • クエリを生成するために使用できます。許可された操作のリストを指定する必要があり、自然言語クエリをこれらの許可された操作に変換するrunnableを返します。
コード例&出力プロンプト(※まだ未確認)
  • コード例
# 今後更新
  • 生成されるプロンプト
# 今後更新

1-5. create_sql_query_chain (GitHub

  • 自然言語からSQLデータベースのクエリを構築したい場合に使用します。
  • SQLデータベース
コード例&出力プロンプト(※まだ未確認)
  • コード例
# 今後更新
  • 生成されるプロンプト
# 今後更新

1-6. create_history_aware_retriever (GitHub

  • 会話履歴を取り込み、それを使用して検索クエリを生成し、基礎となるリトリーバーに渡すチェーンです。
コード例&出力プロンプト(※まだ未確認)
  • コード例
# 今後更新
  • 生成されるプロンプト
# 今後更新

1-7. create_retrieval_chain (GitHub

  • ユーザーの問い合わせを受け取り、関連文書をフェッチするためにリトリーバーに渡し、その文書(および元の入力)をLLMに渡して応答を生成するチェーンです。
コード例&出力プロンプト(※まだ未確認)
  • コード例
# 今後更新
  • 生成されるプロンプト
# 今後更新

2. Legacy Chains

以前のバージョンのLangChainで使用されていた、サブクラス化によって構築されたチェーン。

今後LCELベースのチェーンに置き換えられる予定で、新たにチェーンを構築する際にはLCELの使用が推奨されています。

その他のコード

LLMChain

指定のモデル+プロンプトの組み合わせをChainとして作り、簡単に実行できるものです。

コード例
from langchain.chains import LLMChain
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate


# --- 指定: 使用モデル ---
chat_gpt_4 = ChatOpenAI(model='gpt-4-0125-preview')

# --- プロンプトのテンプレート ---
prompt_template = "ランダムに{theme}選んでください。"
prompt = PromptTemplate(
    input_variables=["theme"], # プロンプトの変数名
    template=prompt_template   # プロンプト
)

# --- チェーン生成 ---
llm = LLMChain(
    llm=chat_gpt_4, # 使用モデル
    prompt=prompt   # プロンプト
)

# --- チェーン実行 ---
result = llm.invoke("動物") # プロンプトの変数「動物」を代入して実行
print(result)

# {'theme': '動物', 'text': '\nライオン'}

(複数の変数を使う場合)

from langchain.chains import LLMChain
from langchain_openai import ChatOpenAI
from langchain_core.prompts import PromptTemplate


# --- 指定: 使用モデル ---
chat_gpt_4 = ChatOpenAI(model='gpt-4-0125-preview')

# --- プロンプトのテンプレート ---
prompt_template = "ランダムに{theme_1}と{theme_2}選んでください。"
prompt = PromptTemplate(
    input_variables=["theme_1", "theme_2"], # プロンプトの変数名
    template=prompt_template   # プロンプト
)

# --- チェーン生成 ---
llm = LLMChain(
    llm=chat_gpt_4, # 使用モデル
    prompt=prompt   # プロンプト
)

# --- チェーン実行 ---
result = llm.invoke({"theme_1": "動物", "theme_2": "数字"})
print(result)

# {'theme_1': '動物', 'theme_2': '数字', 'text': 'カワウソ、7'}

まとめ

主要な用途ではそれぞれチェーンが用意されているような印象でした!

Discussion