Bedrock Flows を本番で6ヶ月使って見えてきたこと【2026年版】

「Lambda + Step Functions でよくない?」と思ってた自分が、Bedrock Flows を本番導入して6ヶ月で気づいたこと。ハマりどころと設計パターンを正直に書きます。

Bedrock Flowsをチームで使い始めて6ヶ月、正直なところを書く

うちのチームがBedrock Flowsを本格的に本番投入したのは2025年の秋頃で、それから半年以上経った。当初は「Lambda + Step Functions + Bedrockを組み合わせればいいじゃん」という声もあったし、自分も最初はそう思っていた。でも実際に複数のLLMステップを連鎖させてみると、状態管理・プロンプトの受け渡し・エラーハンドリングが想像以上に煩雑で、Flows専用のコンソールとAPIに乗っかったほうがトータルで楽だという結論に至った。

ここに書くのは「どういう場面でFlowsを選ぶべきか」「実際にハマった部分」「2026年現在のアップデートを踏まえた設計パターン」、できるだけ生々しく。機能一覧の羅列はAWS公式ドキュメントに任せる。

なお、RAGパイプラインの本番運用については以前RAG本番運用1年で痛感したことに書いたので、チャンキング設計と組み合わせて読んでほしい。ローカルLLM側の話はローカルLLM本番投入でハマった話にまとめてある。


2026年のBedrock Flows、何が変わったか

2025年末〜2026年Q1にかけてのアップデートが、体感としてかなり大きかった。正直、2025年初頭のBedrock Flowsは「便利そうだけどまだ早い」という印象だった。ループがなかったし、並列処理は試験的だったし、CloudWatchとの統合も薄かった。それが今では、本番で使うのに十分なレベルになってきた。

機能変更内容実務インパクト
Inline Agent NodeFlowsからAgentを直接呼び出し、Agentのオーケストレーション結果を後続Nodeに渡せるように外部API呼び出し・KB参照をFlows内で完結できる
Loop Node(GA)条件付きループ処理が正式対応、最大50イテレーション要約→評価→再要約のような反復タスクに使える
Parallel Node(GA)複数ブランチを並列実行してJoin複数ドキュメントの同時処理でレイテンシ削減
Flow Version管理強化バージョン間のdiff表示、ロールバックAPI本番/ステージング管理が格段に楽になった
CloudWatch Logs詳細化Node単位の実行時間・トークン数をメトリクスとして出力コスト分析がようやくできるようになった
Bedrock Guardrails統合FlowレベルでGuardrailsを設定可能Node単位でのインライン設定が不要に

「ようやくできるようになった」という感じが正直なところで、これらが揃って初めて「本番で安心して使える」と思えた。


実際に組んだアーキテクチャ:カスタマーサポート自動化パイプライン

うちが本番で使っているユースケースの一つが、カスタマーサポートのチケット自動トリアージ→回答ドラフト生成→人間レビューキュー振り分けだ。こういうマルチステップのLLMタスクがBedrock Flowsの得意領域で、全体像はこんな構成になっている。

