0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bedrock AgentCoreを使ってみた

0
Last updated at Posted at 2026-08-01

きっかけ

これまで、Bedrock Agentを使って、AIエージェントを遊びで作ってみたりしていました。
(同窓会の出欠確認用サイトを作った際に、出欠の回答状況をLambda経由でDBを確認して回答するAIエージェントを作成した)
ところが、AWS Summit 2026に行った際、どこもかしこも、Bedrock AgentCore、Strands Agent、…という感じで、時代に取り残されている感を感じたのがきっかけです。

気づいたら、Bedrock Agentは新規ユーザの利用はできなくなっていますね・・・
https://docs.aws.amazon.com/ja_jp/bedrock/latest/userguide/agents-how.html

Amazon Bedrock エージェント (2023 年 11 月リリース) は「Amazon Bedrock Agents Classic」となり、  
2026 年 7 月 30 日以降、新規のお客様は利用できなくなります。  
Bedrock Agents Classic と同様の機能については、Amazon Bedrock AgentCore をご覧ください。  
Bedrock Agents Classic を使用する場合は、その日より前にサインアップします。  
既存のお客様は、通常どおりサービスを引き続き使用できます。  
詳細については、「Amazon Bedrock エージェント Classic メンテナンスモード」を参照してください。

作ってみたもの

  • 野球選手の年別データを持ったAurora DSQLに野球選手のデータを確認する
  • Managed KnowledgeBaseに格納された野球のルールを確認する
  • Managed KnowledgeBaseに格納された野球の戦術を確認する
  • Cognitoグループがtigersのユーザには全球団の情報を、carpのユーザにはカープだけの情報を返す
  • 巨人に有利な情報を返さない

というAIエージェントを使ったチャットを作ってみました。
image.png

なお、生成AIも手助けに使いつつ、自分の理解のために、生成AIに全部書かせるようなことはしないようにしました。

デモ

image.png

  • ログインします。
  • Cognito Managed Loginです。

image.png

  • なんとも、質素な画面です。
    image.png
  • 選手の情報をDBから検索して、

image.png

  • ショート2人、4番中野という前衛的なオーダーを返してくれました。
  • システムプロンプトだったり、オーダーの組み方のルールをRAGに置くだったりをするべきかもしれませんが・・・いったん返ってきたのでよしとします。

