「Difyソースコードリーディング #8 - Difyのコード実行環境「dify-sandbox」」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング #8 - Difyのコード実行環境「dify-sandbox」」という勉強会を開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

dify-sandboxのソースコードは以下です。

github.com

今回も 戸塚さん と一緒に話しながらコードを読んでいきました!

今回のポイント

今回はdify-sandboxを理解するべく、コードを読んでいきました。

dify-sandboxの概要

dify-sandboxの概要については、READMEに添付されている画像によく書かれていました。

画像引用元:https://github.com/langgenius/dify-sandbox

概要としては以下のようになります。

  • ビルド時:python.soというファイルが作成され、DifySeccompというchrootによるルートディレクトリの変更やSeccompによるシステムコールの制限のための関数が提供される
  • サーバー起動時:設定ファイルや環境変数が読み込まれ、pip installによりdependencies/python-requirements.txtに記載のパッケージがインストールされる
  • API呼び出し時:APIキーやリクエストの最大値などのチェックを経て、リクエストのコードがファイルに保存され、DifySeccomp関数を使用して実行される

Pythonコードの実行

HTTPリクエストで送られてきたPythonのコードは、internal/core/runner/python/python.go で以下のようにコマンドとして実行する準備がされていました。

   cmd := exec.Command(
        configuration.PythonPath,
        untrusted_code_path,
        LIB_PATH,
        key,
    )

configuration.PythonPathは、conf/config.yaml で「/usr/local/bin/python3」が設定されています。

untrusted_code_pathというのは prescript.py の一部を置換した内容のファイルです。

prescript.py

prescript.py は、最終的に実行されるPythonスクリプトです。

以下の箇所でpython.soを読み込んでDifySeccompを実行しています。

lib = ctypes.CDLL("./python.so")
    :
lib.DifySeccomp({{uid}}, {{gid}}, {{enable_network}})

その後、以下のようにPythonコードが実行されます。

code = b64decode("{{code}}")
    :
code = decrypt(code, key)
exec(code)

{{code}} の箇所は、暗号化したうえでBASE64エンコードされたPythonコードが置換されます。

おそらくGo言語の標準ライブラリではforkとexecの間でDifySeccompを実行するのが大変なので、Go言語で実行した子プロセスのPythonスクリプト内でDifySeccompを実行してexecしているのではないかと思います。(想像なので違ったらすみません)

Pythonパッケージのインストール

よくdify-sandboxに追加のPythonパッケージをインストールしたいという要望があると思いますが、サーバー起動時に dependencies/python-requirements.txt の内容がpip installされるため、ここに必要なパッケージを記述したファイルを配置すればよさそうです。

おそらく、そのためにコンテナイメージをビルドしなおす必要もありません。

また、internal/controller/router.go を参照すると依存関係を更新・リフレッシュするAPIも用意されているため、dependencies/python-requirements.txtを編集してこのどちらかのAPIを実行すれば、サーバー実行中に動的にPythonパッケージを追加したりすることもできるかもしれません。(updateとrefreshのAPIの違いまでは読み解いていません)

       dependencyRouter.POST("update", UpdateDependencies)
        dependencyRouter.GET("refresh", RefreshDependencies)

次回のご案内

以上、dify-sandboxを読み解いてみました。 考えてみれば当然ですが、機能はかなり少なく、1時間ほどで気になるコードのほとんどに目を通すことができました。

次回は「Difyのワーカーは何をしているのか」を読み解いていきます! ご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

また、水曜日にもDifyの活用についてのもくもく会があります。 こちらもご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

「AIエージェントキャッチアップ #5 - Aider」を開催しました

ジェネラティブエージェンツの大嶋です。

「AIエージェントキャッチアップ #5 - Aider」という勉強会を開催しました。

generative-agents.connpass.com

アーカイブ動画はこちらです。

youtube.com

Aider

今回は、The AI Scientistの中でも使われていた「Aider」を動かしたり、公式ドキュメントやソースコードを読んだりしてみました。

