---
title: "Amazon Bedrock Converse APIの使い方｜boto3実装・ConverseStream・Tool Use・IAM権限【2026年最新】"
url: "https://www.issoh.co.jp/tech/details/2391/"
published: 2024-06-11
updated: 2026-09-26
categories: ["AI"]
publisher: "株式会社一創"
---

# Amazon Bedrock Converse APIの使い方｜boto3実装・ConverseStream・Tool Use・IAM権限【2026年最新】

Amazon Bedrock の Converse API は、Claude・Nova・Llama など Bedrock 上のチャット系モデルを**同じリクエスト形式で呼び出せる統一インターフェース**です。モデルごとに異なる InvokeModel の JSON を書き分ける必要がなくなり、モデルを差し替えてもアプリ側のコードはほぼそのまま使えます。この記事では、boto3 での最小実装、ConverseStream によるストリーミング、Tool Use（外部ツール連携）のループ、そして見落としやすい IAM 権限までを、公式仕様に沿った実コードで整理します。検索でよく打ち込まれる `bedrock:converse` というアクション名の誤解も、あわせて解消します。

## まとめ：Converse APIの要点

先に結論だけ押さえます。詳細は各セクションでコードとともに解説します。

- **エンドポイントとメソッド**：`bedrock-runtime` クライアントの `converse`（一括応答）と `converse_stream`（逐次ストリーミング）。リクエスト本文は両者共通。
- **会話状態はアプリ側で保持**：Bedrock は状態を持たない。毎ターン `messages` に全履歴を積み、返ってきた `output.message` をそのまま追記する。
- **IAM の要注意点**：`bedrock:Converse` というアクションは存在しない。`converse` は `bedrock:InvokeModel`、`converse_stream` は `bedrock:InvokeModelWithResponseStream` で認可される。
- **Tool Use は決定論的ループ**：`stopReason` が `tool_use` になったらツールを実行し、`toolResult` を返して再度呼ぶ。

## Converse APIとは：モデル差を吸収する統一インターフェース

Converse API は `bedrock-runtime` エンドポイント上の2つの操作、`Converse` と `ConverseStream` として提供されます。どちらも `messages`・`system`・`inferenceConfig`・`toolConfig` という共通のリクエスト形を取り、レスポンスも `output`・`stopReason`・`usage`・`metrics` に正規化されて返ります。従来の InvokeModel がモデルごとに独自のボディ構造を要求したのに対し、Converse は「一度書けば別モデルでも動く」設計になっています。

### InvokeModelとの違いとConverseを選ぶ判断基準

InvokeModel は Anthropic なら `anthropic_version` や `max_tokens`、Cohere なら別のキー、というようにモデル提供元のスキーマをそのまま渡します。Converse はこの差を `inferenceConfig`（全モデル共通の `maxTokens`・`temperature`・`topP`・`stopSequences`）と `additionalModelRequestFields`（`top_k` などモデル固有パラメータ）に分離して吸収します。**新規のチャット・エージェント実装なら Converse を既定に選ぶべき**です。InvokeModel を選ぶ理由が残るのは、Converse がまだ対応していない特殊なレスポンス項目を生で扱いたい場合や、既存資産の互換維持が優先される場合に限られます。Bedrock 自体の始め方は[Amazon Bedrockの使い方（料金・モデル・APIの始め方）](/tech/details/2942/)を参照してください。

### messages・output・stopReasonのリクエスト／レスポンス構造

`messages` は `role`（`user` または `assistant`）と `content`（テキスト・画像・ドキュメント・ツール結果などのブロック配列）を持つオブジェクトの配列です。レスポンスでは生成メッセージが `output.message.content` に入り、生成が止まった理由が `stopReason` に入ります。取り得る値は `end_turn`・`tool_use`・`max_tokens`・`stop_sequence`・`guardrail_intervened`・`content_filtered` です。トークン数は `usage`（`inputTokens`・`outputTokens`・`totalTokens`）で確認できます。

## boto3でConverse APIを呼び出す最小実装

