【AWS】Strands Agentsのハンズオンをやってみた

以下の記事を見ながら、Strands Agentsのハンズオンをやってみます。

Qiita
Strands & AgentCoreハンズオン! MCPマルチエージェントをAWSに簡単デプロイ - Qiita この記事は人力で書きました。 このイベント用の手順書ですが、本記事を読めば1時間ぐらいで誰でも試せます! Claude Codeなど、AIエージェントを「使う」人はかなり増えて...
引用元: Bedrock AgentCore & Strands Agentsハンズオン(JAWS-UG東京)
目次

環境構築

  • GitHubリポジトリの作成(Private)
  • GitHub Codespacesの起動
  • .gitignoreと.envを作成

.envは決してプッシュしないように注意!
.gitignoreに記載しておこう。

IAMユーザーの作成

  • IAMアクセスキーの作成、シークレット入手
    • .envに記述
  • Bedrockのモデル有効化
    • 2025/11現在は不要(全モデルがデフォルトで有効化済み)

Strands入門

シンプルなエージェント

たった数行。

コード(エラー)

# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent

# .envファイルから環境変数を読み込む
load_dotenv()

# エージェントを作成して起動
agent = Agent("jp.anthropic.claude-3-7-sonnet-20250219-v1:0")
agent("JAWS-UGって何?")

実行結果(エラー)

エラーになりました💦
(jp.ではなくus.にしてもダメでした)

raise error_class(parsed_response, operation_name)
botocore.errorfactory.ValidationException: An error occurred (ValidationException) when calling the ConverseStream operation: The provided model identifier is invalid.
└ Bedrock region: ap-northeast-1
└ Model id: jp.anthropic.claude-3-7-sonnet-20250219-v1:0

マネコン>Bedrock>モデルカタログのところで、ConverseStreamは対応していなさそう。。

AWSマネコンにてモデルカタログ画面の一部

AWS公式ドキュメントの「推論プロファイルでサポートされているリージョンとモデル」を見てみると・・・

こちらに記載されているモデルが使えそうです。
JPを探してみると・・・

Sonnet 4.5を使ってみます。

コード(成功)

# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent

# .envファイルから環境変数を読み込む
load_dotenv()

# エージェントを作成して起動
agent = Agent("jp.anthropic.claude-sonnet-4-5-20250929-v1:0")
agent("JAWS-UGって何?")

実行結果(成功)

成功しました!

【Tips】クロスリージョン推論の際のモデルID記載方法

モデルカタログで「クロスリージョン推論」と記載があるモデルがあります。

クロスリージョン推論

単一のAWSリージョンにアクセスが集中してスロットリングエラー(リクエストの受付制限)が発生した場合に、自動的に利用可能な他のリージョンにリクエストを振り分ける技術です。これにより、大規模なトラフィックが発生する生成AIアプリケーションでも、安定したパフォーマンスと高い可用性を実現できます。

クロスリージョン推論の場合、モデルを指定する際に「jp.anthropic.claude-3-7-sonnet-20250219-v1:0」とプレフィックスを付ける必要があります。

OpenAIのモデルようにクロスリージョン推論でない場合は、

モデルカタログのモデルIDをそのまま記述すればOKでした。

ツールの利用

コード

# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent, tool

# .envファイルから環境変数を読み込む
load_dotenv()

# 文字カウント関数をツールとして定義
@tool
def counter(word: str, letter: str):
    return word.lower().count(letter.lower())

# エージェントを作成
agent = Agent(
    model="jp.anthropic.claude-haiku-4-5-20251001-v1:0",
    tools=[counter]
)

# エージェントを呼び出し
agent("I love coding today.の中にoはいくつある?")

関数に@toolとアノテーション付与し、Agentの引数toolsに渡すんですね。

実行結果

2_tool.pyの実行結果

ツール使わなくても回答できそうですが、「Tool #1: counter」とあるので使ってくれたということですね。

MCPサーバー

コード

# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters

# .envファイルから環境変数を読み込む
load_dotenv()

# MCPクライアントを作成
mcp = MCPClient(lambda: stdio_client(
    StdioServerParameters(
        command="uvx", 
        args=["strands-agents-mcp-server"]
    )
))

