nikkie-ftnextの日記

イベントレポートや読書メモを発信

LangChainでlangchain.verbose = Trueと書くと、それがChainのverbose属性に設定されるまで

はじめに

あっなったっの アーイドル〜♪
ナイスなstapyでした! nikkieです。

最近触っているLangChain、触るたびにこれはすごいライブラリだと実感します。
小さい箇所ですが、langchain.verbose = Trueと指定するだけで、プロンプトが出力され、何が起こっているかの理解にとても役立ちます1
このlangchain.verboseとはなんなのか、ソースコードを少し追ってみました。

目次

langchain.verboseはモジュールの属性

最新のv0.0.231を見ていきます。

https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/__init__.py#L64

verbose: bool = False

langchain.verboseの使われ方

LangChainでは「Chain」という概念2が肝だと思います。
モデルとプロンプトをつないだChainを作ったり、複数のChainをつないだりできます。
このChainを初期化する際にlangchain.verboseの値が参照されます

すべてのChainのベースクラス(と現時点で理解してます)
https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/chains/base.py#L33

読み取り

同じモジュールの中に、langchain.verboseを読み取る関数があります。
https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/chains/base.py#L29-L30

def _get_verbosity() -> bool:
    return langchain.verbose

動作を確認するため、ここで紹介した要素だけを抜き出したスクリプトを用意します。

# my_langchain.py
verbose: bool = False


def _get_verbosity() -> bool:
    return verbose
# verbose_value.py
import my_langchain

print(f"{my_langchain._get_verbosity()=}")

print("---- Set verbose True ----")
my_langchain.verbose = True
print(f"{my_langchain._get_verbosity()=}")

my_langchain.verbose = Trueと値を書き換えると、_get_verbosity関数の返り値も対応して変わります。

% python verbose_value.py
my_langchain._get_verbosity()=False
---- Set verbose True ----
my_langchain._get_verbosity()=True

読み取った値を指定する

LangChainはPyDantic(v0.0.231時点ではPyDantic 1系3)を使っています。
ChainはPyDanticのBaseModelを継承したクラス!
https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/chains/base.py#L33

# SerializableがBaseModelを継承しています
# https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/load/serializable.py#L33
class Chain(Serializable, ABC):

Chainクラスのインスタンスはverbose属性を持ちます。
ここはPyDanticの書き方で、default_factoryに上記の_get_verbosity関数を指定しています。
https://github.com/hwchase17/langchain/blob/v0.0.231/langchain/chains/base.py#L71

class Chain(Serializable, ABC):
    # ... 省略 ...
    verbose: bool = Field(default_factory=_get_verbosity)

PyDanticのFielddefault_factoryはこちら
https://docs.pydantic.dev/latest/usage/fields/#default-values

You can also use default_factory to define a callable that will be called to generate a default value.

フィールドのデフォルト値を生成するために呼び出されるcallable(関数など)を定義してdefault_factory引数に指定できるようです。

というわけで、以上の要素によってlangchain.verbose = Trueという設定がChainに渡ります。
(これによりChainの扱うプロンプトが標準出力に表示される仕組みはまたの機会としたいと思います)

再現させる実装をして検証

動作環境

上記のコードも含めて、以下の環境で動作確認しました。

Python 3.11.4

pip install 'pydantic<2'で以下がインストールされています。

pydantic==1.10.11
typing_extensions==4.7.1

verboseを指定しないときの設定値(Falseのまま)

# my_langchain.py
verbose: bool = False


def _get_verbosity() -> bool:
    return verbose


from pydantic import BaseModel, Field


class Chain(BaseModel):
    verbose: bool = Field(default_factory=_get_verbosity)
# false_example.py
import my_langchain

chain = my_langchain.Chain()
print(repr(chain))
% python false_example.py
Chain(verbose=False)

設定しないときはChainインスタンスのverbose属性はFalseですね

verboseをTrueに指定したときの設定値(Trueになる)

# true_example.py
import my_langchain

my_langchain.verbose = True

chain = my_langchain.Chain()
print(repr(chain))
% python true_example.py
Chain(verbose=True)

my_langchain.verbose = Trueと指定すると(※langchain.verbose = Trueのイメージ)、Chainインスタンスのverbose属性はTrueです!!

my_langchain.verbose = Trueという簡単な方法で、LangChainの肝のChainインスタンス(複数)のverbose属性の値が全部設定できちゃうわけですね!

終わりに

LangChainのlangchain.verbose = Trueにより、Chainインスタンスの属性がTrueに設定されることを見てきました。

  • ライブラリのユーザがlangchain.verbose = Trueと指定する
  • Chainを初期化する際、langchain.verboseの値がverbose属性に設定される
    • langchain.verboseを読み取る_get_verbosity関数
    • PyDanticのFielddefault_factory引数に_get_verbosity関数を指定

langchain.verbose = Trueでプロンプトが出力されるのは魔法のように感じていましたが、扱うコードの一端を知り「こんな実装ができるのか!」と感動しました。
引き続きソースコードを追っていきます。


  1. StudyCoさんの勉強会で知って、素振りのたびに活用しています!
  2. https://python.langchain.com/docs/modules/chains/
  3. PyDanticは最近2系がリリースされましたが、LangChainは1系に依存しています。 https://github.com/hwchase17/langchain/blob/v0.0.231/pyproject.toml#L15