Databricks Appsによるフロントエンドアプリのデプロイ

こちらの続きです。

https://qiita.com/taka_yayoi/items/be87ac7198f03317be77

`llm-rag-chatbot/02-simple-app`のノートブックをウォークスルーします。

ただ、最初の二つのノートブックは[以前](https://qiita.com/taka_yayoi/items/f174599e4721e51e9e1d)とそれほど変わっていないので軽めに。[三つ目のノートブック](#3-databricks-apps-を使用したフロントエンドアプリのデプロイ)では、RAGのフロントエンドをDatabricks Appsで構築しています。こちらがNewです。

# 1/ LLMチャットボットRAGのためのデータ準備

`01-Data-Preparation-and-Index`を実行していきます。

## Databricks Vector Searchに知識ベースを構築・索引付け

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-managed-flow-1.png?raw=true" style="float: right; width: 800px; margin-left: 10px">

このノートブックでは、ドキュメントページを取り込み、Vector Searchインデックスを使用して索引付けし、チャットボットがより良い回答を提供できるようにします。

高品質なデータの準備は、チャットボットのパフォーマンスにとって重要です。次のステップを自分のデータセットで実装する時間を取ることをお勧めします。

幸いなことに、Lakehouse AIは、AIおよびLLMプロジェクトを加速する最先端のソリューションを提供し、大規模なデータの取り込みと準備を簡素化します。

この例では、[docs.databricks.com](docs.databricks.com)からDatabricksのドキュメントを使用します:
- ウェブページをダウンロードする
- ページを小さなテキストチャンクに分割する
- Deltaテーブルの一部としてDatabricks Foundationモデルを使用して埋め込みを計算する
- Deltaテーブルに基づいてVector Searchインデックスを作成する  

```py
%pip install --quiet mlflow==2.14.3 lxml==4.9.3 transformers==4.30.2 langchain==0.2.1 databricks-vectorsearch
dbutils.library.restartPython()
```

```py
%run ../_resources/00-init $reset_all_data=false
```

## Databricksドキュメントのサイトマップとページの抽出

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-data-prep-1.png?raw=true" style="float: right; width: 600px; margin-left: 10px">

まず、Delta Lakeテーブルとして生データセットを作成しましょう。

このデモでは、`docs.databricks.com`からいくつかのドキュメントページを直接ダウンロードし、HTMLコンテンツを保存します。

主な手順は以下の通りです：

- `sitemap.xml`ファイルからページURLを抽出する簡単なスクリプトを実行する
- ウェブページをダウンロードする
- BeautifulSoupを使用してArticleBodyを抽出する
- HTMLの結果をDelta Lakeテーブルに保存する

```py
if not table_exists("raw_documentation") or spark.table("raw_documentation").isEmpty():
    # Download Databricks documentation to a DataFrame (see _resources/00-init for more details)
    doc_articles = download_databricks_documentation_articles()
    #Save them as a raw_documentation table
    doc_articles.write.mode('overwrite').saveAsTable("raw_documentation")

display(spark.table("raw_documentation").limit(2))
```

### 文書ページを小さなチャンクに分割する

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-data-prep-2.png?raw=true" style="float: right; width: 600px; margin-left: 10px">

LLMモデルには通常、最大入力コンテキスト長があり、非常に長いテキストの埋め込みを計算することはできません。
さらに、コンテキストの長さが長いほど、モデルが応答を提供するまでの時間が長くなります。

文書の準備は、モデルがうまく機能するための鍵です。データセットに応じて、複数の戦略が存在します：

- 文書を小さなチャンク（段落、h2など）に分割する
- 文書を固定長に切り詰める
- チャンクのサイズは、コンテンツとそれを使用してプロンプトを作成する方法によって異なります。複数の小さなドキュメントチャンクをプロンプトに追加すると、大きな1つを送信するのとは異なる結果が得られる場合があります
- 大きなチャンクに分割し、モデルに各チャンクを一度のジョブとして要約させ、ライブ推論を高速化する
- 複数のエージェントを作成して、それぞれの大きな文書を並行して評価し、最終的なエージェントに回答を作成させる...

### 大きな文書ページを小さなチャンク（h2セクション）に分割する

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/chunk-window-size.png?raw=true" style="float: right" width="700px">
<br/>
このデモでは、モデルへのプロンプトには長すぎる大きな文書記事を扱います。

RAGコンテキストとして複数の文書を使用することはできません。これは、最大入力サイズを超えてしまうためです。最近の研究によると、ウィンドウサイズが大きい方が常に良いとは限らず、LLMはプロンプトの始まりと終わりに焦点を当てがちです。

このケースでは、HTMLの`h2`タグ間で記事を分割し、HTMLを削除し、LangChainを使用して各チャンクが500トークン未満であることを確認します。

#### LLMウィンドウサイズとトークナイザー

同じ文は、異なるモデルで異なるトークンを返す場合があります。LLMには、与えられた文のトークン数を数えるために使用できる`Tokenizer`が付属しています（通常、単語数よりも多い）（[Hugging Faceのドキュメント](https://huggingface.co/docs/transformers/main/tokenizer_summary)または[OpenAI](https://github.com/openai/tiktoken)を参照）

ここで使用するトークナイザーがモデルと一致していることを確認してください。Databricks DBRX InstructはGPT4と同じトークナイザーを使用しています。これにより、`transformers`ライブラリを使用してDBRX Instructのトークンをそのトークナイザーで数え、文書のトークンサイズを埋め込みの最大サイズ（1024）以下に保ちます。

:::note info
**情報**
次のステップはデータセットに特有のものです。これは、成功したRAGアシスタントを構築するための重要な部分です。常に作成されたチャンクを手動で確認し、それらが意味をなし、関連する情報を含んでいることを確認してください。
:::

```py
from langchain.text_splitter import HTMLHeaderTextSplitter, RecursiveCharacterTextSplitter
from transformers import AutoTokenizer, OpenAIGPTTokenizer

max_chunk_size = 500

tokenizer = OpenAIGPTTokenizer.from_pretrained("openai-gpt")
text_splitter = RecursiveCharacterTextSplitter.from_huggingface_tokenizer(tokenizer, chunk_size=max_chunk_size, chunk_overlap=50)
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=[("h2", "header2")])

# Split on H2, but merge small h2 chunks together to avoid too small. 
def split_html_on_h2(html, min_chunk_size = 20, max_chunk_size=500):
  if not html:
      return []
  h2_chunks = html_splitter.split_text(html)
  chunks = []
  previous_chunk = ""
  # Merge chunks together to add text before h2 and avoid too small docs.
  for c in h2_chunks:
    # Concat the h2 (note: we could remove the previous chunk to avoid duplicate h2)
    content = c.metadata.get('header2', "") + "\n" + c.page_content
    if len(tokenizer.encode(previous_chunk + content)) <= max_chunk_size/2:
        previous_chunk += content + "\n"
    else:
        chunks.extend(text_splitter.split_text(previous_chunk.strip()))
        previous_chunk = content + "\n"
  if previous_chunk:
      chunks.extend(text_splitter.split_text(previous_chunk.strip()))
  # Discard too small chunks
  return [c for c in chunks if len(tokenizer.encode(c)) > min_chunk_size]
 
# Let's try our chunking function
html = spark.table("raw_documentation").limit(1).collect()[0]['text']
print(html)
split_html_on_h2(html)
```

### チャンクを作成し、Deltaテーブルに保存する

最後のステップは、すべてのドキュメントテキストに対してUDFを適用し、それらを`databricks_documentation`テーブルに保存することです。

*この部分は通常、新しいドキュメントページが更新されるとすぐに実行される本番グレードのジョブとして設定されます。これは、Delta Live Tableパイプラインとしてセットアップされ、更新を増分的に消費するように設定できます。*

```sql
%sql
--Note that we need to enable Change Data Feed on the table to create the index
CREATE TABLE IF NOT EXISTS databricks_documentation (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY,
  url STRING,
  content STRING
) TBLPROPERTIES (delta.enableChangeDataFeed = true); 
```

```py
# Let's create a user-defined function (UDF) to chunk all our documents with spark
@pandas_udf("array<string>")
def parse_and_split(docs: pd.Series) -> pd.Series:
    return docs.apply(split_html_on_h2)
    
(spark.table("raw_documentation")
      .filter('text is not null')
      .withColumn('content', F.explode(parse_and_split('text')))
      .drop("text")
      .write.mode('overwrite').saveAsTable("databricks_documentation"))

display(spark.table("databricks_documentation"))
```

## Vector Searchインデックスに必要なもの

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/databricks-vector-search-managed-type.png?raw=true" style="float: right" width="800px">

Databricksでは、複数のタイプのVector Searchインデックスが提供されています：

- **Managed embeddings**: テキスト列とエンドポイント名を指定し、DatabricksがDeltaテーブルとインデックスを同期します **(このデモでは使用します)**
- **Self Managed embeddings**: embeddingsを計算し、Deltaテーブルのフィールドとして保存し、Databricksがインデックスを同期します
- **Direct index**: Deltaテーブルを使用せずにインデックスを使用および更新する場合

このデモでは、**Managed Embeddings**インデックスのセットアップ方法を紹介します（*self managed embeddingsは高度なデモで説明されています*）。

## Databricks GTE埋め込み基盤モデルエンドポイントの紹介

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-data-prep-4.png?raw=true" style="float: right; width: 600px; margin-left: 10px">

FoundationモデルはDatabricksによって提供され、そのまま使用することができます。

Databricksは、埋め込みの計算やモデルの評価に使用するいくつかのエンドポイントタイプをサポートしています：
- Databricksが提供する**foundationモデルエンドポイント**（例：DBRX、MPT、GTE）。**このデモではこれを使用します。**
- 外部モデルへのゲートウェイとして機能する**外部エンドポイント**（例：Azure OpenAI）
- Databricksモデルサービスにホストされた**カスタムなファインチューニングモデル**

[モデルサービングエンドポイントページ](/ml/endpoints)を開いて、foundationモデルを探索して試してみてください。

このデモでは、foundationモデルの`GTE`（埋め込み）と`DBRX`（チャット）を使用します。<br/><br/>

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/databricks-foundation-models.png?raw=true" width="600px" >

```py
import mlflow.deployments
deploy_client = mlflow.deployments.get_deploy_client("databricks")

#Embeddings endpoints convert text into a vector (array of float). Here is an example using GTEgte:
response = deploy_client.predict(endpoint="databricks-gte-large-en", inputs={"input": ["What is Apache Spark?"]})
embeddings = [e['embedding'] for e in response.data]
print(embeddings)
```
```
[[1.044921875, -0.0526123046875, -0.281982421875, -0.0885009765625, 0.09619140625, -0.1337890625, 0.158447265625, 0.281982421875, 0.76318359375, 0.415771484375, 0.6064453125, -0.061676025390625, 0.10528564453125, 0.591796875, -0.40185546875, 0.35400390625, 0.58837890625, 0.4326171875, 0.061676025390625, -0.20361328125, -0.59326171875, 0.0985107421875, -0.33349609375, -2.970703125, 0.3056640625, 0.422607421875, 0.002285003662109375, -0.0919189453125, -0.8525390625, 0.033233642578125, 0.489990234375, 0.007843017578125, -1.4111328125, 0.41845703125, 0.63427734375, -0.272216796875, -0.34033203125, 1.30859375, -0.2802734375, -0.716796875, -0.2236328125, -0.12158203125, -0.76953125, 0.09228515625, 1.3837890625, -0.01202392578125, 0.5712890625, 0.086181640625, -0.35595703125, -0.2496337890625, -2.068359375, 0.05889892578125, 0.45166015625, -0.77978515625, -0.9169921875, -0.035552978515625, 0.93115234375, -0.2418212890625, 0.466064453125, -0.1331787109375, -0.079345703125, 0.55712890625, -0.57568359375, -0.53759765625, -0.1331787109375, -0.583984375, 0.306640625, -0.421875, -0.3662109375, 1.44140625, 0.0231475830078125, 0.76220703125, 0.14599609375, 0.0726318359375, 1.841796875, -0.3583984375, 0.63671875, 1.171875, 0.62451171875, 0.65185546875, -0.05743408203125, -0.59326171875, -0.50390625, 0.27587890625, 0.0765380859375, 0.379638671875, 1.2646484375, -0.26806640625, -0.1390380859375, 0.1260986328125, -0.4228515625, 0.5146484375, 0.01535797119140625, -0.46337890625, 0.3486328125, 1.71875, 0.07696533203125, -0.28173828125, -0.1375732421875, -0.422119140625, -0.54345703125, -0.1502685546875, 0.5947265625, -0.2049560546875, 0.0947265625, 0.1712646484375, 0.6025390625, -0.90380859375, 0.46337890625, -0.0975341796875, 0.46826171875, -0.6181640625, -0.32763671875, 0.427490234375, 0.990234375, 0.50341796875, 0.5185546875, -0.080322265625, 0.07196044921875, 0.56005859375, 0.1217041015625, -0.60107421875, 0.8505859375, 0.51318359375, 0.76416015625, -0.0850830078125, -0.1217041015625, -0.136962890625, -0.58642578125, 0.1639404296875, -0.61962890625, -0.78369140625, -0.322998046875, -0.130859375, -0.1329345703125, 0.275634765625, -0.52001953125, 0.449951171875, 0.74169921875, 0.26416015625, -0.71240234375, 0.27197265625, 0.444580078125, 0.12445068359375, 0.8837890625, -0.1912841796875, 1.1611328125, 0.708984375, 0.748046875, -2.345703125, -1.296875, 0.4130859375, -0.66552734375, -0.849609375, -0.4091796875, 0.5126953125, -0.11572265625, -0.84423828125, -0.1683349609375, -0.98681640625, -0.8818359375, -1.71484375, -0.1910400390625, 0.59326171875, 0.1400146484375, 0.837890625, -0.60546875, -0.062744140625, -0.1785888671875, 0.2113037109375, -1.3388671875, -0.0018310546875, 0.86474609375, -0.13037109375, -0.2403564453125, -0.50146484375, 0.80908203125, -0.5576171875, -0.197998046875, -0.379638671875, 0.21728515625, -1.0927734375, -0.61962890625, -1.2001953125, -2.068359375, 0.382080078125, -0.6484375, 0.3642578125, 0.483154296875, -0.1427001953125, -0.2127685546875, 1.02734375, -0.25390625, -0.19140625, -0.62060546875, -0.73681640625, 0.10076904296875, -0.456787109375, 0.47119140625, 0.328369140625, 0.37451171875, 0.1318359375, -0.79931640625, -0.01279449462890625, 0.0281219482421875, -0.0650634765625, 0.452880859375, 1.53125, -0.10833740234375, 0.50244140625, -1.2783203125, -0.68994140625, -0.78076171875, 0.2257080078125, -0.95751953125, 0.08642578125, 0.430908203125, -1.46484375, 0.02978515625, 0.50732421875, 0.70556640625, 0.7685546875, 0.388916015625, 0.43359375, 0.459228515625, -0.9169921875, -0.78125, -0.46923828125, -0.1270751953125, 0.29931640625, 0.253662109375, 0.34765625, 0.368896484375, -1.39453125, 1.482421875, -1.3046875, -0.3974609375, 0.57666015625, 0.195068359375, -1.3486328125, 0.155029296875, -0.181884765625, -0.0855712890625, -0.108154296875, -0.755859375, 0.55859375, 0.445556640625, -0.70654296875, -0.115966796875, 0.265625, -0.41064453125, 0.2196044921875, 0.345947265625, -0.2178955078125, 0.1497802734375, -0.64599609375, 0.28955078125, 0.0635986328125, 0.108154296875, 0.0999755859375, -1.4580078125, -0.0228118896484375, -0.86865234375, 1.2861328125, 0.2017822265625, 0.3984375, 0.7626953125, -0.06402587890625, -0.59326171875, 0.047393798828125, 0.666015625, 0.53857421875, 1.353515625, -1.4912109375, -0.1689453125, 0.6572265625, 0.459716796875, -0.5322265625, -0.430908203125, 0.61865234375, 0.3779296875, 0.65380859375, -0.271484375, 0.1356201171875, -0.07867431640625, -0.37890625, 0.7861328125, 0.81201171875, 0.5888671875, -0.5146484375, -0.45751953125, 0.005859375, 0.8251953125, -0.2398681640625, 0.66064453125, -0.689453125, -0.380126953125, -0.125, 1.0234375, 0.08270263671875, -0.05548095703125, 0.67919921875, 0.310546875, -0.364013671875, 0.853515625, 0.0193634033203125, 0.0521240234375, 0.5126953125, 0.9697265625, 0.8056640625, 0.470703125, -0.290771484375, -0.90966796875, 0.3310546875, 0.046173095703125, -0.72900390625, -1.849609375, 0.10137939453125, -1.1787109375, -0.2880859375, 1.3369140625, -0.047607421875, 0.1331787109375, 0.6298828125, -0.9033203125, 0.9697265625, -0.2171630859375, -0.37841796875, 0.58837890625, 0.65966796875, 0.82177734375, -0.07635498046875, -0.99462890625, -0.5703125, 0.426025390625, 0.5732421875, 0.78857421875, -0.74951171875, -0.873046875, -0.1627197265625, -0.845703125, -1.4951171875, 0.51220703125, 0.85302734375, 0.8544921875, 1.0791015625, -1.125, -0.360595703125, -1.298828125, -0.1513671875, 0.52685546875, 0.54833984375, -0.44580078125, -0.184814453125, 0.54443359375, -0.249755859375, 1.1962890625, 0.036102294921875, -0.1546630859375, 0.8818359375, 0.2305908203125, -0.043365478515625, -2.689453125, -0.583984375, -0.344482421875, 0.2900390625, 0.1865234375, -0.2462158203125, -0.424072265625, 0.16796875, 0.5126953125, 0.72119140625, -0.587890625, -0.15380859375, 0.6611328125, -0.127197265625, 0.1552734375, 0.53173828125, -0.98193359375, 0.90478515625, 0.69091796875, 0.6328125, 0.2607421875, -0.814453125, 0.13623046875, 0.30712890625, -1.0712890625, -0.783203125, -0.1339111328125, 0.4296875, 0.4765625, 0.1370849609375, -0.94921875, 0.351318359375, -1.38671875, 0.40576171875, 1.53515625, -0.7607421875, 0.28857421875, 0.6533203125, 0.04583740234375, -0.4873046875, -1.130859375, 0.28076171875, -0.1500244140625, 0.8828125, 0.64013671875, -0.413330078125, 0.07891845703125, -0.172119140625, 0.326904296875, -0.79833984375, 0.1895751953125, -0.47412109375, -0.091552734375, -0.01059722900390625, 0.87060546875, 0.73193359375, 0.58984375, -0.451416015625, -0.61376953125, 0.037200927734375, 1.015625, 0.045867919921875, -0.96630859375, 0.0797119140625, 0.78173828125, -0.5029296875, 1.2392578125, 0.44482421875, 0.134521484375, 0.478271484375, 0.47412109375, -0.1903076171875, 1.142578125, -0.2127685546875, 0.85693359375, -0.62255859375, 0.0121002197265625, -0.375732421875, 0.82373046875, 1.02734375, -0.58984375, 0.303955078125, -0.1558837890625, 0.513671875, 1.0771484375, 0.05902099609375, 0.77587890625, -0.91845703125, 0.53076171875, -0.455078125, 0.51025390625, 0.1729736328125, 1.7236328125, -0.452880859375, -0.43701171875, -0.83056640625, -1.00390625, 0.73583984375, 0.73486328125, 0.00540924072265625, 0.429443359375, 0.61767578125, -1.1962890625, -0.13720703125, 0.00424957275390625, -0.5078125, -0.861328125, -0.693359375, -0.18408203125, 0.64697265625, 1.4072265625, -0.1488037109375, -0.8642578125, -0.16357421875, 0.8251953125, 1.0947265625, -0.377197265625, -0.82177734375, -0.83203125, 0.354736328125, -1.0498046875, -0.1981201171875, 0.90869140625, 0.260009765625, 0.1522216796875, -0.31591796875, -0.81396484375, -0.1280517578125, -0.30029296875, 0.31640625, -0.982421875, 0.57958984375, -1.3056640625, -0.734375, 0.257080078125, -0.488037109375, -0.84716796875, -0.119873046875, -0.87451171875, -0.44921875, 0.5703125, 0.32470703125, -0.17578125, 0.72412109375, -0.1942138671875, 0.125, 0.55517578125, 0.1265869140625, 0.427001953125, -0.41357421875, 1.1748046875, 0.5419921875, -0.00922393798828125, -0.7236328125, 0.1744384765625, 0.11090087890625, -0.150390625, 0.13232421875, 0.07672119140625, 0.6240234375, -0.45556640625, -0.92578125, 0.6826171875, 0.52685546875, -0.03472900390625, -0.435546875, 0.3681640625, 0.1368408203125, -0.489013671875, 0.61328125, 0.326171875, -0.09808349609375, 0.59814453125, -1.1435546875, 0.2222900390625, -0.380615234375, -0.69287109375, 0.7900390625, -0.505859375, 0.1591796875, -1.345703125, -0.0013513565063476562, -0.1920166015625, 0.25634765625, 0.35595703125, 0.2457275390625, -0.0712890625, -0.83349609375, 0.0183258056640625, 0.349365234375, 1.1279296875, 0.232666015625, -1.41015625, -0.13232421875, -0.0428466796875, 0.5009765625, 0.30322265625, -0.52880859375, 0.390625, -1.2744140625, -0.30859375, -0.155029296875, -0.30126953125, 1.107421875, 0.599609375, 0.10870361328125, 0.56884765625, -0.57666015625, -0.157958984375, 0.07568359375, -1.2998046875, 0.75, -0.163818359375, 0.646484375, 0.74755859375, -1.1279296875, 0.2315673828125, -0.86669921875, 0.58203125, 0.056732177734375, -0.84765625, -0.35107421875, -0.58154296875, 0.6923828125, 0.82470703125, -0.5703125, -0.5478515625, -0.7255859375, -0.77294921875, -0.5537109375, -0.12939453125, 0.68359375, -0.11639404296875, -0.62744140625, -0.2132568359375, 0.469970703125, 0.163818359375, -0.46044921875, 0.17529296875, 0.65869140625, 1.251953125, -0.24853515625, 0.5849609375, 0.1800537109375, 0.76708984375, -0.479736328125, -0.1439208984375, -0.072998046875, -0.264404296875, 0.93359375, 0.53466796875, 0.2266845703125, 0.431640625, 0.3115234375, -0.98046875, 0.11785888671875, -0.95556640625, 0.40576171875, -0.39404296875, -0.01512908935546875, 0.2783203125, 0.265869140625, -0.759765625, 0.11376953125, 0.0338134765625, -0.1441650390625, 0.5458984375, -0.10308837890625, 0.009521484375, -0.595703125, -0.53662109375, -0.1832275390625, -1.455078125, -0.59423828125, 0.60009765625, 1.1171875, 0.404296875, -1.0458984375, 0.282958984375, -0.027069091796875, -0.1077880859375, -0.3818359375, 1.021484375, -0.407958984375, 0.27392578125, -0.339111328125, -0.234375, 0.2392578125, 0.3291015625, -0.164306640625, -0.5380859375, -0.94091796875, -1.3544921875, 0.95654296875, -0.26611328125, -1.232421875, -0.63525390625, -0.2734375, -1.365234375, 1.88671875, 0.486328125, 0.483154296875, -1.1953125, -1.060546875, -0.74365234375, -0.9990234375, 0.308837890625, 0.5146484375, 1.3740234375, 0.50390625, -0.3369140625, 0.338134765625, 0.223388671875, -1.0400390625, 0.2247314453125, -0.317138671875, -1.1923828125, -0.94287109375, 0.365234375, 1.2333984375, 0.7744140625, -1.1796875, -0.1683349609375, -0.1885986328125, 0.89208984375, -0.80810546875, -0.065673828125, -1.0771484375, -0.158935546875, 0.096435546875, 0.287109375, 0.423095703125, -0.300537109375, -0.79638671875, -0.1754150390625, -0.395263671875, -1.31640625, 0.5830078125, -0.337890625, -0.336669921875, -0.281005859375, -0.44921875, 0.74267578125, -0.380126953125, 0.21240234375, -0.24267578125, -0.13818359375, 0.8759765625, 0.6767578125, -0.0968017578125, -0.448486328125, 0.42041015625, 1.419921875, -0.40380859375, -1.73828125, -0.693359375, 0.07080078125, 0.64697265625, -0.9521484375, -0.2020263671875, 0.0933837890625, -0.1656494140625, 0.306396484375, -0.75341796875, -0.490234375, 0.08349609375, 0.69189453125, -0.49072265625, -0.798828125, -0.27294921875, -0.1876220703125, 0.115234375, 0.92919921875, -0.043487548828125, -1.0146484375, 0.333984375, -0.2105712890625, 0.25634765625, 0.495361328125, 0.2293701171875, 0.15966796875, 0.828125, -1.0849609375, -0.2039794921875, 1.087890625, -0.10333251953125, -0.67431640625, 0.2744140625, 1.9658203125, 0.31005859375, -0.75390625, -0.039459228515625, -0.31884765625, 0.166259765625, -0.74658203125, -0.7861328125, -0.34912109375, 0.08538818359375, 0.86376953125, 0.6611328125, 0.2037353515625, -0.67578125, 0.1783447265625, -0.98291015625, -0.00812530517578125, 0.521484375, 0.30908203125, -0.5498046875, 0.09832763671875, 1.009765625, -0.4384765625, -0.1683349609375, 0.486572265625, -0.85400390625, -0.414794921875, -0.89794921875, 0.49169921875, -1.619140625, 1.4638671875, -1.2529296875, 0.56201171875, -0.4375, 0.08160400390625, -0.048309326171875, -0.3173828125, -0.54833984375, -0.89892578125, -0.65576171875, -1.2578125, -0.248291015625, 0.0721435546875, 0.1400146484375, 0.44970703125, -0.634765625, -0.2078857421875, -0.5498046875, 0.132568359375, 0.90478515625, 1.1533203125, 0.37060546875, -0.32373046875, 0.03167724609375, 0.59375, 0.06842041015625, -0.08636474609375, -0.0156707763671875, 0.9873046875, -0.25830078125, 0.11383056640625, -0.487548828125, -1.205078125, 0.79296875, 0.56201171875, -0.66064453125, 0.82666015625, 0.83544921875, -1.080078125, -0.0640869140625, 0.06640625, -0.486328125, 0.260986328125, -0.51123046875, 0.320068359375, 0.9111328125, 0.315673828125, 0.9560546875, 0.318359375, 0.09173583984375, -0.1619873046875, 0.446533203125, -0.759765625, 0.5908203125, -0.640625, -1.244140625, -1.2939453125, -0.595703125, -0.433837890625, 0.486083984375, -0.9697265625, 0.170166015625, -1.099609375, -1.0166015625, -0.63232421875, -0.80908203125, -0.490234375, -0.364501953125, -0.52294921875, 0.8203125, 0.2357177734375, -0.357421875, -1.3193359375, 0.387451171875, 0.541015625, -2.033203125, -0.97412109375, -0.77392578125, -0.420654296875, -1.79296875, 1.2587890625, -1.2216796875, 0.187744140625, 0.72998046875, -0.71533203125, 0.43603515625, -1.0908203125, 0.51708984375, -0.73193359375, 0.4794921875, -1.103515625, 0.1309814453125, 0.09124755859375, -1.064453125, -0.51025390625, -0.08941650390625, 0.329345703125, -0.58642578125, -0.91796875, 0.67919921875, 0.31396484375, -0.1612548828125, -0.1859130859375, -0.404296875, -0.24658203125, 0.203369140625, -0.50830078125, 0.13720703125, -0.50146484375, 1.1513671875, 1.4169921875, 0.78369140625, 0.76708984375, 0.73095703125, -0.81494140625, -0.1064453125, 0.3291015625, 1.4775390625, 0.5634765625, -0.2254638671875, -0.3603515625, -1.267578125, 0.384521484375, 0.48828125, 0.277099609375, 0.387939453125, 0.748046875, -1.189453125, 0.62451171875, -0.62841796875, -0.1746826171875, -0.297607421875, 1.064453125, -0.477294921875, -0.41455078125, 0.0986328125, -0.576171875, -0.351318359375, 0.4150390625, -0.73681640625, -1.5615234375, -0.451171875, -0.35205078125, -0.1419677734375, 0.896484375, 0.414794921875, -0.297607421875, -0.68408203125, 0.45556640625, 0.09417724609375, -0.0908203125, 0.1820068359375, 0.43603515625, -0.11163330078125, 0.71142578125, 0.06622314453125, -1.3154296875, -1.0576171875, 0.427001953125, 0.15185546875, 0.94775390625, -0.421875, -11.296875, -0.181884765625, 0.14990234375, -0.175048828125, -0.385009765625, 0.466796875, -0.129638671875, 0.01186370849609375, -0.24951171875, 0.003673553466796875, 0.3486328125, -0.365966796875, -0.276123046875, -0.83642578125, 0.58935546875, -0.400390625, 0.09503173828125, -0.36572265625, 0.72607421875, -0.72509765625, -0.24951171875, 0.055572509765625, -0.5078125, -0.47607421875, -0.92041015625, 1.5048828125, -0.298583984375, 0.384765625, -0.5546875, 1.4296875, 0.054656982421875, 0.1065673828125, -1.09765625, 0.91455078125, 0.89013671875, 0.1812744140625, 0.09710693359375, 0.0253143310546875, 0.453857421875, -0.16259765625, 1.015625, 0.276611328125, -1.017578125, 1.4345703125, 0.370849609375, -0.1756591796875, -0.265380859375, 0.0030975341796875, 0.0095977783203125, -0.69384765625, 0.41943359375, -0.2083740234375, 0.266357421875, 0.271728515625, 0.0021991729736328125, -0.1768798828125, 0.09423828125, 0.300537109375, 0.184814453125, -0.48681640625, -0.09613037109375, 0.0408935546875, 0.1363525390625, -0.264892578125, 1.1796875, -0.673828125, 0.2276611328125, 0.164306640625, 0.97216796875, -0.6962890625, -0.252685546875, -0.61181640625, 0.5166015625, -1.283203125, -0.219970703125, 1.2822265625, 0.53759765625, -0.272705078125, -0.56298828125, -0.12481689453125, -0.247802734375, 0.29248046875]]
```

### 管理された埋め込みとGTEを使用してベクトル検索インデックスを作成する

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-data-prep-3.png?raw=true" style="float: right; width: 600px; margin-left: 10px">

Databricksは、管理された埋め込みを使用して自動的に埋め込みを計算します。これは、Databricksを使って始めるための簡単なモードです。

ベクトル検索インデックスは、埋め込みを提供する**ベクトル検索エンドポイント**（ベクトル検索APIエンドポイントと考えることができます）を使用します。

複数のインデックスは同じエンドポイントを使用できます。

まず、1つ作成してみましょう。

```py
from databricks.vector_search.client import VectorSearchClient
vsc = VectorSearchClient()

if not endpoint_exists(vsc, VECTOR_SEARCH_ENDPOINT_NAME):
    vsc.create_endpoint(name=VECTOR_SEARCH_ENDPOINT_NAME, endpoint_type="STANDARD")

wait_for_vs_endpoint_to_be_ready(vsc, VECTOR_SEARCH_ENDPOINT_NAME)
print(f"Endpoint named {VECTOR_SEARCH_ENDPOINT_NAME} is ready.")
```

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/index_creation.gif?raw=true" width="600px" style="float: right">

ベクトル検索エンドポイント UIでエンドポイントを表示できます。エンドポイント名をクリックして、エンドポイントで提供されるすべてのインデックスを表示できます。

### ベクトル検索インデックスの作成

Databricksにインデックスの作成を依頼するだけです。

管理された埋め込みインデックスなので、テキスト列と埋め込み基盤モデル（`GTE`）を指定するだけです。Databricksが自動的に埋め込みを計算します。

これはAPIを使用するか、Unityカタログエクスプローラメニューで数回のクリックで行うことができます。

```py
from databricks.sdk import WorkspaceClient
import databricks.sdk.service.catalog as c

#The table we'd like to index
source_table_fullname = f"{catalog}.{db}.databricks_documentation"
# Where we want to store our index
vs_index_fullname = f"{catalog}.{db}.databricks_documentation_vs_index"

VECTOR_SEARCH_ENDPOINT_NAME = "one-env-shared-endpoint-14"

if not index_exists(vsc, VECTOR_SEARCH_ENDPOINT_NAME, vs_index_fullname):
  print(f"Creating index {vs_index_fullname} on endpoint {VECTOR_SEARCH_ENDPOINT_NAME}...")
  vsc.create_delta_sync_index(
    endpoint_name=VECTOR_SEARCH_ENDPOINT_NAME,
    index_name=vs_index_fullname,
    source_table_name=source_table_fullname,
    pipeline_type="TRIGGERED",
    primary_key="id",
    embedding_source_column='content', #The column containing our text
    embedding_model_endpoint_name='databricks-gte-large-en' #The embedding endpoint used to create the embeddings
  )
  #Let's wait for the index to be ready and all our embeddings to be created and indexed
  wait_for_index_to_be_ready(vsc, VECTOR_SEARCH_ENDPOINT_NAME, vs_index_fullname)
else:
  #Trigger a sync to update our vs content with the new data saved in the table
  wait_for_index_to_be_ready(vsc, VECTOR_SEARCH_ENDPOINT_NAME, vs_index_fullname)
  vsc.get_index(VECTOR_SEARCH_ENDPOINT_NAME, vs_index_fullname).sync()

print(f"index {vs_index_fullname} on table {source_table_fullname} is ready")
```

## 類似コンテンツの検索

これで完了です。Databricksは自動的にDelta Liveテーブルの新しいエントリをキャプチャして同期します。

データセットのサイズやモデルのサイズによっては、インデックスの作成に数秒かかる場合があります。

さあ、試してみて類似コンテンツを検索しましょう。

:::note info
**注意**
`similarity_search`は`filters`パラメータもサポートしています。これはRAGシステムにセキュリティレイヤーを追加するのに役立ちます。ユーザーの設定に基づいて特定の部門でフィルタリングするなど、特定のコンテンツを除外することができます。
:::

```py
import mlflow.deployments
deploy_client = mlflow.deployments.get_deploy_client("databricks")

question = "How can I track billing usage on my workspaces?"

results = vsc.get_index(VECTOR_SEARCH_ENDPOINT_NAME, vs_index_fullname).similarity_search(
  query_text=question,
  columns=["url", "content"],
  num_results=1)
docs = results.get('result', {}).get('data_array', [])
docs
```
```
[['https://docs.databricks.com/en/lakehouse-monitoring/expense.html',
  'View usage from the billing portal\nYou can also check Lakehouse Monitoring expenses using the billing portal.  \nLog in to the Databricks account console.  \nIn the sidebar, click the Usage icon.  \nOn the Usage page, select By tags.  \nIn the first drop-down menu, select LakehouseMonitoring as the tag key.  \nIn the second drop-down menu, select true as the tag value. After you do this, true appears in the UI as shown in the diagram, and the second drop-down menu shows LakehouseMonitoring(1) to indicate that one tag key is selected.',
  0.003093197]]
```

## 次のステップ: DBRXを使用してRAGでチャットボットモデルをデプロイする

Databricks Lakehouse AIを使用してドキュメントを簡単に取り込み、準備し、わずか数行のコードと設定でその上にVector Searchインデックスをデプロイする方法を見てきました。

これにより、データプロジェクトが簡素化され、加速されるため、次のステップに集中できます: プロンプトの拡張を行ったリアルタイムのチャットボットエンドポイントの作成とデプロイ。

`02-Deploy-RAG-Chatbot-Model`ノートブックを開いて、チャットボットエンドポイントを作成してデプロイしてください。

# 2/ Retrieval Augmented Generation (RAG)とDBRX Instructによるチャットbotの構築

`02-Deploy-RAG-Chatbot-Model`ノートブックを実行していきます。

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/llm-rag-managed-flow-2.png?raw=true" style="float: right; margin-left: 10px"  width="900px;">

現在、Vector Search Indexが準備できた状況です！

では、RAGを用いた新しいモデルサービングエンドポイントを作成・展開しましょう。

以下のフローになります：

- ユーザーが質問を投げる
- 質問はサーバーレスChatbot RAGエンドポイントに送信
- エンドポイントは埋め込みを計算し、Vector Search Indexを活用して質問に類似したドキュメントを検索します
- エンドポイントはドキュメントを強化したプロンプトを作成します
- プロンプトはDBRX Instruct Foundation Model Servingエンドポイントに送信されます
- 結果をユーザーに表示します！

:::note info
**注意**
RAGはDatabricks Vector Searchを使用してドキュメントの検索を行います。このノートブックでは、検索インデックスが使用可能な状態であることを前提としています。前の`01-Data-Preparation-and-Index`ノートブックを実行していることを確認してください。
:::

```py
%pip install --quiet -U databricks-agents mlflow-skinny mlflow mlflow[gateway] langchain==0.2.1 langchain_core==0.2.5 langchain_community==0.2.4 databricks-vectorsearch databricks-sdk==0.23.0
dbutils.library.restartPython()
```
```py
%run ../_resources/00-init $reset_all_data=false
```

### チェーンの構築

この例では、langchainの基本的な理解が既にあることを前提としています。一歩ずつ進めたい場合は前のノートブックをチェックしてください！

```py
rag_chain_config = {
    "databricks_resources": {
        "llm_endpoint_name": "databricks-dbrx-instruct",
        "vector_search_endpoint_name": VECTOR_SEARCH_ENDPOINT_NAME,
    },
    "input_example": {
        "messages": [{"content": "Sample user question", "role": "user"}]
    },
    "llm_config": {
        "llm_parameters": {"max_tokens": 1500, "temperature": 0.01},
        "llm_prompt_template": "You are a trusted AI assistant that helps answer questions based only on the provided information. If you do not know the answer to a question, you truthfully say you do not know. Here is the history of the current conversation you are having with your user: {chat_history}. And here is some context which may or may not help you answer the following question: {context}.  Answer directly, do not repeat the question, do not start with something like: the answer to the question, do not add AI in front of your answer, do not say: here is the answer, do not mention the context or the question. Based on this context, answer this question: {question}",
        "llm_prompt_template_variables": ["context", "chat_history", "question"],
    },
    "retriever_config": {
        "chunk_template": "Passage: {chunk_text}\n",
        "data_pipeline_tag": "poc",
        "parameters": {"k": 5, "query_type": "ann"},
        "schema": {"chunk_text": "content", "document_uri": "url", "primary_key": "id"},
        "vector_search_index": f"{catalog}.{db}.databricks_documentation_vs_index",
    },
}
try:
    with open('rag_chain_config.yaml', 'w') as f:
        yaml.dump(rag_chain_config, f)
except:
    print('pass to work on build job')
model_config = mlflow.models.ModelConfig(development_config='rag_chain_config.yaml')
```

```py
%%writefile chain.py
import os
import mlflow
from operator import itemgetter
from databricks.vector_search.client import VectorSearchClient
from langchain_community.chat_models import ChatDatabricks
from langchain_community.vectorstores import DatabricksVectorSearch
from langchain_core.runnables import RunnableLambda
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.runnables import RunnablePassthrough

## Enable MLflow Tracing
mlflow.langchain.autolog()

# Return the string contents of the most recent message from the user
def extract_user_query_string(chat_messages_array):
    return chat_messages_array[-1]["content"]

def extract_previous_messages(chat_messages_array):
    messages = "\n"
    for msg in chat_messages_array[:-1]:
        messages += (msg["role"] + ": " + msg["content"] + "\n")
    return messages

def combine_all_messages_for_vector_search(chat_messages_array):
    return extract_previous_messages(chat_messages_array) + extract_user_query_string(chat_messages_array)

#Get the conf from the local conf file
model_config = mlflow.models.ModelConfig(development_config='rag_chain_config.yaml')

databricks_resources = model_config.get("databricks_resources")
retriever_config = model_config.get("retriever_config")
llm_config = model_config.get("llm_config")

# Connect to the Vector Search Index
vs_client = VectorSearchClient(disable_notice=True)
vs_index = vs_client.get_index(
    endpoint_name=databricks_resources.get("vector_search_endpoint_name"),
    index_name=retriever_config.get("vector_search_index"),
)
vector_search_schema = retriever_config.get("schema")

# Turn the Vector Search index into a LangChain retriever
vector_search_as_retriever = DatabricksVectorSearch(
    vs_index,
    text_column=vector_search_schema.get("chunk_text"),
    columns=[
        vector_search_schema.get("primary_key"),
        vector_search_schema.get("chunk_text"),
        vector_search_schema.get("document_uri"),
    ],
).as_retriever(search_kwargs=retriever_config.get("parameters"))

# Required to:
# 1. Enable the RAG Studio Review App to properly display retrieved chunks
# 2. Enable evaluation suite to measure the retriever
mlflow.models.set_retriever_schema(
    primary_key=vector_search_schema.get("primary_key"),
    text_column=vector_search_schema.get("chunk_text"),
    doc_uri=vector_search_schema.get("document_uri")
)

# Method to format the docs returned by the retriever into the prompt
def format_context(docs):
    chunk_template = retriever_config.get("chunk_template")
    chunk_contents = [
        chunk_template.format(
            chunk_text=d.page_content,
        )
        for d in docs
    ]
    return "".join(chunk_contents)

# Prompt Template for generation
prompt = PromptTemplate(
    template=llm_config.get("llm_prompt_template"),
    input_variables=llm_config.get("llm_prompt_template_variables"),
)

# FM for generation
model = ChatDatabricks(
    endpoint=databricks_resources.get("llm_endpoint_name"),
    extra_params=llm_config.get("llm_parameters"),
)

# RAG Chain
chain = (
    {
        "question": itemgetter("messages") | RunnableLambda(extract_user_query_string),
        "context": itemgetter("messages")
        | RunnableLambda(combine_all_messages_for_vector_search)
        | vector_search_as_retriever
        | RunnableLambda(format_context),
        "chat_history": itemgetter("messages") | RunnableLambda(extract_previous_messages)
    }
    | prompt
    | model
    | StrOutputParser()
)

# Tell MLflow logging where to find your chain.
mlflow.models.set_model(model=chain)

# COMMAND ----------

# chain.invoke(model_config.get("input_example"))
```

```py
# Log the model to MLflow
with mlflow.start_run(run_name=f"dbdemos_rag_quickstart"):
    logged_chain_info = mlflow.langchain.log_model(
        lc_model=os.path.join(os.getcwd(), 'chain.py'),  # Chain code file e.g., /path/to/the/chain.py 
        model_config='rag_chain_config.yaml',  # Chain configuration 
        artifact_path="chain",  # Required by MLflow
        input_example=model_config.get("input_example"),  # Save the chain's input schema.  MLflow will execute the chain before logging & capture it's output schema.
    )

# Test the chain locally
chain = mlflow.langchain.load_model(logged_chain_info.model_uri)
chain.invoke(model_config.get("input_example"))
```

## RAGアプリケーションをデプロイして、外部の専門ユーザーに公開しましょう

```py
from databricks import agents
MODEL_NAME = "dbdemos_rag_demo"
MODEL_NAME_FQN = f"{catalog}.{db}.{MODEL_NAME}"
```
```py
instructions_to_reviewer = f"""### Instructions for Testing the our Databricks Documentation Chatbot assistant

Your inputs are invaluable for the development team. By providing detailed feedback and corrections, you help us fix issues and improve the overall quality of the application. We rely on your expertise to identify any gaps or areas needing enhancement.

1. **Variety of Questions**:
   - Please try a wide range of questions that you anticipate the end users of the application will ask. This helps us ensure the application can handle the expected queries effectively.

2. **Feedback on Answers**:
   - After asking each question, use the feedback widgets provided to review the answer given by the application.
   - If you think the answer is incorrect or could be improved, please use "Edit Answer" to correct it. Your corrections will enable our team to refine the application's accuracy.

3. **Review of Returned Documents**:
   - Carefully review each document that the system returns in response to your question.
   - Use the thumbs up/down feature to indicate whether the document was relevant to the question asked. A thumbs up signifies relevance, while a thumbs down indicates the document was not useful.

Thank you for your time and effort in testing our assistant. Your contributions are essential to delivering a high-quality product to our end users."""

# Register the chain to UC
uc_registered_model_info = mlflow.register_model(model_uri=logged_chain_info.model_uri, name=MODEL_NAME_FQN)

# Deploy to enable the Review APP and create an API endpoint
deployment_info = agents.deploy(model_name=MODEL_NAME_FQN, model_version=uc_registered_model_info.version, scale_to_zero=True)

# Add the user-facing instructions to the Review App
agents.set_review_instructions(MODEL_NAME_FQN, instructions_to_reviewer)

wait_for_model_serving_endpoint_to_be_ready(deployment_info.endpoint_name)
```

しばらくすると、モデルサービングエンドポイントが稼働します。

![Screenshot 2024-10-15 at 15.08.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/169f86bc-8aa7-ddd9-35d1-27862e6adadc.png)


## Mosaic AIエージェント評価アプリへの関係者へのアクセス権付与

さて、関係者にReview Appの使用権限を付与しましょう。アクセスを簡素化するため、関係者はDatabricksアカウントを持つ必要はありません。

```py
user_list = ["takaaki.yayoi@databricks.com"]
# Set the permissions.
agents.set_permissions(model_name=MODEL_NAME_FQN, users=user_list, permission_level=agents.PermissionLevel.CAN_QUERY)

print(f"Share this URL with your stakeholders: {deployment_info.review_app_url}")
```
```
Share this URL with your stakeholders: https://xxxxxx.cloud.databricks.com/ml/review/takaakiyayoi_catalog.simple_rag.dbdemos_rag_demo/1
```

## レビューアプリ名の検索

このノートブックの状態を失った場合、デプロイされたチャットボットのURLを見つける必要がある場合は、次のコマンドを使用してリストを表示できます：

```py
active_deployments = agents.list_deployments()
active_deployment = next((item for item in active_deployments if item.model_name == MODEL_NAME_FQN), None)
if active_deployment:
  print(f"Review App URL: {active_deployment.review_app_url}")
```
```
Review App URL: https://xxxxxx.cloud.databricks.com/ml/review/takaakiyayoi_catalog.simple_rag.dbdemos_rag_demo/1
```

## おめでとうございます！最初の生成AIを用いたRAGモデルをデプロイしました！

これで、Mosaic AIを活用して内部のナレッジベースに同じロジックをデプロイする準備が整いました。

Mosaic AIは、生成AI展開の課題を解決するためにユニークな位置にあります：

- Databricksのエンジニアリング機能によるデータの取り込みと準備の簡素化
- 完全に管理されたインデックスを使用したベクトル検索の展開の加速
- Databricks DBRX Instruct基盤モデルエンドポイントの活用
- RAGの実行とQ&A機能の提供を行うリアルタイムモデルエンドポイントのデプロイ

# 3/ Databricks Apps を使用したフロントエンドアプリのデプロイ

`03-Deploy-Frontend-Lakehouse-App`を実行していきます。

Mosaic AI Agent 評価レビューアプリは、開発プロセス中にステークホルダーからのフィードバックを収集するために使用されます。

しかし、自分のフロントエンドアプリケーションをデプロイする必要があります！

Databricks Apps を活用して、最初のシンプルなチャットボットフロントエンドアプリを構築してデプロイしましょう。

<img src="https://github.com/databricks-demos/dbdemos-resources/blob/main/images/product/chatbot-rag/rag-frontend-app.png?raw=true" width="1200px">

```py
%pip install --quiet -U mlflow databricks-sdk==0.23.0
dbutils.library.restartPython()
```

```py
%run ../_resources/00-init $reset_all_data=false
```

### ヘルパーのロード

```py
%run ../_resources/02-lakehouse-app-helpers
```

## アプリケーション設定を追加

Databricks Appsでは、任意のPythonフレームワークを使用できます。この小さなデモでは、デモで使用されるモデルサービングエンドポイント名を含む小さな設定ファイルを作成し、`chatbot_app/app.yaml`ファイルに保存します。

```py
MODEL_NAME = "dbdemos_rag_demo"
endpoint_name = f'agents_{catalog}-{db}-{MODEL_NAME}'[:60]

# フロントエンドアプリケーションは、デプロイしたモデルのエンドポイントにアクセスします。
# dbdemosではカタログとデータベースを変更できるため、適切なエンドポイント名でアプリをデプロイするようにします。
yaml_app_config = {"command": ["uvicorn", "main:app", "--workers", "1"],
                    "env": [{"name": "MODEL_SERVING_ENDPOINT", "value": endpoint_name}]
                  }
try:
    with open('chatbot_app/app.yaml', 'w') as f:
        yaml.dump(yaml_app_config, f)
except:
    print('pass to work on build job')
```

## Gradioを用いたチャットボットアプリケーションを作成しましょう

```py
%%writefile chatbot_app/main.py
from fastapi import FastAPI
import gradio as gr
import os
from gradio.themes.utils import sizes
from databricks.sdk import WorkspaceClient
from databricks.sdk.service.serving import ChatMessage, ChatMessageRole

app = FastAPI()

# アプリを開発すする際、適切な権限で持ってあなたのエンドポイントが直接セットアップされます
w = WorkspaceClient()
available_endpoints = [x.name for x in w.serving_endpoints.list()]


def respond(message, history, dropdown):
    if len(message.strip()) == 0:
        return "ERROR the question should not be empty"
    try:
        messages = []
        if history:
            for human, assistant in history:
                messages.append(ChatMessage(content=human, role=ChatMessageRole.USER))
                messages.append(
                    ChatMessage(content=assistant, role=ChatMessageRole.ASSISTANT)
                )
        messages.append(ChatMessage(content=message, role=ChatMessageRole.USER))
        response = w.serving_endpoints.query(
            name=dropdown,
            messages=messages,
            temperature=1.0,
            stream=False,
        )
    except Exception as error:
        return f"ERROR requesting endpoint {dropdown}: {error}"
    return response.choices[0].message.content


theme = gr.themes.Soft(
    text_size=sizes.text_sm,
    radius_size=sizes.radius_sm,
    spacing_size=sizes.spacing_sm,
)

demo = gr.ChatInterface(
    respond,
    chatbot=gr.Chatbot(
        show_label=False, container=False, show_copy_button=True, bubble_full_width=True
    ),
    textbox=gr.Textbox(placeholder="What is RAG?", container=False, scale=7),
    title="Databricks App RAG demo - Chat with your Databricks assistant",
    description="This chatbot is a demo example for the dbdemos llm chatbot. <br>It answers with the help of Databricks Documentation saved in a Knowledge database.<br/>This content is provided as a LLM RAG educational example, without support. It is using DBRX, can hallucinate and should not be used as production content.<br>Please review our dbdemos license and terms for more details.",
    examples=[
        ["What is DBRX?"],
        ["How can I start a Databricks cluster?"],
        ["What is a Databricks Cluster Policy?"],
        ["How can I track billing usage on my workspaces?"],
    ],
    cache_examples=False,
    theme=theme,
    retry_btn=None,
    undo_btn=None,
    clear_btn="Clear",
    additional_inputs=gr.Dropdown(
        choices=available_endpoints,
        value=os.environ["MODEL_SERVING_ENDPOINT"],
        label="Serving Endpoint",
    ),
    additional_inputs_accordion="Settings",
)

demo.queue(default_concurrency_limit=100)
app = gr.mount_gradio_app(app, demo, path="/")
```

## アプリケーションのデプロイ

私たちのアプリケーションは、`chatbot_app`フォルダー内にある2つのファイルで構成されています：
- `main.py`は私たちのPythonコードを含んでいます
- `app.yaml`は私たちの設定を含んでいます

すべての作業が完了したら、APIを呼び出して新しいアプリを作成し、`chatbot_app`パスを使用してデプロイするだけです：

```py
app_name = "dbdemos-rag-chatbot-app"

# ヘルパーは resources/02-lakehouse-app-helpers ノートブックにあります
helper = LakehouseAppHelper()
app_details = helper.create(app_name, app_description="Your Databricks assistant")
```

Databricksアプリが作成されます。

![Screenshot 2024-10-15 at 15.17.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/a8674c48-0b7b-fd1c-fc85-0bce0d85a8e0.png)

Databricks Appには、自動プロビジョニングされたサービスプリンシパルが付属しています。デプロイする前に、このサービスプリンシパルにモデルエンドポイントへのアクセス権を付与しましょう...

```py
helper.add_dependencies(
    app_name=app_name,
    dependencies=[
        {
            "name": "rag-endpoint",
            "serving_endpoint": {
                "name": endpoint_name,
                "permission": "CAN_QUERY",
            },
        }
    ],
    overwrite=False # if False dependencies will be appended to existing ones
)
```

アプリのリソースとしてモデルサービングエンドポイントが追加されます。

![Screenshot 2024-10-15 at 15.18.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1801c3e4-a913-95da-89f4-9374302260b7.png)

```py
helper.deploy(app_name, os.path.join(os.getcwd(), 'chatbot_app'))
helper.details(app_name)
```

アプリのデプロイがスタートします。

![Screenshot 2024-10-15 at 15.19.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/fcb43abd-bc01-cb7e-1e96-f2eabb87c842.png)

## Databricksアプリが準備され、デプロイされました！

![Screenshot 2024-10-15 at 15.26.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/70819cc8-cba4-8a78-eee8-ede415af4676.png)


UIを開いて、チャットボットのリクエストを開始してください。

![Screenshot 2024-10-15 at 15.25.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/aceb0287-029d-845a-b104-fff34ccbfac2.png)


改善点として、チャットボットのUIを改善し、悪い回答をレビューして改善できるようにMosaic AI Quality Labsに送信することができます。

## 結論

Databricksはエンドツーエンドのプラットフォームを提供しています：
- エンドポイントの構築とデプロイ
- チャットボットのレビュー、分析、改善のための組み込みソリューション
- レイクハウスアプリでフロントエンドの生成AIアプリケーションをデプロイすることができます！

### はじめてのDatabricks

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

### Databricks無料トライアル

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