raggleに参加してみた感想

# 概要
Raggleの第二回コンペ（製薬企業向け高度なRAGシステムの精度改善コンペ）に参加してみたので振り返りです。
殆ど（最終結果以外）は受付完了直後、最終結果発表前に書いています。
# Raggleとは
名前から想像できる通り、生成AIと文書検索を組み合わせた質問応答システム（RAGシステム）の制度改善コンペティションです。
以下、参加した[第２回コンペの概要](https://raggle.jp/competition/617b10e9-a71b-4f2a-a9ee-ffe11d8d64ae#overview)です。

```
本コンペティションでは、製薬企業の多様なドキュメント（Well-beingレポート、財務諸表、商品紹介資料、研究論文など）を対象とした高度なRAG（Retrieval Augmented Generation）システムの構築に挑戦していただきます。

参加者には、以下の課題に取り組んでいただきます：
1. 提供された各種ドキュメントを効率的に処理し、適切なインデックスを構築する
2. ユーザーからの質問に対して、関連性の高い情報を正確に抽出する
3. 抽出した情報を基に、的確で自然な回答を生成する

まずは、下記の記事を参考にベースとなるアプリケーションの構築から始めましょう！
https://zenn.dev/galirage/articles/raggle_quickstart
```

実際の作業としては、サンプルのドキュメントを使ってローカルで動くコードを作成し、提出する、という流れになります。

# 結果
参加賞でした。
受付完了時点でのリーダーボードでのスコアは338で順位は31位（くらい）でした。

# 実装
最初のコードの完成が締め切り4日前でした。
raggleの提出は１日１回のため、そこから４回提出しました。

1、２回目は評価失敗し、３回目は314点、４回目は338点でした。

## １回め
[公式のチュートリアルコード](https://zenn.dev/galirage/articles/raggle_quickstart)を少し改良したものを提出しました。

- MultiVectorRetrieverを使って、検索のチャンクとLLMに渡すチャンクを別々にしました。
- BM25Retrieverを新規に作成し、MultiVectorRetrieverとアンサンブルしました。
- 上位40件のドキュメントをLLMに与えるようにしました。

結果としては、評価に失敗しました。

## ２回目
- エラーの詳細な原因がわからなかったのですが、おそらくトークンリミットだろうと思ったので、上位４０件ではなく３０件のドキュメントを与えるようにしました。

評価に失敗しました。

## ３回目
- 上位１０件のドキュメントを与えるようにしました。

評価に成功し、スコアは314でした。

## ４回目
- ３回目のスコアで、簡潔さや有害さのスコアが低かったので、簡潔さや有害さの観点で高品質になるように回答を生成するように、回答生成時のプロンプトを工夫しました。
- ３回目のスコアで正確さのスコアが低い質問が１つだけあったので、１回目の回答生成時に参考文献が不足していると思われる場合は、上位２０件を与えて再度生成するようにしました。

評価に成功し、スコアは338でした。

# 振り返り

## １回目の提出を早くしたほうがよかった
なるべく早く、チュートリアルコードのままでもよいので、評価を成功して、スコアを眺めてみるべきでした。
１回目の提出の時点で締切の直前だったうえ、エラーの解消に手間取って最初の評価を得たのが締切の１日前だったので、スコアを上げるための改善のループが全然回せませんでした。
チュートリアルコードのままだとしても、スコアを実際に見ると、色々気づきがあるので、早めにやっておけばよかったと思います。

例えば、今回は、コード提出前に、画像の検索や理解をどの程度詰める必要があるか、考えていたのですが、実際に評価結果を見ると、文字のみでの検索、回答生成でも、正確性の評価が高い質問がほとんどだったので、少なくとも、開発初期には、画像の深い理解は必要なさそうだという方針がたちました。それよりも、有害性や冗長性を抑えるためのワークフローの設計のほうがまずはコスパがよさそうでした。

１日１回しか提出できないというルールのため、提出（＝試行）回数を最大化するように動けていればよかったなと思います。

## トークンリミットエラー対策
トークンリミットのエラーは、ローカルで発生しなくても、本番環境で発生する可能性があります。検索されたドキュメントの長さによるためです。
加えて、raggleのシステム上、評価に失敗してもエラーの原因が詳細にわからずデバッグに日数を要してしまったため、最初からトークンリミットにもっと気を使ったコードにしておけばよかったと思いました。

今回はLLMに渡すチャンクサイズを2000文字にしていましたので、上位４０件でも８万字ということで、gpt-4o-miniの128kトークンには余裕があると思っていたのですが、状況証拠的には、上位３０件でもトークンリミットが生じていたようです。
日本語の場合１文字が複数トークンになる可能性があるのと、langchainの使用上、Documentのmetadataもシリアライズして渡されるため、トークン数が想定より大きめになるのかなと思います。

tiktokenを使ってトークン数を厳密に事前にカウントしたり、try構文を使ってエラーが起こったら文書数を減らして再度生成するような工夫を早期から入れておければよかったと思います。

## 時間（提出回数）があれば試したかったこと
RAGの工夫点として、検索と生成の大きく２点があると思いますが、スコアを眺めた感じ、コレクトネスは単純な検索でも満点近い値になっていたため、検索部分についてできることは多くなかったように感じました。
どちらかというと、生成の部分で工夫できる余地がありそうです。手元で試すと模範解答に比べて眺めの回答が生成される事が多かったので、few-shotを与えて、短めの回答が生成されやすいようにすると、簡潔さのスコアを挙げられたかもしれません。
有害性についてはどういうときにこのスコアが低くなる（＝有害である）のかよくわからなかったので対策が難しかったです。想像するに製薬関係のテーマなので、人体に害を与えるような使い方を生成したりすると、よくないのでしょうか。だとするとそういった具体例をfew-shotや後処理で与えて、スコアがどう変動するかを見ることができれば改善できたかもしれません。試行回数が必要そうです。

あと、もっと生成AIに相談すればよかったと終わってから思いました（[参考](https://qiita.com/yukky_memo/items/6e1c7fa08b9b91278886)）。

## 次回挑戦するとしたら意識しておきたいこと
- 提出（思考）回数を増やす
- 文字検索・理解、画像検索・理解、プロンプト、後処理のどこに注力するかを早期に見定める

# おわりに
こういったコンペみたいなものは初めて参加してみました。
RAGの改善ノウハウは知識としてはいろいろ知っているつもりでしたが、実際に手を動かそうと思うとどれを実装すべきか困ったりしたので、やはり使ってみることが大切だと実感する良い機会でした。
実装に対して定量的な評価が下されるのは改善のモチベーションが湧きやすく、非常によかったです。
また機会があれば参加してみたいです。