Closed11

Haystackのチュートリアルを全部やってみる

kun432kun432

この辺ちょっと気になって、まずはチュートリアルやってみる。

🕵️ Agent: (since 1.15) An Agent is a component that is powered by an LLM, such as GPT-3. It can decide on the next best course of action so as to get to the result of a query. It uses the Tools available to it to achieve this. While a pipeline has a clear start and end, an Agent is able to decide whether the query has resolved or not. It may also make use of a Pipeline as a Tool.

https://github.com/deepset-ai/haystack

kun432kun432

Haystackとは

Haystack is an end-to-end NLP framework that enables you to build applications powered by LLMs, Transformer models, vector search and more. Whether you want to perform question answering, answer generation, semantic document search, or build tools that are capable of complex decision making and query resolution, you can use the state-of-the-art NLP models with Haystack to build end-to-end NLP applications solving your use case.

乱暴に言うと、LangChainとかLlamaIndexとかみたいなLLMフレームワークだと思ってる。

kun432kun432

Haystackの概念(以下日本語訳)

https://docs.haystack.deepset.ai/docs/intro

Haystack入門

Haystackは、大規模な文書コレクションに対してインテリジェントに動作する、プロダクション対応のLLMアプリケーション検索支援生成(RAG)パイプライン最先端の検索システムを構築するためのオープンソースのフレームワークです。Haystackの詳細と動作について学んでいきましょう。


Haystackは、大規模言語モデル(Large Language Models:LLM)を用いて、様々な検索ユースケースに対応できる、パワフルでプロダクション対応のパイプラインを構築するためのエンドツーエンドのフレームワークです。検索支援生成(RAG)、質問応答、セマンティック文書検索のいずれを実行する場合でも、Haystackの最先端のLLMとNLPモデルを使用して、独自の検索エクスペリエンスを提供し、ユーザーが自然言語でクエリを実行できるようにすることができます。Haystackはモジュール方式で構築されており、OpenAI、Cohere、SageMaker、など最高の技術と、Hugging FaceのTransformers、Elasticsearch、Milvusのような他のオープンソースプロジェクトを組み合わせることができます。

Haystackの構成要素

Haystackは、カスタマイズ可能でプロダクション対応の優れた検索システムを構築することを目的としており、それらを構築するために使用できるコンポーネントが多数あります。

ノード

Haystackは様々なノードを提供しており、それぞれが異なる種類のタスクを実行します。これらは最新のLLMやtransformerモデルによって実現されています。コード的には、ノードは直接呼び出せるメソッドを持つPythonのクラスです。例えばPromptNodeで質問応答を実行するために必要なのは、ドキュメント、質問応答用にデザインされたPromptTemplate、そしてクエリを提供することです。

Haystackノードを使ったこのレベルでの作業は、実務的なアプローチです。これにより、入力を直接操作し、出力を検査する非常に直接的な方法が提供されます。これは、探索、プロトタイピング、およびデバッグに役立つことがあります。

以下は、PromptHubの「deepset/question-answering」プロンプトを使用する単一のPromptNodeの例です

from haystack.nodes import PromptNode

prompt_node = PromptNode(model_name_or_path="gpt-4", api_key='YOUR_OPENAI_KEY')
result = prompt_node.prompt(query="What is Haystack?", 
                            documents=documents,
                            prompt_template="deepset/question-answering")

パイプライン

Haystackは、いろいろなパーツを組み合わせることにより、その組み合わせ以上の優れたシステムを構築できるというアイデアにもとづいて基づいて構築されています。異なるノードを組み合わせることで、強力でカスタマイズ可能なシステムを作成できます。パイプラインは、このモジュラーアプローチが機能するキーとなります。

ノードをパイプラインに追加する際、データが次のノードにどのように流れるかを定義できます。これにより、データフローのロジックが単純化されるだけでなく、決定ノードを含む複雑なルーティングオプションも可能になります。

