Agents for Amazon Bedrock の簡素化された作成方法を試す

## はじめに
2024/4/23 に突如降り注いできた Amazon Bedrock のアプデ祭りすごいことになっていますね。この記事では Agent for Amazon Bedrock の簡素化された作成方法 (Function Schema) についてとりあげます。

https://aws.amazon.com/jp/about-aws/whats-new/2024/04/amazon-bedrock-agents-agent-creation-return-control-capability/

https://aws.amazon.com/jp/blogs/aws/agents-for-amazon-bedrock-introducing-a-simplified-creation-and-configuration-experience/

これまでは OpenAPI スキーマを用意して、Agent が呼び出すことのできる API 操作を定義する必要がありました。今回のアップデートで OpenAPI スキーマの作成が不要で、より簡単かつ迅速に Agent を構成できるようになりました。

## OpenAPI スキーマを使用した定義から簡素からされた定義に移行してみる
以下の記事で紹介している Agent の構成を新しい定義方法に移行してみます。

https://qiita.com/hayao_k/items/850cb5ef717de7df99f9

Agent が持つ機能の概要としては、AWS のアップデート記事の URL を入力として受け取り、内容を取得して要約するというものです。

既存の Agent のアクショングループを編集します。Action group type を `Define with API schemas` から `Define with function details` に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/f527dfd1-b486-c68f-e677-94ce3769a078.png)

Action gorup invocation の設定は変更せずに、`Add action group function` をクリックして追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/92955708-8fbd-d61c-95ee-9a708993a5a3.png)

以下のように定義しました。もともと OpenAPI スキーマで記載していた内容を Action group fiunction の項目に合わせて定義しなおしています。

* Name: summarize_article
* 説明: Summarize an article from URL
* Parameter: url

<details>
  <summary>参考: 元の OpenAPI スキーマの定義 (クリックして展開)</summary>

```yaml
openapi: 3.0.0
info:
  title: Summarize an article API
  version: 1.0.0
  description: APIs for summarize an article from URL.
paths:
  /summarize_article:
    post:
      summary: APIs for summarize an article from URL.
      description: The URL should be determined based on the instructions.
      operationId: summarize
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                  description: url of article
              required:
               - url
      responses:
        '200':
          description: Article summarized.
          content:
            application/json:
              schema:
                type: object
                properties:
                  article:
                    type: string
                    description: Summarized article
```
</details>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/9625ad5a-8207-82b9-74cc-012dc09600ae.png)


変更を保存します。この時点では Agent の実行はエラーとなるのでご注意ください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/22a7f7c6-9b9b-5c17-b6ae-45f50087d0e6.png)

OpenAPI スキーマを使用した場合と、Function Schema (簡素された定義方法) では Bedrock から Lambda に渡される入力のスキーマが異なるため、エラーを解消するにはアクショングループに設定している Lambda 関数でパラメータを扱っている箇所のコードを修正する必要があります。

OpenAPI スキーマ使用時の例:

```py
api_path = event['apiPath']
if api_path == '/summarize_article':
    properties = event['requestBody']['content']['application/json']['properties']
    url = next((item['value'] for item in properties if item['name'] == 'url'), '')
    body = {'body': extract_text_from_url(url)}
```

Function Schema (簡素された定義方法) 使用時の例:

```py
function = event['function']
if function == 'summarize_article':
    url = next((item['value'] for item in event['parameters'] if item['name'] == 'url'), '')
    body = {'body': extract_text_from_url(url)}
```

同様に Agent が期待する Lambda 関数のレスポンス型式も異なるため、こちらも修正する必要があります。

OpenAPI スキーマ使用時の例:

```py
response_body = {
    'application/json': {
        'body': json.dumps(body, ensure_ascii=False)
    }
}

action_response = {
    'actionGroup': event['actionGroup'],
    'apiPath': api_path,
    'httpMethod': event['httpMethod'],
    'httpStatusCode': http_status_code,
    'responseBody': response_body,
}

return {
    'messageVersion': '1.0',
    'response': action_response
}
```

Function Schema (簡素された定義方法) 使用時の例:

```py
response_body = {
    "TEXT": {
        "body": json.dumps(body, ensure_ascii=False)
    }
}

action_response = {
    'actionGroup': event['actionGroup'],
    'function': function,
    'functionResponse': {
        'responseBody': response_body
    }
}

return {
    'messageVersion': '1.0',
    'response': action_response
}
```