AiderのGitHubリポジトリはこちらです。

github.com

公式ドキュメントはこちらです。

aider.chat

勉強会の途中でコメントいただきましたが、Aiderは「エイダー」と読む方が多いようです。

今回のポイント

Aiderのインストール・起動

Aiderは「aider-chat」というPythonパッケージとして提供されているため、pipなどでインストールして使うことができます。

インストール後、aiderコマンドで起動して、ターミナルでインタラクティブに指示してコードを書かせることができます。

たとえば「fizz buzzのファイルを作成してください。」と指示すると、fizzbuzz.pyというファイルを作成してGitにコミットし、実行してみるか質問されました。

Aiderではこのようにコードの差分(diff)を出力するため、既存のファイルに対する編集を指示することもできます。

チャットモード

Aiderは4つの「チャットモード」をサポートしています。

  • 「code」モード:単純にコードを実装する
  • 「architect」モード:まず解決策を推論して、次にコードを実装する
  • 「ask」モード:コードについて質問できる
  • 「help」モード:Aiderについて質問できる

たとえば/architect Can we make this simpler?のように入力すると、LLMが2回呼び出され、1度目で解決策の推論、2度目でコードの実装が行われます。

aider.chat

その他のコマンド

Aiderでは他にも様々なコマンドが実装されています。

たとえば、/web <URL>コマンドを実行すると、httpxやPlaywrightによってWebページの情報を取得してプロンプトに入れることができます。

また、こちらは試していませんが、/audioというコマンドで音声入力することもできるとのことです。

音声入力しながらコードを編集させられるというのは、かなり面白いと思います。

ちなみにAiderを起動して「/」と入力するとコマンドの補完が表示されます。

プロンプトに含めるファイル

Aiderのプロンプトには、Aiderの起動時にaider <ファイル名>のように指定したファイルや、/add <ファイル名>のようにして追加したファイルが含まれます。

これらのファイルの情報をもとにコードを記述したりするようです。

Repository map

Aiderでは、上記のようにプロンプトに含められたファイルと、ターミナル上でのチャットの履歴に加えて、Gitリポジトリのマップをプロンプトに入れる挙動になっているそうです。

aider.chat

公式ドキュメントの上記のページによると、コード内からクラスやメソッドのシグネチャが抜粋されてプロンプトに入れられるとのことです。