graph TB
    subgraph Internet
        User([ユーザー問い合わせ])
    end

    subgraph AWS_Cloud[AWS Cloud]
        subgraph API_Layer[API Layer]
            APIGW[API Gateway]
            Lambda_Entry[Lambda\n入力バリデーション]
        end

        subgraph Bedrock_Flow[Bedrock Flows]
            Flow_Input[Input Node\nチケット受信]
            Classify[Prompt Node\nカテゴリ分類\nClaude 3.5 Sonnet]
            Condition[Condition Node\n緊急度判定]

            subgraph Parallel_Branch[Parallel Node]
                KB_Search[Knowledge Base Node\nFAQ検索]
                History_Search[Agent Node\n過去チケット参照]
            end

            Join[Join Node\n結果マージ]
            Draft[Prompt Node\n回答ドラフト生成]
            Quality[Prompt Node\n品質チェック]
            Loop_Check{Loop Node\n品質スコア >= 0.85?}
            Flow_Output[Output Node]
        end

        subgraph Storage[Storage & Queue]
            S3[S3\nチケット保存]
            DynamoDB[DynamoDB\nセッション管理]
            SQS_High[SQS\n緊急キュー]
            SQS_Normal[SQS\n通常キュー]
        end

        subgraph Observability[Observability]
            CW_Logs[CloudWatch Logs]
            CW_Metrics[CloudWatch Metrics\nトークン数・レイテンシ]
        end
    end

    subgraph Human_Review[Human Review]
        Agent_High[サポートチーム\n即時対応]
        Agent_Normal[サポートチーム\n通常対応]
    end

    User --> APIGW --> Lambda_Entry
    Lambda_Entry --> S3
    Lambda_Entry --> Flow_Input
    Flow_Input --> Classify
    Classify --> Condition
    Condition -- 緊急 --> SQS_High --> Agent_High
    Condition -- 通常 --> Parallel_Branch
    KB_Search --> Join
    History_Search --> Join
    Join --> Draft
    Draft --> Quality
    Quality --> Loop_Check
    Loop_Check -- No, 再生成 --> Draft
    Loop_Check -- Yes --> Flow_Output
    Flow_Output --> SQS_Normal --> Agent_Normal
    DynamoDB <--> History_Search
    Bedrock_Flow --> CW_Logs
    Bedrock_Flow --> CW_Metrics

このパイプラインで特に効いたポイントが3つある。

① Parallel NodeでKB検索と過去チケット参照を並列実行

以前はKB検索→Agent呼び出しを直列でやっていて、合計8〜12秒かかっていた。Parallel Node(GA版)に切り替えてから4〜6秒に短縮した。地味だけど、ユーザー体感としてはかなり変わる。

② Loop Nodeで品質チェックを反復

回答ドラフトの後に品質スコアを計算するPrompt Nodeを置き、スコアが0.85未満なら再生成するようにしている。実際には大体1〜2回のループで収束するが、最大3回でキャップをかけていて、3回でも閾値を下回ったら「要人間確認」フラグをつけて次のNodeに渡す。

③ CloudWatch MetricsでNode単位のトークン消費を監視

2026年のアップデートで入力/出力トークン数がNode粒度でCloudWatchに飛ぶようになった。これが本当に助かった。コスト爆発がどのNodeで起きているかすぐ特定できる。具体的にはこんなクエリで確認している。

# CloudWatch でNode単位のコストを可視化するクエリ例
import boto3
from datetime import datetime, timedelta

client = boto3.client('cloudwatch', region_name='us-east-1')

response = client.get_metric_data(
    MetricDataQueries=[
        {
            'Id': 'draft_node_tokens',
            'MetricStat': {
                'Metric': {
                    'Namespace': 'AWS/Bedrock',
                    'MetricName': 'FlowNodeInputTokenCount',
                    'Dimensions': [
                        {'Name': 'FlowId', 'Value': 'YOUR_FLOW_ID'},
                        {'Name': 'NodeName', 'Value': 'DraftGenerationNode'}
                    ]
                },
                'Period': 3600,
                'Stat': 'Sum'
            }
        }
    ],
    StartTime=datetime.utcnow() - timedelta(days=7),
    EndTime=datetime.utcnow()
)

for result in response['MetricDataResults']:
    total_tokens = sum(result['Values'])
    # Claude 3.5 Sonnet 入力: $0.003/1K tokens (2026年5月時点)
    estimated_cost_usd = (total_tokens / 1000) * 0.003
    print(f"Node: {result['Id']}, Tokens: {total_tokens:,}, Est. Cost: ${estimated_cost_usd:.2f}")

実行するとこういう出力になる:

Node: draft_node_tokens, Tokens: 1,240,500, Est. Cost: $3.72

週単位で監視していて、ドラフト生成Nodeが週3〜4ドルと一番コストが高い。品質チェックNodeが週1.2ドル。KB検索はBedrockのKB APIコストが別建てなので注意が必要だ。


Bedrock Flows で本当にハマった3つのポイント

以前Bedrock Flows導入で痛感した落とし穴でも書いたが、2026年版のアップデートを踏まえて改めて整理する。

① 変数スキーマの設計ミスは後で直せない

