Closed6

LlamaIndexでRAPTORを試す

kun432kun432

https://twitter.com/llama_index/status/1765092767188045844

RAPTOR: Recursive Abstractive Processing for Tree-Organized Retrieval らしい。

https://arxiv.org/abs/2401.18059

まとめてもらいました。

https://chat.openai.com/g/g-pHG1jw9yX-luo-he-yang-yi-huomatuto

RAPTOR: 再帰的抽象化処理によるツリー構造を用いた検索

ひとことでまとめるとどんなものですか?

RAPTORは、文章のチャンクを再帰的にクラスタリングし要約する新しい手法で、異なるレベルの要約を持つツリーを構築します。このモデルは、長い文書や抽象レベルが異なる情報を効率的に扱うことができます。

先行研究と比較してどの点がすごいのですか?

従来の検索強化言語モデルと比較して、RAPTORは長い文書全体のコンテキストを理解し、異なるレベルの抽象化を通じて情報を統合する能力があります。これにより、複雑な多段階推論タスクで最先端の結果を達成しています。

技術や手法の重要な点はどこにありますか?

RAPTORは、文章のチャンクをクラスタリングし、それらを要約してツリー構造を構築するプロセスを再帰的に繰り返します。このツリーから情報を検索する際には、異なる抽象レベルの情報を統合することが可能です。

技術や手法はどのように有効だと判断されましたか?

制御実験では、RAPTORを用いた検索が、従来の検索強化言語モデルを使用した場合と比較して、複数のタスクで有意な改善を示しました。特に、質問応答タスクでは、従来の最高性能を20%向上させる結果が得られました。

何か議論や批判すべき点はありますか?

RAPTORの評価は特定のデータセットとタスクに限定されているため、その有効性を広範囲にわたる異なるタスクや条件で評価する必要があります。また、要約プロセスにおける微細な情報の損失や誤りの影響についてもさらなる検討が求められます。

次に読むべき論文・文献は?

  • 強化された検索機能を持つ言語モデルの最近の研究
  • 長い文書や複雑な情報を扱うためのツリー構造の使用に関する研究
  • テキスト要約技術の最新の進展と応用に関する研究

冒頭のツイートにもあるけど、論文内に書かれている図を見ると、


Figure 1:Tree construction process: RAPTOR recursively clusters chunks of text based on their vector embeddings and generates text summaries of those clusters, constructing a tree from the bottom up. Nodes clustered together are siblings; a parent node contains the text summary of that cluster.

チャンク分割してそのまま使うんじゃなくて、チャンクを一定のクラスタリングにまとめてサマリー化、それに対してベクトル検索して、クラスタに紐づいているチャンクをLLMに食わせるって感じっぽい。

チャンク分割することで大きなコンテキストが失われて、小さなコンテキストかつ単なるテキスト文字列になってしまうのを、中間レイヤー挟むことで緩和するっていうイメージを持った。

kun432kun432

RAPTORのLlamaIndex実装は、LlamaPackの形で利用できる。RaptorPackがそれ。

https://llamahub.ai/l/llama-packs/llama-index-packs-raptor

notebookも公開されているので、こちらをやってみる。

https://github.com/run-llama/llama_index/tree/main/llama-index-packs/llama-index-packs-raptor/examples/raptor.ipynb

今回は手元のサーバでJupyter-labを使った。

パッケージインストール。Arize Phonixでトレーシングしつつ確認する予定。

!pip install -qq llama-index llama-index-callbacks-arize-phoenix python-dotenv

APIキーの設定。

from dotenv import load_dotenv

load_dotenv()

notebookで非同期を行う場合のおまじない。

import nest_asyncio

nest_asyncio.apply()

Arize Phonixでトレーシング有効。

import phoenix as px
from llama_index.core import set_global_handler

px.launch_app()
set_global_handler("arize_phoenix")

