Knowledge Base for Amazon Bedrock の Chat with your document を API から利用する

## はじめに
2024/4/24 のアップデートで ベクターストアなしで、単一ドキュメントに対する質問が可能になる機能が追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2024/04/knowledge-bases-amazon-bedrock-asking-questions-single-document/

コンソール上では Chat with your document として用意されている機能で、10 MB までの単一のドキュメント (PDF, MD, TXT, DOCX, HTML, CSV, XLS, and XLSX) をアプロードするか、S3 上のパスを指定するだけで、対象ドキュメントの内容に関して質問が可能です。追加費用無しで利用できるのも嬉しいポイント。

## コンソール上での使用
使い方は簡単でナレッジベースに追加された Chatwith your document タブを選択し、モデルと対象データを選択して質問を入力するだけです。

4/24 時点で モデルは Claude 3 Sonnet のみが利用可能です。またシステムプロンプトもカスタマイズ可能です。

以下は Anthropic on Bedrock の EULA を取り込んで答えてもらった例です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/9a4ea492-1083-b0e4-29b1-fb871db5c25d.png)

注意点としてはファイルサイズの 10 MB 制限の他、入力トークン数にも制限があるようで、20,000トークンを超えるとエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/f8d95fc1-09b5-9a21-208f-44e0262c2f60.png)

### API からの利用
アップデートがアナウンスされた直後、API からの利用ができず、コンソールからしか使えない機能だとちょっと使い勝手が、、、という印象でしたが、本日の boto3 のアップデート内容を眺めていたところ以下の記載が！

```diff
+  {
+    "category": "``bedrock-agent-runtime``",
+    "description": "[``botocore``] This release introduces zero-setup file upload support for the RetrieveAndGenerate API. This allows you to chat with your data without setting up a * + Knowledge Base.",
+    "type": "api-change"
+  },
```
https://github.com/boto/boto3/commit/6bfee910292ef4be7451fd3aa0234a48c48edbae

RetrieveAndGenerate API のリファレンスを確認したところ、`retrieveAndGenerateConfiguration` に`externalSourcesConfiguration` が追加されていたので、これを使えばアプリケーションからも利用できそうです！

https://docs.aws.amazon.com/bedrock/latest/APIReference/API_agent-runtime_RetrieveAndGenerate.html

前置きが長くなりましたが。サンプルコードは以下です。
boto3 の v1.34.90 以降で使用できます。

```app.py
import boto3

def main():
    client = boto3.client("bedrock-agent-runtime")
    
    response = client.retrieve_and_generate(
        input={"text": "Anthropicのモデルで生成されたデータは誰のものですか？"},
        retrieveAndGenerateConfiguration={
            "type": "EXTERNAL_SOURCES",
            "externalSourcesConfiguration": {
                "modelArn": "arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-sonnet-20240229-v1:0",
                "sources": [{
                    "sourceType": "S3",
                    "s3Location": {
                        "uri": "s3://<your-bucket-name>/Anthropic on Bedrock EULA.pdf"
                    }
                }]
            }
        }
    )
    
    print(response["output"]["text"])
    
if __name__ == "__main__":
    main()
```

`retrieveAndGenerateConfiguration.type` で `EXTERNAL_SOURCES` を指定し、`retrieveAndGenerateConfiguration.sources` で S3 上のオブジェクトの URI を指定しています。

結果は以下です (見やすさ優先で改行を入れてます)。

```shell-session
$ python3 app.py
Anthropicのモデルで生成されたデータ(Outputs)は、Anthropicの利用規約によると、
顧客(Customer)が所有権を持つことになっています。
利用規約には「Anthropicは、これらの利用規約に基づいて、
Outputsに対する権利を顧客に譲渡することに同意します」と明記されています。
```

sourceType には BYTE_CONTENT も指定可能で、Base64 エンコーディングしたバイナリデータを直接渡すこともできるようです。コンソールのファイルアップロードはこちらで実装されていると思われます。

```py
"sources": [{
    "sourceType": "BYTE_CONTENT",
    "byteContent": {
        "contentType": "application/pdf",
        "data": bs64,
        "identifier": "Anthropic on Bedrock EULA.pdf"
    }
}]
```


ちなみに: 1 
modelArn を Claude 3 Haiku に差し替えて実行したところ、やっぱりエラーになりました。
> botocore.errorfactory.ValidationException: An error occurred (ValidationException) when calling the RetrieveAndGenerate operation: The provided model is not supported for EXTERNAL_SOURCES RetrieveAndGenerateType. Update the model arn then retry your request.

ちなみに: 2
単一ファイルに対して有効な機能なのに `externalSourcesConfiguration.sources` がリストなのが気になって 2 つのファイルを指定してみましたが、やっぱりエラーになりました。

> otocore.errorfactory.ValidationException: An error occurred (ValidationException) when calling the RetrieveAndGenerate operation: 1 validation error detected: Value '[ExternalSource(sourceType=S3, s3Location=S3ObjectDoc(uri=s3://bucket-name/Anthropic on Bedrock EULA.pdf), byteContent=null), ExternalSource(sourceType=S3, s3Location=S3ObjectDoc(uri=s3://bucket-name/bedrock-api.pdf), byteContent=null)]' at 'retrieveAndGenerateConfiguration.externalSourcesConfiguration.sources' failed to satisfy constraint: Member must have length less than or equal to 1

以上です。
参考になれば幸いです。