Cohere）Command R/R+ のSearch Query機能で検索クエリがどう置き換わっているか確認してみた

## はじめに
Cohere Command R/R+のクエリ置き換え機能は、プロンプトに明示せずともサブクエリに分割され、ユーザーが求める情報を迅速かつ正確に取得できるように設計されています。
どのようにクエリが書き換えられているか気になったので試してみました。

## クエリ置き換えのメリット
ユーザーの[クエリを書き換えると検索精度が上がる](https://arxiv.org/abs/2305.14283)といわれています。
この論文を読んでいくと、
ユーザーの質問をLLMで書き換えてから検索しようというアイデアがあります。
要約すると、
- 強化学習を使って書き換え用のモデルを学習する検証
    - 既存のLLMに書き換えさせても効果があるという結果

になっています。
***Cohere Command R/R+には書き換え用のモデルを使わずとも、内部的にクエリの書き換えを行ってくれます。***

## OCI Genarative AI Command R/R+ をAPIコール
### 環境
今回はこちらの環境で構築していきます。

- Python 3.12.2

## 1. 必要なライブラリを設定

```Python
import oci

from oci.auth.signers import InstancePrincipalsSecurityTokenSigner
from oci.generative_ai_inference.generative_ai_inference_client import GenerativeAiInferenceClient
from oci.generative_ai_inference.models import (
    ChatDetails,
    OnDemandServingMode,
    CohereChatRequest,
    CohereTool,
    CohereParameterDefinition,
    CohereToolCall,
    CohereToolResult
)
```
## 2. OCI認証設定を行う
```import os```で環境変数からcompartment_idやendpointを指定していただいても問題ないです。
```Python
compartment_id ="ocid1.compartment.***********************************"
endpoint = "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com"
config = oci.config.from_file(file_location='~/.oci/config', profile_name="CHICAGO")
signer = InstancePrincipalsSecurityTokenSigner()
## AIクライアント作成
generative_ai_inference_client = GenerativeAiInferenceClient(config = {}, signer = signer, service_endpoint = endpoint)
```
## 3. is_search_queries_only=Trueで検索クエリを確認
```is_search_queries_only=True``` に設定すると、
***生成された検索クエリのリストを確認することができ***、モデルはユーザーのメッセージに回答しません。

```model_id```を変えてそれぞれ回答を見てみます。
- command Rの場合：cohere.command-r-16k
- command R +の場合：cohere.command-r-plus

と、モデルを指定しています。
今回の質問はカレーの作り方を質問します。
質問文：```How to make hamburgers?```

```Python
response = generative_ai_inference_client.chat(
    chat_details=ChatDetails(
        compartment_id=compartment_id,
        serving_mode=OnDemandServingMode(
            model_id="cohere.command-r-16k"
        ),
        chat_request=CohereChatRequest(
            message="How to make hamburgers?",
            max_tokens=200,
        )
    )
)
print(f"response text: {response.data.chat_response.search_queries}")
```
## 4. クエリの結果
それでは、クエリが内部的にどう置き換わっているかを確認します。
- Command R
```Python
response text: [{
  "text": "hamburger recipe"
}]
```
内部的に作り方→レシピとして置き換わっていることが分かります。
- Command R +
```Python
response text: [{
  "text": "how to make hamburgers"
}]
```

使用モデルを変更すると検索クエリも異なるのが確認できました。

## 5. 質問文を複雑にしてみる 
次は、
How to make hamburgers and curry and pizza?に書き換えてみます。
(どんな質問やねん・・・)

- Command R
```Python
response text: [{
  "text": "hamburger recipe"
}, {
  "text": "curry recipe"
}, {
  "text": "pizza recipe"
}]
```

- Command R +
```Python
response text: [{
  "text": "how to make hamburger"
}, {
  "text": "how to make curry"
}, {
  "text": "how to make pizza"
}]
```
内部的に複数のクエリに分割されていることが確認できます！


## おまけ）実際にRAGで使用されそうな質問文にしてみる

さらに複雑な質問を考えます。
```Can you provide a breakdown of the monthly sales figures for the top 10 products in terms of revenue for the past year, along with a comparison to the same period?```

(過去1年間の売上高上位10製品の月次売上高の内訳と前年同期との比較を教えてください。)

今までの結果から考察するに、
- 過去1年間の売上高上位10製品の月次売上高の内訳
- 過去1年間の売上高上位10製品の月次売上高の前年同期との比較

の2つのクエリに分割されることが予想できます。


- Command R 
```Python
response text: [{
  "text": "monthly sales figures for the top 10 products in the last year"
}, {
  "text": "monthly sales figures for the top 10 products a year ago"
}, {
  "text": "comparison of sales figures for the top 10 products between the last year and year"
}]
```
3つのクエリに分割されました。

1. "過去1年間の上位10商品の月間販売数"
2. "1年前の上位10商品の月間販売数"
3. "上位10商品の昨年と一昨年の販売数比較"

この1.2つのクエリは last year/ a year agoの言い回しが違うのみでクエリの意味内容が重複しています。

- Command R +

```Python
response text: [{
  "text": "monthly sales figures for top 10 products last year"
}]
```
Command R +では、comparison（比較）のクエリが消えました・・・・
"前年の上位10商品の月間販売数"とかなり端的＆クエリ1つのみになっています。
たしかに、欲しいデータ自体は昨年および前年の上位10商品の月間販売数のみで、RAGでDBを検索する上でのクエリとしてはこちらが正しいのかもしれません。
## 最後に
Command R/R+で生成される検索クエリは異なっていることが確認できました。
実際にRAGで実装すると検索クエリの違いが結果に反映されるのか気になります。。。