で、RaptorPackをインストールしたいのだけど、

  • サマリのプロンプトが英語になっててそのままだとサマリが英語になってしまう。RaptorPackをダウンロードしてコードを直接修正する
  • LlamaPackのダウンロードは、llamaindex-clillama_index.core.llama_pack.download_llama_packを使う必要があるが、llamaIndex側の不具合でRaptorPackがダウンロードできない
    • 英語のままで修正せずに使うならばpip install llama-index-packs-raptorでOK。
    • issueはもう修正・マージしてもらったけど、v0.10.16のパッケージには反映されていない。次のパッケージには反映されるのではなかろうかと思う。

ということでちょっと今だけのworkaround。

import json

# llamaIndexのcoreパッケージに含まれているmappings.jsonを修正する。パスは環境により適宜修正
mapping_json = "./.venv/lib/python3.11/site-packages/llama_index/core/command_line/mappings.json"

with open(mapping_json, 'r+') as f:
    mappings = json.load(f)
    mappings["RaptorPack"] = "llama_index.packs.raptor"
    f.seek(0)
    json.dump(mappings, f, indent=4)

RaptorPackをダウンロード

!llamaindex-cli download-llamapack RaptorPack --download-dir ./raptor_pack

RaptorPackに含まれるファイルの以下の部分がサマリー時のプロンプト。

https://github.com/run-llama/llama_index/blob/f916839e81ff8bd3006fe3bf4df3f59ba7f37da3/llama-index-packs/llama-index-packs-raptor/llama_index/packs/raptor/base.py#L35-L37

これを修正する。"in Japanese"を追加しておいた。

!sed -i -e 's/Summarize the provided text,/Summarize the provided text in Japanese,/' ./raptor_pack/llama_index/packs/raptor/base.py

では、Packを読み込み。download_llama_packは本来はllamaindex-cli download-llamapackと同じくPackをダウンロード・依存関係等を解決してインポートしてくれるものなので、そのまま実行するとさっきの修正が上書きされてしまう。refresh_cache=Falseにするとすでにダウンロード先パスにPackがあればダウンロードせずにインポートしてくれるだけになるっぽい。

from llama_index.core.llama_pack import download_llama_pack
RaptorPack = download_llama_pack("RaptorPack", "./raptor_pack", refresh_cache=False)

ではインデックスを作成していく。まず、ドキュメントを用意。以下を使用。

https://ja.wikipedia.org/wiki/オグリキャップ

from pathlib import Path
import requests

# Wikipediaからのデータ読み込み
wiki_titles = ["オグリキャップ"]
for title in wiki_titles:
    response = requests.get(
        "https://ja.wikipedia.org/w/api.php",
        params={
            "action": "query",
            "format": "json",
            "titles": title,
            "prop": "extracts",
            # 'exintro': True,
            "explaintext": True,
        },
    ).json()
    page = next(iter(response["query"]["pages"].values()))
    wiki_text = page["extract"]

    data_path = Path("data")
    if not data_path.exists():
        Path.mkdir(data_path)

    with open(data_path / f"{title}.txt", "w") as fp:
        fp.write(wiki_text)

こんな感じでテキストファイルが作成される。

これをDocumentに読み込む。

from llama_index.core import SimpleDirectoryReader

documents = SimpleDirectoryReader("data").load_data()

RaptorPackを初期化。

from llama_index.core.node_parser import SentenceSplitter
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.vector_stores.chroma import ChromaVectorStore
import chromadb

client = chromadb.PersistentClient(path="./raptor_db")
collection = client.get_or_create_collection("raptor")

vector_store = ChromaVectorStore(chroma_collection=collection)

raptor_pack = RaptorPack(
    documents,
    embed_model=OpenAIEmbedding(model="text-embedding-3-small"),  # クラスタのembeddingsに使用
    llm=OpenAI(model="gpt-3.5-turbo-0125", temperature=0.1),  # サマリの生成に使用
    vector_store=vector_store,  # ストレージの設定
    similarity_top_k=5,  # 各レイヤーごとのtop-k、または"collapsed"の場合は全体のtop-k
    mode="collapsed",  # モード設定のデフォルト値
    transformations=[
        SentenceSplitter(chunk_size=400, chunk_overlap=50)
    ],  # インデックスへの投入時にtransformationを適用
)

クラスタとサマリが作成される。

