見出し画像

LlamaIndexの新機能である、Query Pipelinesの紹介

Clip source: Introducing Query Pipelines. Today we introduce Query Pipelines, a… | by Jerry Liu | Jan, 2024 | LlamaIndex Blog

Introducing Query Pipelines

Published in:LlamaIndex Blog:Jan 9

LlamaIndexのQuery Pipelineは、データクエリワークフローを簡潔に定義し実行するための宣言型APIです。このツールを使用すると、逐次的(シーケンシャル)な処理や複雑な有向非巡回グラフ(DAG)を簡単に構築できます。モジュールの組み合わせやクエリの変換、出力の処理などが柔軟に行え、コードの行数を減らしつつ効率的にデータを操作できるようになるため、RAG開発が楽になります。
こういう新機能がどんどん出てくる様になると、RAGや企業内のLLMの開発が一層促進され、OpenAIやGeminiの様な巨大化されたLLMとは逆方向の小型化されたLLMが企業内にいっぱい開発される様になると予測されます。


今日は、LlamaIndex内で新たに導入された「Query Pipelines」という宣言型APIについてご紹介します。このAPIを使用することで、さまざまなユースケース(例えばRAGや構造化データの抽出など)に対応する、シンプルから高度なクエリワークフローをデータ上で簡潔に組み立てることが可能になります。
これらすべての中核にあるのは、私たちのQueryPipelineの抽象化です。これは多くのLlamaIndexモジュール(LLM、プロンプト、クエリエンジン、リトリーバー、そしてQueryPipeline自体)を取り込むことができます。これにより、これらのモジュール上で計算グラフを作成することが可能になります(例えば、逐次的な連鎖やDAG(有向非巡回グラフ)など)。コールバックのサポートがあり、私たちのオブザーバビリティパートナーとのネイティブサポートも提供しています。
最終的な目標は、皆さんのデータ上でLLMワークフローをさらに簡単に構築できるようにすることです。より詳細な情報については、私たちの包括的な導入ガイドドキュメントページを是非ご覧ください。

高度なRAGパイプラインのための「QueryPipeline」設定の例です。

コンテキスト

過去1年間にわたり、AIエンジニアはさまざまなユースケースを解決するために、LLM(Large Language Models)を使用したカスタマイズされた複雑なオーケストレーションフローを開発してきました。時間が経つにつれて、いくつかの共通のパターンが形成されました。トップレベルでは、ユーザーのデータをクエリするためのパラダイムが出現しました。これには、非構造化データをクエリするためのRAG(Retriever-And-Generator、狭義での定義)や、構造化データをクエリするためのテキスト・ツー・SQLなどが含まれます。その他にも、構造化データ抽出(例えば、LLMにJSON形式の出力を促し、それを解析する)、プロンプトチェーン(例えば、思考の連鎖)、外部サービスと対話できるエージェント(プロンプトチェーンを組み合わせる)などのユースケースを取り巻くパラダイムが出現しました。

RAG(Retriever-And-Generator)には多くのクエリオーケストレーションが含まれています。RAG自体の中でも、パフォーマンスを最適化するために高度なRAGパイプラインを構築するために多くの作業が必要になることがあります。ユーザーのクエリから始めて、クエリ理解・変換(書き換え、ルーティング)を実行したい場合があります。また、マルチステージの検索アルゴリズムを実行することもあります。例えば、トップkのルックアップに加えてリランキングなどです。さらに、プロンプトとLLMを使用して、さまざまな方法でレスポンスの合成を行うことも考えられます。高度なRAGコンポーネントに関する素晴らしいブログがこちらにあります。

LlamaIndexの高度なRAG QueryPipelineをnetworkxとpyvisを使用して視覚化

使用方法

QueryPipelineを使用すると、LlamaIndexモジュールを使用したDAG(有向非巡回グラフ)ベースのクエリワークフローを構築できます。主に2つの方法で使用できます:

  • 逐次的なチェーンとして(最も簡単で簡潔)

  • 完全なDAGとして(より表現力がある)

    1. 詳細については、私たちの使用パターンガイドを参照してください。

シーケンシャルなチェーン

いくつかのシンプルなパイプラインは、その性質上完全に線形です — 前のモジュールの出力が直接次のモジュールの入力になります。
例えば:

  • プロンプト → LLM → 出力の解析

  • リトリーバー → レスポンスの合成

    1. ここに最も基本的な例があります、プロンプトとLLMを連結することです。単純にQueryPipeline をchain パラメータとともに初期化します。

# try chaining basic prompts
prompt_str = "Please generate related movies to {movie_name}"
prompt_tmpl = PromptTemplate(prompt_str)
llm = OpenAI(model="gpt-3.5-turbo")
p = QueryPipeline(chain=[prompt_tmpl, llm], verbose=True)