NodeとNodeの間のデータ受け渡しはFlow変数(JSON Schema)で定義する。問題は、Flowをいったんデプロイすると変数スキーマを変更するにはFlow全体を作り直す必要があることが多い点だ(2026年5月時点でも部分的なスキーマ変更は制約あり)。

自分たちは最初にスキーマを甘く設計して、後から「このNodeにチケットIDを引き回したい」となったときに地獄を見た。最初から「全NodeでIDとmetadataを必ず渡す」設計にすべきだったと反省している。

// 推奨: 最初から汎用フィールドを入れておく
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "ticket_id": { "type": "string" },
    "content": { "type": "string" },
    "metadata": {
      "type": "object",
      "additionalProperties": true  // ← これが後で救ってくれる
    },
    "trace": {
      "type": "array",
      "items": { "type": "string" }
    }
  },
  "required": ["ticket_id", "content"]
}

additionalProperties: true を入れておくと、後から後続Nodeで追加フィールドを乗せられる。地味に大事なので最初から入れておいてほしい。

② Inline AgentのToolsは事前にテストを徹底する

Inline Agent Nodeは非常に強力で、FlowsからAgentのツール実行(Lambda呼び出し)を直接トリガーできる。ただ、Agent内のToolが例外を投げたときのエラーハンドリングがFlowsレベルでは粗い。Tool失敗→Agentがリトライループにはまってタイムアウト、という事象が本番で2回起きた。これは正直かなり焦った。

現実的な対策は2つ。Agent側のLambdaで例外をちゃんとキャッチして {'errorMessage': '...', 'httpStatusCode': 500} 形式のレスポンスを返すこと、そしてAgent側の max_retrievals 設定を必ずデフォルト(5)より下げること(自分たちは3に設定している)。

③ Condition Nodeの評価式は「文字列比較」が基本

Condition NodeはLLMの出力を文字列として受け取り、その文字列に基づいてルーティングする。数値比較や複雑なロジックをCondition NodeのJSONPath式だけで表現しようとすると詰まる。

うちのやり方は、前段のPrompt Nodeに「緊急度を HIGH / MEDIUM / LOW のどれか1単語で返せ」と指示して、Condition Nodeはその文字列マッチだけにしている。複雑な判定ロジックはLLM側に押し込む、という設計思想が結果的にシンプルで保守しやすかった。最初は「LLMに判定させるのは怖い」と思っていたけど、プロンプトをちゃんと書けばかなり安定する。


パフォーマンスとコストの実測値

6ヶ月の本番運用データからざっくりまとめる。月次コストはこんな推移だった。

xychart-beta
    title "Bedrock Flows 月次コスト推移(USD)"
    x-axis ["2025-11", "2025-12", "2026-01", "2026-02", "2026-03", "2026-04"]
    y-axis "Cost (USD)" 0 --> 1200
    bar [210, 380, 620, 750, 880, 940]
    line [210, 380, 620, 750, 880, 940]

月1000ドル手前で推移している。チケット処理数は月2万件ほどなので、1チケットあたり約4.7セントという計算になる。Flows自体のオーバーヘッドはほぼゼロに近く(Flow実行自体の追加コストは今のところ見えていない)、コストの大半はモデルのトークン代だ。

エンド・ツー・エンドのレイテンシ内訳はこんな感じになっている。

pie title Flowエンド・ツー・エンドレイテンシ内訳(平均9.2秒)
    "分類Prompt Node" : 1.8
    "並列処理(KB+Agent)" : 2.4
    "回答ドラフト生成" : 3.1
    "品質チェック" : 1.5
    "その他オーバーヘッド" : 0.4

回答ドラフト生成が一番重い。Claude 3.5 Sonnetを使っているが、品質チェックにはHaiku 3.5を使うようにコスト/品質のトレードオフを調整した。同じNodeでもモデルを選べるので、「重い処理はSonnet、判定系はHaiku」という使い分けは積極的に試してみる価値がある。

なお、SageMaker Pipelinesとの比較をよく聞かれるが、あちらはML学習・バッチ推論向け、Bedrock FlowsはリアルタイムなLLMオーケストレーション向けで、用途が全然違う。SageMaker Pipelines ML CI/CDと混同しないように注意してほしい。


CDKでのFlows管理と運用のコツ