Generating embeddings for level 0.
Performing clustering for level 0.
Generating summaries for level 0 with 27 clusters.
Level 0 created summaries/clusters: 27
Generating embeddings for level 1.
Performing clustering for level 1.
Generating summaries for level 1 with 5 clusters.
Level 1 created summaries/clusters: 5
Generating embeddings for level 2.
Performing clustering for level 2.
Generating summaries for level 2 with 1 clusters.
Level 2 created summaries/clusters: 1

ざっくりどうなっているかをトレーシングで見ていく。

まずすべてのチャンクのEmbeddingsが生成される。

これを階層ごとにクラスタリングしていく。

まずlevel 0。ここが一番下の階層で、Embeddingsしたチャンクで類似しているものを集めてクラスタ化してサマリを生成する。当然上記にある通り、一番数が多い。

例えば、以下はオグリキャップの競争能力についての評価、という感じでクラスタ化されているように見える。

もう一つ。以下はオグリキャップの故障とその後の不振、といった感じ。

で、このlevel 0のクラスタをさらにEmbeddings生成、クラスタ化、サマリを生成しているのがlevel 1。

これに繰り返していって、最後がlevel2。

kun432kun432

ということでインデックスが作成されたので、retrievalがどのように動作するかを確認してみる。

RAPTORには検索に2つのモードがある

RAPTORでは、情報の検索において「tree traversal」と「collapsed tree」の2つの異なる戦略が導入されています。

  • Tree Traversalモードでは、RAPTORの木構造を層ごとに横断していき、各レベルで最も関連性の高いノードを選択し、刈り取ります。この方法では、木を上から下へと移動し、各ステップで最適なノードを選択することで、関連性の高い情報に迅速にアクセスできるように設計されています。

  • Collapsed Treeモードでは、木の全てのノードを一括で評価し、最も関連性の高いものを見つけ出します。この方法では、木の全層を通じてノードを一つの大きなプールとして扱い、その中から最も情報に富んだノードを選び出します。

これら2つのモードは、RAPTORが様々な文脈やクエリーに対して柔軟に対応できるようにするために設計されています。Tree Traversalは階層的な構造を利用して情報を絞り込みながら検索するのに対し、Collapsed Treeは全ノードから一度に最適な情報を抽出するアプローチを取ります​

それぞれの動きを見てみる。まず"collapsed"。

nodes = raptor_pack.run("オグリキャップの主な勝ち鞍は?", mode="collapsed")

formatted_nodes = [f"ID: {n.id_}\nScore: {n.get_score()}\n\n{n.get_content()[:100]}..." for n in nodes]
print("total nodes: ", len(formatted_nodes))
print()
print("\n----\n".join(formatted_nodes))
total nodes:  5

ID: ea8aa374-1c38-4a48-a001-513a9b07b5b2
Score: 0.46109331748201277

オグリキャップは競馬界で非常に有名な存在であり、多くの関係者から高い評価を受けていた。武豊や関口隆哉、瀬戸慎一郎などがオグリキャップの能力や勝利についてコメントしており、特に1993年のレースにおいて...
---
ID: 4d0733fb-576a-4141-8e3e-9a75ee6578b1
Score: 0.435802323887247

オグリキャップは競走馬として活躍し、種牡馬としても知られる。1991年に優駿スタリオンステーションに到着し、300人以上の出席者が歓迎セレモニーを行った。オグリキャップは中央競馬で成功を収め、重賞6連...
---
ID: 69bd9d92-017a-42e0-8030-4e6e70933023
Score: 0.4301157849256141

オグリキャップはGI競走初制覇を遂げ、有馬記念で優勝した芦毛馬であり、山口瞳は彼を史上最強の馬と評価した。1988年度のJRA賞最優秀4歳牡馬にも選ばれた。オグリキャップの調教助手である辻本は、タマモ...
---
ID: 046556dd-7eac-494a-95cf-5d8c1dff9bbb
Score: 0.4274001111614396

