LangChainのSummarizationサンプルノートブックのウォークスルー

こちらのサンプルノートブックをDatabricksでウォークスルーします。

https://python.langchain.com/docs/use_cases/summarization

# ユースケース

手元に一連のドキュメント(PDF、Notionのページ、顧客問い合わせなど)があり、コンテンツを要約したいものとします。

LLMはテキストの理解と合成に長けており、優れたツールとなります。

このウォークスルーでは、LLMを用いてどのように文書要約を行うのかを説明します。
![Image description](https://github.com/langchain-ai/langchain/blob/master/docs/static/img/summarization_use_case_1.png?raw=1)

# 概要

要約器(summarizer)を構築する際の主な疑問は、お手元の文書をLLMのコンテキストウィンドウにどのようにして渡すのかということです。これに対する一般的な2つのアプローチは:

1. `Stuff`: 単体のプロンプトにお手元の文書全てをシンプルに「詰め込み"stuff"」ます。これはもっともシンプルなアプローチです(この手法で用いられる`create_stuff_documents_chain`コンストラクタの詳細については[こちら](https://python.langchain.com/docs/modules/chains#lcel-chains)をご覧ください)
1. `Map-reduce`: それぞれの文書をそれぞれの"map"ステップで要約し、最終的な要約に"reduce"します(この手法で用いられる`MapReduceDocumentsChain`の詳細については[こちら](https://python.langchain.com/docs/modules/chains#legacy-chains)をご覧ください)。

![Image description](https://github.com/langchain-ai/langchain/blob/master/docs/static/img/summarization_use_case_2.png?raw=1)

# クイックスタート

簡単に機能を試せるように、いずれのパイプラインも単一のオブジェクト`load_summarize_chain`にラップすることができます。

ここでは、ブログ記事を要約したいものとします。これは数行のコードで行うことができます。

:::note
**注意**
ここでは、Databricksのマニュアルを使っています。
:::

最初に環境変数を定義し、パッケージをインストールします:

```py
%pip install --upgrade --quiet  langchain-openai tiktoken chromadb langchain
%pip install sqlalchemy==2.0.0
%pip install langchainhub
dbutils.library.restartPython()
```

OpenAIのAPIキーを設定します。

```py
import os

OPENAI_API_TOKEN = dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key")
os.environ["OPENAI_API_KEY"] = OPENAI_API_TOKEN
```

以下のように長いコンテキストウィンドウを持つモデルである場合には特に、`chain_type="stuff"`を活用することができます:

* 16k トークン OpenAI `gpt-3.5-turbo-1106`
* 100k トークン Anthropic [Claude-2](https://www.anthropic.com/index/claude-2)

また、`chain_type="map_reduce"`や`chain_type="refine"`を指定することができます(詳細は[こちら](https://python.langchain.com/docs/modules/chains/document/refine)をご覧ください)。

```py
from langchain.chains.summarize import load_summarize_chain
from langchain_community.document_loaders import WebBaseLoader
from langchain_openai import ChatOpenAI

loader = WebBaseLoader("https://docs.databricks.com/ja/introduction/index.html")
docs = loader.load()

llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-1106")
chain = load_summarize_chain(llm, chain_type="stuff")

chain.run(docs)
```

# オプション 1. Stuff

`load_summarize_chain`で`chain_type="stuff"`を指定する際、[StuffDocumentsChain](https://api.python.langchain.com/en/latest/chains/langchain.chains.combine_documents.stuff.StuffDocumentsChain.html#langchain.chains.combine_documents.stuff.StuffDocumentsChain)を使うことになります。

このチェーンでは、文書のリストを受け取り、これら全てをプロンプトに挿入し、LLMのそのプロンプトを引き渡します:

```py
from langchain.chains.combine_documents.stuff import StuffDocumentsChain
from langchain.chains.llm import LLMChain
from langchain.prompts import PromptTemplate

# プロンプトの定義
prompt_template = """以下の簡潔な要約を記述してください:
"{text}"
簡潔な要約:"""
prompt = PromptTemplate.from_template(prompt_template)

# LLMチェーンの定義
llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-16k")
llm_chain = LLMChain(llm=llm, prompt=prompt)

# StuffDocumentsChainの定義
stuff_chain = StuffDocumentsChain(llm_chain=llm_chain, document_variable_name="text")

docs = loader.load()
print(stuff_chain.run(docs))
```

> Databricksは、エンタープライズグレードのデータ分析とAIソリューションを提供する統合されたオープンなアナリティクスプラットフォームです。Databricksは、データのセマンティクスを理解し、パフォーマンスを最適化し、データとAIアプリケーションのガバナンスとセキュリティを提供します。Databricksは、データ処理、機械学習、データウェアハウジング、データガバナンスなどのさまざまなユースケースに対応しています。また、Databricksはオープンソースとのマネージド統合を提供し、ワークフロー、Unity Catalog、Delta Live Tablesなどのツールを使用してアクセスできます。DatabricksはAWSと連携し、セキュアなインテグレーションを構成してデータを処理および格納します。Databricksの一般的なユースケースには、エンタープライズデータレイクハウスの構築、ETLとデータエンジニアリング、機械学習とAI、データウェアハウジングと分析、データガバナンスとセキュアなデータ共有、DevOpsとタスクオーケストレーション、リアルタイム分析とストリーミング分析があります。

素晴らしい！`load_summarize_chain`を用いて上の結果を再現できることを確認することができます。

## より深く理解する

* 容易にプロンプトをカスタマイズすることができます。
* `llm`パラメータを通じて容易に別のLLM(例 [Claude](/docs/integrations/chat/anthropic))を試すことができます。

# オプション 2. Map-Reduce

Map Reduceアプローチを紐解きましょう。そのためには、まず初めに`LLMChain`を用いて、それぞれの文書を個別の要約にマッピングします。そして、これらの要約を単一の全体的な要約に組み合わせるために`ReduceDocumentsChain`を活用します。

初めに、それぞれの文書を個々の要約にマッピングするために使うLLMChainを指定します。

```py
from langchain.chains import MapReduceDocumentsChain, ReduceDocumentsChain
from langchain_text_splitters import CharacterTextSplitter

llm = ChatOpenAI(temperature=0)

# Map
map_template = """以下は一連の文書です
{docs}
この文書をベースとして、メインテーマを特定してください
有用な回答:"""
map_prompt = PromptTemplate.from_template(map_template)
map_chain = LLMChain(llm=llm, prompt=map_prompt)
```

また、プロンプトを保存、取得するためにPrompt Hubを活用することもできます。

これはあなたの[LangSmith API key](https://docs.smith.langchain.com/)でも動作します。

例えば、[こちら](https://smith.langchain.com/hub/rlm/map-prompt)のmapプロンプトをご覧ください。

```py
from langchain import hub

map_prompt = hub.pull("rlm/map-prompt")
map_chain = LLMChain(llm=llm, prompt=map_prompt)
```

`ReduceDocumentsChain`は文書のマッピング結果を受け取り、単一のアウトプットにまとめます。これはジェネリックな(`StuffDocumentsChain`のような)`CombineDocumentsChain`をラッピングしますが、累積サイズが`token_max`を超えた場合には、`CombineDocumentsChain`に引き渡す前に文書を折りたたむ機能を追加しています。この例では、実際には文書を結合するためのチェーンを再利用していますが、対象文書の畳み込みでも再利用しています。

このため、マッピングされた文書の累積トークン数が4000トークンを超えた場合、バッチ化された要約を作成するために`StuffDocumentsChain`に対して再帰的に4000トークンより少ないバッチで文書を引き渡すことになります。そして、これらのバッチ下された要約の累積トークン数が4000を下回ったら、最終的な要約を作成するためにこれらを`StuffDocumentsChain`に引き渡します。

```py
# Reduce
reduce_template = """以下は要約のセットです:
{docs}
これらを受け取り、メインテーマの最終的かつ統合された要約にまとめ上げてください。
有用な回答:"""
reduce_prompt = PromptTemplate.from_template(reduce_template)
```
```
reduce_prompt
```
```
PromptTemplate(input_variables=['docs'], template='以下は要約のセットです:\n{docs}\nこれらを受け取り、メインテーマの最終的かつ統合された要約にまとめ上げてください。\n有用な回答:')
```

```py
# チェーンの実行
reduce_chain = LLMChain(llm=llm, prompt=reduce_prompt)

# 文書のリストを受け取り、それらを単一の文字列に結合し、LLMChainに引き渡す
combine_documents_chain = StuffDocumentsChain(
    llm_chain=reduce_chain, document_variable_name="docs"
)

# マッピングされた文書を結合し、繰り返しreduceを実施
reduce_documents_chain = ReduceDocumentsChain(
    # これが呼び出される最終的なチェーンです
    combine_documents_chain=combine_documents_chain,
    # 文書が`StuffDocumentsChain`のコンテキストを超える場合
    collapse_documents_chain=combine_documents_chain,
    # ドキュメントをまとめる最大のトークン数
    token_max=4000,
)
```

ここまでで作成したmapとreduceのチェーンを1つにまとめます:

```py
# 文書にチェーンをマッピングし、結果を結合することで統合
map_reduce_chain = MapReduceDocumentsChain(
    # Mapチェーン
    llm_chain=map_chain,
    # Reduceチェーン
    reduce_documents_chain=reduce_documents_chain,
    # llm_chainへの入力となる文書の変数名
    document_variable_name="docs",
    # アウトプットにmapステップの結果を含める
    return_intermediate_steps=False,
)

text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
    chunk_size=1000, chunk_overlap=0
)
split_docs = text_splitter.split_documents(docs)
```
```py
print(map_reduce_chain.run(split_docs))
```

> 主要なテーマは、データ開発ライフサイクルと管理、DevOpsと自動化、リアルタイムおよびストリーミングデータ分析、Apache SparkとDelta Lakeとの統合、著作権と法的情報、ユーザーフィードバックとポリシーです。これらのテーマに焦点を当て、データの処理、管理、分析、セキュリティ、ガバナンス、および開発ツールの活用について包括的に取り組んでいます。データのリアルタイム処理やストリーミングデータの取り扱い、Apache SparkやDelta Lakeを活用したデータ処理、データのアクセス制御と管理、著作権や法的情報の重要性、そしてユーザーフィードバックやポリシーの遵守が強調されています。

## より深く理解する

**カスタマイズ**

* 上に示したように、mapやreduceステージでのLLMやプロンプトをカスタマイズすることができます。

**現実世界でのユースケース**

* ユーザーインタラクションの分析(LangChainドキュメントに関する質問)に関するケーススタディに関する[こちらのブログ記事](https://blog.langchain.dev/llms-to-improve-documentation/)をご覧ください！
* ブログ記事および関連[repo](https://github.com/mendableai/QA_clustering)では、要約の手段としてクラスタリングも紹介しています。
* これによって、`stuff`や`map-reduce`アプローチに次ぐ、特筆すべき3つ目のパスが示されています。

![Image description](https://github.com/langchain-ai/langchain/blob/master/docs/static/img/summarization_use_case_3.png?raw=1)

# オプション 3. Refine

[RefineDocumentsChain](/docs/modules/chains#legacy-chains)はmap-reduceと似ています:

> The refine documents chain constructs a response by looping over the input documents and iteratively updating its answer. For each document, it passes all non-document inputs, the current document, and the latest intermediate answer to an LLM chain to get a new answer.

> refine documentsチェーンは、入力文書に対するループ処理を行い、解答を繰り返し更新することでレスポンスを構成します。それぞれの文書に対して、新たな解答を得るために、LLMチェーンに対して文書以外の入力、現在の文書、最新の中間解答の全てを引き渡します。

これは、`chain_type="refine"`を指定することで容易に実行することができます。

```py
chain = load_summarize_chain(llm, chain_type="refine")
chain.run(split_docs)
```

> 'The existing summary provides a comprehensive overview of Databricks as an integrated open analytics platform that leverages AI and Data Lakehouse for building, deploying, and maintaining enterprise-grade data analysis and AI solutions at scale. It highlights key features such as Unity Catalog, Delta Live Tables, Databricks SQL, and Photon Compute Cluster for optimal performance and ease of use. The platform integrates with AWS securely, allowing for compute clusters and data processing without data migration. Databricks Workspace meets security and network requirements for large enterprises, offering customization and control over cloud infrastructure operations. It is used for building Enterprise Data Lakehouses, simplifying data solutions for various users. Additionally, Databricks provides tools for efficient ETL processes, machine learning applications, and AI functions. The platform also supports SQL data analysts and offers a user-friendly UI for running analytics queries. With the new context provided on DevOps, CI/CD, task orchestration, real-time and streaming analytics, Databricks simplifies the development lifecycle by providing common tools for version control, automation, scheduling, and deployment. It allows for scheduling Databricks notebooks, SQL queries, and other code using workflows, and syncing projects with popular Git providers. The platform also handles streaming data and incremental data changes through Apache Spark structured streaming integrated with Delta Lake. Overall, Databricks offers a comprehensive solution for data analysis and AI applications with a focus on efficiency, scalability, and ease of use.'

プロンプトを指定したり、中間ステップの結果を取得することも可能です。

```py
prompt_template = """以下の簡潔な要約を記述してください:
"{text}"
簡潔な要約:"""
prompt = PromptTemplate.from_template(prompt_template)

refine_template = (
    "あなたの仕事は最終的な要約を作成することです\n"
    "我々の方であるところまでの要約を作成しました: {existing_answer}\n"
    "(必要であれば)以下のコンテキストを用いて既存の要約を改善する余地があります\n"
    "------------\n"
    "{text}\n"
    "------------\n"
    "新たなコンテキストを用いて、オリジナルの要約を日本語で改善してください"
    "コンテキストが役に立たない場合には、オリジナルの要約を返却してください。"
)
refine_prompt = PromptTemplate.from_template(refine_template)
chain = load_summarize_chain(
    llm=llm,
    chain_type="refine",
    question_prompt=prompt,
    refine_prompt=refine_prompt,
    return_intermediate_steps=True,
    input_key="input_documents",
    output_key="output_text",
)
result = chain({"input_documents": split_docs}, return_only_outputs=True)
```
```py
print(result["output_text"])
```

> Databricksは、エンタープライズグレードのデータ分析とAIソリューションを提供する統合されたオープンなアナリティクスプラットフォームです。クラウドストレージとセキュリティを統合し、自然言語処理やデータのガバナンスとセキュリティにも対応しています。また、オープンソースコミュニティとの連携を重視し、Delta Lake、MLflow、Apache Sparkなどのプロジェクトをサポートしています。AWSとの連携により、セキュアなインテグレーションを構築し、セキュリティを重視しています。さらに、Databricksは、大規模な言語モデルや生成AI、データウェアハウジング、分析、BIなどの機能を提供しており、ユーザーに高い精度と柔軟性を提供しています。Unity Catalogを使用することで、データガバナンスとセキュアなデータ共有が容易になり、プラットフォームの管理者とエンドユーザーの責任を効果的に分担することができます。また、DevOps、CI/CD、タスクオーケストレーションにより、Databricksを使用することで、作業の重複や同期されていないレポートを減らすことができ、監視、オーケストレーション、運用のオーバーヘッドを簡素化することができます。さらに、Apache Spark構造化ストリーミングを利用して、ストリーミングデータと増分データ変更を扱い、Delta Lakeと緊密に統合されています。

```py
print("\n\n".join(result["intermediate_steps"][:3]))
```

> Databricksは、エンタープライズグレードのデータ分析とAIソリューションを構築、デプロイ、共有、保守するための統合されたオープンなアナリティクスプラットフォームであり、クラウドストレージとセキュリティを統合し、クラウドインフラストラクチャを管理およびデプロイします。
> 
> Databricksは、エンタープライズグレードのデータ分析とAIソリューションを構築、デプロイ、共有、保守するための統合されたオープンなアナリティクスプラットフォームであり、クラウドストレージとセキュリティを統合し、クラウドインフラストラクチャを管理およびデプロイします。また、自然言語処理やデータのガバナンスとセキュリティにも対応しており、BIから生成AIまでの幅広い用途に対応しています。さらに、オープンソースコミュニティとの連携を重視し、Delta Lake、MLflow、Apache Sparkなどのプロジェクトをサポートしています。
> 
> Databricksは、エンタープライズグレードのデータ分析とAIソリューションを構築、デプロイ、共有、保守するための統合されたオープンなアナリティクスプラットフォームです。クラウドストレージとセキュリティを統合し、クラウドインフラストラクチャを管理およびデプロイします。自然言語処理やデータのガバナンスとセキュリティにも対応し、BIから生成AIまでの幅広い用途に対応しています。また、オープンソースコミュニティとの連携を重視し、Delta Lake、MLflow、Apache Sparkなどのプロジェクトをサポートしています。Databricksは、ワークフロー、Unity Catalog、Delta Live Tables、Databricks SQL、Photon コンピュート クラスターなどのツールを提供し、REST API、CLI、Terraformなどのプログラムでの操作も可能です。AWSとの連携により、セキュアなインテグレーションを構築し、お客様のクラウドアカウントを使用してデータを処理および格納します。Unity Catalogは、SQL構文を使用してデータにアクセスする権限を管理します。Databricksは、セキュリティを重視し、世界最大規模の企業のセキュリティおよびネットワーク要件を満たしています。

ここまでの精度で動くと要約も有用ですね(数十年前はキーワードベースでの拙い要約だったのを思い出しました)。ユースケースも色々ありそうです。

### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)