見出し画像

【LangChain魔法学校】ライトノベルで学ぶ「LangChain Expression Language(LCEL)」

夜が更けるLangChain魔法学校。

リリィは図書館の奥深くにある秘密の部屋で、古びた魔法の書「LangChain Expression Language(LCEL)」を開いていた。

「LCELって、一体どんな魔法なんだろう?」とリリィは思いながら、魔法書のページをめくった。

その時、部屋の扉がゆっくりと開き、リリィの先輩であるエリオットが入ってきた。

「リリィ、君もLCELに興味があるのか?」と彼は微笑んで言った。

リリィは驚いて、エリオットに尋ねた。「エリオット先輩、この魔法書は何ですか?」

エリオットは椅子に座り、リリィに説明を始めた。

「LCELは、魔法の連鎖を作るための特別な言語だよ。例えば、君が複数の魔法を組み合わせて新しい魔法を生み出したいとき、LCELを使えばそれが簡単にできるんだ。」

リリィは興味津々で聞き入った。

「それはすごいですね!でも、どうやって使うんですか?」

エリオットは考えながら言った。

「うーん、例えば…君が一つの魔法で雨を降らせ、もう一つの魔法で雷を鳴らすとしよう。LCELを使えば、これらの魔法を組み合わせて、雷雨を起こす魔法を作ることができるんだ。」

リリィは目を輝かせた。
「それはすごい!」

エリオットはリリィの目の輝きを見て、さらに詳しくLCELの魔法について説明することにした。

「リリィ、実際の魔法の詠唱を考えてみて。君が一つの魔法を詠唱して、それが何らかの理由で失敗したとき、どうする?」

エリオットの質問に、リリィは考え込んだ。

「うーん、もう一度詠唱するか、別の魔法を詠唱するか…」

エリオットはうなずいた。

「その通り。LCELのフォールバックは、まさにそのためのものだよ。魔法が失敗したときに、自動的に別の魔法を詠唱することができるんだ。」

「それは便利!」

さらに大きくなったリリィの目を見て、エリオットは微笑みながら続けた。

「そして、複数の魔法を同時に詠唱したいときはどうする?」

「それは難しそう…」
コロコロと変わるリリィの表情にエリオットは面白味を感じながら説明をつづけた。

「でも、LCELの並列処理を使えば、それが可能になるんだ。
複数の魔法を同時に、または連続して詠唱することができる。これにより、時間を節約することができるんだよ。」

「それはすごいわ!」リリィは驚きの表情を浮かべた。

エリオットはさらに続けた。

「そして、最後にトレーシングの統合についてだけど、これは魔法の連鎖の各ステップを詳細に追跡することができる機能だ。君が詠唱した魔法の連鎖がどのように動作しているのか、どこで問題が発生しているのかを正確に知ることができるんだ。」

リリィは深く頷いた。
「エリオット先輩、LCELは本当に強力な魔法ですね。これを学べば、私ももっと上手な魔法使いになれるかもしれません!」

エリオットはリリィの頭を撫でながら言った。
「君ならきっとできるよ。頑張ってね!」

公式ドキュメントの和訳:LangChain Expression Language(合ってるかどうかは保証できませぬ)

LangChain Expression Language、略してLCELは、チェーンを簡単に組み合わせるための宣言的な手法です。

宣言的なプログラミングとは?

この方法でチェーンを書くことには、通常のコードを書くのとは異なるいくつかの利点があります。

  1. 非同期、バッチ、ストリーミングのサポート: この方法で構築された任意のチェーンは、同期、非同期、バッチ、ストリーミングをフルにサポートします。これにより、Jupyterノートブックで同期インターフェースを使用してチェーンのプロトタイプを簡単に作成し、非同期ストリーミングインターフェースとして公開することができます。

  2. フォールバック: LLMの非決定性のため、エラーを上手く処理することが重要です。LCELを使用すると、任意のチェーンに簡単にフォールバックを追加できます。

  3. 並列処理: LLMアプリケーションは(時には長い)API呼び出しを伴うため、並行して実行することが重要になることがよくあります。LCELの構文を使用すると、並行して実行できるコンポーネントは自動的にそうなります。

  4. シームレスなLangSmithトレーシングの統合: チェーンがどんどん複雑になるにつれて、各ステップで正確に何が起こっているのかを理解することがますます重要になります。LCELを使用すると、すべてのステップが最大の観察可能性とデバッグ可能性のために自動的にLangSmithにログされます。