オグリキャップは競馬界で非常に人気のある競走馬であり、多くの競馬ファンに感動を与えた存在である。オグリキャップは地方出身の馬でありながら、中央競馬で活躍し、数々の名勝負を演じた。彼はクラシックに出走す...
---
ID: e71a0277-f7af-454e-ace8-f7dba8fe754c
Score: 0.4210392272834549

オグリキャップは1991年にJRA顕彰馬に選出された競走馬で、愛称は「オグリ」「芦毛の怪物」などと呼ばれていました。中央競馬時代にはスーパークリーク、イナリワンとともに「平成三強」として知られ、第二次...

次に"tree_traversal"

nodes = raptor_pack.run("オグリキャップの主な勝ち鞍は?", mode="tree_traversal")

formatted_nodes = [f"ID: {n.id_}\nScore: {n.get_score()}\n\n{n.get_content()[:100]}..." for n in nodes]
print("total nodes: ", len(formatted_nodes))
print()
print("\n---\n".join(formatted_nodes))

こちらの場合はコンソール出力を見ると、ツリー上にノードが辿られているのがわかる。

Retrieved parent IDs from level 2: ['4d0733fb-576a-4141-8e3e-9a75ee6578b1']
Retrieved 5 from parents at level 2.
Retrieved parent IDs from level 1: ['28b33c62-8a4c-4a28-bb55-aa7df48ed2b5', '2addd5d1-bd0b-43b7-9695-cfb1d4db99cd', '861f5223-43a4-4d80-9a9c-10b325c23dad', 'd1c77a4d-859c-45b5-bc69-e5f25d2fe434', '8c54f095-d902-47a8-a543-fed31d4e12c9']
Retrieved 23 from parents at level 1.
Retrieved parent IDs from level 0: ['ea8aa374-1c38-4a48-a001-513a9b07b5b2', '69bd9d92-017a-42e0-8030-4e6e70933023', '046556dd-7eac-494a-95cf-5d8c1dff9bbb', 'e71a0277-f7af-454e-ace8-f7dba8fe754c', '8e643712-a4fb-420f-a557-ef0e31ac6a52']
Retrieved 20 from parents at level 0.

なので返ってくる結果も多い。

total nodes:  20

ID: 704dea89-76c9-4519-8f54-78351f965d49
Score: 0.4061003933220813

一方でGIクラスを相手にした時のオグリキャップは抜け出すまでにモタつく面があるため多頭数のレースだとかなり不安が残る馬と分析し、「直線の入り口でスーッと行ける脚が欲しい」と要望していた。
河内の次に主...
---
ID: 9318fa0a-c8f2-493c-845c-22dd0c4cb47e
Score: 0.35362336027443797

武豊は1993年に同レースを振り返った際には「別に謙遜してるわけじゃなく、強い馬が走りやすいように走らせただけなんですよ。だから、勝っても驚きはしなかった。奇跡でも何でもないと思う」と語り、「あの馬の...
---
ID: a14ed8cd-f9ed-425b-8983-ebc879ee6c63
Score: 0.34543744901790124

武豊は自身が騎乗するまでのオグリキャップに対して「にくいほど強い存在でしたし、あこがれの存在でもありました」と述べ、初めてコンビを組んだ安田記念は「自分でも乗っていて、ビックリするというか、あきれるく...
---
ID: 3d1e399c-1188-493d-ad68-331539874ab4
Score: 0.3381281476280913

南井克巳は初めて騎乗した京都4歳特別についてこの時にも強いと感じたが、オールカマーで騎乗した際には「本当に強い馬だなと感じましたね。とにかく力が抜けていました」と回顧し、自身が騎乗したレースの中で最も...
---
ID: 7d0c264f-1716-43d7-b48e-760d9c236e02
Score: 0.2584424347901353

またライターの関口隆哉も、「レース展開、出走馬たちのレベル、当日の状態など、すべてのファクターがオグリキャップ有利に働いた」とし、瀬戸慎一郎は「2着、3着に入った馬が、幾度となくジリ脚に泣いたメジロラ...
---
ID: 18627be9-8cf7-44ef-b510-ecf277b14b43
Score: 0.38514294697883916

