どうもこんにちは。
今回は、Ruby製のLLMクライアントライブラリである RubyLLM を、Amazon Bedrock AgentCore Runtime 上にデプロイして動かしてみます。
Amazon Bedrock AgentCore Runtime は、Strands Agents、LangGraph、CrewAI などのエージェントフレームワークをサーバーレスにホストできる実行環境です。
公式の導線としては Python SDK や AgentCore CLI がかなり整っていますが、AgentCore Runtime 自体は HTTP プロトコル契約に従ったコンテナも動かせます。
つまり、Ruby でもコンテナとして /invocations と /ping を実装すれば、AgentCore Runtime に載せられるはずです。
ということで、今回は Rails や Sinatra を使わず、Rack + WEBrick + RubyLLM で最小構成の Runtime コンテナを作ってみました。
もうこの時点で「Rubyistっぽいこと言ってるぅ!!」と思いながら記事を書いてます。(全然そんなことないのに。)
この記事は誰向け?
この記事は以下のような方向けに執筆しています。
- RubyLLM を Amazon Bedrock で使ってみたい方
- Ruby 製のアプリケーションを Bedrock AgentCore Runtime に載せたい方
- AgentCore Runtime の HTTP プロトコル契約を自前実装したい方
- AWS CDK(Python)で AgentCore Runtime へコンテナをデプロイしたい方
- Strands Agents 以外の実装を AgentCore Runtime に載せる検証をしたい方
デモコードの場所
今回の検証コードは以下のリポジトリに置いてあります。
この検証でやりたいこと
今回のゴールは次の3点です。
- RubyLLM を使って Amazon Bedrock を呼び出す
- Ruby アプリを AgentCore Runtime の HTTP コンテナとして動かす
- AWS CDK で ECR、IAM Role、AgentCore Runtime をまとめて作成する
構成としては以下のようになります。
User
|
v
InvokeAgentRuntime
|
v
AgentCore Runtime
|
| HTTP /invocations
v
Ruby container
|
| RubyLLM
v
Amazon Bedrock
ぶっちゃけ、AgentCore Runtime から見ると、コンテナ内の実装がなんの言語で実装されているのかは関係ありません。重要なのは、コンテナが AgentCore Runtime の HTTP プロトコル契約を満たしていることです。
Bedrock AgentCore runtime上にデプロイされるエージェントは、AWSネイティブなStrands Agentsがよく使用されているイメージがありますが、HTTP プロトコル契約を満たしていればなんでも動きます。
前提
今回の検証では ap-northeast-1 にデプロイしています。
手元では以下を利用しました。
- Ruby 3.4 container image
- RubyLLM 1.16.0
- AWS CDK CLI
- AWS CDK v2
- Docker
- AWS CLI
- CDK bootstrap 済みの AWS アカウント
相変わらず、CDKはPythonで書いてます!
TypeScriptの型宣言の文字数の分だけトークン数節約できるんじゃね?という安易な考えです。
また、Amazon Bedrock のモデルアクセスが有効化されている必要があります。
今回は、Claude Sonnet 4.6を使用しています。
jp.anthropic.claude-sonnet-4-6
Sonnet 4.6ならリリースされて日が経ってるからRubyLLMでもサポートされているよな?という意図で4.6にしてます。
実装の流れ
0. 作業プロジェクトの用意
mkdir ruby-llm-demo
cd ruby-llm-demo
最終的な構成は次のとおりです。
.
├── agent/
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── Gemfile
│ ├── config.ru
│ └── ruby_llm_agent/
│ ├── app.rb
│ └── bedrock_config.rb
├── infra/
│ ├── __init__.py
│ └── ruby_llm_agentcore_stack.py
├── tests/
│ └── test_stack.py
├── app.py
├── cdk.json
├── pytest.ini
└── requirements.txt
agent/ が Runtime 上で動く Ruby アプリです。
infra/ が AgentCore Runtime、ECR、IAM Role を作る CDK コードです。
1. CDK プロジェクトの雛形を整える
1-1. 依存パッケージ
CDK 側の依存関係は以下です。
requirements.txt
aws-cdk-lib>=2.210.0
constructs>=10.0.0,<11.0.0
cdk-ecr-deployment>=4.0.0
cdk-ecr-deployment は、CDK がビルドした Docker image asset を、Runtime 用に作成した専用 ECR Repository へコピーするために使います。
Python 仮想環境を作成します。
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt pytest
1-2. CDK エントリーポイント
app.py は通常の CDK エントリーポイントです。
#!/usr/bin/env python3
import os
import aws_cdk as cdk
from infra.ruby_llm_agentcore_stack import RubyLLMAgentCoreStack
app = cdk.App()
RubyLLMAgentCoreStack(
app,
"RubyLLMAgentCoreStack",
env=cdk.Environment(
account=os.environ.get("CDK_DEFAULT_ACCOUNT"),
region=os.environ.get("CDK_DEFAULT_REGION", "us-east-1"),
),
)
app.synth()
このサンプルでは CDK_DEFAULT_REGION が未指定の場合は us-east-1 になります。
実際には ap-northeast-1 にデプロイしたので、以下のように指定して実行しています。
export CDK_DEFAULT_REGION=ap-northeast-1
1-3. CDK 実行設定
{
"app": "python3 app.py",
"context": {
"@aws-cdk/core:newStyleStackSynthesis": true
}
}
2. RubyLLM アプリを実装する
2-1. Ruby 側の依存関係
source "https://rubygems.org"
ruby ">= 3.2"
gem "aws-sdk-core", "~> 3.0"
gem "rack", "~> 3.0"
gem "rackup", "~> 2.0"
gem "ruby_llm", "~> 1.16"
gem "webrick", "~> 1.8"
group :test do
gem "rack-test", "~> 2.1"
gem "rspec", "~> 3.13"
end
RubyのWebアプリケーションフレームワークである、Rails や Sinatra は使っていません。
AgentCore Runtime の HTTP プロトコル契約を満たすだけなら、Rack を使えば十分です。
2-2. Rack エントリーポイント
Rackのエントリーポイントを用意します。後々出てきますが、Dockerfileでこのエントリーポイントを呼び出しています。
# frozen_string_literal: true
require_relative "ruby_llm_agent/app"
run RubyLLMAgent::App.new
2-3. AgentCore Runtime 用の HTTP API
AgentCore Runtime の HTTP プロトコル契約では、主に以下の endpoint が必要です。
POST /invocationsGET /ping
今回の Rack アプリではこの2つを実装しています。
# frozen_string_literal: true
require "json"
require "logger"
require "rack"
require_relative "bedrock_config"
# AgentCore上ではログがCloudWatchへ転送されるため、バッファリングを避ける。
$stdout.sync = true
$stderr.sync = true
module RubyLLMAgent
class App
def initialize(agent: Agent.new, logger: Logger.new($stdout))
@agent = agent
@logger = logger
end
def call(env)
request = Rack::Request.new(env)
# AgentCore RuntimeのHTTP契約で必要なエンドポイントだけを実装する。
case [request.request_method, request.path_info]
when ["GET", "/ping"], ["POST", "/ping"]
json_response(200, status: "Healthy")
when ["POST", "/invocations"]
invoke(request)
else
json_response(404, error: "not_found")
end
end
private
def invoke(request)
payload = parse_json(request.body.read)
@logger.info("agent_invocation_started")
response = @agent.invoke(payload)
@logger.info("agent_invocation_completed")
json_response(200, response)
rescue InvalidPayload => e
json_response(400, error: e.message)
rescue StandardError => e
@logger.error(
"agent_invocation_failed class=#{e.class} message=#{e.message} " \
"backtrace=#{Array(e.backtrace).first(5).join(" | ")}"
)
# 原因切り分け時だけ、AgentCoreに500で丸められないよう200で例外内容を返す。
status = ENV["DEBUG_RESPONSE_ERRORS"] == "1" ? 200 : 500
json_response(status, error: "agent_invocation_failed", errorClass: e.class.name, detail: e.message)
end
def parse_json(raw_body)
raise InvalidPayload, "request body must not be empty" if raw_body.nil? || raw_body.empty?
JSON.parse(raw_body)
rescue JSON::ParserError
raise InvalidPayload, "request body must be valid JSON"
end
def json_response(status, body)
[status, { "content-type" => "application/json" }, [JSON.generate(body)]]
end
end
end
Runtime の入力は次の形式とします。
{
"prompt": "こんにちは!"
}
2-4. RubyLLM から Bedrock を呼ぶ
RubyLLM の Bedrock provider を使って、Amazon Bedrock の Claude を呼び出します。
# frozen_string_literal: true
require "aws-sdk-core"
require "ruby_llm"
require "securerandom"
require "time"
module RubyLLMAgent
class InvalidPayload < StandardError; end
class Agent
DEFAULT_MODEL_ID = "jp.anthropic.claude-sonnet-4-6"
def initialize(model_id: ENV.fetch("BEDROCK_MODEL_ID", DEFAULT_MODEL_ID))
@model_id = model_id
@configured = false
end
def invoke(payload)
prompt = payload["prompt"]
raise InvalidPayload, "payload.prompt must be a non-empty string" unless prompt.is_a?(String) && !prompt.strip.empty?
# RubyLLMのグローバル設定は初回呼び出し時にだけ行う。
configure_ruby_llm
request_id = SecureRandom.uuid
started_at = monotonic_milliseconds
# Bedrock inference profileはRubyLLMのモデルレジストリ未登録の場合がある。
chat = RubyLLM.chat(
model: @model_id,
provider: :bedrock,
assume_model_exists: true
)
answer = chat.ask(prompt.strip)
{
response: answer.content,
evidence: {
requestId: request_id,
provider: "bedrock",
modelId: @model_id,
rubyLlmVersion: RubyLLM::VERSION,
durationMs: monotonic_milliseconds - started_at
}
}
end
private
def configure_ruby_llm
return if @configured
RubyLLM.configure do |config|
config.bedrock_region = ENV.fetch("AWS_REGION", "us-east-1")
config.bedrock_api_base = ENV["BEDROCK_API_BASE"] if present?(ENV["BEDROCK_API_BASE"])
# ruby_llm 1.16.0にはbedrock_credential_providerがないため、解決済み認証情報を渡す。
credentials = resolve_aws_credentials
config.bedrock_api_key = credentials.access_key_id
config.bedrock_secret_key = credentials.secret_access_key
config.bedrock_session_token = credentials.session_token
end
@configured = true
end
def resolve_aws_credentials
# AgentCore Runtime上では実行ロール由来の一時認証情報がここで解決される。
provider = Aws::CredentialProviderChain.new.resolve
raise Aws::Errors::MissingCredentialsError, "unable to resolve AWS credentials" unless provider
provider.credentials
end
def present?(value)
value && !value.empty?
end
def monotonic_milliseconds
(Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1000).round
end
end
end
重要なのは次の2点です。
assume_model_exists: true
Bedrock の inference profile 形式のモデル ID は、RubyLLM のモデルレジストリに未登録の場合があります。
そのため、RubyLLM 側のモデル存在チェックを bypass しています。
もう1つは認証情報の渡し方です。
credentials = resolve_aws_credentials
config.bedrock_api_key = credentials.access_key_id
config.bedrock_secret_key = credentials.secret_access_key
config.bedrock_session_token = credentials.session_token
RubyLLM のドキュメント上は bedrock_credential_provider が紹介されていますが、RubyGems の ruby_llm 1.16.0 ではまだこの setter がありませんでした。
そのため、AWS SDK for Ruby の Aws::CredentialProviderChain で一時認証情報を解決し、RubyLLM には静的キー形式で渡しています。
AgentCore Runtime 上では、ここで Runtime 実行ロール由来の一時認証情報が解決されます。
3. Ruby アプリを Docker 化する
AgentCore Runtime では ARM64 コンテナが必要です。
FROM public.ecr.aws/docker/library/ruby:3.4
ENV APP_HOME=/app
ENV BUNDLE_WITHOUT=test
ENV PORT=8080
ENV RACK_ENV=production
WORKDIR ${APP_HOME}
COPY Gemfile ./
RUN bundle install
COPY config.ru ./
COPY ruby_llm_agent ./ruby_llm_agent
EXPOSE 8080
CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "--port", "8080", "config.ru"]
最初は ruby:3.4-slim を使って実装を進めていたのですが、json や bigdecimal の native extension build でコンパイラが必要になったので、ruby:3.4を使っています。
ローカルビルドします。
docker build -t ruby-llm-agentcore-demo:local agent
ローカル起動します。
docker run --rm -p 18080:8080 ruby-llm-agentcore-demo:local
ヘルスチェックします。
curl -s http://localhost:18080/ping
レスポンス:
{"status":"Healthy"}
ローカルで /invocations まで成功させるには、Bedrock を呼べる AWS 認証情報が必要です。
curl -s http://localhost:18080/invocations \
-H 'content-type: application/json' \
-d '{"prompt":"こんにちは!"}'
ここまででうまくいけば、Ruby側での実装は終わりです。
4. ECR リポジトリとイメージ配布を実装する
CDK スタックでは、Runtime 用の専用 ECR Repository を作成します。
image_repository = ecr.Repository(
self,
"AgentImageRepository",
repository_name="ruby-llm-agentcore-demo",
image_scan_on_push=True,
image_tag_mutability=ecr.TagMutability.IMMUTABLE,
lifecycle_rules=[
ecr.LifecycleRule(
description="Keep the ten most recent agent images",
max_image_count=10,
)
],
removal_policy=RemovalPolicy.DESTROY,
empty_on_delete=True,
)
続いて、Docker image asset を ARM64 でビルドします。
image_asset = ecr_assets.DockerImageAsset(
self,
"AgentImageAsset",
directory=str(Path(__file__).resolve().parents[1] / "agent"),
platform=ecr_assets.Platform.LINUX_ARM64,
)
CDK の Docker image asset は、CDK bootstrap 用の ECR に push されます。
今回は Runtime 用に専用 ECR Repository を作っているため、cdk-ecr-deployment でイメージをコピーします。
image_tag = image_asset.asset_hash
runtime_image_uri = image_repository.repository_uri_for_tag(image_tag)
image_deployment = ecr_deployment.ECRDeployment(
self,
"DeployAgentImage",
src=ecr_deployment.DockerImageName(image_asset.image_uri),
dest=ecr_deployment.DockerImageName(runtime_image_uri),
)
5. Runtime 用 IAM Role を実装する
Runtime 実行ロールを作成します。
runtime_role = iam.Role(
self,
"AgentRuntimeRole",
assumed_by=iam.ServicePrincipal(
"bedrock-agentcore.amazonaws.com",
conditions={
"StringEquals": {"aws:SourceAccount": Aws.ACCOUNT_ID},
"ArnLike": {
"aws:SourceArn": (
f"arn:{Aws.PARTITION}:bedrock-agentcore:"
f"{Aws.REGION}:{Aws.ACCOUNT_ID}:*"
)
},
},
),
description="Execution role for the RubyLLM AgentCore demo runtime.",
)
このロールに以下の権限を付与します。
- ECR からのイメージ取得
- CloudWatch Logs への出力
- Bedrock モデル呼び出し
Bedrock 呼び出し権限は以下です。
runtime_role.add_to_policy(
iam.PolicyStatement(
actions=[
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
],
resources=self._model_resource_arns(model_id),
)
)
モデル ARN は次のようにしています。
def _model_resource_arns(self, model_id: str) -> list[str]:
# 明示ARNが渡された場合は、そのモデルまたはinference profileだけに絞る。
if model_id.startswith("arn:"):
return [model_id]
return [
f"arn:{Aws.PARTITION}:bedrock:*::foundation-model/*",
(
f"arn:{Aws.PARTITION}:bedrock:{Aws.REGION}:{Aws.ACCOUNT_ID}:"
"inference-profile/*"
),
]
foundation model と inference profile の両方を許可しています。
6. AgentCore Runtime を作成する
AgentCore Runtime を作成します。
runtime = bedrock_agentcore.CfnRuntime(
self,
"AgentRuntime",
agent_runtime_name="RubyLLMAgentCoreDemoRuntime",
description="RubyLLM agent hosted on Amazon Bedrock AgentCore Runtime.",
agent_runtime_artifact=bedrock_agentcore.CfnRuntime.AgentRuntimeArtifactProperty(
container_configuration=bedrock_agentcore.CfnRuntime.ContainerConfigurationProperty(
container_uri=runtime_image_uri,
)
),
network_configuration=bedrock_agentcore.CfnRuntime.NetworkConfigurationProperty(
network_mode="PUBLIC",
),
protocol_configuration="HTTP",
role_arn=runtime_role.role_arn,
environment_variables={
"AWS_REGION": self.region,
"AWS_DEFAULT_REGION": self.region,
"BEDROCK_MODEL_ID": model_id,
"APP_TIMEZONE": "Asia/Tokyo",
},
lifecycle_configuration=bedrock_agentcore.CfnRuntime.LifecycleConfigurationProperty(
idle_runtime_session_timeout=900,
max_lifetime=3600,
),
)
ポイントは以下です。
protocol_configuration="HTTP"
今回は Python SDK の BedrockAgentCoreApp を使っていないため、コンテナ側で HTTP プロトコル契約を自前実装しています。
そのため、Runtime 側は HTTP プロトコルとして作成します。
環境変数の用途は次のとおりです。
| 環境変数 | 用途 |
|---|---|
AWS_REGION |
RubyLLM / AWS SDK が Bedrock を呼ぶリージョン |
AWS_DEFAULT_REGION |
AWS SDK の region fallback |
BEDROCK_MODEL_ID |
RubyLLM が呼び出す Bedrock モデル |
APP_TIMEZONE |
アプリ側で日時処理が必要になった場合のタイムゾーン |
CloudFormation Outputs も出しておきます。
CfnOutput(self, "AgentRuntimeArn", value=runtime.attr_agent_runtime_arn)
CfnOutput(self, "AgentRuntimeId", value=runtime.attr_agent_runtime_id)
CfnOutput(self, "AgentImageRepositoryUri", value=image_repository.repository_uri)
CfnOutput(self, "AgentImageUri", value=runtime_image_uri)
7. テストする
CDK テンプレートの最低限のテストを書いています。(本当はもっとちゃんとテストは書いてね!)
from aws_cdk import App
from aws_cdk.assertions import Match, Template
from infra.ruby_llm_agentcore_stack import RubyLLMAgentCoreStack
def test_runtime_uses_http_protocol_and_container_artifact():
app = App()
stack = RubyLLMAgentCoreStack(app, "TestStack")
template = Template.from_stack(stack)
template.has_resource_properties(
"AWS::BedrockAgentCore::Runtime",
{
"ProtocolConfiguration": "HTTP",
"NetworkConfiguration": {"NetworkMode": "PUBLIC"},
},
)
def test_runtime_role_can_invoke_bedrock_models():
app = App()
stack = RubyLLMAgentCoreStack(app, "TestStack")
template = Template.from_stack(stack)
template.has_resource_properties(
"AWS::IAM::Policy",
{
"PolicyDocument": {
"Statement": Match.array_with(
[
Match.object_like(
{
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream",
],
"Effect": "Allow",
}
)
]
)
}
},
)
テスト実行:
env JSII_RUNTIME_PACKAGE_CACHE_ROOT=/tmp/jsii-package-cache \
JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION=1 \
.venv/bin/pytest -q
自分のローカル環境では jsii が ~/Library/Caches に書き込もうとして失敗したため、JSII_RUNTIME_PACKAGE_CACHE_ROOT を /tmp に向けています。
8. デプロイする
対象リージョンを指定します。
export CDK_DEFAULT_REGION=ap-northeast-1
初回だけ bootstrap します。
cdk bootstrap
デプロイします。
cdk deploy
モデルを指定したい場合は context で渡します。
cdk deploy -c modelId=jp.anthropic.claude-sonnet-4-6
デプロイが完了すると、以下のような Output が出ます。
RubyLLMAgentCoreStack.AgentRuntimeArn = arn:aws:bedrock-agentcore:ap-northeast-1:123456789012:runtime/RubyLLMAgentCoreDemoRuntime-xxxxxxxxxx
RubyLLMAgentCoreStack.AgentRuntimeId = RubyLLMAgentCoreDemoRuntime-xxxxxxxxxx
RubyLLMAgentCoreStack.AgentImageRepositoryUri = 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ruby-llm-agentcore-demo
RubyLLMAgentCoreStack.AgentImageUri = 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/ruby-llm-agentcore-demo:...
9. Runtime を呼び出す
CloudFormation Output の AgentRuntimeArn を使います。
export AGENT_RUNTIME_ARN="arn:aws:bedrock-agentcore:ap-northeast-1:123456789012:runtime/RubyLLMAgentCoreDemoRuntime-xxxxxxxxxx"
Runtime を呼び出します。
aws bedrock-agentcore invoke-agent-runtime \
--region ap-northeast-1 \
--agent-runtime-arn "$AGENT_RUNTIME_ARN" \
--runtime-session-id "$(uuidgen | tr '[:upper:]' '[:lower:]')" \
--payload '{"prompt":"こんにちは!"}' \
/tmp/ruby-llm-agentcore-response.json
runtime-session-id は 33 文字以上が必要です。
UUID を使っておけば問題ありません。
レスポンスファイルを確認します。
cat /tmp/ruby-llm-agentcore-response.json
実際に返ってきたレスポンス例です。
{
"response": "こんにちは!\n\nお元気ですか?何かお手伝いできることはありますか?",
"evidence": {
"requestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"provider": "bedrock",
"modelId": "jp.anthropic.claude-sonnet-4-6",
"rubyLlmVersion": "1.16.0",
"durationMs": 1310
}
}
AWSマネジメントコンソール上からも呼び出すことができました。
RubyLLM が AgentCore Runtime 上で動き、Amazon Bedrock を呼び出せました。
ハマりどころ
RubyLLM 1.16.0 には bedrock_credential_provider がなかった
RubyLLM のドキュメントを見て、最初は次のように書いていました。
config.bedrock_credential_provider = Aws::CredentialProviderChain.new.resolve
しかし、RubyGems から入る ruby_llm 1.16.0 ではこの setter が存在せず、以下のエラーになりました。
NoMethodError: undefined method 'bedrock_credential_provider=' for an instance of RubyLLM::Configuration
そのため、AWS SDK で認証情報を解決し、RubyLLM には bedrock_api_key、bedrock_secret_key、bedrock_session_token として渡しました。
credentials = resolve_aws_credentials
config.bedrock_api_key = credentials.access_key_id
config.bedrock_secret_key = credentials.secret_access_key
config.bedrock_session_token = credentials.session_token
実装が完了してから、以下の記述を見つけたので、以下に記載されているような方法では試せていないです...
model_anthropic = RubyLLM.models.find('claude-sonnet-4-6', :anthropic)
model_bedrock = RubyLLM.models.find('claude-sonnet-4-6', :bedrock)
AgentCore の 500 は詳細が見えづらい
Runtime 内で例外が起きると、CLI やコンソールでは以下のように丸められることがあります。
Received error (500) from runtime. Please check your CloudWatch logs for more information.
ただ、AgentCore のアプリケーショントレースだけでは、Ruby 側の例外が見えないこともありました。
そのため、切り分け用に以下の環境変数を用意しました。
DEBUG_RESPONSE_ERRORS=1
これを設定すると、例外時に HTTP 200 でエラー内容を JSON として返します。
{
"error": "agent_invocation_failed",
"errorClass": "NoMethodError",
"detail": "undefined method ..."
}
ただし、これはデバッグ用途です。
例外内容をクライアントへ返すため、確認が終わったら無効にします。
片付け
検証が終わったら destroy します。
cdk destroy
今回の構成では ECR Repository も以下の設定にしています。
removal_policy=RemovalPolicy.DESTROY
empty_on_delete=True
そのため、スタック削除時に ECR Repository も一緒に削除されます。
まとめ
RubyLLM を Amazon Bedrock AgentCore Runtime 上にデプロイし、Runtime 経由で Bedrock の Claude を呼び出してみました。
ポイントは以下です。
- AgentCore Runtime は HTTP プロトコル契約に従えば Ruby コンテナも動かせる
- Rails や Sinatra は必須ではなく、Rack + WEBrick でも最小構成は作れる
- Runtime コンテナは
0.0.0.0:8080で/invocationsと/pingを提供する - RubyLLM 1.16.0 では Bedrock 認証情報を静的キー形式で渡す必要があった
- Bedrock inference profile を使う場合は
assume_model_exists: trueが実用上必要だった - ap-northeast-1 では
jp.anthropic.claude-sonnet-4-6を使うと動作確認できた
AgentCore Runtime は Strands Agents 向けの印象が強いですが、HTTP プロトコル契約に合わせれば Ruby のような別言語の実装も載せられます。
次は RubyLLM の streaming を AgentCore Runtime の SSE や WebSocket に載せる構成も試してみたいと思います。
