Strands Agents から LiteLLM Proxy 経由で Amazon Bedrock を呼び出してみた

Strands Agents から LiteLLM Proxy 経由で Amazon Bedrock を呼び出してみた

2026.04.12

はじめに

こんにちは、スーパーマーケットのラ・ムーが好きなコンサル部の神野(じんの)です。

最近、AI エージェントフレームワークの Strands Agents を触っているのですが、LLM の呼び出し先を一元管理したいケースがありました。例えばチームごとにアクセスできるモデルを制限したい、使用量を把握したい、といった要件です。

こういったマルチプロバイダー対応の LLM ゲートウェイとしては、AWS 公式のソリューションが公開されています。

https://aws.amazon.com/jp/solutions/guidance/multi-provider-generative-ai-gateway-on-aws/

この公式ソリューションは CloudFront + WAF + Route53 + Middleware コンテナなどフル装備の本番向け構成で、すぐに展開するのに便利ですが、軽い検証目的にはちょっと重たく感じます。

そこで今回は、勉強がてら Terraform で必要最小限の LiteLLM Proxy 環境を自前で構築し、Strands Agents から Proxy 経由で Amazon Bedrock の Claude モデルを呼び出す構成を試してみました。

LiteLLM には OSS 版(MIT ライセンス)と Enterprise 版がありますが、今回使用するのは OSS 版です。Team 管理、仮想 API Key、使用量トラッキングといった機能は OSS 版で利用できるので、無料で試せます。

LiteLLM の管理画面で Team を作成し、仮想 API Key を発行して、アクセス制御付きで通信するところまでやっていきます。

なお、LiteLLM Proxy の管理画面(Admin UI)でどんなことができるかについては、弊社の記事で網羅的に紹介されています。管理画面の機能を把握したい方はこちらもあわせてご覧ください。

https://dev.classmethod.jp/articles/litellm-admin-ui-features/

前提

環境

  • Python 3.12
  • strands-agents 1.29.0(litellm extras 込み)
  • strands-agents-tools 0.2.22
  • LiteLLM Proxy main-v1.81.14-stable(AWS ECS Fargate 上にデプロイ済み)
  • Amazon Bedrock(us-east-1)

通信の流れ

Strands Agents から見ると、LiteLLM Proxy は OpenAI 互換の API エンドポイントとして振る舞います。Bedrock の認証情報はプロキシ側(ECS Task Role)が持っているため、クライアント側では AWS の認証情報を意識する必要がありません。

LiteLLM Proxy の構築(Terraform)

今回は Terraform でシンプルな LiteLLM Proxy 環境を構築しました。コード全体は GitHub リポジトリに公開しています。

https://github.com/yuu551/lite-llm-sample

アーキテクチャ

VPC + ALB + ECS Fargate + RDS のシンプルな構成です。

01-architecture

RDS にログやモデル情報を永続化し、S3 には LiteLLM の設定ファイル(config.yaml)を格納します。

Terraform のモジュール構成

terraform/
├── main.tf                  # プロバイダー + モジュール構成
├── variables.tf             # 入力変数
├── outputs.tf               # ALB DNS 名の出力
├── terraform.tfvars.example # 変数サンプル
├── config/
│   └── config.yaml.tpl      # LiteLLM 設定テンプレート
└── modules/
    ├── network/              # VPC + public/private subnets + NAT Gateway
    ├── ecs/                  # ECS Fargate + ALB + IAM + S3(config) + SG
    ├── rds/                  # (optional) PostgreSQL 15
    └── redis/                # (optional) ElastiCache Redis 7.1

RDS や Redis は enable_rds / enable_redis 変数でオプショナルに切り替えられるようにしています。今回は Team 機能を使うために RDS を有効にしています。

デプロイ手順

実行コマンド
cd terraform
cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars を編集して litellm_master_key を設定
terraform init
terraform apply

terraform.tfvars は下記のような内容です。

terraform.tfvars
aws_region         = "us-east-1"
name_prefix        = "litellm"
litellm_version    = "main-v1.81.14-stable"
litellm_master_key = "sk-your-secret-key-here"

ecs_cpu       = 512
ecs_memory    = 1024
desired_count = 1

enable_rds       = true
enable_redis     = false

litellm_version で LiteLLM のイメージタグを固定しています。ghcr.io/berriai/litellm の公開イメージを直接利用するため、ECR へのビルド・プッシュは不要です。litellm_master_key が管理者用の API Key で、enable_rds = true にすると Team / 仮想 API Key / 使用量トラッキングが使えるようになります。

apply が完了すると ALB の DNS 名が output に表示されます。

実行結果
Apply complete! Resources: 44 added, 0 changed, 0 destroyed.

Outputs:

alb_dns_name = "litellm-alb-xxxxxxxxx.us-east-1.elb.amazonaws.com"
service_url = "http://litellm-alb-xxxxxxxxx.us-east-1.elb.amazonaws.com"

LiteLLM の config.yaml

Terraform の templatefile() で生成される LiteLLM の設定は下記のようになっています。