高度なRAGワークフローのためのDAGの設定

一般的にクエリワークフローを設定するには、DAGを構築するために私たちの低レベル関数を使用する必要があります。
例えば、「高度なRAG」を構築するために、クエリの書き換え、検索、リランキング、合成などを行う場合、以下のような手順を踏みます。

from llama_index.postprocessor import CohereRerank
from llama_index.response_synthesizers import TreeSummarize
from llama_index import ServiceContext
# define modules
prompt_str = "Please generate a question about Paul Graham's life regarding the following topic {topic}"
prompt_tmpl = PromptTemplate(prompt_str)
llm = OpenAI(model="gpt-3.5-turbo")
retriever = index.as_retriever(similarity_top_k=3)
reranker = CohereRerank()
summarizer = TreeSummarize(
    service_context=ServiceContext.from_defaults(llm=llm)
)
# define query pipeline
p = QueryPipeline(verbose=True)
p.add_modules(
    {
        "llm": llm,
        "prompt_tmpl": prompt_tmpl,
        "retriever": retriever,
        "summarizer": summarizer,
        "reranker": reranker,
    }
)
# add edges 
p.add_link("prompt_tmpl", "llm")
p.add_link("llm", "retriever")
p.add_link("retriever", "reranker", dest_key="nodes")
p.add_link("llm", "reranker", dest_key="query_str")
p.add_link("reranker", "summarizer", dest_key="nodes")
p.add_link("llm", "summarizer", dest_key="query_str")

このコードブロックでは、1) モジュールを追加し、その後 2) モジュール間の関係を定義します。source_keyとdest_keyはオプショナルであり、最初のモジュールが複数の出力を持つ場合、または2番目のモジュールが複数の入力を持つ場合にのみ必要となります。

パイプラインの実行

パイプラインが1つの「ルート」ノードと1つの出力ノードを持つ場合は、runを使用します。前の例を使用すると、

output = p.run(topic="YC")
# output type is Response
type(output)

パイプラインに複数のルートノードと/または複数の出力ノードがある場合は、run_multiを使用します。

output_dict = p.run_multi({"llm": {"topic": "YC"}})
print(output_dict)


カスタムクエリコンポーネントの定義

CustomQueryComponentをサブクラス化することは非常に簡単で、これによりQueryPipelineにプラグインすることができます。
詳細については、私たちのウォークスルーを確認してください。

サポートされているモジュール

現在、以下のLlamaIndexモジュールがQueryPipeline内でサポートされています。自分自身で定義することも覚えておいてください!

  1. LLM(完成とチャットの両方)(LLM)

  2. プロンプト(PromptTemplate)

  3. クエリエンジン(BaseQueryEngine)

  4. クエリ変換(BaseQueryTransform)

  5. リトリーバー(BaseRetriever)

  6. 出力パーサー(BaseOutputParser)

  7. ポストプロセッサー/リランカー(BaseNodePostprocessor)

  8. レスポンスシンセサイザー(BaseSynthesizer)

  9. その他のQueryPipelineオブジェクト

  10. カスタムコンポーネント(CustomQueryComponent)

    1. 詳細については、モジュールの使用ガイドを確認してください。

ウォークスルーの例

私たちの「Query Pipelinesへの導入」ガイドを確認して、詳細を把握してください。上記のすべてのステップを具体的な例と共に説明しています!
ノートブックガイドでは、Arize Phoenixを通してトレースも記録します。Phoenixダッシュボードで各QueryPipelineの完全な実行を見ることができます。QueryComponent内のすべてのコンポーネントにおける完全なコールバックサポートにより、どんなオブザーバビリティプロバイダーとも簡単に統合できます。

関連する研究

LLM(Large Language Models)を活用したパイプラインを構築するための宣言型構文のアイデアは新しいものではありません。関連する研究には、HaystackLangChain Expression Languageなどがあります。また、Langflow / Flowiseのようなノーコード/ローコード設定でセットアップされるパイプラインも関連する研究に含まれます。
ここでの主な目標は上述したとおりです:データ上での一般的なクエリワークフローを定義するための便利な開発者体験(dev UX)を提供すること。ここには多くの最適化やガイドが必要です!

FAQ(よくある質問)

QueryPipelineIngestionPipelineの違いは何ですか?
素晴らしい質問です。現在、IngestionPipelineはデータ摂取段階で操作され、QueryPipelineはクエリ段階で操作されます。とはいえ、両方に共通する抽象化を今後開発する可能性もあります!
結論 + リソース
これで全てです!上述したように、もっと多くのリソースとガイドを近々追加する予定です。その間に、現在のガイドをチェックしてみてください:

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