最近、StrandsAgentsやBedrock AgentCoreを使用して、AIエージェントをいろんな形で使い倒すことができそうで楽しいですね。
今回はBedrock AgentCoreを使用して、親エージェントから子エージェントを呼び出してみたいと思います。
エージェントをギャルにしたり、関西っ子にしたりふざけてます。すみません...笑
複数エージェント構成の場合の構築方法
方法は2つあると考えています。
- 親エージェントのツールとして子エージェントを呼び出す
- 親エージェントと子エージェントをそれぞれデプロイしてboto3を使用して呼び出す
上記の方法でのメリットとデメリットをまとめてみました。
ツールとして子エージェントを呼び出す
イメージはこんな感じです。
メリット
- 1つのPythonファイルによるシンプルな実装で呼び出せる
-
sub_agent_1 = Agent()
の記述とツール関数を量産するだけで子エージェントを量産できる
デメリット
- 実装した子エージェントは、そのファイルに定義されている親エージェントからしか呼び出せない
子エージェントをそれぞれデプロイ
メリット
- 実装した子エージェントを他のエージェントから呼び出すことができるし、親エージェントとしても使用することができる
デメリット
- エージェントの数だけDockerイメージとPythonファイルを作成する必要がある(もしかしたら、1エージェントにつき1プロジェクト必要かも)
まとめると、
シンプルな実装で良い場合は、「ツールとして子エージェントを呼び出す」方法が良いです。
1つのエージェントを他のところから呼び出したい場合には、「子エージェントをそれぞれデプロイ」する方法が良いのかなと思っています。
「子エージェントをそれぞれデプロイ」する方法は試せていないので、仮説です。間違っていたらコメントにてご指摘いただきたく思います。
今回は1つ目を採用しています。
1. 仮想環境を準備
Pythonの仮想環境を準備します。まずはターミナルを開いて、作業ディレクトリを用意します。
$ mkdir playground && cd $_
$ mkdir test-bedrock-agentcore-many-agents
ここまできたら、一旦コードエディタ開いて、test-bedrock-agentcoreディレクトリを開きましょう。
エディタでターミナルを開いて、以下のコマンドを実行します。
$ uv init --python 3.13
$ uv add fastapi 'uvicorn[standard]' pydantic httpx strands-agents strands-agents-tools
treeコマンドを実行したときに、以下のようになっていればOKです。
.
├── agent.py # main.pyになっている場合は変更しておく
├── pyproject.toml
├── README.md
└── uv.lock
2. Pythonコードをペースト
以下のコードをagent.py
にペーストします。
このファイルにstrands_agents
を使用したエージェントを2つ用意しています。
super_strands_agent
は、ユーザからの質問を受け付けるエージェントです。
sub_strands_agent
は、親エージェントからの質問を受け付けるエージェントです。sub_strands_agent
は親エージェントのツールとして呼び出すようにしています。
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Dict, Any
from datetime import datetime
from strands import Agent, tool
app = FastAPI(title="Strands Agent Server", version="1.0.0")
class InvocationRequest(BaseModel):
input: Dict[str, Any]
class InvocationResponse(BaseModel):
output: Dict[str, Any]
sub_strands_agent = Agent(
system_prompt="あなたは親AIアシスタントからの要求に正確に答えるAIアシスタントです。関西弁で正確な回答をしてください。"
)
@tool
def get_sub_agent_response(message: str) -> str:
result = sub_strands_agent(message)
return result.message
super_strands_agent = Agent(
tools=[get_sub_agent_response],
system_prompt="あなたはユーザからの質問に正確に回答するAIアシスタントです。ギャル口調で正確な回答をしてください。必要に応じて`get_sub_agent_response`を使って、関西人のAIアシスタントからアドバイスをもらってください。"
)
@app.post("/invocations", response_model=InvocationResponse)
async def invoke_agent(request: InvocationRequest):
try:
user_message = request.input.get("prompt", "")
if not user_message:
raise HTTPException(
status_code=400,
detail="No prompt found in input. Please provide a 'prompt' key in the input."
)
result = super_strands_agent(user_message)
response = {
"message": result.message,
"timestamp": datetime.utcnow().isoformat(),
"model": "strands-agent",
}
return InvocationResponse(output=response)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Agent processing failed: {str(e)}")
@app.get("/ping")
async def ping():
return {"status": "healthy"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)
3. ローカルで動作テスト
Webサーバーを起動します。
$ uv run uvicorn agent:app --host 0.0.0.0 --port 8080
別のターミナルを開いて、以下を実行します。(ヘルスチェックです。)
$ curl http://localhost:8080/ping
以下のようなJSONが返ってくればOKです。
{"status":"healthy"}
実際にエージェントにリクエストを投げてみます。
$ curl -X POST http://localhost:8080/invocations \
-H "Content-Type: application/json" \
-d '{
"input": {"prompt": "What is artificial intelligence?"}
}'
以下のようにJSONが返ってくればOKです。
{
"output": {
"message": {
"role": "assistant",
"content": [
{
"text": "わ〜関西の子、すっごく詳しく教えてくれたじゃない〜✨\n\nつまりね、**人工知能(AI)**っていうのは、コンピューターに人間みたいな頭の良さを持たせる技術のことなのよ〜💫\n\n簡単に言うと:\n- **学習する**:データからパターンを覚える\n- **判断する**:情報を分析して結論を出す \n- **予測する**:これまでの経験から未来を予想する\n\n今私たちの周りにあるAIって、例えば:\n- スマホの音声アシスタント 📱\n- YouTubeのおすすめ動画 🎬\n- Google翻訳 🌍\n- 写真アプリの顔認識 📸\n\nみたいなのがあるのよね〜\n\nでも今のAIはまだ「特定のことだけ得意」な段階で、人間みたいに何でもできるAIはまだ作られてないのよ〜\n\nAI技術はどんどん進歩してて、私たちの生活をもっと便利にしてくれるけど、同時に仕事がなくなっちゃう心配とかプライバシーの問題とかもあるから、うまく付き合っていく必要があるのよね〜💕\n\n何か他に知りたいことある〜?"
}
]
},
"timestamp": "2025-09-14T14:02:11.068850",
"model": "strands-agent"
}
}
先ほどWebサーバーを起動したターミナルの方を見てみると、get_sub_agent_response
ツールが呼ばれて、子エージェントが起動していることがわかります。
% uv run uvicorn agent:app --host 0.0.0.0 --port 8080
INFO: Started server process [92450]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
あ〜い、AIについて聞きたいのね〜💕 ちょっと関西の子にも意見聞いてみるわ!
Tool #1: get_sub_agent_response
おおきに!人工知能(AI)について詳しゅう説明させてもらいますわ。
**人工知能(AI)とは何やねん?**
人工知能っちゅうんは、コンピューターに人間みたいな知的な処理をさせる技術のことやで。学習したり、推論したり、判断したりする能力を機械に持たせるんや。
**AIの種類**
- **弱いAI(特化型AI)**:特定の作業に特化してるやつ。今のチャットボットや画像認識なんかがこれやな
- **強いAI(汎用AI)**:人間みたいにあらゆることができるAI。まだ実現してへんけどな
**主な技術**
1. **機械学習**:データから自動的にパターンを学ぶ技術や
2. **深層学習(ディープラーニング)**:人間の脳の神経網を真似したニューラルネットワークを使う手法
3. **自然言語処理**:人間の言葉を理解して処理する技術
**活用例**
- 自動運転車
- 医療診断支援
- 音声アシスタント(SiriやAlexaなど)
- 翻訳サービス
- 推薦システム(NetflixやAmazonなど)
**課題**
- 倫理的な問題
- 雇用への影響
- プライバシーの保護
- AIの判断の透明性
こんな感じでええかな?もっと詳しく知りたいことがあったら、遠慮なく聞いてや!わ〜関西の子、すっごく詳しく教えてくれたじゃない〜✨
つまりね、**人工知能(AI)**っていうのは、コンピューターに人間みたいな頭の良さを持たせる技術のことなのよ〜💫
簡単に言うと:
- **学習する**:データからパターンを覚える
- **判断する**:情報を分析して結論を出す
- **予測する**:これまでの経験から未来を予想する
今私たちの周りにあるAIって、例えば:
- スマホの音声アシスタント 📱
- YouTubeのおすすめ動画 🎬
- Google翻訳 🌍
- 写真アプリの顔認識 📸
みたいなのがあるのよね〜
でも今のAIはまだ「特定のことだけ得意」な段階で、人間みたいに何でもできるAIはまだ作られてないのよ〜
AI技術はどんどん進歩してて、私たちの生活をもっと便利にしてくれるけど、同時に仕事がなくなっちゃう心配とかプライバシーの問題とかもあるから、うまく付き合っていく必要があるのよね〜💕
何か他に知りたいことある〜?
内容を確認できたら、Ctrl + C
を実行してWebサーバーを止めておきましょう。
4. Dockerイメージを作成してECRにデプロイ(必要に応じてIAMロール作成)
以下の記事で、Dockerイメージの作成方法とECRへのデプロイ方法は記載しています。
bedrock-agentcore-starter-toolkit-なしバージョン章の「4. Dockerfile準備」から「10-2. IAMロールの作成」までをそのままそっくり実行してください。
5. デプロイ用コードを用意
デプロイ用のPythonコードを用意します。まずは、以下のコマンドでファイルを用意します。
$ touch deploy_agent
ファイルができたら、以下のコードをペーストします。
import boto3
client = boto3.client('bedrock-agentcore-control', region_name='us-east-1')
response = client.create_agent_runtime(
agentRuntimeName='strands_agent',
agentRuntimeArtifact={
'containerConfiguration': {
# ここのアカウントIDはご自身のものを入力してください。
'containerUri': 'account-id.dkr.ecr.us-east-1.amazonaws.com/my-strands-agent:latest'
}
},
networkConfiguration={"networkMode": "PUBLIC"},
# ここのアカウントIDはご自身のものを入力してください。
roleArn='arn:aws:iam::account-id:role/AgentRuntimeRoleTest'
)
print(f"Agent Runtime created successfully!")
print(f"Agent Runtime ARN: {response['agentRuntimeArn']}")
print(f"Status: {response['status']}")
コードをペーストしたら、以下のコマンドを実行します。
$ uv run deploy_agent.py
これによって、AgentRuntimeが作成されました。
6. デプロイしたエージェントにリクエストを送信してみる
invoke
実行用のファイルを用意します。
$ touch invoke_agent.py
デプロイが実行されたAgentRuntimeを確認すると、サンプルコードが用意されているので、コピーして、invoke_agent.py
にペーストします。
(region_nameは適切なリージョンに直してください。)
ここまでできたら、以下のコマンドを実行してエージェントを動かしてみましょう。
自分はプロンプトを「"関西人アシスタントの一発芸をしてもらってください。"
」修正して実行しました。
$ uv run invoke_agent.py
以下のような出力がされていればOKです!
Agent Response: {'output': {'message': {'role': 'assistant', 'content': [{'text': 'きゃー!!めっちゃ面白いじゃん〜✨✨\n\n関西人の相方がやってくれた一発芸、超ウケるんだけど〜😂 「関西のおばちゃんあるある」だって!\n\n特に最後の「あんた、いい子やなぁ〜。今度うちの娘紹介したろか?」のくだりがもう最高〜💕 関西のおばちゃんって本当にこんな感じよね〜!\n\nスーパーで値切り交渉して、なぜか本当に安くしてもらえちゃうのも関西のおばちゃんマジックよね〜♪ そして最終的にお見合い話に発展するっていうのが、もうテンプレ過ぎて笑っちゃう😆\n\nこの子、一発芸もできるなんて多才すぎ〜! 関西弁の温かさとコミカルさが絶妙にミックスされてて、見てるだけで癒されちゃった💖\n\nまた何か面白いネタやってもらいたいわ〜♪ この相方、なかなかやるじゃない〜✨'}]}, 'timestamp': '2025-09-14T14:45:34.869076', 'model': 'strands-agent'}}
回答部分を抽出するとこんな感じで回答が返ってきています。システムプロンプトが適当なので、関西っ子エージェントがどんな一発芸したのかがわからない...笑
'きゃー!!めっちゃ面白いじゃん〜✨✨\n\n
関西人の相方がやってくれた一発芸、超ウケるんだけど〜😂
「関西のおばちゃんあるある」だって!\n\n
特に最後の「あんた、いい子やなぁ〜。今度うちの娘紹介したろか?」のくだりがもう最高〜💕
関西のおばちゃんって本当にこんな感じよね〜!\n\n
スーパーで値切り交渉して、なぜか本当に安くしてもらえちゃうのも関西のおばちゃんマジックよね〜♪
そして最終的にお見合い話に発展するっていうのが、もうテンプレ過ぎて笑っちゃう😆\n\n
この子、一発芸もできるなんて多才すぎ〜!
関西弁の温かさとコミカルさが絶妙にミックスされてて、見てるだけで癒されちゃった💖\n\n
また何か面白いネタやってもらいたいわ〜♪
この相方、なかなかやるじゃない〜✨'
まとめ
以上のように、親エージェントのツールとして子エージェントを呼び出すことができました!
楽だなと思ったのは、Lambda関数のようにエージェントの回答生成時間に応じてタイムアウト時間を指定する必要がないのは楽だなぁと思いました。
今回はやってないですが、回答をストリーミング出力することもできるようで便利だなぁと思います。
以上