GI競走初制覇を達成し、芦毛馬初の有馬記念優勝馬となった。作家の山口瞳は有馬記念の結果を受けて、「タマモクロスは日本一の馬、オグリキャップは史上最強の馬だ」といい、オグリキャップを称えた(レースに関す...
---
ID: 432b5966-a1a6-436c-b9a4-969c92924460
Score: 0.35577066266551277

クインナルビーの子孫には他にアンドレアモン、キョウエイマーチなどの重賞勝ち馬がいる。


=== 血統表 ===

兄弟オグリローマン - 1994年桜花賞優勝馬
オグリイチバン - オグリキャップの...
---
ID: 317e4abd-f737-48e2-8e28-73369bbbdd2d
Score: 0.39311234156951486

また岡部幸雄は「ハイセイコーを超えるほど」であったとしている(ハイセイコー#人気(ハイセイコーブーム)も参照)。
オグリキャップが人気を得た要因についてライターの市丸博司は、「地方出身の三流血統馬が中...
---
ID: dc7fe5a5-6282-4fff-b12a-66a087e6cffa
Score: 0.3788986959974277

オグリキャップに乗ることができたのは、自分にとって大きな財産です」と述べている。
大川慶次郎は、フジテレビが放送した第35回有馬記念の最後の直線でメジロライアンの競走馬名を連呼したことから競馬ファンか...
---
ID: 8140f0af-300f-4290-b7af-c1e1ea5e9162
Score: 0.32789811547121434

斎藤修は、日本人が好む「田舎から裸一貫で出てきて都会で名をあげる」という立身出世物語に当てはまったことに加え、クラシックに出走することができないという挫折や、タマモクロス、イナリワン、スーパークリーク...
---
ID: 9f0a0f8f-e100-4019-8009-24bea0a40a58
Score: 0.314486659608286

=== 第二次競馬ブームとの関係 ===
オグリキャップの人気は、ほぼ同時期にデビューした騎手の武豊の人気、JRAのCMによるイメージ戦略、およびバブル景気との相乗効果によって競馬ブームを巻き起こした...
---
ID: f5f418af-a3b3-497e-aaf0-62861fb27683
Score: 0.3130876646351368

当時の状況について競馬評論家の石川ワタルは、「あの頃が日本の競馬全盛時代だったのではないか。今後二度と訪れることのないような至福の競馬黄金時代だったのではないか」と回顧している。
一方で須田鷹雄は、優...
---
ID: 2c54a96e-b3d3-472d-9a7b-859639a110c6
Score: 0.30174286290736313

一周忌となった2011年7月3日には、種牡馬時代を過ごした優駿SSに接する「優駿メモリアルパーク」に新たな銅像が設置された。


== 成績 ==


=== 競走成績 ===
下記の内容は、netk...
---
ID: 196d2840-f4bd-40a8-a788-19da2b1b1de0
Score: 0.30109599762408384

1991年、JRA顕彰馬に選出。愛称は「オグリ」「芦毛の怪物」など多数。
中央競馬時代はスーパークリーク、イナリワンの二頭とともに「平成三強」と総称され、自身と騎手である武豊の活躍を中心として起こった...
---
ID: d0705154-2d83-4696-926a-209259908257
Score: 0.2932855873035784

1994年に産駒がデビューし、JRA新種牡馬リーディングにおいては首位となったサンデーサイレンスに大きく水をあけられたものの、内国産種牡馬としては最上位となる6位にランクインし、アーニングインデックス...
---
ID: f64cfea1-c1ca-4872-9b4e-84ae92e1a3f5
Score: 0.35078669744698204

須田鷹雄「未来に語り継ぎたい名馬物語(3) 競馬ブームを牽引した絶対的エース オグリキャップとその時代」『優駿』2015年5月号、中央競馬ピーアール・センター、2015年、64-69頁。 
瀬戸慎一郎...
---
ID: a8213c7e-18d0-4269-a032-4a50e7285e3d
Score: 0.3234904816993487

ISBN 4584302553。 
渡辺敬一郎 編『星になった名馬たち』オークラ出版〈OAK MOOK 37 ウルトラブック 12〉、2000年。ISBN 4872785185。 
『競馬ボロボロ読本...
---
ID: a8bf5155-cf22-4b87-bf3a-f731c0460141
Score: 0.32261852519159373

ISBN 4931367291。 
文庫版あり(角川文庫、2000年)ISBN 4043542011
岡部幸雄『勝負勘』角川書店〈角川oneテーマ21〉、2006年。ISBN 4047100609。 ...
---
ID: 455a6bfe-a90c-4d85-be3b-3c2003c583d6
Score: 0.32130011724763596

「"芦毛の怪物"オグリキャップよ、永遠に」『優駿』2010年9月号、中央競馬ピーアール・センター、2010年、22-61頁。 
『ありがとうオグリキャップ』産業経済新聞社〈Gallop臨時増刊〉、20...
---
ID: 586ae44f-d3ed-40b5-b9b9-f6058294537b
Score: 0.30826075453275165

『創刊50周年記念 優駿増刊号 TURF』、日本中央競馬会、1991年。 


== 外部リンク ==
笠松競馬

競走馬成績と情報 netkeiba、スポーツナビ、KEIBA.GO.JP、JBISサ...
kun432kun432

これをQuery Engineで使ってみる。

最初に初期化してインデックスを作成した際にChromaでベクトルDBを永続化しているので、RaptorのRetrieverはこんな感じで読み出せる。

from llama_index.packs.raptor import RaptorRetriever

collapsed_retriever = RaptorRetriever(
    [],
    embed_model=OpenAIEmbedding(
        model="text-embedding-3-small"
    ),
    llm=OpenAI(model="gpt-3.5-turbo-0125", temperature=0.1),
    vector_store=vector_store,
    similarity_top_k=5,
    mode="collapsed",
)

tree_traversal_retriever = RaptorRetriever(
    [],
    embed_model=OpenAIEmbedding(
        model="text-embedding-3-small"
    ),
    llm=OpenAI(model="gpt-3.5-turbo-0125", temperature=0.1),
    vector_store=vector_store,
    similarity_top_k=5,
    mode="tree_traversal",
)

オプション的なものも含まれているし、ここでは不要なものもあるけど、一旦これで。モードだけもっとシンプルに切り替えできればいいんだけど、ちょっとわからなかった。

でこれをRetrieverQueryEngineでラップする。

from llama_index.core.query_engine import RetrieverQueryEngine

collapsed_retriever_query_engine = RetrieverQueryEngine.from_args(    
    collapsed_retriever, llm=OpenAI(model="gpt-3.5-turbo-0125", temperature=0.3)
)

tree_traversal_retriever_query_engine = RetrieverQueryEngine.from_args(    
    tree_traversal_retriever, llm=OpenAI(model="gpt-3.5-turbo-0125", temperature=0.3)
)

"collapsed"モードでクエリ

response = collapsed_retriever_query_engine.query("オグリキャップの主な勝ち鞍を教えて。")
print(str(response))

オグリキャップの主な勝ち鞍は、有馬記念とGI競走初制覇です。

response = collapsed_retriever_query_engine.query("オグリキャップはどうしてこんなに人気があったのですか?")
print(str(response))

オグリキャップは競走馬時代から人気を集め、食欲旺盛で愛される存在だった。彼の競走成績や個性、競馬ファンや一般の人々に与えた感動、有馬記念での武豊とのエピソードなどが人気の要因であると言えます。

response = collapsed_retriever_query_engine.query("オグリキャップの血統について教えて。")
print(str(response))

オグリキャップの父はダンシングキャップであり、種牡馬成績はあまり優れていなかったため、オグリキャップの血統について「突然変異で生まれた」もしくは「ネイティヴダンサーの隔世遺伝で生まれた競走馬である」という主張もある。

"tree_traversal"モードでクエリ

response = tree_traversal_retriever_query_engine.query("オグリキャップの主な勝ち鞍は?")
print(str(response))

オグリキャップの主な勝ち鞍は、GI競走初制覇となった有馬記念、1989年の毎日王冠などが挙げられます。

response = tree_traversal_retriever_query_engine.query("オグリキャップはどうしてこんなに人気があったのですか?")
print(str(response))

オグリキャップは、競走馬としての強さや勝利だけでなく、その人気の要因は、地方出身の馬が中央競馬のエリートたちを凌駕し、数々の名勝負を演じ、挫折を乗り越えた姿がファンの心を捉えたこと、競馬ファンに感動を与え、競馬ブームを巻き起こしたこと、女性ファンを競馬場に呼び込んだこと、競馬ゲームやPOGを通じて競馬人気を高めたことなどが挙げられます。その他にも、オグリキャップが競馬ファンにとって特別な存在として記憶され、競馬界に多大な影響を与えたことが人気の理由とされています。

response = tree_traversal_retriever_query_engine.query("オグリキャップの血統について教えて。")
print(str(response))

オグリキャップの血統は、父がダンシングキャップであり、母の名前はホワイトナルビーです。母の母は笠松で4勝を挙げたクインナルビーで、クインナルビーは1953年の天皇賞(秋)を制しています。オグリキャップの血統には、アンドレアモンやキョウエイマーチなどの重賞勝ち馬が含まれています。

kun432kun432

チャンク化するとより大きなコンテキストが失われてしまう、というのはその通りで、セマンティックにクラスタ化して階層ツリー構造までほぼ自動で作る、ってのがところでこれをカバーするって感じかな。

個人的に思ったこと

  • 階層化とかを自分でやるのはけっこう大変なので、そのへんをセマンティックに自動でやってくれるってのは良いと思う。
  • ドキュメント向きだと思う。FAQみたいなインデックスを作成するのには向いてない気がする。
  • サマリー化すると一定のコンテキスト量は落ちる。それに加えてツリー構造化すると、間違ったツリーを選択してしまうと辿れない可能性がある
  • 試してみた感じだと"tree_traversal"のほうがいい感じの回答が出るようには思えるけど、最終的にそこそこのトークン量になる。階層数とかtop-kの数とかで調整はできるけど、精度とのバランス取るのも難しそう

あとはRaptorPackの実装として以下は気が気になった。

  • チャンク分割の数によっては階層上限を超えてエラーになる場合がある
  • まれに各チャンクごとにつけられているIDが重複する場合がある
  • 階層構造をRaptorPackが完全に抽象化してしまっているので、各ノードがどういうふうにつながっているかを調べるのは、トレーシングがないと無理だし、あっても大変
  • プロンプトの設定とかモードの切替とかがモジュール内で閉じているように思えるので、現状はコードを直接修正するしかなさそう。

あたりかな。実運用で使うには、ちょっと複雑過ぎるし、まだこなれてない、という感はある。

あくまでも個人的な印象だけど、劇的に精度が上がる、というふうには正直感じなかった。定量評価してみないと判断はできないけど。

kun432kun432

補足

  • top-kの設定やチャンクサイズとかで結構変わる。いい感じのパラメータ見つけるのは結構手間がかかりそう。
    • top-k=2みたいに少ないと、あんまりいいretrievalにならない感がある。top-k=5ぐらいは必要かな。
    • SentenceSplitterじゃなくて、MarkdownNodeParserで文書構造を意識したチャンク化とかもやってみたけど、あんまりいい感じにならなかった。
      • そもそも似た意味のチャンクでクラスタ化するので、一定のコンテキストが保持されている構造化文書だとあまりメリット感はない気がする。むしろ雑なチャンク分割のほうがこういうのには向いてそう。

むしろ雑なチャンク分割のほうがこういうのには向いてそう。

改めて考えると、ドキュメントごとにきっちり構造化意識してチャンク分割手法を変える、みたいなのができるんならいいんだけど、色んな種類・たくさんのボリュームのドキュメントとかがあって個別に手をかけていられない、っていうケースはまあある。そういったケースには、シンプルにチャンク分割して、

  • サマリ
  • 階層化

ってのは向いてるのかもしれないな。個々でみるとイマイチな場合があるとしても全体としてはそれなりの精度になる、みたいな。そういうケースにはRAPTORは合いそうな気がする。

しらんけど。

このスクラップは2ヶ月前にクローズされました