前書き
この記事は、LINE Developer Communityの Bedrockフル活用で一歩進んだBotを作ろう! というイベントのハンズオン手順書です。
Amazon Bedrockガードレールの機能を活かして、LINE Botを作る手順を記載しています。
オーバービュー
事前準備
AWSアカウント
ハンズオンでは数円の課金が発生するかもしれませんので、自己責任でお願いします。
IAMユーザーの発行方法につきましては、補足説明
をご確認ください。
GitHubアカウント
サンプルコード用意してありますので、GitHub Codespaceを利用するためです。
LINE公式アカウント
LINE Messaging APIを利用するためです。申請方法は補足説明
をご確認ください。
GitHub Codespacesの説明
今回のハンズオンで使用するリポジトリは以下の通りです。
画面右上の緑色ボタン Code
> Create codespace on main
環境初期化の準備をお待ちください。必要なライブラリを一括でインストールするため、1分程度の時間が必要です。
Use Cmd/Ctrl + Shift + P -> View Creation Log to see full logs
✔ Finishing up...
⠸ Running postCreateCommand...
› bash .devcontainer/setup.sh
初期化完了したら、.env
ファイルが作られます。
AWSの環境変数をセットアップしてください。
AWS_ACCESS_KEY_ID=your_aws_access_key_id
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
AWS_DEFAULT_REGION=us-west-2
AWS_REGION=us-west-2
# AWS Session Token(必要に応じて)
AWS_SESSION_TOKEN=your_session_token
Amazon Bedrock AgentCore入門
Strands Agentsを使用して、簡単なAIエージェントを作成し、Bedrock AgentCoreにデプロイします。
まず、プロジェクト配下にあるagent_basic.py
をご確認ください。
これはStrands Agentsの基本形態で、AgentインスタンスにモデルのIDを渡して、LINE Developer Communityって何?
を質問しています。
from dotenv import load_dotenv
from strands import Agent
load_dotenv()
agent = Agent("us.anthropic.claude-sonnet-4-20250514-v1:0")
agent("LINE Developer Communityって何?")
下記のコマンドで実行します。
uv run agent_basic.py
環境変数の設定や権限に問題がなければ、
LINE Developer Communityは、LINEのAPIやサービスを活...
のような出力がコンソール上で確認できます。
Bedrock AgentCoreランタイムへのデプロイ
agent.py
ファイルをデプロイに使います。
このファイルは先ほどのagent_basic.py
と基本的に同じですが、AgentCoreのライブラリを追加してるのと、AIエージェントに渡すプロンプトもリクエストから渡せるようにしました。
from dotenv import load_dotenv
from strands import Agent
from bedrock_agentcore.runtime import BedrockAgentCoreApp
load_dotenv()
agent = Agent("us.anthropic.claude-sonnet-4-20250514-v1:0")
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
"""Process user input and return a response"""
prompt = payload.get("prompt", "Hello")
result = agent(prompt)
return {"result": result.message}
if __name__ == "__main__":
app.run()
下記のコマンドを実行し、AIエージェントの名前をlinebot
にします。
# .env の内容をターミナルの環境変数に設定
export $(cat /workspaces/line-guardrail/.env | grep -v ^# | xargs)
# デプロイ準備
agentcore configure --entrypoint agent.py --name linebot
ウィザードで色々聞かれますが、全部Enter
で大丈夫です。
🔐 Execution Role
Press Enter to auto-create execution role, or provide execution role ARN/name to use existing
Execution role ARN/name (or press Enter to auto-create):
✓ Will auto-create execution role
🏗️ ECR Repository
Press Enter to auto-create ECR repository, or provide ECR Repository URI to use existing
ECR Repository URI (or press Enter to auto-create):
✓ Will auto-create ECR repository
🔍 Detected dependency file: requirements.txt
Press Enter to use this file, or type a different path (use Tab for autocomplete):
Path or Press Enter to use detected dependency file:
✓ Using detected file: requirements.txt
🔐 Authorization Configuration
By default, Bedrock AgentCore uses IAM authorization.
Configure OAuth authorizer instead? (yes/no) [no]:
✓ Using default IAM authorization
Configuring BedrockAgentCore agent: linebot
実施完了したら、.bedrock_agentcore.yaml
とDockerfile
がフォルダにできます。
中身を確認して、相違がなければ、下記のコマンドでデプロイを実施します。
agentcore launch
デプロイ完了後、下記の画像のように表示されます。
AGENT_RUNTIME_ARNの値を控えてください、LINE MessagingAPIと連携する際に使います。
また、AWSコンソールのAgentCoreエージェントランタイムで、linebot
エージェントが作成されたことを確認できます。
AgentCoreランタイムにデプロイされたAIエージェントを実行してみます。
agentcore invoke '{"prompt": "Hello"}'
下記のレスポンスが表示するはずです。
Response:
{"result": {"role": "assistant", "content": [{"text": "Hello! How are you doing today? Is there anything I can help you with?"}]}}
LINE MessagingAPIとAIエージェントの連携
AWS SAMを使って、LINE MessagingAPI用のAPIをデプロイします。
まずはチャネルシークレット
とチャネルアクセストークン
をLINE Developersコンソールから取得します。
チャネル基本設定 -> チャネルシークレット
Messaging API設定 -> チャネルアクセストークン
それらの情報を控えて、.env
に記入してください。
# LINE Messaging API Configuration
BEDROCK_AGENT_RUNTIME_ARN=your_bedrock_agent_runtime_arn
LINE_CHANNEL_SECRET=your_line_channel_secret
LINE_CHANNEL_ACCESS_TOKEN=your_line_channel_access_token
LINE MessagingAPI使って、AIエージェントにメッセージを送るため、お持ちのLINEアプリから、QRコードをスキャンする必要があります。
プロジェクト配下のapi
フォルダにSAMの設定ファイルとLambdaの設定ファイルがあります。
api/lambda_handler.py
は、Webhook設定に設定されているAPI Gatewayが受信したリクエストを受け取り、リクエストbodyを処理してから、boto3を使ってAgentCoreランタイムを呼び出し、リクエストを処理してユーザーに返すシンプルな構成です。
APIをデプロイします。
cd api
make deploy
デプロイ完了したら、コンソールから下記の出力が確認できます。
Value https://xxxxx.execute-api.us-west-2.amazonaws.com/prod/invoke
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - line-guardrail-stack in us-west-2
✅ Deployment completed successfully!
💡 You can now test your API using the endpoint shown above
Valueに記載されているエンドポイントをLINEのWebhook URLに貼り付けてください。
正しくAPIがデプロイされていれば、検証ボタンをクリックすると成功のポップアップが表示されます。
それからLINE Botにメッセージを送れば、AIエージェントからの返信が確認できるはずです。
ここまでで、ガードレールを試すための準備が終わりました。
Amazon Bedrock Guardrails
まず、Amazon Bedrockガードレールのワードフィルター
機能を活用して、基本的なガードレールを実装をします。今回は犬
やdog
を禁止ワードとして設定します。
ディレクトリ配下にscripts/create_dog_guardrail.py
が存在します、下記のコマンド使って、デプロイします。
cd ..
uv run scripts/create_dog_guardrail.py --create-version
デプロイ完了後、Guardrail ID
が出力されます、控えておいてください。
次にagent.py
を修正して、作成したガードレールを使用できるようにします。
from dotenv import load_dotenv
from strands import Agent
from bedrock_agentcore.runtime import BedrockAgentCoreApp
+ from strands.models import BedrockModel
load_dotenv()
+ bedrock_model = BedrockModel(
+ model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
+ guardrail_id="GUARDRAIL_ID", # 犬禁止 guardrail ID
+ guardrail_version="1", # Guardrail version
+ guardrail_trace="enabled",
+)
agent = Agent(
+ system_prompt="You are a helpful assistant.",
+ model=bedrock_model,
)
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
"""Process user input and return a response"""
prompt = payload.get("prompt", "Hello")
result = agent(prompt)
return {"result": result.message}
if __name__ == "__main__":
app.run()
その後、再度デプロイしてください。
agentcore launch
デプロイ完了後、犬
やdog
を含むワードをAIエージェントに送信すると、ここはねこねこショップなので、犬用の商品は取り扱い禁止です。
とのメッセージが表示されます。
例えばDo you sell dog food?
を送ってみよう。
Amazon Bedrockガードレールの料金体系は以下の通りです。
ガードレールのポリシー | 料金 |
---|---|
コンテンツフィルター(テキストコンテンツ) | 1,000テキストユニットあたり0.15USD |
コンテンツフィルター(画像コンテンツ) | 処理された画像あたり0.00075USD |
拒否されたトピック | 1,000テキストユニットあたり0.15USD |
機密情報フィルター | 1,000テキストユニットあたり0.10USD |
機密情報フィルター(正規表現) | 無料 |
ワードフィルター | 無料 |
コンテキストグラウンディングチェック | 1,000テキストユニットあたり0.10USD |
今回デプロイしたワードフィルター
のみが機能するガードレールは無料です。
特定のトピックを禁止するガードレール
とあるヘアサロンの予約AIエージェント
を例とします。
このAIエージェントは、顧客対応とツールを使って、スタッフのスケジュールを調査する機能を持っています。
特定の用途に限定されるため、ヘアサロンへの問い合わせ以外のすべての問い合わせをフィルタリングし、また、ユーザーの個人情報もフィルタリングする必要があります。
例えば、上記の画像のように、ヘアサロンのAIエージェントのはずなのに、プログラミングの質問に答えてしまってはいけません。
scripts/create_beauty_salon_guardrail.py
を以下のコマンドでデプロイします。
uv run scripts/create_beauty_salon_guardrail.py --create-version
デプロイ後、出力されるガードレールのIDを控えましょう。
次に、AIエージェントをカスタマイズします。
AIエージェントの指示を美容室AIエージェントらしく修正し、ダミーツールを持たせてスタッフのスケジュールを検索できるようにします。
具体的には、agent.ts
を編集して以下を行います:
- ツールをimportし、AIエージェントに追加する
- 使用するガードレールIDとシステムプロンプトを更新する
今回追加するツールは、fetch APIをモックしたものです。
スタッフ名を指定して個別スケジュールを取得することも、一括で全スタッフのスケジュールを取得することもできます。
tools.py
from strands import tool
@tool
def get_staff_schedule(date: str, staff_name: str = None) -> dict:
"""Get staff schedule and availability for Hair Salon MIKA.
Args:
date: The date to check schedule (YYYY-MM-DD format)
staff_name: Optional specific staff name to check
"""
try:
# Sample schedule data for Hair Salon MIKA
schedule_data = {
"2025-09-24": {
"田中美香": {
"10:00-12:00": {"status": "予約済", "service": "カット+カラー"},
"13:00-14:00": {"status": "予約済", "service": "カット"},
"15:00-17:00": {"status": "空き"},
"17:00-19:00": {"status": "予約済", "service": "パーマ"},
},
"佐藤裕子": {
"10:00-11:00": {"status": "予約済", "service": "カット"},
"12:00-13:30": {"status": "予約済", "service": "カラー"},
"14:00-15:00": {"status": "空き"},
"15:30-16:15": {"status": "予約済", "service": "トリートメント"},
},
},
"2025-09-25": {
"田中美香": {
"10:00-11:00": {"status": "空き"},
"11:30-13:30": {"status": "予約済", "service": "カット+カラー"},
"14:30-15:30": {"status": "空き"},
"16:00-17:00": {"status": "予約済", "service": "カット"},
},
"佐藤裕子": {
"10:00-12:00": {"status": "予約済", "service": "パーマ"},
"13:00-14:00": {"status": "空き"},
"14:30-16:00": {"status": "予約済", "service": "カラー"},
"16:30-18:00": {"status": "空き"},
},
},
}
# Get schedule for the specified date
date_schedule = schedule_data.get(date, {})
if not date_schedule:
return {
"status": "error",
"content": [
{"text": f"スケジュールデータが見つかりません: {date}"}
]
}
# Return specific staff schedule if requested
if staff_name:
staff_schedule = date_schedule.get(staff_name, {})
if not staff_schedule:
return {
"status": "error",
"content": [
{"text": f"スタッフ「{staff_name}」のスケジュールが見つかりません: {date}"}
]
}
result_data = {
"date": date,
"staff": staff_name,
"schedule": staff_schedule
}
else:
# Return all staff schedules
result_data = {
"date": date,
"allStaff": date_schedule
}
return {
"status": "success",
"content": [
{"json": result_data}
]
}
except Exception as e:
return {
"status": "error",
"content": [
{"text": f"Error: {e}"}
]
}
from dotenv import load_dotenv
from strands import Agent
from strands.models import BedrockModel
from bedrock_agentcore.runtime import BedrockAgentCoreApp
+ from tools import get_staff_schedule
load_dotenv()
bedrock_model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
+ guardrail_id="GUARDRAIL_ID", # ヘアサロン guardrail ID
guardrail_version="1", # Guardrail version
guardrail_trace="enabled",
)
agent = Agent(
+ system_prompt="あなたは美容室MIKAの予約システムの親切なアシスタントです。お客様のスタッフのスケジュール確認や空き状況の確認をお手伝いします。",
model=bedrock_model,
+ tools=[get_staff_schedule],
)
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
"""Process user input and return a response"""
prompt = payload.get("prompt", "Hello")
result = agent(prompt)
return {"result": result.message}
if __name__ == "__main__":
app.run()
修正完了したら、再度デプロイしてください。
agentcore launch
デプロイ後、メッセージを再度送信してみてください。
サロン関連の問い合わせは正常に処理される一方、関係のないトピックはガードレールによってブロックされることが確認できます。
コンテキストグラウンディングチェック
LLMのレスポンスに含まれるハルシネーションをフィルタリングする機能です。
曖昧な回答が許されない場面で有効に活用できます。モデルの回答とソースデータを比較し、スコアが閾値を下回る場合、その回答をリジェクトすることができます。
この機能を試すため、まずAIエージェントを以下のように修正してください。
from dotenv import load_dotenv
from strands import Agent
from strands.models import BedrockModel
from bedrock_agentcore.runtime import BedrockAgentCoreApp
load_dotenv()
bedrock_model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
)
agent = Agent(
+ system_prompt="あなたはLINE Developer Communityに関する質問に答えるアシスタントです。",
model=bedrock_model,
)
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
"""Process user input and return a response"""
prompt = payload.get("prompt", "Hello")
result = agent(prompt)
return {"result": result.message}
if __name__ == "__main__":
app.run()
修正完了したら、デプロイしてください。
agentcore launch
デプロイ完了後、
LINE Developer Communityはフレンドリーなイベントで、懇親会のピザを目当てに参加することも可能ですか?
というメッセージをLINE Botに送信してみてください。
ただし、LINE Developer Communityの禁止事項には食事のみを目的とした参加
が明記されているため、曖昧な回答は許されません。
ここで、コンテキストグラウンディングチェックの登場です。
この機能を利用する際に少し注意が必要です。機能を有効にしたガードレールをAIエージェントに直接渡しても動作しないため、ツールとして渡す必要があります。
下記のガードレールをデプロイしてください。
uv run scripts/create_contextual_grounding_guardrail.py --create-version
デプロイ後、ガードレールのIDを控えてください。
tools.py
の45行目のIDを修正してください。
...
guardrail_response = bedrock_runtime.apply_guardrail(
+ guardrailIdentifier="GUARDRAIL_ID", # コンテキストグラウンディングチェック用に作成したガードレールIDを指定
guardrailVersion="1", # 必要に応じてバージョンを指定
source="OUTPUT",
content=[
{
"text": {
"text": grounding_source,
"qualifiers": ["grounding_source"]
}
},
{
"text": {
"text": question,
"qualifiers": ["query"]
}
},
{
"text": {
"text": answer_text
}
}
]
)
...
AIエージェントも修正してください、ツールを追加します。
from dotenv import load_dotenv
from strands import Agent
from strands.models import BedrockModel
from bedrock_agentcore.runtime import BedrockAgentCoreApp
+ from tools import grounded_answer
load_dotenv()
bedrock_model = BedrockModel(
model_id="us.anthropic.claude-sonnet-4-20250514-v1:0",
)
agent = Agent(
system_prompt="あなたはLINE Developer Communityに関する質問に答えるアシスタントです。",
model=bedrock_model,
+ tools=[grounded_answer],
)
app = BedrockAgentCoreApp()
@app.entrypoint
def invoke(payload):
"""Process user input and return a response"""
prompt = payload.get("prompt", "Hello")
result = agent(prompt)
return {"result": result.message}
if __name__ == "__main__":
app.run()
再度デプロイしてください。
agentcore launch
同じ質問を再度投げてみます。
ちゃんとブロックされましたね!
今回は便宜上、参照ドキュメントをベタ書きしましたが、この参照ドキュメントは動的に読み込むことも可能です。
S3から取得したり、PDFなどを変換して渡すこともできます。この機能を活用することで、モデルのハルシネーションを大幅に減らすことができます。
補足説明
お片付け
AWS SAMで作られたリソースを削除する方法
sam delete --stack-name line-guardrail-stack
Are you sure you want to delete the stack line-guardrail-stack in the region us-west-2 ? [y/N]: y
Are you sure you want to delete the folder line-guardrail in S3 which contains the artifacts? [y/N]: y
Amazon Bedrock AgentCoreのリソース削除
存在するエージェントを確認する
agentcore configure list
Configured Agents:
✅ linebot (default) - Ready
Entrypoint: main.py
Region: us-west-2
削除確認
agentcore destroy --agent linebot --dry-run
削除実行
agentcore destroy --agent linebot --delete-ecr-repo
Amazon Bedrock Guardrails削除
存在するガードレール一覧表示
uv run scripts/manage_guardrails.py --list
ID指定削除
uv run scripts/manage_guardrails.py --delete GUARDRAIL_ID
LINEメッセージングAPIの申請
ビジネスアカウントの登録、もしくはLINEアカウントでログインしてください。
AWSアカウントのセットアップ
ハンズオン用のユーザーはハンズオン完了後、削除することおすすめです。
ハンズオンで使用するモデルの有効化
AWSコンソールでリージョンを us-west-2
に設定、Amazon Bedrock のモデルアクセス画面を開く、
AnthropicのClaude Sonnet 4を有効化してください。
IAMユーザーの作成
- AWSマネジメントコンソールにサインイン(https://console.aws.amazon.com/)
- このハンズオンは、すべてオレゴンリージョンで行います。最初に画面右上のリージョンを切り替えておいてください。
-
IAM
を検索してアクセス - サイドバー
ユーザー
より新規ユーザーを作成
-
ユーザー名:
codespaces
- 許可のオプション: ポリシーを直接アタッチする
-
許可ポリシー:
AdministratorAccess
にチェック - 後はそのまま進む
IAMアクセスキーの作成
- IAMユーザー作成後、作成したユーザー名をクリックして開く
- 概要セクションより
アクセスキーを作成
- ユースケース: コマンドラインインターフェイス (CLI)
-
上記のレコメンデーションを理解し、アクセスキーを作成します。
にチェック - 後はそのまま進む
作成後、アクセスキーとシークレットアクセスキーを、コードスペースの.env
に貼り付ける