config.yaml
model_list:
  - model_name: claude-sonnet
    litellm_params:
      model: bedrock/us.anthropic.claude-sonnet-4-5-20250929-v1:0
      aws_region_name: us-east-1

  - model_name: claude-haiku
    litellm_params:
      model: bedrock/us.anthropic.claude-haiku-4-5-20251001-v1:0
      aws_region_name: us-east-1

general_settings:
  store_model_in_db: true
  store_prompts_in_spend_logs: true

litellm_settings:
  drop_params: true
  num_retries: 3

router_settings:
  routing_strategy: usage-based-routing-v2

model_name がプロキシ上のモデルエイリアスで、クライアントからはこのエイリアス名で呼び出します。store_model_in_db: true を設定すると管理画面からモデルの追加・変更ができるようになり、store_prompts_in_spend_logs: true でリクエスト / レスポンスの内容も管理画面から確認できます。

Bedrock の認証は ECS Task Role に bedrock:* の IAM ポリシーを付与しているため、API Key の設定は不要です。

LiteLLM 管理画面での Team 作成と仮想 API Key 発行

LiteLLM Proxy には管理画面が組み込まれています。http://<ALB_DNS>/ui にアクセスし、Username に admin、Password に litellm_master_key で設定した Master Key を入力してログインします。

02-litellm-login