aider/coders/base_coder.py:
⋮...
│class Coder:
│    abs_fnames = None
⋮...
│    @classmethoddef create(
│        self,
│        main_model,
│        edit_format,
│        io,
│        skip_model_availabily_check=False,
│        **kwargs,
⋮...
│    def abs_root_path(self, path):
⋮...
│    def run(self, with_message=None):
⋮...

aider/commands.py:
⋮...
│class Commands:
│    voice = None
│
⋮...
│    def get_commands(self):
⋮...
│    def get_command_completions(self, cmd_name, partial):
⋮...
│    def run(self, inp):
⋮...

Aiderのコード内では、aider/queriesディレクトリに、Tree-sitterというパーサージェネレータのための各言語の構文の定義が書かれており、おそらくこれを使って構文解析したうえで必要な箇所のみプロンプトに入れているのだと思われます。

Pythonコードからの利用

最後に、そもそもAiderに注目した理由として、Pythonのコードから呼び出せることが挙げられます。

aider.chat

公式ドキュメントの上記のページには、以下のようなサンプルコードが記載されています。

from aider.coders import Coder
from aider.models import Model

# This is a list of files to add to the chat
fnames = ["greeting.py"]

model = Model("gpt-4-turbo")

# Create a coder object
coder = Coder.create(main_model=model, fnames=fnames)

# This will execute one instruction on those files and then return
coder.run("make a script that prints hello world")

# Send another instruction
coder.run("make it say goodbye")

# You can run in-chat "/" commands too
coder.run("/tokens")

aiderからCoderやModelというクラスをimportして初期化し、coder.runとするだけでAiderにコードを実装させることができます。

The AI Scientistのようにコードを実装・実行するようなエージェントを実装したい場合、このようにPythonライブラリとして使えるのはかなり便利そうだと感じました。

ただし、サンドボックス環境でコードを実行するような機能はなさそうなので、その点は注意が必要そうです。

次回のご案内

Aiderは個人的にかなり面白いと感じました。 実際に動かして試してみることができてよかったです。

次回は「AIエージェントキャッチアップ #6 - Swarm (OpenAI)」ということで、OpenAI社が公開した実験的なマルチエージェントフレームワーク「Swarm」がテーマです!

github.com

generative-agents.connpass.com

ご興味・お時間ある方はぜひご参加ください!

また、その次の回以降のテーマも募集しているので、気になるエージェントのOSSなどあれば教えてください!

「Difyソースコードリーディング #7 - ビルドやリリース時のバージョン番号付けなどを読み解く」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング #7 - ビルドやリリース時のバージョン番号付けなどを読み解く」という勉強会を開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

Difyのソースコードは以下です。

github.com

今回も 戸塚さん と一緒に話しながらコードを読んでいきました!

今回のポイント

今回は、Difyのコンテナイメージのビルドなどはどのようにしているのかを確認するため、主に .github ディレクトリ以下を読んでいきました。

workflows

.github/workflows ディレクトリを見ると、GitHub Actionsのワークフローが確認できます。

具体的には、

  • api-tests.yml
  • build-push.yml
  • db-migration-test.yml
  • deploy-dev.yml
  • stale.yml
  • style.yml
  • tool-test-sdks.yaml
  • translate-i18n-base-on-english.yml
  • web-tests.yml

という約10個のワークフローがありました。

基本的にはその名の通りの内容だったので、特筆すべきものだけここにまとめます。

build-push.yml

build-push.yml は、その名の通りコンテナイメージのbuild・pushを行うワークフローでした。

on:
  push:
    branches:
      - "main"
      - "deploy/dev"
  release:
    types: [published]

ということで、mainブランチかdeploy/devブランチにpushされた際、またはreleaseが作られた際に実行されます。

ワークフローの中ではlinux/amd64linux/arm64のイメージがQEMU + Docker Buildxビルドされ、Docker Hubにpushされていました。

また、docker buildx imagetools createコマンドを使って、マルチプラットフォームに対応したタグ付けの設定もしていました。

個人的にDockerのこの機能は使ったことがなかったので勉強になりました。

deploy-dev.yml

deploya-dev.yml では、何らかのデプロイ操作を実行しているようでしたが、詳細はsecretsなどに保存されているようで分かりませんでした。

deploy/devブランチでのbuild-and-push後に実行されるとのことで、名前的にはdev環境にデプロイするということのようには思います。 (あくまで想像です)

stale.yml

stale.yml では、actions/staleというアクションを使った古いIssue・Pull Requestに対する処理が設定されていました。

github.com

style.yml

style.yml では、RuffやSuper-Linterを使ったコードのスタイルチェックが設定されていました。

Super-Linterはデフォルトの動作で.github/lintersディレクトリの設定ファイルを読み込むようで、.github/lintersディレクトリにいくつか設定ファイルが置かれていました。

github.com

translate-i18n-base-on-english.yml

translate-i18n-base-on-english.yml では、web/i18nディレクトリ以下の多言語の翻訳が自動生成されるようになっていました。

具体的には web/i18n/auto-gen-i18n.js というスクリプトが実行されており、en-USをベースにbing-translate-apiを使って翻訳されているようでした。

次回のご案内

以上、Difyのビルドなどの処理を読み解いてみました。

今まではバックエンドのソースコードリーディングが多かったので、今回フロントエンドも少し扱えたのはよかったです。

次回はDifyのコード実行環境「dify-sandbox」がテーマです。 ご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

また、水曜日にもDifyの活用についてのもくもく会があります。 こちらもご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

「AIエージェントキャッチアップ #4 - OpenHands (旧OpenDevin)」を開催しました

ジェネラティブエージェンツの大嶋です。

「AIエージェントキャッチアップ #4 - OpenHands (旧OpenDevin)」という勉強会を開催しました。

generative-agents.connpass.com

アーカイブ動画はこちらです。

youtube.com

OpenHands (旧OpenDevin)

今回は、OpenHands (旧OpenDevin) を動かしながら、公式ドキュメントやソースコードを読んだりしてみました。

OpenHandsのGitHubリポジトリはこちらです。

github.com

公式ドキュメントはこちらです。

docs.all-hands.dev

今回のポイント

OpenHandsの起動

公式ドキュメントの Installation に記載されているdocker runコマンドを実行すると、しばらくして無事に起動し、ブラウザでOpenHandsのエディタにアクセスできました。

Dockerのイメージとして提供されているので動く可能性は高いと思っていましたが、実際に動作して一安心しました。

このエディタ画面の左でエージェントとやりとりしつつ、エージェントが自動でコマンドを実行したりしてコードを実装していく、ということになります。

簡単な例

Getting Started には、hello.shというシェルスクリプトを書かせたり、ReactでTODOアプリを書かせる例が載っていました。

hello.shというhello worldを表示するだけのシェルスクリプトを実装させる場合でも、

  1. ファイルの作成
  2. コードの実装
  3. 実装したコードの確認
  4. パーミッションの設定
  5. 実行

のようにいくつものステップをエージェントが自動で実行していく様子を見られました。

このような小さなスクリプトであっても、実際には人間は複雑なステップで実装していることを改めて感じました。

Prompting Best Practices

OpenHandsのドキュメントには Prompting Best Practices というページがあり、できるだけ具体的に指示すべきといったことが書かれています。

スコープとしては、一度の指示で実装させるコードの行数は通常100行を超えないようにと書かれており、かなり具体的な指示を出しながらコーディングしていく想定のようです。

OpenHandsの実行モード

ドキュメントを読んでいくと、OpenHandsには4つの実行モードがあることが分かりました。

  • ブラウザ上で動作するエディタとして使う
  • CLI Modeでインタラクティブに使う
  • Headless Modeで1度だけ指示して実行完了したらプロセスを終了する
  • GitHub Actionsで使用する

とくにGitHub Actionsで使用するのが気になったので、少し掘り下げていきました。

GitHub Actionsでのopenhands-resolverの使用

OpenHandsとは別のopenhands-resolverというリポジトリで、GitHubのIssueをもとにOpenHandsを動かす拡張機能のようなものが提供されていました。

github.com

Issueに対して fix-me というラベルを付与すると、OpenHandsが自動で実装してくれるというものです。

openhands-resolverはGitHub Actionsで実行することができ、OpenHandsのリポジトリにも設定されていました。

たとえばOpenHandsのドキュメントを改善する以下のIssueに対して、OpenHandsが自動で修正を作成している様子を確認できます。

github.com

OpenHandsのアーキテクチャソースコード

ドキュメントには OpenHandsアーキテクチャを説明するページ もあり、ソースコードを読む際に参考になりそうでした。

ソースコード内にも適宜READMEファイルが配置されており、どのように実装しているかの説明が比較的手厚いように感じました。

例: https://github.com/All-Hands-AI/OpenHands/blob/main/openhands/README.md

次回のご案内

OpenHands (旧OpenDevin) は実際に動かして試すことができ、なかなか面白かったです。

次回は「AIエージェントキャッチアップ #5 - Aider」ということで、The AI Scientistの中でも使われていた「Aider」を動かしてみます!

github.com

generative-agents.connpass.com

ご興味・お時間ある方はぜひご参加ください!

また、その次の回以降のテーマも募集しているので、気になるエージェントのOSSなどあれば教えてください!

「Difyソースコードリーディング #6 - DSLのYAMLファイルの扱いを読み解く」を開催しました #もくもくDify

ジェネラティブエージェンツの大嶋です。

もくもくDifyで「Difyソースコードリーディング #6 - DSLYAMLファイルの扱いを読み解く」という勉強会を開催しました。

dify-mokumoku.connpass.com

アーカイブ動画はこちらです。

youtube.com

Difyのソースコードは以下です。

github.com

今回も 戸塚さん と一緒に話しながらコードを読んでいきました!

今回のポイント

DifyにはアプリをDSLと呼ばれるYAMLファイルでexport・importする機能があります。

参考:https://docs.dify.ai/ja-jp/guides/application-orchestrate/creating-an-application

今回はDSLYAMLファイルの内容がどのように作られるのかを読み解いていきました。

YAMLファイルのexportのAPI

まず最初に、YAMLファイルをexportするAPIを見つけました。

api.add_resource(AppExportApi, "/apps/<uuid:app_id>/export")

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/api/controllers/console/app/app.py#L369C1-L370C1

その処理では、AppDslServiceのexport_dslが使われていました。

        return {"data": AppDslService.export_dsl(app_model=app_model, include_secret=args["include_secret"])}

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/api/controllers/console/app/app.py#L245

AppDslServiceのexport_dsl

AppDslServiceのexport_dslを読んでいくと、dictをYAMLに変換して返していることが分かりました。

    def export_dsl(cls, app_model: App, include_secret: bool = False) -> str:
            :
        export_data = {
            "version": current_dsl_version,
            :
        }
            :
        return yaml.dump(export_data, allow_unicode=True)

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/api/services/app_dsl_service.py#L159

Workflowクラス(workflowsテーブル)

さらに読み進めていくと、DBのworkflowsテーブルに対応するWorkflowクラスに、このクラスのデータ(つまりworkflowsテーブルのレコード)をdictに変換する処理が実装されており、これが使われていることが分かりました。

    def to_dict(self, *, include_secret: bool = False) -> Mapping[str, Any]:

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/api/models/workflow.py#L269

workflowsテーブルにはgraphやfeaturesといったカラムがあり、ここにJSON形式でワークフローのグラフなどが保存されているようです。

    graph: Mapped[str] = db.Column(db.Text)
    features: Mapped[str] = db.Column(db.Text)

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/api/models/workflow.py#L122C1-L124C1

そのJSONが具体的にどのように構成されているのかを確認しようと読み進めたところ、バックエンドではなくフロントエンドで定義されていることに辿り着きました。

(おそらくですが、バックエンドでのバリデーションなどはなさそうでした)

フロントエンドのNode・Edgeのtype

フロントエンドには、CommonNodeTypeやCommonEdgeTypeといったtypeが定義されていました。

export type CommonNodeType<T = {}> = {

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/web/app/components/workflow/types.ts#L43C1-L44C1

export type CommonEdgeType = {

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/web/app/components/workflow/types.ts#L69C1-L70C1

各ノードは、CommonNodeTypeを拡張して用意されていました。 たとえばLLMのノードのtypeは以下のようになっています。

export type LLMNodeType = CommonNodeType & {
  model: ModelConfig
  prompt_template: PromptItem[] | PromptItem
    :

https://github.com/langgenius/dify/blob/4373777871b33daa13ae55c52a06f8e76764cbfc/web/app/components/workflow/nodes/llm/types.ts#L4

React Flow

ワークフローのフロントエンドは、上記のtypeを使いつつ、React Flowというライブラリを使って実装されていることが分かりました。

reactflow.dev

次回のご案内

以上、DSLYAMLファイルがどのように作られるのか、雰囲気を読み解いてみました。

今まではバックエンドのソースコードリーディングが多かったので、今回フロントエンドも少し扱えたのはよかったです。

次回は「ビルドやリリース時のバージョン番号付けなどを読み解く」というテーマです。 ご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

また、水曜日にもDifyの活用についてのもくもく会があります。 こちらもご興味ある方はぜひ気軽にご参加ください!

dify-mokumoku.connpass.com

「AIエージェントキャッチアップ #3 - The AI Scientist」を開催しました

ジェネラティブエージェンツの大嶋です。

「AIエージェントキャッチアップ #3 - The AI Scientist」という勉強会を開催しました。

generative-agents.connpass.com

アーカイブ動画はこちらです。

youtube.com

The AI Scientist

今回は、Sakana AI社のThe AI Scientistを動かそうと挑戦したり、ソースコードを読んだりしてみました。

The AI ScientistのGItHubリポジトリはこちらです。

github.com

今回のポイント

The AI Scientistの概要

The AI Scientistは、研究・論文の作成を自動化するAIエージェントです。

コードを生成して実行することで、機械学習の研究の実験を行い、その結果を論文にすることができます。

The AI Scientistで生成された論文の例がいくつかGitHubで公開されています。

https://github.com/SakanaAI/AI-Scientist/tree/main/example_papers

研究のアイデア生成・実験・論文生成に加えて、LLMによる論文のレビューもできるようです。

動くか試したところ...

READMEを読みながら動かそうとしてみましたが、結論として、今回はうまく動かすことができませんでした。

Google Colab上で動くか試したところ、Semantic Scholar APIのレートリミットで処理がなかなか先に進まず、断念しました。

Semantic Scholar APIは、APIキーを払い出すことでレートリミットが緩和されるようです。 The AI Scientistを動かそうと挑戦する方は、まずSemantic Scholar APIAPIキーを取得するとよさそうです。

ちなみに、Dockerで動かす手順についても挑戦しようとしましたが、docker buildがエラーになり、こちらも断念しました。

処理の流れ

The AI Scientistを動かす際は、launch_scientist.py というファイルを実行することになります。

ここには主な処理の流れが実装されていて、このコードを読むとおおよそ以下のように処理が進むことが分かります。

  1. generate_ideas(アイデアの生成)
  2. check_idea_novelty(新規性のチェック)
  3. perform_experiments(実験)
  4. perform_writeup(論文の生成)
  5. perform_review(レビュー)
  6. perform_improvement(論文の改善)

各処理のソースコード

上記の各処理のソースコードai_scientist ディレクトリに置かれています。 プロンプトもこの中に含まれています。

このディレクトリに含まれるプロンプト・ソースコードは全部で2000行程度で、想像していたよりも短いコードで実装されていて驚きました。

実験のためのコード生成・実行には Aider が使われていました。 この部分でAiderを使用していることで、The AI Scientist自体は比較的コンパクトに実装できた、ということだと思います。

Aiderは比較的有名かつ今回の件で気になったので、そのうち勉強会のテーマとして扱うかもしれません。

次回のご案内

The AI Scientistはとても話題になっていたので、今回扱うことができてよかったです。

次回は「AIエージェントキャッチアップ #4 - OpenHands (旧OpenDevin)」ということで、OpenHands (旧OpenDevin) を動かしてみます!

github.com

generative-agents.connpass.com

ご興味・お時間ある方はぜひご参加ください!

また、その次の回以降のテーマも募集しているので、気になるエージェントのOSSなどあれば教えてください!

勉強会「【LangChainゆる勉強会#13】LangChain v0.3やその周辺のアップデートをチェック」を開催しました #StudyCo

ジェネラティブエージェンツの大嶋です。

運営している勉強会コミュニティStudyCoで「【LangChainゆる勉強会#12】LangGraphの最新ドキュメントを全体的にざっと読む」というイベントを開催しました。

studyco.connpass.com

アーカイブ動画はこちらです。

youtube.com

今回は「LangChain v0.3やその周辺のアップデートをチェック」というテーマで、LangChainの公式ドキュメントや公式ブログを参照しながら、LangChain v0.3やその周辺のアップデートをチェックしていきました。

LangChain v0.3での破壊的変更

公式ドキュメントに書かれている通りですが、LangChain v0.3での主な変更は、LangChainの内部でPydantic v1が使われていた箇所がPydantic v2に変更されたことです。

from langchain_core.pydantic_v1 import BaseModel などとしていた箇所がある場合、from pydantic import BaseModel のように変更することになります。

その他、Pydantic v1特有の機能を使っている場合は、Pydantic v2へのマイグレーションが必要です。

詳細は公式ドキュメントを参照してください。

python.langchain.com

LangChain v0.2の間のアップデート

LangChain v0.3がリリースされるタイミングでの変更は上記のPydanticの件が中心ですが、それ以外にもLangChain v0.2の間にはさまざまなアップデートが入っています。

v0.2の間の主要なアップデートについても、LangChain v0.3についての公式ドキュメントとブログで解説されています。

以下、いくつか抜粋して簡単に紹介していきます。

Tool関連のインターフェースの強化

Tool関連のインターフェースの強化として、以下のようなアップデートがありました。

  • llm.bind_tools でツールを設定
  • runnable.as_tool でRunnableをツールに変換
  • ツールの引数がRunnableConfigに対応
  • ツールの戻り値にartifactを追加可能

(Tool関連のアップデートは他にもいくつかあります)

詳細は以下のブログ記事にまとまっています。

blog.langchain.dev

init_chat_model

Chat modelの共有の初期化方法として、init_chat_modelという関数が追加されました。

たとえば以下のようにして、ChatOpenAIのインスタンスを得ることができます。

from langchain.chat_models import init_chat_model

gpt_4o = init_chat_model("gpt-4o", model_provider="openai", temperature=0)

python.langchain.com

Rate limiter

モデルのレートリミットを設定するRate limiterが追加されました。

たとえば以下のようにして利用可能です。

from langchain_core.rate_limiters import InMemoryRateLimiter
from langchain_openai import ChatOpenAI

rate_limiter = InMemoryRateLimiter(
    requests_per_second=1,
    check_every_n_seconds=0.1,
    max_bucket_size=10,
)

model = ChatOpenAI(model="gpt-4o-mini", rate_limiter=rate_limiter)

python.langchain.com

Message関連のユーティリティ

SystemMessage、HumanMessage、AIMessageなどのMessage関連のユーティリティとして、以下の3つが追加されました。

  • trim_messages: messagesを、最大トークン数などでトリミング
  • filter_messages: messagesから、HumanMessageだけといったフィルタリング
  • merge_message_runs: messagesでHuman・Humanのように同じ種別が連続している場合に1つにマージ

たとえばAnthropicのClaudeはHumanMessageが連続しているとエラーとなりますが、そのようなケースでmerge_message_runsが役立つことになります。

python.langchain.com

python.langchain.com

python.langchain.com

カスタムイベントのサポート

adispatch_custom_eventを使用することで、astream_eventsやCallbackにカスタムイベントを追加できるようになりました。

python.langchain.com

レガシーChainの非推奨化

LCEL以前のレガシーChainがいくつか追加で非推奨になりました。

これはたまたま先日見つけたのですが... LLMChainのような以前からdeprecatedだったChainはv0.3で廃止予定だったのですが、v1.0での廃止に変更されているようです。

@deprecated(
    since="0.1.17",
    alternative="RunnableSequence, e.g., `prompt | llm`",
    removal="1.0",
)
class LLMChain(Chain):

引用元:https://github.com/langchain-ai/langchain/blob/9404e7af9d8768a7e884dae3e9fafb712eaf4e99/libs/langchain/langchain/chains/llm.py#L41

おわりに

以上、LangChain v0.3についてと、v0.2の間のアップデートを紹介しました。

とくにv0.2の間のアップデートは、地味に便利なものが多く、この機会に改めて確認できてよかったです。

LangChain / LangGraph、その他のテーマで引き続き勉強会を開催していきます。 もしも「こんな話が聞きたい」というテーマがあれば、ぜひお声がけください!