非同期と同期の違いを理解するために、簡単な例を使って説明します。

同期(Synchronous):あなたがレストランで料理を注文したと想像してください。同期の場合、あなたは注文した料理が届くまで待って、他のことをせずにその場で待ち続けます。料理が届いたら、次にデザートを注文することができます。つまり、一つのタスクが完了するまで次のタスクに移ることができません。


非同期(Asynchronous):同じレストランのシチュエーションを考えますが、今回は非同期の場合。料理を注文した後、待っている間に本を読んだり、友達と話したりすることができます。料理が準備できたら、ウェイターがあなたに知らせてくれます。この間に、他の活動を同時に行うことができます。


要点:同期: 一つのタスクが完了するまで、次のタスクに進むことができません。タスクが順番に実行されます。
非同期: 一つのタスクが実行されている間に、他のタスクも同時に開始することができます。タスクの完了順序は保証されません。


技術的な観点から言うと、非同期処理は特に多くのタスクを同時に処理する必要がある場合や、待ち時間が発生する可能性がある場合(例: データベースへのクエリや外部APIの呼び出し)に有効です。同期処理はシンプルで理解しやすいですが、効率的でない場合があります。

公式ドキュメントの和訳:LangChain Expression Language (LCEL)の使用をおすすめするワケ

LangChain Expression Language(LCEL)は、最もシンプルな「プロンプト + LLM」チェーンから、数百のステップを持つ複雑なチェーンまで、コードの変更なしにプロトタイプを本番環境に移行することを目的として、初めから設計されました。

LCELを使用する理由のいくつかを以下に示します:

  1. ストリーミングの第一級サポート: LCELでチェーンを構築すると、最初のトークンが出力されるまでの時間(time-to-first-token)が最も短縮されます。これにより、例えば、LLMからストリーミング出力パーサーにトークンを直接ストリームし、LLMプロバイダーが生のトークンを出力するのと同じ速度で、解析されたインクリメンタルな出力のチャンクを取得できます。最近、ストリーミングJSONパーサーが追加され、さらに改善が進められています。

  2. 非同期サポートの第一級サポート: LCELで構築された任意のチェーンは、同期API(例: プロトタイピング中のJupyterノートブック)および非同期API(例: LangServeサーバー)の両方で呼び出すことができます。これにより、同じコードをプロトタイプおよび本番環境で使用し、高いパフォーマンスを実現し、同じサーバーで多数の同時リクエストを処理することができます。

  3. 最適化された並行実行: LCELチェーンに並行して実行できるステップがある場合(例: 複数のリトリーバーからドキュメントを取得する場合)、それを自動的に行います。これにより、最小限の遅延で同期および非同期のインターフェースの両方で実行されます。

  4. リトライとフォールバックのサポート: 最近、LCELチェーンの任意の部分に対してリトライとフォールバックを設定するサポートを追加しました。これは、チェーンを大規模にしても信頼性を高めるための素晴らしい方法です。現在、リトライ/フォールバックのストリーミングサポートを追加する作業を行っており、遅延のコストなしに信頼性を向上させることができます。

  5. 中間結果へのアクセス: より複雑なチェーンの場合、最終出力が生成される前に中間ステップの結果にアクセスすることが非常に有益です。これは、エンドユーザーに何かが進行中であることを知らせるためや、チェーンをデバッグするために使用できます。中間結果のストリーミングのサポートを追加し、すべてのLangServeサーバーで利用できます。

  6. 入力および出力スキーマ: 入力および出力スキーマは、チェーンの構造から推測されたPydanticおよびJSONSchemaスキーマをすべてのLCELチェーンに提供します。これは、入力および出力の検証に使用でき、LangServeの統合部分です。

  7. LangSmithでのトレース: LCELで構築されたすべてのチェーンには、第一級のトレースサポートがあり、チェーンをデバッグするためや、本番環境で何が起こっているかを理解するために使用できます。これを有効にするには、環境変数としてLangSmith APIキーを追加するだけです。

この記事が気に入ったらサポートをしてみませんか?