Team の作成

  1. サイドバーから「Teams」を選択
  2. 「+ Create New Team」ボタンを押下
    03-teams-create-new-team
  3. 下記情報を入力
    • Team Name: 任意のチーム名(例:dev-team
    • Models: チームがアクセスできるモデルを選択(例:claude-haiku のみ)
      04-create-team-form
  4. 「Create Team」ボタンを押下

これでチームが作成されました。ここで設定したモデルだけが、このチームに所属する API Key からアクセスできるようになります。

なお、今回は検証していませんが、Team には Max Budget(予算上限)や Budget のリセット期間(日次・月次など)、TPM / RPM のレートリミットも設定できます。予算を超過するとリクエストがブロックされるため、チームごとのコスト管理にも活用できそうですね。詳しくは公式ドキュメントを参照してください。

https://docs.litellm.ai/docs/proxy/team_budgets

仮想 API Key の発行

  1. サイドバーから「Virtual Keys」を選択
  2. 「+ Create New Key」ボタンを押下
    05-virtual-keys-create-new-key
  3. 下記情報を入力
    • Key Name: 任意のキー名(例:dev-team-key
    • Team: 先ほど作成したチームを選択(例:dev-team
    • Models: Team から継承するため、All Team Modelsを選択
      06-create-key-form
  4. 「Create Key」ボタンを押下
  5. 生成された API Key(sk-xxxxxxxx 形式)をコピー
    07-save-your-key

これで Team に紐づいた仮想 API Key が発行されました。この Key を使って Strands Agents からアクセスしていきます。

実装

依存関係のインストール

まずは必要なパッケージをインストールします。

実行コマンド
uv add 'strands-agents[litellm]' strands-agents-tools

Agent の実装

LiteLLM Proxy 経由で Bedrock Claude を呼び出す Agent を実装します。
litellm用の処理も用意されているので、基本はそれを使うだけです。便利ですね。

https://strandsagents.com/docs/user-guide/concepts/model-providers/litellm/

main.py
"""Strands Agents + LiteLLM Proxy sample."""

from strands import Agent
from strands.models.litellm import LiteLLMModel
from strands_tools import calculator

# LiteLLM Proxy の接続情報
LITELLM_PROXY_URL = "http://<ALB_DNS>"
LITELLM_PROXY_KEY = "sk-xxxxxxxx"  # 発行した仮想 API Key

model = LiteLLMModel(
    client_args={
        "api_key": LITELLM_PROXY_KEY,
        "api_base": LITELLM_PROXY_URL,
        "use_litellm_proxy": True,
    },
    model_id="claude-haiku",
    params={
        "max_tokens": 4096,
        "temperature": 0.7,
    },
)

agent = Agent(
    model=model,
    tools=[calculator],
    system_prompt="あなたは親切な日本語アシスタントです。計算が必要な場合はcalculatorツールを使ってください。",
)

def main():
    print("=== Strands Agent + LiteLLM Proxy サンプル ===\n")

    # 単純な会話
    print("--- 会話テスト ---")
    response = agent("日本の首都はどこですか?")
    print(f"回答: {response}\n")

    # ツール使用(calculator)
    print("--- ツール使用テスト ---")
    response = agent("123 * 456 + 789 を計算してください")
    print(f"回答: {response}\n")

if __name__ == "__main__":
    main()

client_argsuse_litellm_proxy: True を設定することで、 Strands の LiteLLM プロバイダーがプロキシモードで動作します。

api_base にプロキシの URL、api_key に発行した仮想 API Key を指定します。model_id には config.yaml で定義したモデルエイリアス名を指定する点に注意してください。Bedrock のモデル ID ではなく、プロキシ側で定義した claude-haikuclaude-sonnet を使います。

今回は strands_toolscalculator をツールとして渡して、LiteLLM Proxy 経由でも Function Calling が動くか確認してみます。

補足

use_litellm_proxy: True の代わりに、model_idlitellm_proxy/ プレフィックスを付ける方法もあります。

model = LiteLLMModel(
    client_args={
        "api_key": LITELLM_PROXY_KEY,
        "api_base": LITELLM_PROXY_URL,
    },
    model_id="litellm_proxy/claude-haiku",
)

どちらでも動作しますが、use_litellm_proxy を使う方が明示的でわかりやすいかなと思います。

動作確認

正常系:会話テスト

実行コマンド
python main.py
実行結果
--- 会話テスト ---
日本の首都は**東京**です。

東京は日本の政治、経済、文化の中心地であり、内閣総理大臣官邸や国会議事堂などの重要な政府機関が置かれています。また、人口も日本最大の都市で、世界的にも有数の大都市として知られています。回答: 日本の首都は**東京**です。

東京は日本の政治、経済、文化の中心地であり、内閣総理大臣官邸や国会議事堂などの重要な政府機関が置かれています。また、人口も日本最大の都市で、世界的にも有数の大都市として知られています。

--- ツール使用テスト ---
計算させていただきます。
Tool #1: calculator
**123 × 456 + 789 = 56,877** です

計算過程:
- 123 × 456 = 56,088
- 56,088 + 789 = 56,877回答: **123 × 456 + 789 = 56,877** です

計算過程:
- 123 × 456 = 56,088
- 56,088 + 789 = 56,877

会話もツール呼び出しも問題なく動いていますね!(2重で表示されているのはprint文を仕込んだからです・・・)

LiteLLM Proxy を経由していますが、Strands Agents のツール呼び出しがそのまま使えています。Proxy はリクエストを透過的に Bedrock へ中継してくれるので、Agent の実装側は直接 Bedrock を呼ぶ場合と変わらない書き方ができます。

モデルアクセス制御の確認

先ほど claude-haiku のみ許可した Team の API Key を使っている状態で、claude-sonnet を呼び出してみます。

main.py
  model = LiteLLMModel(
      client_args={
          "api_key": LITELLM_PROXY_KEY,
          "api_base": LITELLM_PROXY_URL,
          "use_litellm_proxy": True,
      },
-     model_id="claude-haiku",
+     model_id="claude-sonnet",
  )
実行結果
litellm.exceptions.AuthenticationError: litellm.AuthenticationError: AuthenticationError: Litellm_proxyException - team not allowed to access model. This team can only access models=['claude-haiku']. Tried to access claude-sonnet

Team で許可されていないモデルへのアクセスがブロックされていますね!

このように、LiteLLM Proxy の Team 機能を使うことで、API Key 単位でアクセスできるモデルを制御できます。開発チームには Haiku のみ、本番環境には Sonnet も許可する、といった運用が可能になります。

管理画面での使用量確認

管理画面(/ui)から、使用量やログを確認できます。サイドバーの OBSERVABILITY セクションに Usage と Logs があります。

Team 別の使用量

Usage タブで Team Usage を選択すると、チーム単位での利用状況が確認できます。

08-usage-team

Total Spend(合計コスト)、Total Requests(リクエスト数)、Successful Requests(成功数)、Failed Requests(失敗数)、Total Tokens(トークン数)がひと目でわかります。Daily Spend のグラフで日ごとの推移も確認できますね。

Key 別の使用量

Key Activity タブに切り替えると、API Key 単位でさらに詳細な内訳が確認できます。

09-usage-key

Model Usage のテーブルでは、モデルごとの Spend(コスト)、Successful / Failed リクエスト数、Tokens が表示されます。先ほどの動作確認で claude-sonnet にアクセスしてブロックされた分が Failed Requests: 1 としてカウントされていますね。アクセス制御がログにもしっかり反映されています。

リクエストログ

Logs 画面では、個々のリクエストの詳細を確認できます。

10-logs

store_prompts_in_spend_logs: true を設定しているため、各リクエストのプロンプトとレスポンスの内容まで確認できます。右側のパネルでは、System Prompt、ユーザーの入力、モデルの応答、ツール呼び出し(calculator)の結果、トークン数やコストの内訳が表示されています。デバッグや監査に便利ですね。

おわりに

Strands Agents 側の実装はほとんど変わらず、client_args でプロキシの接続情報を渡すだけでした。シンプルに利用できて良いですね!

LiteLLM Proxy をゲートウェイとして挟むことで、Team / 仮想 API Key によるモデルアクセス制御や使用量トラッキング、リクエスト / レスポンスの監査ログが使えるようになります。もし要件として必要であれば検討したいですね。

ちなみに、今回の Terraform モジュールには Bedrock Guardrails を LiteLLM のガードレール機能と連携させる仕組みも組み込んでいます。こちらについては別の記事で詳しく紹介したいと思います。

本記事が少しでも参考になりましたら幸いです。最後までご覧いただきありがとうございました!

この記事をシェアする

関連記事