以下は、PromptNodeの次に、ドキュメントを提供するRetrieverが続く、Retrieval-Augmented Generative pipeline(RAG)のシンプルな例です。

from haystack import Pipeline

p = Pipeline()
p.add_node(component=retriever, name="Retriever", inputs=["Query"])
p.add_node(component=prompt_node, name="PromptNode", inputs=["Retriever"])
result = p.run(query="What did Einstein work on?")
パイプラインを使用する理由

異なるノードをチェインさせる価値は、Haystackで最も一般的に構築されるシステムの1つである、RAG(Retrieval-Augmented Generative)パイプラインを見ると最も明確でしょう。これにより、PromptNodeの支援を受けながらLLM(Large Language Models)の言語生成能力を活用するだけでなく、同時にRetrieverの助けを借りて大規模な文書ベースからLLMへ関連コンテキストを提供することができます。

PromptNodeは、LLM(例:GPT-4、Llama2など)とのインターフェースで、必要なLLMとの対話モードをカスタマイズできます。これはPromptTemplateの使用によって行われ、その結果、PromptTemplateの設計に基づいて応答を生成します。たとえば、ドキュメントに基づいてクエリを受け取り、そのクエリに回答するように設計されたPromptTemplateを使用することができます。PromptNodeは、選択したLLMに正しい指示が送られることを確実にします。

PromptNodeは、LLM(例:GPT-4、Llama2など)とのインターフェースであり、LLMとの対話モードをカスタマイズするために使用できます。PromptTemplateを使用すると、テンプレートに設計された動作に基づいて応答を生成することができます。たとえば、受け取ったクエリを元にドキュメントから回答するようなPromptTemplateを使用できます。PromptNodeは、選択したLLMが正しい指示を受け取ることを確実にします。

Retrieverは、PromptNodeをサポートし、LLMが正確にクエリに応答するために必要なコンテキストの量を減らす軽量フィルターとして機能します。これはデータベース内のすべてのドキュメントをスキャンし、関連するものを素早く特定し、関連しないものを無視します。その結果、少数の候補ドキュメントがPromptNodeに渡されることになります。

Haystackの強力で軽量なコンポーネントのもう1つの例は、特定のドメインに特化した質問応答システムとしても知られるReaderです。これらは、ドキュメントを詳細に分析し、検索型の質問応答を実行する強力なモデルを提供します。HaystackのReaderは、最新のtransformerベースの言語モデルを使ってトレーニングされており、GPUアクセラレーションを使用して大幅に高速化することができます。ただし、Readerを大量のドキュメントに直接使用することは現状は現実的ではありません。

Haystackは、一連の簡単な自然言語処理タスクのためのビルトインのパイプラインも提供しています。以下は、RetrieverとReaderを組み合わせてExtractiveQAPipelineを作成するビルトインのパイプラインの例です。

p = ExtractiveQAPipeline(reader, retriever)
result = p.run(query="What is the capital of Australia?")

Retrieverだけでは質問応答はできません。また、Readerだけでは非常に遅い処理となります。このシステムが強力なのは、これら2つのノードを組み合わせることから生まれます。

これらのパイプラインは決してHaystackが提供する唯一のパイプラインではありませんが、ノードを組み合わせることの利点を最もわかりやすく示しているでしょう。相乗効果のあるノードの組み合わせはビルトインパイプラインで紹介していますが、まだ発見されていない組み合わせもあるかもしれません!

エージェント

エージェントは非常に汎用性の高いプロンプトベースのコンポーネントで、大規模な言語モデルを使用し、検索型または生成型の質問応答の機能を超える複雑な質問に答える推論を利用できます。特に、複数のソースからの情報を組み合わせて答えを導き出さなければならないマルチホップの質問応答シナリオに役立ちます。

エージェントはクエリを受け取ると、完了するための複数のステップを行動計画として立案します。そして、適切なツールを選択することから始め、各ツールからの出力を次のツールの入力として使用します。最終的な答えに到達するまで、ループの中でツールを使用します。

