BedrockのConverse APIでモデル固有のパラメーターを指定する

できないと思ってたらできた。

## 通常のConverse API呼び出し

Cohere Command Rを使って、簡単なテキストを渡してみます。

```python:app.py
import json

import boto3

client = boto3.client("bedrock-runtime")

result = client.converse(
    modelId="cohere.command-r-v1:0",
    messages=[
        {
            "role": "user",
            "content": [{"text": "こんにちは。ダジャレを言ってみて"}],
        }
    ],
)

print(json.dumps(result, indent=2, ensure_ascii=False))
```

実行します。

```shell
python app.py
```

```json:レスポンス
{
  "ResponseMetadata": {
    "RequestId": "156cd130-f7b9-4b7f-b7fc-91d379d51706",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Thu, 11 Jul 2024 14:36:19 GMT",
      "content-type": "application/json",
      "content-length": "248",
      "connection": "keep-alive",
      "x-amzn-requestid": "156cd130-f7b9-4b7f-b7fc-91d379d51706"
    },
    "RetryAttempts": 0
  },
  "output": {
    "message": {
      "role": "assistant",
      "content": [
        {
          "text": "こんにちは！ 夏が来ると、海に「行きたし貝」！"
        }
      ]
    }
  },
  "stopReason": "end_turn",
  "usage": {
    "inputTokens": 13,
    "outputTokens": 19,
    "totalTokens": 32
  },
  "metrics": {
    "latencyMs": 531
  }
}
```

ダジャレかどうかはさておき、動作しました。

## Command R固有のパラメーター

Command Rシリーズは、`search_queries_only`パラメーターを指定することで、通常のテキスト生成ではなく、検索クエリー生成を行うことができます。

Invoke Modelで呼び出す場合はこのような感じです。

```python:Invoke Model呼び出し
response = client.invoke_model(
    modelId="cohere.command-r-v1:0",
    body=json.dumps(
        {
            "message": "KendraとBedrockが両方とも使えるリージョンを知りたいです。",
            "search_queries_only": True,
        }
    ),
)

response_body = json.loads(response.get("body").read())
print(json.dumps(response_body["search_queries"], indent=2, ensure_ascii=False))
```
```json:レスポンス
[
  {
    "text": "Kendra available regions",
    "generation_id": "648f6d66-d0f7-48f4-b3e1-d2c970ad833c"
  },
  {
    "text": "bedrock available regions",
    "generation_id": "648f6d66-d0f7-48f4-b3e1-d2c970ad833c"
  }
]
```

:::note
詳細な使い方は、以前投稿したこちらを参照ください。

Amazon BedrockにCohere Command R と Command R+ が来たよ！RAGがすげーよ！
https://qiita.com/moritalous/items/16797ea9d82295f40b5e
:::

## Converse APIでモデル固有のパラメーターを指定する

Converse APIではパラメーターの共通化が図られているため、モデル固有のパラメーターを渡せないと思っていたのですが、実はできました。

「additionalModelRequestFields」と「additionalModelResponseFieldPaths」の２つを追加します。

* additionalModelRequestFields: 追加で指定するリクエストパラメーターをセット
* additionalModelResponseFieldPaths: レスポンスに追加したいJSONポインター

```python
result = client.converse(
    modelId="cohere.command-r-v1:0",
    additionalModelRequestFields={"search_queries_only": True},
    additionalModelResponseFieldPaths=["/search_queries"],
    messages=[
        {
            "role": "user",
            "content": [
                {"text": "KendraとBedrockが両方とも使えるリージョンを知りたいです。"}
            ],
        }
    ],
)

print(result)
```

こうすることで、「additionalModelResponseFields」の項目としてsearch_queriesを取得できます。

```json:レスポンス
{
  "ResponseMetadata": {
    "RequestId": "271d3b01-6fdd-4159-9a66-58ab574c9867",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Thu, 11 Jul 2024 14:47:32 GMT",
      "content-type": "application/json",
      "content-length": "416",
      "connection": "keep-alive",
      "x-amzn-requestid": "271d3b01-6fdd-4159-9a66-58ab574c9867"
    },
    "RetryAttempts": 0
  },
  "output": {
    "message": {
      "role": "assistant",
      "content": [
        {
          "text": ""
        }
      ]
    }
  },
  "stopReason": "end_turn",
  "usage": {
    "inputTokens": 19,
    "outputTokens": 8,
    "totalTokens": 27
  },
  "metrics": {
    "latencyMs": 475
  },
  "additionalModelResponseFields": {
    "search_queries": [
      {
        "text": "Kendra available regions",
        "generation_id": "6edb49eb-3175-4f76-89a3-efd44379a57e"
      },
      {
        "text": "bedrock available regions",
        "generation_id": "6edb49eb-3175-4f76-89a3-efd44379a57e"
      }
    ]
  }
}
```

:::note
通常のテキスト生成の際にセットされる`["output"]["message"]["content"][0]["text"]`には、空の値が返却されます。
:::


## おまけ：Command Rにドキュメントを渡してRAGしてもらうやつのConverse版

以前投稿した内容のConverse API版ができました。

https://qiita.com/moritalous/items/16797ea9d82295f40b5e

```python
import json

import boto3
from duckduckgo_search import DDGS

client = boto3.client("bedrock-runtime")

model_id = "cohere.command-r-plus-v1:0"
question = "AWS上でRAGを構築するときのおすすめのLLMは？検索はどうするといいの？フレームワークも教えて"

# 検索クエリを生成
result = client.converse(
    modelId=model_id,
    additionalModelRequestFields={"search_queries_only": True},
    additionalModelResponseFieldPaths=["/search_queries"],
    messages=[
        {
            "role": "user",
            "content": [{"text": question}],
        }
    ],
)

search_queries = result["additionalModelResponseFields"]["search_queries"]

# 検索クエリを使って検索
documents = []

for search_query in search_queries:
    text = search_query["text"]
    search_results = DDGS().text(text, max_results=5)
    documents.extend(search_results)

# 回答生成
result = client.converse(
    modelId=model_id,
    additionalModelRequestFields={"documents": documents},
    additionalModelResponseFieldPaths=["/chat_history", "/citations"],
    messages=[
        {
            "role": "user",
            "content": [{"text": question}],
        }
    ],
)

print(json.dumps(result, indent=2, ensure_ascii=False))
```