Amazon Bedrock Converse API — Python SDK Quick Reference
Condensed patterns for boto3 bedrock-runtime. For full API structure and provider-specific formats, see model-invocation.md.
Table of Contents
- Install
- Quick Start
- Non-Obvious Patterns
- Streaming
- Tool Use
- Guardrail Integration
- Best Practices
Install
pip install "boto3>=1.34.0"Quick Start
import boto3
from botocore.config import Config
# MUST use bedrock-runtime client (not bedrock) for inference
# MUST configure adaptive retry for production
client = boto3.client(
"bedrock-runtime",
config=Config(retries={"max_attempts": 5, "mode": "adaptive"})
)
response = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [{"text": "Hello"}]}],
inferenceConfig={
"maxTokens": 1024, # MUST set explicitly — see Non-Obvious Patterns
"temperature": 0.7,
},
)
print(response["output"]["message"]["content"][0]["text"])Non-Obvious Patterns
- maxTokens MUST be set explicitly. Leaving it unset defaults to model maximum (64K for Claude) and silently reserves 43x more quota than needed — the #1 cause of unexpected ThrottlingException.
- Cross-region model IDs require a geographic prefix (
us.,eu.,apac.,global.,us-gov.,au.,jp.,ca., etc.). Using a direct model ID without the prefix for cross-region inference causesResourceNotFoundExceptionorAccessDeniedException. Model IDs in code examples below may be outdated — always verify current model IDs before use:aws bedrock list-foundation-models --region <region>andaws bedrock list-inference-profiles --region <region>, or refer to the latest Bedrock supported models and cross-region inference profiles. - Newer models may require inference profile IDs instead of model IDs. Verify the correct ID format: `aws bedrock get-foundation-model --model-identifier``<model-id>```
- Prompt management: Pass prompt ARN as
modelId— it replaces the model ID, not alongside it. When using managed prompts, MUST NOT includeinferenceConfig,system,toolConfig, oradditionalModelRequestFields(baked into the prompt). Messages are appended after the prompt's messages, not replacing them. - Streaming events arrive in order:
messageStart→contentBlockStart→contentBlockDelta(repeated) →contentBlockStop→messageStop→metadata. - Retry only: ThrottlingException, ModelTimeoutException, ServiceUnavailableException, InternalServerException. Do NOT retry: ValidationException, AccessDeniedException.
- bedrock-runtime for inference, bedrock for management. Using the wrong client is the #1 cause of
UnknownOperationException.
Streaming
response = client.converse_stream(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [{"text": "Explain RAG in 3 sentences."}]}],
inferenceConfig={"maxTokens": 1024},
)
for event in response["stream"]:
if "contentBlockDelta" in event:
print(event["contentBlockDelta"]["delta"].get("text", ""), end="")
elif "metadata" in event:
usage = event["metadata"]["usage"]
print(f"\nTokens: {usage['inputTokens']} in, {usage['outputTokens']} out")Tool Use
tool_config = {
"tools": [{
"toolSpec": {
"name": "get_weather",
"description": "Get current weather for a city",
"inputSchema": {
"json": {
"type": "object",
"properties": {"city": {"type": "string", "description": "City name"}},
"required": ["city"],
}
},
}
}]
}
response = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [{"text": "What's the weather in Seattle?"}]}],
inferenceConfig={"maxTokens": 1024},
toolConfig=tool_config,
)
# Check if model wants to use a tool
if response["stopReason"] == "tool_use":
tool_block = next(
b["toolUse"] for b in response["output"]["message"]["content"] if "toolUse" in b
)
tool_name = tool_block["name"] # "get_weather"
tool_input = tool_block["input"] # {"city": "Seattle"}
tool_use_id = tool_block["toolUseId"]
# IMPORTANT: Validate tool_input before use — model outputs are untrusted.
# The model could return malformed or unexpected values. Validate types,
# lengths, and allowlists before passing to any tool handler.
# Execute tool, then send result back
messages = [
{"role": "user", "content": [{"text": "What's the weather in Seattle?"}]},
response["output"]["message"], # assistant message with toolUse
{
"role": "user",
"content": [{
"toolResult": {
"toolUseId": tool_use_id,
"content": [{"text": "72°F, sunny"}],
}
}],
},
]
final = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=messages,
inferenceConfig={"maxTokens": 1024},
toolConfig=tool_config,
)Guardrail Integration
response = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [{"text": "Tell me about investments"}]}],
inferenceConfig={"maxTokens": 1024},
guardrailConfig={
"guardrailIdentifier": "my-guardrail-id",
"guardrailVersion": "1", # Pin version in production, don't use DRAFT
"trace": "disabled", # MUST be "disabled" in production — "enabled" exposes PII/harmful content in response (HIPAA/GDPR risk)
},
)Best Practices
- Always set
maxTokensexplicitly — never rely on default - Use
bedrock-runtimefor inference,bedrockfor management - Use adaptive retry:
Config(retries={"max_attempts": 5, "mode": "adaptive"}) - Use cross-region model IDs (
us.prefix) for higher availability - Pin prompt management versions in production (
:1suffix in ARN) - Use
converse_streamfor user-facing applications (lower time-to-first-token) - Pin guardrail versions — don't use DRAFT in production