8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Mastra on Bedrock AgentCore RuntimeでもAgentCore Observabilityがしたい!

8
Posted at

遅れました🙇‍♂️

AI Agent on AWS Advent Calendar 2025の20日の投稿です

Bedrock AgentCoreはプログラミング言語やフレームワークに依存しない素敵なサービスとなっております。ただ、公式ドキュメントやSDKはPython優先で整備されているのでTypeScriptでの実現方法がわからない🙀

Mastraの実行結果をAgentCore Observabilityに送信する方法を調べましたので、御覧ください。

採用したアーキテクチャ

  • AIエージェントフレームワーク:Mastra(※v1のベータバージョン)
  • Webフレームワーク:Hono
  • Bedrock Agentcore Runtime、Observability

Mastraは2026年1月にv1をリリースする予定があるようです。一足早く新しいバージョンを使ってみたかったので@beta版を使用してます

手順

プロジェクトを新規作成

参考ドキュメント:https://mastra.ai/guides/v1/getting-started/hono

まずはHonoでプロジェクトを新規作成します。

npm create hono@latest mastra-hono -- --template nodejs --install --pm npm
cd mastra-hono

続いてMastraを追加します。beta版を使用します。ウィザードは全部Yで回答します。

npx mastra@beta init

サンプルエージェントが追加されます。

src/mastra/
├── agents
│   └── weather-agent.ts
├── index.ts
├── tools
│   └── weather-tool.ts
└── workflows
    └── weather-workflow.ts

HonoとMastraをつなぐアダプターを追加します。

(後々見返すと、この手順いらないかも?)

npm install @mastra/hono@beta

この状態でnpm run devは実行できるのですが、npm run buildでエラーが発生します。

ちょっとしたことなのでこのタイミングで修正しておきます。(拡張子を指定してるかどうかです)

mastra-hono/src/mastra/agents/weather-agent.ts
- import { weatherTool } from '../tools/weather-tool';
+ import { weatherTool } from '../tools/weather-tool.js';
mastra-hono/src/mastra/index.ts
- import { weatherWorkflow } from './workflows/weather-workflow';
- import { weatherAgent } from './agents/weather-agent';
+ import { weatherWorkflow } from './workflows/weather-workflow.js';
+ import { weatherAgent } from './agents/weather-agent.js';

Bedrockを呼び出すように修正

今の状態ではOpenAIのAPIを呼び出す様になっています。Bedrockを呼び出すように修正しましょう。

MastraではAI SDKが使えます。

参考ドキュメント:https://ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock

AI SDKのBedrockプロバイダーを追加します。

npm install @ai-sdk/amazon-bedrock @aws-sdk/credential-providers

Bedrockのモデルを使うように修正します。

mastra-hono/src/mastra/agents/weather-agent.ts
+ import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock';
+ import { fromNodeProviderChain } from '@aws-sdk/credential-providers';

中略

-   model: 'openai/gpt-4o',
+   model: createAmazonBedrock({
+     region: 'ap-northeast-1',
+     credentialProvider: fromNodeProviderChain()
+   })("openai.gpt-oss-120b-1:0"),

Bedrock AgentCore Runtimeで必要なAPIを追加

Pythonの場合はAgentCore SDKを使う場合は意識しないのですが、AgentCore Runtimeでは以下の2つのAPIが必要です。

  • /invocations POST
  • /ping GET

最近、WebSocket対応のため/wsが追加されましたがこれはオプションです

/invocationsでweather-agentを呼び出すように実装します。また、ポート番号もAgentCore Runtimeの使用に合わせ、8080に変更します。

mastra-hono/src/index.ts
  import { serve } from '@hono/node-server'
  import { Hono } from 'hono'
+ import { mastra } from './mastra/index.js'

  const app = new Hono()

- app.get('/', (c) => {
-   return c.text('Hello Hono!')
- })

