Strands Agentsを試してみた話

はじめに
こんにちは!
KINTOテクノロジーズのデータ戦略部DataOpsG所属の上平です。
普段は社内のデータ分析基盤と「cirro」というAIを活用した社内アプリの開発・保守・運用を担当しています。
「cirro」では、AIにAmazon Bedrockを利用しており、Bedrockの呼び出しにはAWSのConverse APIを使用しています。
本記事では、「cirro」にツールや子エージェントの機能を実装するために、ローカル環境でStrands Agentsを検証した事例をご紹介します。
本記事の対象者
本記事は、Amazon BedrockをConverse APIやInvoke Model経由で利用した経験のある方を対象としています。
Strands Agentsとは
2025年5月16日にAWS Open Source Blogで公開されたオープンソースのAIエージェントSDKです。
以下は、AWSのAmazon Web Services ブログで公開されている図です。
図のように、ツールを備えたAIを実装するには、Agentic Loopと呼ばれるループ処理が必要です。
この処理では、AIの応答がユーザーへの回答なのか、ツールを使ってさらに処理を進めるべきかを判断します。
Strands Agentsを使えば、このループ処理を開発者が自前で実装することなく、AIエージェントを構築できます。
参考、図の出典:Strands Agents – オープンソース AI エージェント SDK の紹介
ローカル環境でStrands Agentsを動かす!
※本セクションは、過去にConverse APIなどを用いてBedrockを利用した経験がある方を前提としています。
そのため、モデルのアクセス許可設定などの基本的な手順については説明を省略しています。
また、サンプルのため例外処理も省略しています。
準備
- ライブラリ
以下のコマンドで、ライブラリをインストールします。
pip install strands-agents strands-agents-tools
実行①
(運のいい方は・・・)最短下記のコードで動きます。
from strands import Agent
agent = Agent()
agent("こんにちは!")
多くのブログなどではこのコードが紹介されていますが、私の環境ではうまく動きませんでした😂
それはそうですよね・・・モデルもBedrockを呼び出すリージョンも指定していないので・・・
実行②
モデルを正しく呼び出すためには、以下のようにモデルとリージョンを指定する必要があります。
ここでは、弊社のようにSSOでログインし、スイッチロールによって権限を取得する環境を前提としています。
【ポイント】
- 呼び出すモデルとリージョンをロールが呼び出せるものに設定する。
例:anthropic.claude-3-sonnet-20240229-v1:0(モデル)、us-east-1(リージョン)※リージョンはセッション作成時のプロファイル内で指定しています。
import boto3
from strands import Agent
from strands.models import BedrockModel
if __name__ == "__main__":
# セッション作成
session = boto3.Session(profile_name='<スイッチ先のロール>')
# モデル設定
bedrock_model = BedrockModel(
boto_session=session,
model_id="us.amazon.nova-pro-v1:0",
temperature=0.0,
max_tokens=1024,
top_p=0.1,
top_k=1,
# Trueにするとストリーミングで出力される。
# ストリーミングでツール利用がサポートされないモデルがあるため、OFF
streaming=False
)
# エージェントのインスタンスを作成
agent = Agent(model=bedrock_model)
# 質問を投げる
query = "こんにちは!"
response = agent(query)
print(response)
ここまでで、Converse APIと同様に temperature などのパラメータを指定してBedrockを呼び出すことができるようになりました🙌
でも、Strands Agentsを使うなら…やっぱりツールを呼び出したいですよね!
実行③
下記のようにツールを定義すれば、質問に応じてツールを使用し、Agentic Loopを実行した後の回答を出力してくれます。
【ポイント】
- ツールとしたい関数を「@tool」でデコレートしてます。
- ツールは
Agent(model=bedrock_model, tools=[get_time])
で、関数の配列として渡しています。
import boto3
from strands import Agent
from strands.models import BedrockModel
#------ツール用に読み込んだライブラリ------------
from strands import tool
from datetime import datetime
# ツールの定義
@tool(name="get_time", description="時刻を回答します。")
def get_time() -> str:
"""
現在の時刻を返すツール。
"""
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return f"現在の時刻は {current_time} です。"
if __name__ == "__main__":
# セッション作成
session = boto3.Session(profile_name='<スイッチ先のロール>')
# モデル設定
bedrock_model = BedrockModel(
boto_session=session,
model_id="us.amazon.nova-pro-v1:0",
temperature=0.0,
max_tokens=1024,
top_p=0.1,
top_k=1,
# Trueにするとストリーミングで出力される。
# ストリーミングでツール利用がサポートされないモデルがあるため、OFF
streaming=False
)
# ツールを使用するエージェントのインスタンスを作成
agent = Agent(model=bedrock_model, tools=[get_time])
# 質問を投げる。ツールを使用しないとAIは時刻が判別できない。
query = "こんにちは!今何時?"
response = agent(query)
print(response)
私の環境では下記回答を得ることができました!
<thinking> 現在の時刻を調べる必要があります。そのためには、`get_time`ツールを使用します。 </thinking>
Tool #1: get_time
こんにちは!現在の時刻は 2025-07-09 20:11:51 です。こんにちは!現在の時刻は 2025-07-09 20:11:51 です。
応用
ツールについて、今回ロジックベースの処理を返すだけのツールでしたが、
例えばツール内でAgentを作成し、回答をチェックさせるなどの処理を組み込めば、
AIがAIを呼び出すマルチエージェントな仕組みが簡単に作れます。
時刻に加え、子エージェントがトリビアも返すように、ツールを修正したコードは以下です。
【ポイント】
if __name__ == "__main__":
で宣言したグローバルスコープのsession
を使いまわしています。
これをしない場合、私の環境ではモデル設定に1分程度オーバーヘッドが発生しました。
おそらくは何らかの資源確保で時間がかかってしまうのでは…と思います。
@tool(name="get_time", description="現在日時と、日時にちなんだトリビアを回答します。")
def get_time() -> str:
"""
現在の時刻を返すツール。
注意:この関数では boto3.Session を使った BedrockModel の初期化に
グローバルスコープで定義された `session` 変数が必要です。
`session` は `if __name__ == "__main__":` ブロックなどで事前に定義しておく必要があります。
"""
current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# モデル設定
bedrock_model = BedrockModel(
boto_session=session,
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
temperature=0.0,
max_tokens=1024,
top_p=0.1,
top_k=1,
streaming=False
)
agent = Agent(model=bedrock_model)
# ここが子エージェントから回答を得る部分!
response = agent(f"現在の時刻は {current_time} です。日時と日付にちなんだトリビアを1つ教えてください。")
return f"現在の時刻は {current_time} です。{response}"
最終的なAIの回答は以下にりました。
こんにちは!現在の時刻は 2025-07-10 18:51:23 です。今日は「納豆の日」です!
これは「なっ(7)とう(10)」の語呂合わせから制定されました。1992年に関西納豆工業協同組合が関西での納豆消費拡大を目的として始めたのがきっかけです。
面白いことに、納豆は関東では古くから親しまれていましたが、関西では苦手な人が多く、この記念日も「関西で納豆をもっと食べてもらおう」という願いから生まれたんです。現在では全国的に「納豆の日」として認知されており、この日にはスーパーなどで納豆の特売が行われることも多いですよ。
夕食の時間帯ですし、今日は納豆を食べてみるのはいかがでしょうか?
備考
マルチエージェントは比較的簡単に実装できますが、
実際に試してみたところ、AIを複数呼び出す分だけトークン数と応答時間が増加するため、使いどころに悩むところです。
以下は、親エージェントと子エージェントを用いた際の処理コストの内訳です。
区分 | 親エージェント | 子エージェント | 全体 |
---|---|---|---|
入力トークン | 1086 | 54 | 1140 |
出力トークン | 256 | 219 | 475 |
処理時間 | 7.2秒 | 7.3秒 | 14.5秒 |
このように、子エージェントの応答が加わることで全体の処理時間が倍増していることがわかります。
そのため、マルチエージェントの活用は、出力の多様性が求められたり、ロジックベースでは対応が難しい複雑なタスクに限定するのが現実的かもしれません。
おわりに
今回は、データ戦略部で展開しているAI活用システム「cirro」を拡張するために、
Strands Agentsを検証した際の“動かすためのポイント”をご紹介しました。
意外とハマりどころが多く、実際に動かす際の参考になれば幸いです。
Strands Agentsを使うことで、ツールや子エージェントによる機能拡張が容易になります。
一方で、処理時間やトークン数の増加、システム組み込み時の権限管理など、課題も見えてきました。
なお、記事内で触れた「cirro」は、Pythonで開発された完全サーバレスなシステムで、
ユーザー自身がタスクや参照データを柔軟に拡張できることが特徴です。
現在は、ダッシュボードの案内やアンケート分析などに活用しています。
こちらについて、AWSの紹介記事はありますが、いずれ詳しくご紹介できればと思っています!
AWSのcirroの紹介記事
関連記事 | Related Posts
We are hiring!
生成AIエンジニア/AIファーストG/東京・名古屋・大阪・福岡
AIファーストGについて生成AIの活用を通じて、KINTO及びKINTOテクノロジーズへ事業貢献することをミッションに2024年1月に新設されたプロジェクトチームです。生成AI技術は生まれて日が浅く、その技術を業務活用する仕事には定説がありません。
【クラウドエンジニア(クラウド活用の推進)】Cloud Infrastructure G/東京・大阪
KINTO Tech BlogCloud InfrastructureグループについてAWSを主としたクラウドインフラの設計、構築、運用を主に担当しています。