:::note warn
簡素化された作成方法の場合、レスポンスの Content Type は TEXT のみが許容されます。application/json を指定した場合は次のようなエラーが発生します。
`The Lambda response is malformed. Only TEXT is supported for functionContentType`
:::

エラーなく Agent が動作すれば移行完了です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/4fb8ab68-e691-ed88-4a36-b492ffc78ca1.png)

## CloudFormation テンプレート
先日、Agents for Amazon Bedrock が CloudFormation によるデプロイをサポートしましたが、2024/4/23 時点では OpenAPI スキーマによる定義でのみ利用できます。冒頭のブログでは簡素化された作成方法も対応中と書いてあったので、楽しみに待ちましょう！

> CloudFormation support for Agents for Amazon Bedrock has been released recently and is now being updated to support the new simplified syntax.

### 2024/5/13 追記
2024/5/9 Function Schema (簡素化された作成方法) も CloudFormation によるデプロイがサポートされました。

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-bedrock-agent-agentactiongroup.html

具体的には以下のような記述が可能です。

```yaml
Resources:
  BedrockAgent:
    Type: AWS::Bedrock::Agent
    Properties:
      AgentName: !Ref "AWS::StackName"
      AgentResourceRoleArn: !GetAtt BedrockAgentRole.Arn
      AutoPrepare: true
      FoundationModel: !Ref pModelId
      IdleSessionTTLInSeconds: 120
      ActionGroups:
        - ActionGroupName: "explainLatestAWSUpdate"
          ActionGroupExecutor:
            Lambda: !GetAtt BedrockAgentFunction.Arn
          FunctionSchema:
            Functions:
              - Name: "summarize_article"
                Description: "summarize an article from url."
                Parameters: 
                  url:
                    Description: "url of article"
                    Required: false
                    Type: "string"
      Instruction: |
        As an AWS Principal Engineer, you have been assigned the following tasks:
        以下省略
```

<details>
  <summary>参考 OpenAPI Schema 使用時の CloudFormation テンプレート (クリックして展開)</summary>

```yaml
  BedrockAgent:
    Type: AWS::Bedrock::Agent
    Properties:
      AgentName: !Ref "AWS::StackName"
      AgentResourceRoleArn: !GetAtt BedrockAgentRole.Arn
      AutoPrepare: true
      FoundationModel: !Ref pModelId
      IdleSessionTTLInSeconds: 110
      ActionGroups:
        - ActionGroupName: "explainLatestAWSUpdate"
          ActionGroupExecutor:
            Lambda: !GetAtt BedrockAgentFunction.Arn
          ApiSchema:
            Payload: |
              openapi: 3.0.0
              info:
                title: Summarize an article API
                version: 1.0.0
                description: APIs for summarize an article from URL.
              paths:
                /summarize_article:
                  post:
                    summary: APIs for summarize an article from URL.
                    description: The URL should be determined based on the instructions.
                    operationId: summarize
                    requestBody:
                      required: true
                      content:
                        application/json:
                          schema:
                            type: object
                            properties:
                              url:
                                type: string
                                description: url of article
                            required:
                             - url
                    responses:
                      '200':
                        description: Article summarized.
                        content:
                          application/json:
                            schema:
                              type: object
                              properties:
                                article:
                                  type: string
                                  description: Summarized article
      Instruction: |
        As an AWS Principal Engineer, you have been assigned the following tasks:
      
        1. Access the AWS service update URL and provide a summary of the English text in Japanese. There is no need to categorize the URL content.
        2. Share your thoughts on the update in Japanese, focusing on the following points:
          2.1. Discuss the advantages of this technology or service compared to existing technologies or services, and explain how it achieves these benefits.
          2.2. Describe the technical challenges that this technology or service addresses.
        3. Respond in json format.

        Here’s an example:
        summary, advantages, and addresses are all required fields
        <example>
        {
          "summary": "Amazon EC2シリアルコンソールがすべてのAWSローカルゾーンで利用できるようになりました。",
          "advantages": "インスタンスの起動やネットワークの接続の問題をトラブルシューティングするために、シリアルポートへのテキストベースのアクセスを簡単かつ安全に提供します。これにより、SSHやRDPで接続できない場合でも、対話形式でコマンドを実行して構成の問題を解決できます。",
          "addresses": "これまでも管理コンソールやAPIを通じてシリアルコンソール出力にアクセスできましたが、それらは主に診断のためで、対話式のトラブルシューティングには適していませんでした。この新機能により、こうした制限がなくなり、はるかに使いやすくなります。"
        }
        </example>

        If the tool did not return a summary, reply "Could not retrieve.".
```

</details>



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