+ app.get('/ping', (c) => {
+   return c.json({
+     status: 'Healthy',
+     time_of_last_update: Math.floor(Date.now() / 1000)
+   })
+ })
+ 
+ app.post('/invocations', async(c) => {
+   const body = await c.req.json();
+   const agent = mastra.getAgent('weatherAgent')
+   const response = await agent.generate(body.messages);
+ 
+   return c.text(response.text)
+ })

  serve({
    fetch: app.fetch,
-   port: 3000
+   port: 8080
  }, (info) => {
    console.log(`Server is running on http://localhost:${info.port}`)
  })

ここまでで起動して呼び出せる状態になりました。

サーバー起動
npm run dev
Server is running on http://localhost:8080

cURLで呼び出してみましょう。エージェントは天気を取得するツールがあり、都市を指定すると天気を教えてくれます。

「What is the weather like in Tokyo?(東京の天気はどうですか?)」

curl -X POST http://localhost:8080/invocations \
  -H "Content-Type: application/json" \
  -d "{\"messages\":[{\"role\":\"user\",\"content\":\"What is the weather like in Tokyo?\"}]}"
It’s a pleasant, mild day—great for outdoor activities or a stroll around the city. Let me know if you’d like a forecast or activity suggestions!**Current weather in Tokyo**

- **Temperature:** 15 °C (59 °F)  
- **Condition:** Light drizzle  
- **Humidity:** 90 %  
- **Wind:** 7 km/h (4 mph) with gusts up to 32 km/h from the west  

It’s cool and damp, so you might want to carry an umbrella or a light rain jacket if you head outside. Let me know if you’d like a short‑term forecast or activity ideas for this weather!

Observability機能を追加

さて、いよいよ本題のObservabilityです。

Pythonの手順の場合にインストールする「aws-opentelemetry-distro」ですが、これは「AWS Distro for OpenTelemetry 」というものです。

これのJavaScript版を使用します。

ざっくり、こんな使い方になります。

npm install @aws/aws-distro-opentelemetry-node-autoinstrumentation

export NODE_OPTIONS="--require @aws/aws-distro-opentelemetry-node-autoinstrumentation/register"
node app.js

AWS Distro for OpenTelemetryやOpenTelemetryについてはこちらが詳しいです。

OpenTelemetry Collector の中身と種類を知ろう
https://aws.amazon.com/jp/builders-flash/202503/opentelemetry-collector/

そしてMastra側ですが、OpenTelemetryへ対応するために「OpenTelemetry Bridge」の追加が必要です。(OpenTelemetry Bridgeは執筆時点でexperimental扱いです)

参考:https://mastra.ai/docs/v1/observability/tracing/bridges/otel

多分、こんな感じになってるんだと思います。

[Mastra] -> [OpenTelemetry Bridge] -> [AWS Distro for OpenTelemetry] -> [CloudWatch / X-Ray]

では実装を進めていきます。

まず、必要なライブラリーを追加します。

npm install \
  @aws/aws-distro-opentelemetry-node-autoinstrumentation \
  @opentelemetry/exporter-trace-otlp-proto \
  @mastra/otel-exporter@beta \
  @mastra/otel-bridge@beta

Mastraの設定を修正します。

mastra-hono/src/mastra/index.ts
+ import { OtelBridge } from '@mastra/otel-bridge';

    observability: new Observability({
      // Enables DefaultExporter and CloudExporter for tracing
-      default: { enabled: true },
+     configs: {
+       default: {
+         serviceName: 'weather-agent',
+         bridge: new OtelBridge(),
+       }
+     }
    }),

package.jsonscriptを修正し、NODE_OPTIONSの指定を追加します。

package.json
-   "dev": "tsx watch src/index.ts",
+   "dev": "NODE_OPTIONS=\"--require @aws/aws-distro-opentelemetry-node-autoinstrumentation/register\" tsx watch src/index.ts",
    "build": "tsc",