「boto3 converse」で検索される実装部分です。ポイントは**クライアント名が `bedrock-runtime` である**こと。`boto3.client('converse')` のような呼び出しは誤りで、そのようなサービスは存在しません。clientの生成方法やリトライの既定値といったSDK側の前提は、[boto3のclientとresourceの違い・認証・リトライの実装](https://www.issoh.co.jp/tech/details/17697/)で整理しています。

### bedrock-runtimeクライアントとconverseメソッド

次のコードは system プロンプトと推論パラメータを付けて1回の応答を得る最小例です。`additionalModelRequestFields` で Claude 固有の `top_k` を渡しています。

```
import boto3

bedrock = boto3.client(service_name="bedrock-runtime", region_name="ap-northeast-1")

response = bedrock.converse(
    modelId="apac.anthropic.claude-sonnet-4-5-20250929-v1:0",
    system=[{"text": "あなたは簡潔に答える技術サポートです。"}],
    messages=[
        {"role": "user", "content": [{"text": "Converse APIとInvokeModelの違いを一言で。"}]}
    ],
    inferenceConfig={"maxTokens": 512, "temperature": 0.3},
    additionalModelRequestFields={"top_k": 200},
)

print(response["output"]["message"]["content"][0]["text"])
print(response["stopReason"], response["usage"]["totalTokens"])
```

`modelId` には推論プロファイルID（先頭に `apac.` や `global.` が付く形）を指定します。多くの新しい Claude モデルはオンデマンドの素のモデルIDだと `ValidationException` になり、クロスリージョン推論プロファイルの指定が必須です。利用可能なIDはリージョンで変わるため、最新はマネジメントコンソールの「Cross-region inference」で確認してください。

### マルチターン会話のstateless維持

Bedrock は会話状態を保存しません。データはその応答の生成にだけ使われ、サーバー側に残りません。したがって**会話の継続はアプリ側の責任**です。前ターンで返った `output.message` を `messages` にそのまま追記し、次のユーザー発話を足して再送します。`role` の交互（user → assistant → user …）が崩れるとエラーになるため、モデル応答を加工せず丸ごと積むのが安全です。

```
messages = [{"role": "user", "content": [{"text": "AWSの生成AIサービスは？"}]}]
resp = bedrock.converse(modelId=MODEL_ID, messages=messages)

# 返答をそのまま履歴に追加してから次の発話を足す
messages.append(resp["output"]["message"])
messages.append({"role": "user", "content": [{"text": "その中でチャット向けはどれ？"}]})
resp = bedrock.converse(modelId=MODEL_ID, messages=messages)
```

履歴が長くなると入力トークン＝コストが増えます。固定の長い system プロンプトやツール定義を繰り返し送るなら、[Amazon Bedrockのプロンプトキャッシュ](/tech/details/4764/)で `cachePoint` を挟むと入力トークンを節約できます。

## IAM権限の設定：「bedrock:Converse」というアクションは存在しない

`bedrock:converse` や `bedrock.converse` は実際によく検索される表記ですが、ここには見落とされがちな事実があります。**Converse 専用のIAMアクションは無い**のです。認可は既存の推論アクションで行われます。

| API操作          | 必要なIAMアクション                           |
| -------------- | ------------------------------------- |
| Converse       | bedrock:InvokeModel                   |
| ConverseStream | bedrock:InvokeModelWithResponseStream |

そのため、ポリシーに `bedrock:Converse` と書いても効果はなく、逆に `bedrock:InvokeModel` を付け忘れると `AccessDeniedException` になります。推論プロファイル経由で呼ぶ場合は、プロファイルARNと、その背後の基盤モデルARNの両方に許可が要る点にも注意してください。なお、ClaudeをMessages API（bedrock-mantle）経由で呼ぶ場合の認可は `bedrock-mantle:CreateInference` という別の名前空間になり、経路ごとの違いは[Bedrock Claudeの使い方｜Messages API・InvokeModel・Claude Codeの設定](https://www.issoh.co.jp/tech/details/17865/)で比べています。最小構成の例は次のとおりです。

```
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "bedrock:InvokeModel",
      "bedrock:InvokeModelWithResponseStream"
    ],
    "Resource": [
      "arn:aws:bedrock:*::foundation-model/*",
      "arn:aws:bedrock:*:123456789012:inference-profile/*"
    ]
  }]
}
```

特定モデルへのアクセスを止めたいときは、この2つのアクションを `Deny` すれば、Converse・ConverseStream 経由の呼び出しも同時に遮断できます（基盤アクションを塞ぐと上位の Converse も塞がるため）。

## ConverseStreamでストリーミング応答を実装する

「converse stream」「conversestream」系のクエリが示すとおり、逐次表示の需要は高い領域です。チャットUIで生成テキストを1文字ずつ流したいなら `converse_stream` を使います。リクエスト本文は `converse` と同じで、違いは応答の受け取り方だけです。

### converse\_streamのイベント列を処理する

応答は `stream` フィールドのイベント列として届きます。順序は `messageStart` →（各コンテンツブロックごとに `contentBlockStart`・`contentBlockDelta`・`contentBlockStop`）→ `messageStop`（`stopReason` を運ぶ）→ `metadata`（`usage` と `metrics`）です。テキストは `contentBlockDelta` の `delta.text` に少しずつ入ります。

```
resp = bedrock.converse_stream(
    modelId=MODEL_ID,
    messages=[{"role": "user", "content": [{"text": "Bedrockを3行で紹介して。"}]}],
)

for event in resp["stream"]:
    if "contentBlockDelta" in event:
        print(event["contentBlockDelta"]["delta"].get("text", ""), end="")
    elif "messageStop" in event:
        print("\n停止理由:", event["messageStop"]["stopReason"])
    elif "metadata" in event:
        print("トークン:", event["metadata"]["usage"]["totalTokens"])
```

### ストリーミング時のTool Useは部分JSONで届く

ストリーミングとツール利用を組み合わせる場合、注意点があります。ツール呼び出しの入力（`toolUse` の `input`）は**完成した JSON ではなく、`contentBlockDelta` の中に分割された部分文字列として順次届く**点です。各 `contentBlockIndex` ごとに `delta.toolUse.input` を連結し、`contentBlockStop` を受け取ってから `json.loads` でパースします。途中の断片を単体でパースしようとすると壊れるため、ブロック単位でバッファリングするのが定石です。

```
tool_input = ""
for event in resp["stream"]:
    if "contentBlockDelta" in event:
        delta = event["contentBlockDelta"]["delta"]
        if "toolUse" in delta:
            tool_input += delta["toolUse"]["input"]   # 部分JSONを連結
    elif "contentBlockStop" in event:
        if tool_input:
            args = json.loads(tool_input)             # ブロック確定後にパース
            tool_input = ""
```

逐次表示が不要ならツール利用は非ストリーミングの `converse` で書いた方が、前掲の実行ループが素直になります。

## Tool Use（外部ツール連携）をConverseで実装する

Tool Use は、天気APIやデータベース照会など**モデル単体では答えられない情報**を取りに行かせる仕組みです。Bedrock ではモデルがツールを直接実行するわけではなく、モデルは「このツールをこの引数で呼びたい」と要求するだけで、実行はアプリ側（クライアントサイド）が担います。

### toolConfigでツールを定義する

ツールは `toolConfig.tools[].toolSpec` に、名前・説明・入力スキーマ（`inputSchema.json`）で定義します。入力スキーマは JSON Schema で書き、`required` で必須引数を指定します。`toolChoice` でモデルの選択方針を `auto`（任せる）・`any`（必ず何かのツール）・`tool`（特定ツール指定）から選べます。

```
tool_config = {
    "tools": [{
        "toolSpec": {
            "name": "get_weather",
            "description": "指定都市の現在の天気を返す",
            "inputSchema": {"json": {
                "type": "object",
                "properties": {
                    "city": {"type": "string", "description": "都市名。例: Tokyo"}
                },
                "required": ["city"]
            }}
        }
    }],
    "toolChoice": {"auto": {}}
}
```

### stopReason=tool\_useを起点にした実行ループ

流れは決定論的です。モデルが `stopReason` を `tool_use` で返したら、`content` 内の `toolUse` ブロック（`toolUseId`・`name`・`input`）を取り出してツールを実行し、結果を `toolResult`（同じ `toolUseId` を付ける）として返して再度 `converse` を呼びます。ここで**1回の応答に複数の `toolUse` が含まれることがある**（Claude は並列でツールを要求する）ため、各結果を別々の user メッセージで積むと `ValidationException` になります。**複数の `toolResult` は1つの user メッセージにまとめて返す**のが正解です。モデルがツール結果を見てさらにツールを要求する多段のケースに備え、`tool_use` でなくなるまで `while` でループさせます。失敗時は `status` に `error` を付けるとモデルが再試行や別応答を判断できます。

```
def run(bedrock, user_text):
    messages = [{"role": "user", "content": [{"text": user_text}]}]
    resp = bedrock.converse(modelId=MODEL_ID, messages=messages, toolConfig=tool_config)
    messages.append(resp["output"]["message"])

    # tool_useが続く限りツールを実行し結果を返し続ける
    while resp["stopReason"] == "tool_use":
        tool_results = []
        for block in resp["output"]["message"]["content"]:
            if "toolUse" not in block:
                continue
            tu = block["toolUse"]
            try:
                data = get_weather(tu["input"]["city"])   # 自作の実処理
                tool_results.append({"toolUseId": tu["toolUseId"],
                                     "content": [{"json": data}]})
            except Exception as e:
                tool_results.append({"toolUseId": tu["toolUseId"],
                                     "content": [{"text": str(e)}], "status": "error"})

        # 複数ツールの結果は1つのuserメッセージにまとめて返す（別々に積むとValidationException）
        messages.append({"role": "user",
                         "content": [{"toolResult": r} for r in tool_results]})
        resp = bedrock.converse(modelId=MODEL_ID, messages=messages, toolConfig=tool_config)
        messages.append(resp["output"]["message"])

    return "".join(b["text"] for b in resp["output"]["message"]["content"] if "text" in b)
```

ツールの実行主体をアプリではなく Bedrock 側に寄せたい（Lambda 登録などで集中管理したい）場合は、サーバーサイド Tool Use を持つ[Amazon Bedrock AgentCore](/tech/details/8230/)の利用が選択肢になります。

## 実装時の判断と失敗パターン

最後に、公式手順どおりに書いても詰まりやすい点を、判断込みで挙げます。

- **ValidationException（modelId）**：新しめの Claude をオンデマンドの素のIDで呼ぶと失敗する。`apac.` や `global.` 付きの推論プロファイルIDに変える。
- **AccessDeniedException**：IAMに `bedrock:InvokeModel`／`bedrock:InvokeModelWithResponseStream` が無い、またはモデルのアクセス有効化（コンソールの Model access）が未実施。
- **会話が壊れる**：モデル応答を要約・整形して履歴に積むと `role` 交互やツールIDの対応が崩れる。`output.message` は無加工で追記する。
- **トークン肥大**：全履歴を毎回送る仕様上、長い会話ほど入力コストが増える。古い発話の切り詰めやプロンプトキャッシュで抑える。

逆に **Converse を使わない方がよい場面**もあります。単発のバッチ推論で会話文脈もツールも不要なら、Converse の正規化は恩恵が薄く、料金や検索を組み合わせるなら[RAG（KendraとBedrockの組み合わせ）](/tech/details/4204/)のような別構成が適します。「チャット的な多ターン対話」か「ツールを挟む」なら Converse、それ以外は用途に合わせて選ぶのが実務的な線引きです。

## よくある質問

### bedrock:converse というIAMアクションはありますか？

ありません。Converse は `bedrock:InvokeModel`、ConverseStream は `bedrock:InvokeModelWithResponseStream` で認可されます。ポリシーにはこの2つのアクションを記述してください。

### ConverseとConverseStreamの違いは何ですか？

リクエスト本文は同一で、応答の返り方だけが違います。`converse` は生成完了後に一括で返し、`converse_stream` はイベント列（`contentBlockDelta` など）として逐次返します。UIで文字を流したいなら後者を使います。

### boto3でConverseを呼ぶクライアント名は何ですか？

`bedrock-runtime` です（`boto3.client(service_name="bedrock-runtime")`）。`converse` と `converse_stream` メソッドが生えています。`bedrock`（管理系）や存在しない `converse` サービスと混同しないよう注意してください。

### 会話の履歴はどう保持しますか？

Bedrock は状態を持たないため、アプリ側で `messages` に全ターンを積みます。モデルの返答は `output.message` をそのまま追記し、次のユーザー発話を足して再送します。

### Tool Useはどのモデルで使えますか？

Converse のツール利用は、ツール呼び出しに対応した複数モデル（Anthropic Claude、Amazon Nova、Cohere Command R など）で使えます。対応状況はモデルごとに異なるため、利用モデルの対応可否を公式のモデル一覧で確認してください。Converse の対応可否を含めた選定の考え方は[AWS Bedrockのモデル選定｜Claude・Nova・OpenAI・Gemmaの選び分けと切替判断](https://www.issoh.co.jp/column/details/16543/)で扱っています。

## 関連記事

- [Amazon Bedrockの使い方｜料金・モデル・APIの始め方を4ステップで解説【2026年版】](/tech/details/2942/)
- [Amazon Bedrockのプロンプトキャッシュとは｜仕組み・対応モデル・料金・実装方法【2026年最新】](/tech/details/4764/)
- [Amazon Bedrock AgentCore APIの使い方｜SDK・CLIでAIエージェントを本番デプロイ【2026年最新】](/tech/details/8230/)
- [Amazon BedrockとAmazon Kendraを活用したRAGの実装方法](/tech/details/4204/)

---

出典: [Amazon Bedrock Converse APIの使い方｜boto3実装・ConverseStream・Tool Use・IAM権限【2026年最新】](<https://www.issoh.co.jp/tech/details/2391/>)（株式会社一創）
