Amazon Bedrock Mantle OpenAI 兼容 API 实测:支持矩阵、Claude 走哪条路、Guardrail 生效端点¶
⚠️ 此文结论有误,已废弃
本文 2026-05-01 发布时的核心结论第 1 条("OpenAI 兼容 API 只给 openai.* 家模型")在 2026-05-02 补跑完整 40 × 3 API 支持矩阵后被证伪。实际情况是 Mantle 是多厂商模型 marketplace,Chat Completions API 对 38/40 模型开放。
请直接阅读修正版:Bedrock Mantle API 支持矩阵实测
原文保留作为勘误留档,以下结论请不要引用。
Lab 信息
- 难度: ⭐⭐ 中级
- 预估时间: 40 分钟
- 预估费用: < $1(13 次左右 API 调用 + 一个临时 Guardrail)
- Region: us-east-1
- 最后验证: 2026-05-01
背景¶
Amazon Bedrock 近期通过新端点 bedrock-mantle.{region}.api.aws 暴露了 OpenAI 兼容的 Responses API 与 Chat Completions API,目标是让已有 OpenAI SDK 代码只改 base_url 和 api_key 就能迁移。
笔者(AWS SA)在看到公告时的第一反应是:"Bedrock 支持 OpenAI 兼容 API ✅,那 Claude 也能用 OpenAI SDK 调了"。这个直觉是错的——而且错得很具体。实测之后得到的结论是:
Bedrock Mantle 提供的是一组 OpenAI 兼容的 API 路径,而不是一个"对所有模型都兼容 OpenAI 的统一入口"。哪些模型能走这些路径、Guardrail 在哪个端点生效、Claude Sonnet 4.6 应当怎么调用,都各自有不同的答案。
本文用 15 项实测(含反面测试)把这个支持矩阵画清楚,帮读者避开从公告到落地中间的三类误读。
前置条件¶
- AWS 账号,在目标 Region 已开通 Amazon Bedrock 并订阅所用模型
AmazonBedrockLimitedAccess或等效权限;另需bedrock:CreateGuardrail/DeleteGuardrail以复现 Guardrail 部分- Python ≥ 3.10、
pip install openai boto3 aws-bedrock-token-generator requests - AWS CLI v2 已配置默认凭证
使用 Bedrock short-term API key 作为 OPENAI_API_KEY。短期 Key 有效期最长 12 小时,只能在生成它的 Region 使用。
核心概念¶
端点支持的 API 一览¶
| 端点 | Host | OpenAI Responses | OpenAI Chat Completions | Anthropic Messages | Converse/Invoke |
|---|---|---|---|---|---|
bedrock-mantle.{region}.api.aws |
/v1/*、/anthropic/v1/messages |
✅ | ✅ | ✅ | ❌ |
bedrock-runtime.{region}.amazonaws.com |
原生路径 + /openai/v1/* |
❌ | ✅ | ✅ | ✅ |
来源:Endpoints supported by Amazon Bedrock。两个端点对 Chat Completions 的 URL 前缀不同:
- Mantle:
https://bedrock-mantle.us-east-1.api.aws/v1/chat/completions - Runtime:
https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1/chat/completions(多一段/openai)
模型能走哪条路径,以模型卡为准¶
| 模型 | Mantle Model ID | Runtime Model ID | Responses API | Chat Completions | Messages API |
|---|---|---|---|---|---|
openai.gpt-oss-120b |
openai.gpt-oss-120b |
openai.gpt-oss-120b-1:0 |
✅ | ✅ | — |
anthropic.claude-opus-4-7 |
anthropic.claude-opus-4-7 |
anthropic.claude-opus-4-7 |
❌ | ❌ | ✅ |
anthropic.claude-haiku-4-5 |
anthropic.claude-haiku-4-5 |
anthropic.claude-haiku-4-5 |
❌ | ❌ | ✅ |
| Claude Sonnet 4.6 | 未挂载 | anthropic.claude-sonnet-4-6 / geo us.anthropic.claude-sonnet-4-6 |
❌ | ❌ | ✅ |
来源:gpt-oss-120b 模型卡、Claude Sonnet 4.6 模型卡。
关键点:OpenAI 兼容 API 只给 openai.* 家模型使用;Anthropic 模型在 Mantle 上走 /anthropic/v1/messages 的 Anthropic native 路径。Claude Sonnet 4.6 在 us-east-1 无 In-Region 部署,需用 Cross-Region inference ID us.anthropic.claude-sonnet-4-6。
动手实践¶
以下测试都在 us-east-1 执行。完整脚本放在文末仓库链接,下文只展示关键片段与实测输出。
Step 1: 设置 OpenAI 客户端指向 Mantle¶
from aws_bedrock_token_generator import provide_token
from openai import OpenAI
api_key = provide_token(region="us-east-1") # short-term Bedrock API key
mantle = OpenAI(
api_key=api_key,
base_url="https://bedrock-mantle.us-east-1.api.aws/v1",
)
provide_token() 基于默认 AWS 凭证生成 SigV4-sealed 的 bearer token;官方文档将其称为 short-term API key。
Step 2: Responses API 基础调用¶
resp = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "In one sentence, explain what Amazon Bedrock is."}],
)
print(resp.id, resp.status, resp.usage)
实测输出:
resp_dk3m5cjjg7x3g7e3lwedzorqpywkxv557yq3u4uys4vbeggdcekq completed
Usage(input_tokens=78, output_tokens=85, total_tokens=163)
latency: 1667 ms
响应对象包含 30+ 字段,除了 output/usage/status 之外还有 previous_response_id、background、conversation、reasoning、prompt_cache_key、service_tier 等——这些字段对应了 Responses API 的 stateful、异步、推理专用能力。
Step 3: Responses API 流式¶
stream = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "Count from 1 to 10, one number per line."}],
stream=True,
)
for event in stream:
print(event.type)
实测输出(节选事件类型统计):
response.created 1
response.in_progress 1
response.output_item.added ...
response.output_text.delta (多次)
response.output_text.done 1
response.completed 1
共 15 个事件,TTFB = 1340 ms,total = 1429 ms
Responses API 的事件流是 语义事件(而非 Chat Completions 的逐 token chunk),比如 response.output_text.delta 携带一段文本 delta、response.completed 标志结束。
Step 4: Responses API 用 previous_response_id 串多轮¶
多轮不再需要把 history 拼回请求体:
r1 = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "My favorite color is teal. Remember this."}],
)
r2 = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "What is my favorite color? Respond with just the color word."}],
previous_response_id=r1.id,
)
print(r2.output[0].content[0].text) # -> "teal."
三轮对话均只传入当轮用户消息 + previous_response_id,模型在第 2、3 轮都能正确回答 teal。上下文由服务端维护。
Step 5: Responses API 调工具(OpenAI function calling 语法)¶
tools = [{
"type": "function",
"name": "get_current_weather",
"description": "Return the current weather for a given city.",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
},
"required": ["city"],
},
}]
r1 = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "What's the weather in Tokyo? Use the tool."}],
tools=tools,
)
# 检视 r1.output 会看到一个 type=function_call 的输出:
# name=get_current_weather, arguments='{"city":"Tokyo","unit":"celsius"}'
# 执行本地工具后,把结果通过 function_call_output 回传
r2 = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{
"type": "function_call_output",
"call_id": "<来自 r1 的 call_id>",
"output": '{"temperature": 22, "condition": "sunny"}',
}],
previous_response_id=r1.id,
tools=tools,
)
两轮后得到最终回答。与 Bedrock 原生 Converse 的 tool-use schema 不同,Responses API 用的是 OpenAI 一致的 function_call / function_call_output 对。
Step 6: Responses API 后台任务¶
created = mantle.responses.create(
model="openai.gpt-oss-120b",
input=[{"role": "user", "content": "Write a 150-word story about a lighthouse keeper..."}],
background=True,
)
# created.status 立即是 "in_progress"
while True:
r = mantle.responses.retrieve(created.id)
if r.status in ("completed", "failed", "cancelled", "incomplete"):
break
time.sleep(1)
实测输出:
适用于长耗时 prompt、要做 fire-and-forget 的场景。retrieve 也可配合 webhook 消费。
Step 7: 两端点 Chat Completions 对比¶
对同一个 prompt "Reply with the single word: OK" 分别打两端点:
| 端点 | Model ID | latency | prompt_tokens | completion_tokens | response.id 前缀 |
|---|---|---|---|---|---|
bedrock-mantle/v1 |
openai.gpt-oss-120b |
1245 ms | 84 | 35 | chatcmpl- |
bedrock-runtime/openai/v1 |
openai.gpt-oss-120b-1:0 |
1301 ms | 84 | 32 | chatcmpl- |
响应 JSON 顶层字段一致(id/object/created/model/choices/usage/service_tier/system_fingerprint)。注意模型 ID 不同:Mantle 是 openai.gpt-oss-120b;Runtime 是 openai.gpt-oss-120b-1:0(带 -1:0 版本后缀)。
样本量 N=1,延迟数字仅作示意,不作 SLA 论断。
Step 8: 反面测试——OpenAI SDK + Claude model ID¶
大多数使用者最容易掉进的坑是直接把 Claude Sonnet 4.6 的 model ID 替换到 OpenAI 客户端里。实测三组组合:
8a. Mantle + Responses API + Claude 4.6:
报错:
HTTP 404
{"error":{"code":"not_found_error","type":"invalid_request_error",
"message":"The model 'us.anthropic.claude-sonnet-4-6' does not exist"}}
8b. Mantle + Chat Completions + Claude 4.6: 同样 404 / not_found_error / 同一措辞。
8c. Runtime + Chat Completions + Claude 4.6:
HTTP 404
{"error":{"code":"model_not_found","type":"not_found_error",
"message":"The model doesn't exist or doesn't support this API. Retry your request with a different model ID."}}
两端点返回的 错误 code 和 message 都不同:Mantle 版是"model does not exist"(强调目录缺席),Runtime 版是"doesn't exist or doesn't support this API"(兼顾两种原因)。
Step 9: Claude 走 Bedrock 原生 API(对照基线)¶
import boto3, json
client = boto3.client("bedrock-runtime", region_name="us-east-1")
# Converse
converse = client.converse(
modelId="us.anthropic.claude-sonnet-4-6",
messages=[{"role": "user", "content": [{"text": "Reply with the single word: OK"}]}],
inferenceConfig={"maxTokens": 20},
)
# latency ≈ 1716 ms, usage input=14, output=4
# Invoke(Anthropic Messages JSON)
invoke = client.invoke_model(
modelId="us.anthropic.claude-sonnet-4-6",
body=json.dumps({
"anthropic_version": "bedrock-2023-05-31",
"messages": [{"role": "user", "content": "Reply with the single word: OK"}],
"max_tokens": 20,
}),
accept="application/json",
contentType="application/json",
)
# latency ≈ 1487 ms, 同样的 14/4 tokens
两条路径等价,Converse 返回 Bedrock 统一的 schema(含 metrics.latencyMs),Invoke 保留 Anthropic 原生的 content[] + usage.cache_read_input_tokens 等字段。
Step 10: Mantle 上的 Claude 模型只能走 Anthropic Messages¶
Mantle /v1/models 确实列出了 Claude Opus 4.7 和 Haiku 4.5(但没有 Sonnet 4.6):
curl -s -H "Authorization: Bearer $BEDROCK_API_KEY" \
https://bedrock-mantle.us-east-1.api.aws/v1/models | jq '.data[].id'
实测:40 个模型,包含 anthropic.claude-haiku-4-5、anthropic.claude-opus-4-7、openai.gpt-oss-120b 等;无 anthropic.claude-sonnet-4-6。
对这些 Anthropic 模型使用 OpenAI API:
mantle.responses.create(model="anthropic.claude-opus-4-7", input=[...])
# HTTP 400 validation_error
# "The model 'anthropic.claude-opus-4-7' does not support the '/v1/responses' API"
mantle.chat.completions.create(model="anthropic.claude-opus-4-7", messages=[...])
# HTTP 400 validation_error
# "The model 'anthropic.claude-opus-4-7' does not support the '/v1/chat/completions' API"
走 Mantle 的 Anthropic native 路径则可以:
curl -X POST https://bedrock-mantle.us-east-1.api.aws/anthropic/v1/messages \
-H "Authorization: Bearer $BEDROCK_API_KEY" \
-H "Content-Type: application/json" \
-H "anthropic-version: bedrock-2023-05-31" \
-d '{"model":"anthropic.claude-opus-4-7","max_tokens":20,
"messages":[{"role":"user","content":"Reply with OK."}]}'
# HTTP 200
Step 11: Guardrail 在两端点的行为差异¶
在 Console 或 CLI 创建一个开启 VIOLENCE/HATE 过滤的 Guardrail:
aws bedrock create-guardrail --region us-east-1 \
--cli-input-json file://guardrail.json
# 返回 guardrailId=9bq7insnsizo, version=DRAFT
同 prompt(一段含仇恨内容的翻译请求)分别打两端点,带上 Guardrail header:
for base, model in [
("https://bedrock-runtime.us-east-1.amazonaws.com/openai/v1", "openai.gpt-oss-120b-1:0"),
("https://bedrock-mantle.us-east-1.api.aws/v1", "openai.gpt-oss-120b"),
]:
c = OpenAI(api_key=api_key, base_url=base)
r = c.chat.completions.create(
model=model,
messages=[{"role": "user", "content": hate_prompt}],
extra_headers={
"X-Amzn-Bedrock-GuardrailIdentifier": "9bq7insnsizo",
"X-Amzn-Bedrock-GuardrailVersion": "DRAFT",
"X-Amzn-Bedrock-Trace": "ENABLED",
},
)
实测对比:
| 端点 | response.id 前缀 | usage.prompt_tokens | content | 解读 |
|---|---|---|---|---|
bedrock-runtime |
bedrock-guardrails-c64164bf |
0 | "INPUT_BLOCKED: This request was blocked by a guardrail." | Guardrail 前置拦截,未进入模型,无 token 计费 |
bedrock-mantle |
chatcmpl-1e27ced2... |
86 | "I'm sorry, but I can't help with that." | 请求直达模型,模型自带安全拒绝,token 正常计费 |
对照 gpt-oss-120b 的官方模型卡:"Features supported using bedrock-mantle endpoint" 一栏未列出 Guardrails,"Features supported using bedrock-runtime endpoint" 一栏明确列 Yes Guardrails。文档与实测一致:Guardrail header 只在 bedrock-runtime 生效。
测试结果¶
| # | 测试场景 | 结果 | 关键数据 | 备注 |
|---|---|---|---|---|
| T01 | Mantle Responses 基础 | ✅ | 78/85 tokens, 1667 ms | 响应含 30+ 字段 |
| T02 | Mantle Responses streaming | ✅ | TTFB 1340 ms, 15 events | 语义事件流 |
| T03 | Mantle Responses stateful (previous_response_id) |
✅ | 3 轮均正确召回上下文 | 服务端维护 history |
| T04 | Mantle Responses tool use | ✅ | 1 次 function_call → function_call_output | OpenAI 原生语法 |
| T05 | Mantle Responses background | ✅ | 4 次 poll, total 6147 ms | 异步流程跑通 |
| T06 | Mantle Chat Completions | ✅ | 84/35 tokens, 1245 ms | 基线 |
| T07 | Runtime Chat Completions | ✅ | 84/32 tokens, 1301 ms | Model ID 带 -1:0 后缀 |
| T08a | Runtime + Guardrail 触发 | ✅ | id=bedrock-guardrails-*, 0 token |
前置拦截 |
| T08b | Runtime + Guardrail 放行 | ✅ | 正常回答 | |
| T09a | Mantle + Guardrail header + 触发 prompt | ⚠️ | id=chatcmpl-*, 86 prompt tokens 计费 |
Header 未生效 |
| T09b | Mantle + Guardrail header + 安全 prompt | ✅ | 正常回答 | |
| T10 | Claude 4.6 Converse | ✅ | 14/4 tokens, 1716 ms | 基线 |
| T10b | Claude 4.6 Invoke (Messages JSON) | ✅ | 14/4 tokens, 1487 ms | |
| T11 | Claude 4.6 Messages on Mantle | ❌ | 404, not found in Mantle catalog | Sonnet 4.6 未挂载 Mantle |
| T12a | OpenAI SDK + Claude 4.6 → Mantle Responses | ❌ (预期) | HTTP 404 not_found_error |
错误措辞见正文 |
| T12b | OpenAI SDK + Claude 4.6 → Mantle Chat | ❌ (预期) | HTTP 404 not_found_error |
|
| T13 | OpenAI SDK + Claude 4.6 → Runtime Chat | ❌ (预期) | HTTP 404 model_not_found |
措辞与 Mantle 不同 |
| T14a | GET Mantle /v1/models |
✅ | 40 个模型 | 含 Opus 4.7 / Haiku 4.5,无 Sonnet 4.6 |
| T14b | OpenAI SDK + Claude Opus 4.7 → Mantle | ❌ (预期) | HTTP 400 validation_error:不支持该 API |
路径精准报错 |
| T14c | Anthropic native /anthropic/v1/messages + Claude Opus 4.7 |
✅ | 200 OK |
延迟均为单次采样,仅作示意。
踩坑记录¶
坑 1:OpenAI 兼容 ≠ 全模型 OpenAI 兼容
Mantle 的 /v1/responses、/v1/chat/completions 只接受 openai.* 家模型的 ID。把 Claude、Mistral、Qwen 的 model ID 直接塞进去,得到 404 not_found_error(Mantle 侧)或 400 validation_error(Mantle 侧,对已挂载但不支持该 API 的模型)。
每一个模型卡的 "APIs supported" 列是真实契约,以模型卡为准。
坑 2:Guardrail header 在 Mantle 上被静默忽略
X-Amzn-Bedrock-GuardrailIdentifier / X-Amzn-Bedrock-GuardrailVersion 只在 bedrock-runtime 端生效。对 Mantle 端带相同 header 不会报错,但请求会绕过 Guardrail 直达模型,token 正常计费,response.id 前缀为 chatcmpl-* 而非 bedrock-guardrails-*。
来源:gpt-oss-120b 模型卡列出的 Bedrock 特性表中,Guardrails 仅出现在 bedrock-runtime 行。生产需要 Guardrail 时,改用 Runtime 端点(Chat Completions 通过 /openai/v1/ 前缀或 Converse/Invoke)。
坑 3:Chat Completions 的 Model ID 在两端点不同
同一个模型在 Mantle 上是 openai.gpt-oss-120b,在 Runtime 上是 openai.gpt-oss-120b-1:0(带 -1:0 版本后缀)。跨端点迁移代码时不能仅改 base_url,还需要调整 model 字段。
坑 4:同样叫 Claude,Sonnet 4.6 / Opus 4.7 / Haiku 4.5 走的路径不一样
- Sonnet 4.6:仅
bedrock-runtime,只能走 Converse / Invoke / Messages,且 us-east-1 必须用us.anthropic.claude-sonnet-4-6跨区域推理 ID。 - Opus 4.7 / Haiku 4.5:Runtime 和 Mantle 都有,但 Mantle 侧只接受
/anthropic/v1/messages;用 OpenAI SDKresponses.create/chat.completions.create会被 Mantle 以 400validation_error拒绝。
计划用 OpenAI 生态的 agent 框架接 Claude 前,先以模型卡确认再写代码。
无关宏旨的小差异
- 两端点 Chat Completions 的响应 JSON 顶层字段一致,但 Mantle 版本的
content在 gpt-oss 上可能包含<reasoning>...</reasoning>块(推理痕迹),Runtime 版本也有。应用层记得剥离再展示给终端用户。
选型建议¶
| 需求 | 推荐端点 | 模型 ID 形式 | API |
|---|---|---|---|
| 新项目、希望用 OpenAI SDK 生态 | bedrock-mantle |
openai.gpt-oss-120b / openai.gpt-oss-20b |
Responses 或 Chat Completions |
| 需要 stateful 多轮 / 异步后台 / server-side tool | bedrock-mantle |
openai.* |
Responses API |
| 必须用 Bedrock Guardrail 做内容过滤 | bedrock-runtime |
模型卡列出 runtime 支持的 ID | Chat Completions via /openai/v1/ 或 Converse |
| 已有 Anthropic SDK 代码迁移到 Bedrock | Mantle 或 Runtime | anthropic.* |
/anthropic/v1/messages(同一套 Messages 语义) |
| 需要调用 Claude Sonnet 4.6 | bedrock-runtime |
us.anthropic.claude-sonnet-4-6 |
Converse 首选,Invoke 亦可 |
| 想用 OpenAI SDK 调 Claude | 不可行 | — | Anthropic 模型不接受 OpenAI Responses / Chat Completions API |
费用明细¶
| 资源 | 说明 | 费用 |
|---|---|---|
openai.gpt-oss-120b 调用 |
共约 1500 input + 1600 output tokens(T01-T09, T15) | < $0.05 |
us.anthropic.claude-sonnet-4-6 调用 |
共约 50 input + 20 output tokens(T10, T10b) | < $0.01 |
anthropic.claude-opus-4-7 / anthropic.claude-haiku-4-5 调用 |
6 次 400/200 响应的探针 | < $0.01 |
| Bedrock Guardrail(DRAFT 版本) | 创建无固定费用,调用按次计 | < $0.01 |
| 合计 | < $0.10 |
清理资源¶
# 删除测试 Guardrail
aws bedrock delete-guardrail --region us-east-1 \
--guardrail-identifier 9bq7insnsizo
# 如果启用了 model invocation logging,检查并按需删除日志流
aws logs describe-log-streams --region us-east-1 \
--log-group-name /aws/bedrock/modelinvocations 2>/dev/null || true
Short-term API key 无需显式撤销,12 小时后自动失效。IAM 凭证本身如仍有效,仅需停止持有并将本地环境变量清空。
务必清理
Guardrail 创建不收费但保留占用一个 quota 名额;测试结束后建议删除。
结论¶
Amazon Bedrock 通过 bedrock-mantle 端点引入的 OpenAI 兼容 API,实际价值比"可以用 OpenAI SDK 了"要精细:
- Responses API 是 Mantle 独占能力——stateful 多轮、background 异步、OpenAI 一致的 tool-use 语法,在
bedrock-runtime上都拿不到。 - OpenAI 兼容路径仅对
openai.*家模型生效,Claude/Mistral/Qwen 等走同端点的/anthropic/v1/messages或只能回到 Runtime 端点。 - Guardrail 是
bedrock-runtime的特性,Mantle 上附带 Guardrail header 不会报错也不会拦截;依赖合规审计的项目需要明确用 Runtime 端点。 - Claude Sonnet 4.6 这种未挂载到 Mantle 的模型,无论调用方式如何变都得回到 Runtime。
概括成一条简单准则:先查模型卡的 "APIs supported" 与 "Endpoints supported" 列,再决定用哪个 SDK 和哪个 base_url。