-   "start": "node dist/index.js"
+   "start": "NODE_OPTIONS=\"--require @aws/aws-distro-opentelemetry-node-autoinstrumentation/register\" node dist/index.js"

CloudWatchの設定変更

AgentCore Observabilityの事前準備として、CloudWatchの設定を変更します。(リージョンごとに1回だけ必要です)

CloudWatchの画面の左メニュー最下部の「Setup」の中の「設定」を選択します。

「X-Rayトレース」タブにある「トランザクション検索」の「ビュー設定」をクリックします。

Transaction Searchのところの「編集」からTransaction Searchを有効にします。

Observabilityの動作確認(ローカル)

ローカル環境でエージェントを動かしAgentCore Observabilityで確認してみましょう。

ローカルの場合、いくつか環境変数のセットが必要です。

export AWS_REGION=$(aws configure get region)

export AGENT_OBSERVABILITY_ENABLED=true
export OTEL_RESOURCE_ATTRIBUTES=service.name=weather-agent,aws.log.group.names=/aws/bedrock-agentcore/runtimes/weather-agent,cloud.resource_id=AgentEndpointArn:weather-agent
export OTEL_EXPORTER_OTLP_LOGS_HEADERS=x-aws-log-group=/aws/bedrock-agentcore/runtimes/weather-agent,x-aws-log-stream=runtime-logs,x-aws-metric-namespace=bedrock-agentcore

export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_TRACES_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://xray.${AWS_REGION}.amazonaws.com/v1/traces

export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://logs.${AWS_REGION}.amazonaws.com/v1/logs

環境変数をセットした状態で、npm run devでサーバーを起動します。そして、cURLでアクセスし、トレース情報を生成します。

curl -X POST http://localhost:8080/invocations \
  -H "Content-Type: application/json" \
  -d "{\"messages\":[{\"role\":\"user\",\"content\":\"What is the weather like in Tokyo?\"}]}"

CloudWatchの画面を見てみます。左メニューの「GenAI Observability」にある「Bedrock AgentCore」を選択します。一番下の「エージェント」のところに届いているようですね。

めでたく、こんな感じでトレースが確認できます。

AgentCore Runtimeへのデプロイ

エージェントができたのでAgentCore Runtimeへデプロイしましょう。

AgentCore Runtimeへのデプロイはコンテナで行いますので、Dockerfileを作成します。

Dockerfile
# Build stage
FROM --platform=linux/arm64 node:22-slim AS builder

WORKDIR /app

COPY package*.json tsconfig.json ./
RUN npm ci

COPY src ./src
RUN npx tsc

# Production stage
FROM --platform=linux/arm64 node:22-slim

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY --from=builder /app/dist ./dist

EXPOSE 8080
ENV NODE_ENV=production

CMD ["npm", "start"]

コンテナイメージをビルドしてECRにプッシュします。

export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export AWS_REGION=$(aws configure get region)
export AGENT_NAME=mastra-hono

docker buildx create --use

aws ecr create-repository --repository-name ${AGENT_NAME} --region ${AWS_REGION}
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com

docker buildx build --platform linux/arm64 -t ${ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${AGENT_NAME}:latest --push .

AgentCore Runtimeの画面でエージェントを作成します。(すいません、画面キャプチャを取り忘れました。。いい感じにレッツトライ)

Observabilityの動作確認(AgentCore Runtime)

エージェントが作成できたらサンドボックスから実行してみます。

ローカル実行と同様、トレースが確認できます。

AgentCore Runtimeでの動作時には環境変数のセットは不要なようです。AgentCoreがいい感じにやってくれてるのでしょうか?

AgentCore Runtimeの環境では定期的に/pingが呼ばれるのですが、これもトレースとして取得されます。どうにか抑制したいのですが、どうしたらいいかわかりません…

あと、トレースはAgentCore Observabilityに届いてるのですが、見た目が、ちょっと変な気がします。(イベントがなく、メタデータのJSONを直接見ないといけない感じになってる)これもどうしたらいいかわかりません…

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?