エージェントは、最も複雑な検索タスクを解決するために、Haystackパイプライン、ノード、ウェブ検索をツールとして使用することができます。

agent = Agent(
    prompt_node=prompt_node,
    prompt_template=few_shot_agent_template,
    tools=[web_qa_tool],
    final_answer_pattern=r"Final Answer\s*:\s*(.*)",
)

hotpot_questions = [
    "What year was the father of the Princes in the Tower born?",
    "Name the movie in which the daughter of Noel Harrison plays Violet Trefusis.",
    "Where was the actress who played the niece in the Priest film born?",
    "Which author is English: John Braine or Studs Terkel?",
]

REST API

検索システムをデプロイするには、単なるPythonスクリプトだけでは不十分です。リクエストを処理し、さまざまなアプリケーションから呼び出せるサービスが必要です。そのために、Haystackは本番環境で動作するように設計されたREST APIを提供しています。

以下のように設定すると、YAMLファイルからパイプラインを読み込んだり、HTTPリクエストを介してパイプラインと対話したり、Haystackをユーザー向けのGUIに接続したりできます。

$ curl -X 'POST' \
  'http://127.0.0.1:8000/query' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json' \
  -d '{
  "query": "Who is the father of Arya Stark?",
  "params": {}
}'
kun432kun432

ふむ、LangChainの最初の頃に感じた、コンポーネントの違いの曖昧さみたいなのがなくて、スッキリ入ってくる感はある。

もう少し触ってみて判断。

kun432kun432

チュートリアル(以下日本語訳)

https://docs.haystack.deepset.ai/docs/get_started

始めてみよう

このページでは、Haystackをすぐに使い始める方法を説明します。インストール、基本的なパイプラインの構築、ファイルの準備、検索の実行についての説明があります。


インストール

Haystackのインストールについての完全なガイドは、インストールをご覧ください。

デモ

私たちがホストしているExplore the Worldデモにアクセスすれば、実際に動いているHaystackシステムを簡単に試すことができます。

Haystackの構成要素

HaystackでRetrieverとReaderを使用した質問応答システムのコードサンプルです。実際に動作するコードについては、Starter Tutorialをご覧ください。

# DocumentStore: データを保持します
document_store = InMemoryDocumentStore()

# ドキュメントを整形してDocumentStoreに読み込みます
dicts = convert_files_to_dicts(doc_dir, clean_func=clean_wiki_text)
document_store.write_documents(dicts)

# Retriever: 最も適切な候補文書を特定するための高速かつシンプルなアルゴリズム
retriever = BM25Retriever(document_store)

# Reader: パワフルだけどやや遅い、QAのために学習されたニューラルネットワーク
model_name = "deepset/roberta-base-squad2"
reader = FARMReader(model_name)

# Pipeline: コンポーネントを組み合わせます
pipe = ExtractiveQAPipeline(reader, retriever)

# ジャジャーン! 質問してみてください!
question = "サンサ・スタークの父親は誰ですか?"
prediction = pipe.run(query=question)
print_answers(prediction)

ドキュメントをDocumentStoreに読み込む

Haystackでは、DocumentStores は辞書形式のドキュメント(Documents)を想定しています。これらは以下のようにロードされます:

document_store = InMemoryDocumentStore()
dicts = [
    {
        'content': DOCUMENT_TEXT_HERE,
        'meta': {'name': DOCUMENT_NAME, ...}
    }, ...
]
document_store.write_documents(dicts)

HaystackでDocumentsと言えば、特にDocumentStoreに保持されている個々のテキストブロックを指します。1つのファイル内のすべてのテキストをDocumentとして使用したい場合もあれば、複数のDocumentに分割したい場合もあるでしょう。この分割は、スピードとパフォーマンスに大きな影響を与える可能性があります。

検索クエリを実行する

Haystackを使って作成できる検索には様々な種類があります。何が実現できるかのほんの一例として、オープンドメイン質問応答(ODQA)パイプラインを詳しく見てみましょう。