コンソールをぽちぽちして作ったFlowを本番で運用するのは正直しんどいので、うちはCDK(TypeScript)でFlow定義を管理している。2025年末からCDKのL2 ConstructがBedrockに対応し始めて、aws-cdk-lib/aws-bedrock でFlowのリソースを記述できるようになった。

import * as bedrock from 'aws-cdk-lib/aws-bedrock';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class SupportFlowStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    const flowRole = new iam.Role(this, 'BedrockFlowRole', {
      assumedBy: new iam.ServicePrincipal('bedrock.amazonaws.com'),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonBedrockFullAccess')
      ]
    });

    // Flow定義はJSONで管理(コンソールのエクスポート機能でドラフトを得る)
    const flowDefinition = require('./flow-definition.json');

    const flow = new bedrock.CfnFlow(this, 'SupportTriageFlow', {
      name: 'support-triage-flow',
      executionRoleArn: flowRole.roleArn,
      definition: flowDefinition,
      description: 'カスタマーサポートチケット自動トリアージ v2.3'
    });

    // バージョン管理
    const flowVersion = new bedrock.CfnFlowVersion(this, 'SupportFlowV1', {
      flowIdentifier: flow.attrId,
      description: '品質チェックループ追加版'
    });

    // エイリアスで本番/ステージングを切り替え
    new bedrock.CfnFlowAlias(this, 'ProdAlias', {
      flowIdentifier: flow.attrId,
      name: 'production',
      routingConfiguration: [{
        flowVersion: flowVersion.attrVersion
      }]
    });
  }
}

Flow定義のJSONはコンソールの「エクスポート」機能でベースを作って、それをGitで管理する運用にしている。コンソールで試作→Gitにコミット→CDKでデプロイ、というフローが今のところ一番回りやすい。ただ、コンソールで変更してGitに戻すのを忘れるとdriftが発生するので、CIでFlow定義のdiffチェックを入れている。

個人的には「完全にコード管理する」に拘ると複雑なJSON定義との格闘になってコストが高い。「コンソールでプロトタイプ、CDKで本番管理」のハイブリッドが現実的な落とし所だと思っている。CDKのセキュリティ検証についてはCDK Aspects・Nag活用ガイドも参考にしてほしい。


まとめ

6ヶ月Bedrock Flowsを本番で動かして、「ハマりは多いが、複数ステップLLMタスクにはかなり有効」という評価に落ち着いた。やって良かったと思っているし、今から始めるなら2026年時点はかなりタイミングがいいと思う。要点をまとめると以下の通りだ。

① 変数スキーマは最初から余裕を持って設計する additionalProperties: true とIDフィールドの全Node引き回しを最初から入れておく。後から変えるのは本当に痛い。

② Parallel NodeとLoop NodeのGAで本番投入のハードルが下がった 2026年現在、並列処理と反復タスクが安定して動く。レイテンシ最適化に積極的に使っていい。

③ CloudWatch Metrics(Node粒度)でコスト可視化を必ずやる どのNodeがトークンを食っているか見えないとコスト管理ができない。アップデートで入ったNode単位メトリクスを最初から設定しておくこと。

④ Inline Agent NodeはTool側のエラーハンドリングを先に作る Flows側でできることは限られているので、Lambda(Tool)側で防御的なエラー処理を徹底する。

⑤ CDKで管理するが「コンソールでプロトタイプ、CDKで本番」のハイブリッドが現実的 完全コード管理に拘ると初期コストが高い。

次のアクションとしては、まず小さいユースケース(3〜4 Node程度の直列パイプライン)から試して、Parallel NodeとLoop Nodeを段階的に追加するのをおすすめする。最初からフル機能を使おうとするとデバッグが辛い。皆さんはどういうユースケースでBedrockのオーケストレーションを使っていますか?Step FunctionsとFlowsの使い分けとか、ぜひ聞かせてほしい。

U

Untanbaby

ソフトウェアエンジニア|AWS / クラウドアーキテクチャ / DevOps

10年以上のIT実務経験をもとに、現場で使える技術情報を発信しています。 記事の誤りや改善点があればお問い合わせからお気軽にご連絡ください。

関連記事