# MCPクライアントを起動しながら、エージェント作成&呼び出し
with mcp:
    agent = Agent(
        model="jp.anthropic.claude-haiku-4-5-20251001-v1:0",
        tools=mcp.list_tools_sync()
    )
    agent("StrandsでA2Aサーバーの最小サンプルコードを書いて!")

実行結果

Processing request of type ListToolsRequest
Strands AgentsでのA2A(Agent to Agent)サーバーの最小サンプルコードを探して、ドキュメントを確認させます。
Tool #1: search_docs

Tool #2: search_docs
Processing request of type CallToolRequest
Processing request of type CallToolRequest
A2Aのドキュメントが見つかりました。詳細なコンテンツを確認させます。
Tool #3: fetch_doc
Processing request of type CallToolRequest
完璧です!Strands AgentsでのA2Aサーバーの最小サンプルコードをまとめました。

## 🚀 A2Aサーバーの最小サンプルコード

### インストール
```bash
pip install 'strands-agents[a2a]'
```

### 最小限のA2Aサーバー実装
```python
import logging
from strands_tools.calculator import calculator
from strands import Agent
from strands.multiagent.a2a import A2AServer

logging.basicConfig(level=logging.INFO)

# Strandsエージェントを作成
strands_agent = Agent(
    name="Calculator Agent",
    description="計算が得意なエージェント",
    tools=[calculator],
    callback_handler=None
)

# A2Aサーバーを作成(デフォルトはストリーミング有効)
a2a_server = A2AServer(agent=strands_agent)

# サーバーを起動
a2a_server.serve()
```

### サーバー設定オプション
```python
# より詳細な設定例
a2a_server = A2AServer(
    agent=strands_agent,
    host="127.0.0.1",      # バインドするホスト(デフォルト)
    port=9000,             # バインドするポート(デフォルト)
    version="0.0.1"        # エージェントバージョン
)

a2a_server.serve()
```

### クライアント側の使用例

**同期型クライアント:**
```python
import asyncio
from uuid import uuid4
import httpx
from a2a.client import A2ACardResolver, ClientConfig, ClientFactory
from a2a.types import Message, Part, Role, TextPart

async def send_message(message: str):
    async with httpx.AsyncClient(timeout=300) as httpx_client:
        # エージェントカードを取得
        resolver = A2ACardResolver(httpx_client=httpx_client, base_url="http://127.0.0.1:9000")
        agent_card = await resolver.get_agent_card()

        # クライアントを作成
        config = ClientConfig(httpx_client=httpx_client, streaming=False)
        factory = ClientFactory(config)
        client = factory.create(agent_card)

        # メッセージを送信
        msg = Message(
            kind="message",
            role=Role.user,
            parts=[Part(TextPart(kind="text", text=message))],
            message_id=uuid4().hex,
        )

        async for event in client.send_message(msg):
            if isinstance(event, Message):
                print(event.model_dump_json(exclude_none=True, indent=2))
                return event

asyncio.run(send_message("what is 101 * 11"))
```

**ストリーミング型クライアント:**
```python
# config = ClientConfig(httpx_client=httpx_client, streaming=True)
# を使用してストリーミングモードで応答を受け取ります
```

### デプロイ時のパス設定
```python
# ロードバランサー配下にデプロイする場合
a2a_server = A2AServer(
    agent=strands_agent,
    http_url="http://my-alb.amazonaws.com/calculator"
)
```

MCPサーバー「strands-agents-mcp-server」とは?

AIに聞いてみました。「Strands Agentsの開発者向けドキュメントアシスタント」とのことです。

strands-agents-mcp-serverはどんなMCPサーバーですか?
`strands-agents-mcp-server`について調べますね。## `strands-agents-mcp-server`の概要

`strands-agents-mcp-server`は、Strands AgentsのドキュメントをAIコーディングアシスタントに提供するMCPサーバーです。llms.txtファイルを通じてキュレーションされたドキュメントへのアクセスを可能にし、AIアシスタントが関連ドキュメントをインテリジェントなランキングで検索・取得できるようにします。

## 主な機能

### 1. **ドキュメント検索機能**
TF-IDFベースの検索システムで、Markdownを認識したスコアリングを行い、タイトル、ヘッダー、コードブロックを優先的に評価します。