ODQAシステムにおけるクエリとは、DocumentStore全体から与えられた質問に対する答えを検索することです。このプロセスは以下を実行します:

  • Retrieverに、関連する候補文書の小さなセットをフィルタリングさせます。
  • Readerにこの候補文書のセットを処理させます。
  • 与えられた質問に対する答えの候補を返します

通常、クエリの実行には厳しい時間的制約があるため、軽量な操作である必要があります。ドキュメントが読み込まれると、Haystackはクエリ時に有用な結果を事前に算出します。

Haystackでは、クエリは、ReaderとRetrieverをつなぐパイプラインオブジェクトを使って実行されます。

# Pipeline: コンポーネントを組み合わせます
pipe = ExtractiveQAPipeline(reader, retriever)

# ジャジャーン! 質問してみてください!
question = "サンサ・スタークの父親は誰ですか?"
prediction = pipe.run(query=question)
print_answers(prediction)

クエリーが完了すると、次のような結果が表示されます:

[
    {   'answer': 'エダード',
        'context': '伝説の戦士の女王にちなんでナイメリアと名付けられた。',
        '父エダードが王の手となったとき、彼女はエダードとともに王都へ向かう。',
        '彼女が旅立つ前に'
    }, ...
]

独自の検索パイプライン

Haystackには、組み合わせ自由なさまざまなブロックが用意されています。その中には以下のようなものがあります:

  • Readers
  • Retrievers (疎と密)
  • DocumentStores
  • Summarizers
  • Generators
  • Translators

これらはすべて、好きな構成で組み合わせることができます。パイプラインのページをご覧ください!

kun432kun432

なるほど。

LangChainに置き換えるとこういうことだと思う。

  • Pipelines ≒ Chains
  • Readers ≒ Retrieval Chain
  • Retrievers (疎と密)≒ Retrievers
  • DocumentStores ≒ Document loaders
  • Summarizers ≒ Summarize Chain
  • Generators ≒ LLMs
  • Translators ≒ Translate Chain

完全にイコールにはできないけど、コンポーネントの考え方が色々違うことはよくわかった。

基本的にHaystackでは個々の機能というか処理がノードで、それを組み合わせるのがパイプラインだと思えば良さそう。

最近はLangChain触ってないけど、以下にもある通り、初期のコンポーネントは概念が結構曖昧な感があって、コード読まないとわからないことも多々あった。今はその辺がだいぶ整理されたみたいだけど、それが逆に初期のコンポーネントのドキュメントがもう見当たらないとかになってたりして、中々の辛みがある。

抽象化したけどやりすぎて実際に使ってみたら見直しが必要になった、ってのはまあ黎明期なのでしょうがなかったかなとも思う。

https://qiita.com/sakasegawa/items/9b6c79dc11bc3a1bc0ed

Haystackは実際のコードをまだ全然さわれてないけども、ここまでで見てきた限りでは、そこまで細かく抽象化してないように思えるので、まあざっくりと理解するのはこちらの方が簡単かなとは感じてる。

kun432kun432

ということで前置きが長くなったけど、ここからチュートリアルを始めていく。

2023/10/03時点で全25のチュートリアルがあるけど、一部Outdatedなものもある様子で、それを除くと22。

https://haystack.deepset.ai/tutorials

レベル別の内訳。Outdatedなものは除いた。

  • Beginner(5)
  • Intermediate(11)
  • Advanced(6)

ということで順番にやっていく次第。

なお、以下のリンクの順序はよくわからない。

kun432kun432

そういやずっとやってなかった。

当時はよくわからないながらもハイブリッドやりたかったのだけど、サーバレスな感じで動かしたいというのもあってTransformerモデルの例が多いhaystackから徐々に離れてしまったのだった。

LlamaIndexも一通り触ったので、もう一度触れてみるのもいいかもしれない。パイプラインとかはエージェント作ったりするのに必要になりそうな気がするし。

このスクラップは2024/01/18にクローズされました