思ったこと

  • Bedrock Agentでもツール群は使わせることはできた(Target)のですが、リクエストを受けた後は生成AIに任せることになり、確定的な動きはさせることができないため、
    アプリからAgentに投げるまでの間に確定的な処理は行ったうえで投げて、ツールのLambdaの中でまた確定的な処理は書く必要がありますが、
    そのあたりをStrands AgentのPythonの中で完結できるのは楽だなと思いました。

    • 前処理でユーザ属性を確認しています
    @app.entrypoint
    async def invoke_agent(payload, context):
    
        # frontend から送られた token を受け取る
        token = payload.get("token")
        session_start_time = payload.get("sessionStartTime")
    
        # tokenから、ユーザ情報を取得
        try:
            user = get_user(token)
            user_sub = user.get("sub")
            user_group = user.get("cognito:groups", [])
        except Exception as e:
            print(f"Error in get_user: {e}")
            return
    
        # ユーザがtigersに所属しているか確認
        tigers = False
        carp = False
    
        for g in user_group:
            if g == "tigers":
                tigers = True
            if g == "carp":
                carp = True
    
    
    • そのあと、Tool群を定義して(後述)
    • Agentを呼び出します
    agent = Agent(
        model=model,
        tools=[
            search_baseball_players,
            search_player_position,
            search_player_batter_stats,
            search_player_pitcher_stats,
            get_team_mst,
            get_position_mst,
            search_player_by_team_and_year,
            search_player_by_position_and_year,
            get_streamable_http_mcp_client()
        ],
        session_manager=session_manager,
        system_prompt=system_prompt
    )
    
    # エージェントをストリーミング呼び出し
    stream = agent.stream_async(
        payload.get("prompt")
    )
    
    • Agentに呼び出されたTool内で、また確定的な処理をします(ここはCarp用とTigers用にToolを分けて、Identityで認可を行うほうが良いのかもしれません)
    @tool  
    def search_baseball_players(first_name: str = "", last_name: str = ""):
        """
        # 概要
        野球選手(プロ野球選手)のデータをDBから検索するツール。
    
        #引数
        - 姓(last_name) : 部分一致、未指定可
        - 名(first_name) : 部分一致、未指定可
    
        # 戻り値
        JSON形式で返される
        - player_id : 選手ID
        - first_name : 名
        - last_name : 姓
        - team_id : 所属チームID
        - team_name : 所属チーム名
        - start_year : 在籍開始年
        - end_year : 在籍終了年
        - ren_no : 一年の間で移籍した場合の連番
        """
    
        query = """
                    SELECT 
                        pm.player_id,
                        pm.first_name,
                        pm.last_name,
                        pt.team_id,
                        tm.name as team_name,
                        pt.start_year,
                        pt.end_year,
                        pt.ren_no
                    FROM player_mst as pm
                    INNER JOIN player_team as pt
                        ON pm.player_id = pt.player_id
                    LEFT JOIN team_mst as tm
                        ON pt.team_id = tm.team_id
                    WHERE 1=1
                """
        params = {}
        
        if carp and not tigers:
            # カープファンの場合は、検索結果をカープに強制絞り込み
            query += " AND pt.team_id = %(carp_id)s"
            params["carp_id"] = carp_id
        elif tigers:
            # タイガースファンは何でも見れる
            pass
        else:
            return "検索権限がありません。"
    
        if first_name:
            query += " AND pm.first_name LIKE %(first_name)s"
            params["first_name"] = f"%{first_name}%"
    
        if last_name:
            query += " AND pm.last_name LIKE %(last_name)s"
            params["last_name"] = f"%{last_name}%"
    
        print(f"Executing query: {query}")
        print(f"With params: {params}")
    
        rows = execute_query_with_logging(query, params)
    
    
        result_list = []
        if rows:
            for row in rows:
                result_list.append({
                    "player_id": row[0],
                    "first_name": row[1],
                    "last_name": row[2],
                    "team_id": row[3],
                    "team_name": row[4],
                    "start_year": row[5],
                    "end_year": row[6],
                    "ren_no": row[7]
                })
        
        return result_list
    
    
  • ここが目玉なのかな、と思いますが、Memoryなど、いろんな機能があって便利だなと思いました。

    • 下記のようにしています
      session_id = f"{user_sub}_{session_start_time}"
      
      memory_config = AgentCoreMemoryConfig(
          memory_id=memory_id,
          session_id=session_id,
          actor_id=user_sub
      )
      
      session_manager = AgentCoreMemorySessionManager(
          agentcore_memory_config=memory_config
      )
      

ストリーミングについて

今回、フロントエンド側にもストリーミングでレスポンスが表示されるようにしました。
が、その中で、API Gatewayの時間制限(30秒)に引っかかったためクォータ申請をしたのですが、
SAMが30秒以上は対応しておらず、ここは手でマネジメントコンソールから更新せざるを得ませんでした。

  InvokeAgentRuntimeServerlessFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "${ResourceNamePrefix}-lambda-invoke-agent-runtime"
      Runtime: nodejs22.x
      Handler: index.handler
      Role: !GetAtt LambdaInvokeAgentRuntimeRole.Arn
      Timeout: 179 ##ここで179秒としても、API Gatewayのタイムアウトが30秒から動かない
      CodeUri: ../../app/invoke-runtime/
      Environment:
        Variables:
          AGENT_ARN: !Ref AgentCoreArn
      Events:
        AgentApi:
          Type: Api
          Properties:
            RestApiId: !Ref ServerlessApi
            Path: /agent
            Method: post
            ResponseTransferMode: RESPONSE_STREAM
    Metadata:
      BuildMethod: esbuild
      BuildProperties:
        Minify: true
        Target: "es2020"
        EntryPoints: 
        - index.ts

追加で書きたいことがあれば追記します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?