### 2. **提供されるツール**
search_docs(ドキュメント検索)とfetch_doc(ドキュメント取得)の2つのツールが自動承認されています。

### 3. **最適化された取得**
必要な時のみ完全なドキュメントコンテンツを遅延ロードし、パフォーマンスを最適化。関連性スコアリング付きのコンテキストスニペットを提供します。

## 使用目的

このMCPサーバーは以下の用途で使われます:

- **Strands Agentsの開発支援** - カスタムツールやエージェントの開発をガイド付きプロンプトでサポート
- **デバッグ・トラブルシューティング** - Strands実装の問題解決
- **概念理解** - Strandsの概念やパターンに関する迅速な回答
- **マルチエージェントシステム設計** - GraphやSwarmパターンを使った設計支援

## 対応クライアント

Q Developer CLI、Cursor、Claude、Clineなど40以上のMCP対応アプリケーションで使用可能です。

## 設定例

あなたのコードで使われているように、`uvx strands-agents-mcp-server`で簡単に起動できます:

```python
StdioServerParameters(
    command="uvx", 
    args=["strands-agents-mcp-server"]
)
```

つまり、このMCPサーバーは**Strands Agentsの開発者向けドキュメントアシスタント**として機能し、コーディング中にリアルタイムでStrands関連の情報を提供してくれるツールです。

マルチエージェント

独立したエージェント同士が連携し合うというよりも、監督者エージェント(orchestrator)が複数のエージェントをツールのように呼び出すイメージです。

「Agent-as-Tools」パターンと呼ぶそうよ

コード

# 必要なライブラリをインポート
from dotenv import load_dotenv
from strands import Agent, tool
from strands_tools import calculator

# .envファイルから環境変数を読み込む
load_dotenv()

# サブエージェント1を定義
@tool
def math_agent(query: str):
    agent = Agent(
        model="jp.anthropic.claude-haiku-4-5-20251001-v1:0",
        system_prompt="ツールを使って計算を行ってください",
        tools=[calculator]
    )
    return str(agent(query))

# サブエージェント2を定義
@tool
def haiku_agent(query: str):
    agent = Agent(
        model="jp.anthropic.claude-haiku-4-5-20251001-v1:0",
        system_prompt="与えられたお題で五・七・五の俳句を詠んで"
    )
    return str(agent(query))

# 監督者エージェントの作成と実行
orchestrator = Agent(
    model="jp.anthropic.claude-haiku-4-5-20251001-v1:0",
    system_prompt="与えられた問題を計算して、答えを俳句として詠んで",
    tools=[math_agent, haiku_agent]
)
orchestrator("200円持っている健司君が10円の駄菓子を3つ買いました。今いくら?")

実行結果

まず計算して、その答えを短歌に詠みますね。
Tool #1: math_agent
200円から10円の駄菓子を3つ買った場合の残額を計算します。
Tool #1: calculator
200円から10円の駄菓子を3つ買った場合の**残額は170円**です。

計算内訳:
- 初期金額:200円
- 駄菓子の価格:10円 × 3つ = 30円
- 残額:200円 - 30円 = **170円**次に、この答えを短歌として詠みます。
Tool #2: haiku_agent
# 秋の日の買い物

200円持ちて
駄菓子三つ買ふ
10円ずつ
秋風そよぐ
170円残す

---

**解説:**
- 五句:200円持ちて(5音)
- 七句:駄菓子三つ買ふ(7音)
- 五句:10円ずつ(5音)
- 七句:秋風そよぐ(7音)
- 七句:170円残す(7音)

与えられたお題(200円から10円の駄菓子3つで170円残る)を詠みながら、「秋風」を秋の季語として入れました。**答え:健司君は今170円持っています。**

**計算内訳:**
- 初期金額:200円
- 支出:10円 × 3つ = 30円
- 残額:200円 - 30円 = **170円**

**短歌:**
```
200円持ちて
駄菓子三つ買ふ
10円ずつ
秋風そよぐ
170円残す
```

うーーん、短歌そのものはちょっと微妙💦

まとめ

Strands Agentsのハンズオンを行いました。

簡単な処理だったこともありますが、思った以上にシンプルなコードで書けそうです。
慣れるまで色々試していこうと思います。

次回はAgetnCoreをハンズオンします。

目次