一、背景
当考虑在云上部署自有模型或第三方模型时,有两条技术路线,一是采用EC2 GPU机型部署,自己构建对外服务API;二是采用Bedrock的Import Model导入功能导入自有模型然后使用Bedrock的ServerlessAPI对外提供服务。在过往的博客文章中,如下文章分别介绍了这两种部署方式:
本文将演示如何在Bedrock上导入 Xiaomi-MiMo-VL-Miloco 模型。
关于在这两种方式之间如何选择,这里方案对比如下:
| 对比 | EC2 GPU部署 | Bedrock导入模型 |
|---|---|---|
| 架构限制 | 无,任何架构均可 | 有限制,目前Bedrock仅支持特定架构模型导入,例如Qwen-2.5系列 |
| 部署方便程度 | 复杂 | 简单 |
| 后续维护成本 | 高,需要自建监控、告警、日志等 | 低, Bedrock负责基础设施运维 |
| 安全性 | 手工管理认证、日志等,复杂且风险点和漏洞多 | 借助Bedrock服务API的认证和审计,安全 |
| 高可靠性 | 手工部署多台实例、手工搭建负载均衡、健康检查等 | 借助Bedrock服务的高可用设计,无需关注底层基础设施 |
| 弹性扩展 | 手工配置EC2监控并实现自动弹性扩展 | Bedrock自动管理负载和弹性扩展 |
| 冷启动 | EC2长期不关机时候,不存在冷启动的情况 | 持续2个五分钟无人访问资源暂停,会触发冷启动,因此高频访问需要预热 |
| 成本 | 长期占用EC2、需要买预留实例,适合并发压力巨大、能跑满GPU的场景 | 按需调用,无访问不收费,适合并发不高、波峰波谷变化幅度较大的场景,但如果全天24小时调用成本较高 |
| 适用场景 | 复杂业务逻辑、个性化定制需求强 | 快速部署、标准化API调用、对模型进行推理 |
Bedrock的模型导入功能,允许用户将自己训练的模型或者第三方模型导入到Bedrock中,并以Serverless的方式对外提供。在2025年初的时候,仅支持Meta开源的Llama架构的模型,在2025年下半年,支持国产Qwen系列模型,目前对Qwen-2.5-VL等提供支持。后续支持的版本以官网为准。
二、从Huggingface下载模型并上传到S3
1、原始文件下载
由于模型文件体积较大,因此这里不将模型下载到开发者本机了,而是选择在云上创建一个EC2,下载模型后,直接上传到S3并完成导入。
创建一个不含GPU的EC2,例如m7i.large,系统选择Ubuntu 24.04,磁盘选择大于30GB即可(满足下载要求)。创建完毕后,通过SSH登陆到这个EC2,安装Huggingface的软件包。执行如下命令:
sudo apt update
sudo apt upgrade -y
sudo apt install pipx net-tools curl unzip -y
pipx install huggingface_hub
pipx ensurepath
sudo reboot
重启完成后,下载模型文件到用户的根目录下。
cd /home/ubuntu/
hf download xiaomi-open-source/Xiaomi-MiMo-VL-Miloco-7B --local-dir ./Xiaomi-MiMo-VL-Miloco-7B
2、修改模型配置文件
Amazon Bedrock服务支持Qwen-2.5-VL架构的模型的,但是在模型配置文件中,不支持填写rope_scaling字段。因此这个字段需要从配置文件中删除后,再上传到S3。
编辑文件 /home/ubuntu/Xiaomi-MiMo-VL-Miloco-7B/config.json ,找到其中rope_scaling这一段,内容如下:
"rope_scaling": {
"factor": 1.0,
"mrope_section": [
16,
24,
24
],
"original_max_position_embeddings": 128000,
"rope_type": "default",
"type": "default"
},
将以上整个rope_scaling的标签删除。保存退出。
3、配置AWSCLI及密钥用于上传数据的权限
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
aws configure
按提示配置好AWSCLI的Access key和Secrect key,就具有了上传到S3的权限。
4、创建S3存储桶并上传模型文件
进入AWS控制台,在要使用Bedrock的区域,创建S3存储桶,类型选择General purpose buckets即可。
在刚才的EC2上运行如下命令上传模型:
aws s3 cp --recursive Xiaomi-MiMo-VL-Miloco-7B s3://your-bucket-name/Xiaomi-MiMo-VL-Miloco-7B/
由此即可完成模型上传。
三、导入到Bedrock
1、执行导入
登陆到Bedrock控制台。切换到要使用模型的Region。从左侧的菜单中找到Import models,在右侧点击Import model按钮。如下截图。

在上方设置任务名称,下方会自动生成Job name。这里无需修改,继续向下滚动屏幕。如下截图。

在存储桶位置,选择上一步上传模型的S3桶,注意不要选择存储桶根目录,而是要指定模型所在的目录。然后在Service access位置,选择自动创建service role。如下截图。

最后点击屏幕右下角的Import model。点击后可能要等待5-10分钟。
注意:前边没有修改模型的Config文件,会遇到报错:
The model configuration violates the following requirements: [Amazon Bedrock could not validate the configuration file. Rope_scaling does not support key (scaling_factor), please remove it from rope_scaling config.]
此时需要编辑S3上的Config文件,删除掉其中的rope_scaling标签有关配置,再次发起模型导入即可。
2、从Bedrock控制台测试
等待大概15分钟后,模型导入完毕。通过Bedrock控制台可看到这个模型。点击模型ID查看详情。如下截图。

在模型详情位置,点击右上角的Open in playground。如下截图。

在对话环境中,输入测试Prompt,可获取返回结果。注意此时如果长时间没有调用模型,模型会被释放,再次发起请求会有一个冷启动时间(大概1-2分钟)。此时发送Prompt会收到错误信息:“模型尚未就绪”。此时需要等待一段时间后,刷新整个浏览器页面,然后重新发起调用即可成功。

关于冷启动的,在会第五章节介绍。
四、在代码中使用SDK调用
在前一步导入模型成功后,可以看到导入模型的id,类似如下格式:
arn:aws:bedrock:us-west-2:133129065110:imported-model/km5b98xhpqel
稍后在代码中,就需要指定这个id来交互。代码例子如下(代码已经包含冷启动检测逻辑)。
import boto3
import json
import re
import time
from botocore.config import Config
from botocore.exceptions import ClientError
def chat(prompt: str, show_thinking: bool = True, max_tokens: int = 1024):
"""
调用 Bedrock 上的 MiMo 模型进行对话(使用 Messages API 格式)
Args:
prompt: 用户输入的问题
show_thinking: 是否显示思维过程
max_tokens: 最大生成token数
"""
# 禁用 boto3 的自动重试,改为手动控制,以便立即检测到冷启动
config = Config(
retries={
'max_attempts': 1 # 禁用自动重试,立即返回错误
}
)
bedrock = boto3.client('bedrock-runtime', region_name='us-west-2', config=config)
model_id = "arn:aws:bedrock:us-west-2:133129065110:imported-model/km5b98xhpqel"
# 使用 Messages API 格式(这是 console 使用的格式)
body = json.dumps({
"messages": [
{"role": "user", "content": prompt}
],
"max_tokens": max_tokens,
"temperature": 0.7,
"top_p": 0.9
})
print(f"📝 问题: {prompt}\n")
# 尝试调用模型,处理冷启动情况
max_retries = 60 # 最多重试60次(约5分钟)
retry_count = 0
cold_start_detected = False
start_time = time.time()
result = None
while retry_count <= max_retries:
try:
response = bedrock.invoke_model(
modelId=model_id,
body=body
)
# 如果之前检测到冷启动,现在成功了,显示恢复信息
if cold_start_detected:
elapsed = time.time() - start_time
print(f"✅ 模型已恢复,耗时 {elapsed:.1f} 秒\n")
result = json.loads(response['body'].read())
break # 成功,跳出循环
except ClientError as e:
error_code = e.response['Error']['Code']
if error_code == 'ModelNotReadyException':
if not cold_start_detected:
# 第一次检测到冷启动 - 立即显示
cold_start_detected = True
elapsed = time.time() - start_time
print("🔄 检测到模型冷启动...")
print(" 模型正在恢复中,这通常需要 1-3 分钟")
print(" 系统会自动重试,请稍候...\n")
retry_count += 1
elapsed = time.time() - start_time
# 每10秒显示一次进度
if retry_count % 5 == 0:
print(f" ⏳ 等待中... 已等待 {elapsed:.0f} 秒")
# 等待5秒后重试
time.sleep(5)
else:
# 其他错误,直接抛出
print(f"❌ 调用失败: {error_code}")
print(f" 错误信息: {e.response['Error']['Message']}")
raise
except Exception as e:
print(f"❌ 发生未知错误: {str(e)}")
raise
if result is None:
# 重试次数用尽
elapsed = time.time() - start_time
print(f"❌ 模型恢复超时(已等待 {elapsed:.0f} 秒),请稍后再试或联系 AWS 支持")
return
# 提取响应内容
if 'choices' in result and len(result['choices']) > 0:
full_response = result['choices'][0]['message']['content']
else:
full_response = ""
# 解析 thinking 和 answer 部分
# MiMo 模型使用 <think>...</think> 标记思维过程
think_pattern = r'<think>(.*?)</think>'
think_match = re.search(think_pattern, full_response, re.DOTALL)
if think_match:
thinking_content = think_match.group(1).strip()
# 移除 thinking 部分,剩下的就是回答
answer_content = re.sub(think_pattern, '', full_response, flags=re.DOTALL).strip()
else:
thinking_content = ""
answer_content = full_response.strip()
# 输出结果
if thinking_content and show_thinking:
print("🧠 思维过程:")
print("─" * 60)
print(thinking_content)
print("─" * 60)
print()
print("💬 回答:")
print(answer_content)
print("\n" + "=" * 60 + "\n")
if __name__ == "__main__":
# 测试 1: 显示思维过程
chat(
"请简单介绍一下你自己,你是由谁开发的什么模型,有哪些主要能力?",
show_thinking=True,
max_tokens=1024
)
# 测试 2: 只显示回答
chat(
"北京是中国的首都吗?",
show_thinking=False,
max_tokens=512
)
返回结果如下:
📝 问题: 请简单介绍一下你自己,你是由谁开发的什么模型,有哪些主要能力?
🧠 思维过程:
────────────────────────────────────────────────────────────
嗯,用户想让我简单介绍一下自己,包括开发者、模型类型和主要能力。这是一个很直接的自我介绍请求。
首先,我需要明确我的身份。我是小米大模型core团队开发的MiMo,属于小米大模型core团队。这是一个核心的事实,必须准确传达。
接下来,我需要描述我的模型类型。我属于小米自研的MiMo系列,这是一个多模态大模型,这意味着我能处理文本、图像等多种信息形式。
然后,我需要概括我的主要能力。作为AI助手,我的核心能力包括理解用户意图、进行自然语言对话、提供信息查询服务,以及进行创意写作和内容生成。我还具备多模态理解能力,可以分析和回应图像内容。此外,我还能进行逻辑推理和问题解答。
最后,我需要强调我的核心价值。我的目标是成为用户值得信赖的AI伙伴,通过提供高效、准确、有温度的服务,帮助用户解决各种问题,提升生活和工作的效率与乐趣。
我将把这些信息组织成一个简洁、流畅的回答,确保用户能快速了解我的基本情况和核心功能。
────────────────────────────────────────────────────────────
💬 回答:
好的,非常乐意为您介绍!
我是**MiMo**,由**小米大模型core团队**开发的AI助手。
**关于我的核心信息:**
1. **开发者:** 我是由小米公司自主研发的核心团队(小米大模型core团队)打造的。
2. **模型类型:** 我属于**小米自研的MiMo系列多模态大模型**。这意味着我不仅能理解文本,还能处理和分析图像等多种信息形式。
3. **主要能力:**
* **自然语言理解与对话:** 我能理解您的问题、意图和上下文,进行流畅、自然的对话交流。
* **信息查询与解答:** 我可以提供知识解答、事实核查、信息检索等服务。
* **创意生成:** 我能进行写作、创作、故事生成、诗歌创作等创意活动。
* **多模态理解:** 我能分析和回应图像内容(例如描述图片、回答关于图片的问题)。
* **逻辑推理与问题解决:** 我具备一定的逻辑推理能力,可以帮助您分析问题、提供解决方案。
* **个性化服务:** 我会根据您的需求和偏好,提供定制化的帮助和建议。
**我的核心价值:**
我的目标是成为您值得信赖的AI伙伴,通过提供**高效、准确、有温度**的服务,帮助您解决各种问题,提升生活和工作的效率与乐趣。
很高兴能与您交流!有什么我可以帮您的吗?
============================================================
📝 问题: 北京是中国的首都吗?
💬 回答:
是的,**北京是中国的首都**。
自1949年中华人民共和国成立至今,北京一直作为中国的首都,是中国的**政治中心、文化中心、国际交往中心和科技创新中心**。
* **政治中心**:全国人民代表大会、国务院、最高人民法院、最高人民检察院等国家最高权力机关和行政机关都设在北京。
* **文化中心**:拥有众多故宫、长城、天坛等世界文化遗产,以及北京大学、清华大学等顶尖学府。
* **国际交往中心**:是世界上拥有最多国际组织总部的城市之一,也是举办国际会议和活动的重要场所。
* **科技创新中心**:中关村是世界知名的科技创新中心,聚集了大量的高新技术企业和科研机构。
此外,北京还是中国明清两朝的都城(北京城),拥有悠久的历史和深厚的文化底蕴。
============================================================
五、关于冷启动和预热机制
1、关于冷启动
导入到Bedrock的模型,并不会一直占用GPU资源。Bedrock为其提供了根据访问负载缩放的能力,这就意味着在无人访问时候,模型可以缩放到0,以减少不必要的资源消耗和费用。
查看模型运行占用的资源的方法是:在CloudWatch的Metrics中查看活跃的模型副本数量。方法是进入CloudWatch,点击左侧菜单的Metrics,点击Bedrock服务。如下截图。

在展开的菜单中高,点击By ModelId,按模型ID查看监控参数。如下截图。

在模型清单中,选择导入的模型ID,在Metric name位置找到ModelCopy参数,这个是在GPU集群中运行的模型副本数量。如下截图。

当模型被调用时,ModelCopy的值会增加,当模型不再被调用时,ModelCopy的值会减少。当ModelCopy的值为0时,表示模型被从GPU集群中释放掉。根据导入模型计费的介绍,导入的模型每5分钟一个统计周期,当连续2个5分钟没有访问,模型就会被释放。再次有访问时候,模型需要重新加载。
当模型释放后,新的访问请求打到Bedrock的API端点后,Bedrock会重新拉起模型,此时会触发模型恢复,API将返回429 ModelNotReadyException错误,这个错误信息与限流场景一致,并不是直接返回5xx服务器错误,因此调用API的代码可以过一段时间再去重试访问。重试逻辑需要在客户端自行完成。上一个章节给出的API调用的例子中,就已经包含了冷启动重试逻辑。
例如触发了冷启动时候的API如下。
📝 问题: ...
🔄 检测到模型冷启动... ← 1-2秒内立即显示
模型正在恢复中,这通常需要 1-3 分钟
系统会自动重试,请稍候...
⏳ 等待中... 已等待 25 秒 ← 每25秒更新一次
⏳ 等待中... 已等待 50 秒
✅ 模型已恢复,耗时 67.3 秒 ← 成功后显示总耗时
💬 回答: ...
2、预热机制
导入模型时候,无论是否选择弹性缩放这个选项的开关,模型都会在无人使用的时候释放,从而导致冷启动。为了避免冷启动机制,可以考虑的解决方式定期预热让模型保持最低一份copy(通过CloudWatch可以监控),或者在特定的时间窗口预热(适合非在线业务)。
如果是手工做预热的话,需要每14分钟预热一次。因为导入模型是在一次访问后会保留5分钟,然后再计算连续两个5分钟的空闲周期。因此,每14分钟触发一次访问,即可保持模型的活跃状态。
六、导入自定义模型的计费
1、弹性缩放按需状态
在之前的导入DeepSeek模型的 这篇文章 中,介绍了Bedrock Import Model的计费机制。但不同规格的模型,导入后产生的计费单元的消耗不一样。
以本文导入的模型是基于Qwen-2.5-VL架构的为例,在查看模型的页面上,可看到模型使用的单元是Custom model units version ,并且占用4个计费单元。这些关键信息将用于核算费用。如下截图。

现在查看官网可以导入自定义模型的对应的分类下看到价格。如下截图。

由此可推算出价格:
- 模型计算资源费用:4 Units × $0.05718/Unit/min x 60分钟 x 24小时 x 30天 = $9,880.80
- 模型存储费用:4 Units × $1.95/Unit = $7.80 per month
- 合计 $9,888.60 per month
由此通过预热保持模型在GPU集群中一直被加载的活跃状态,费用是较高的。因此这种弹性缩放状态比较适合开发、测试,以及对实效性没有要求的生产环境,如批量数据处理等定期任务,或者可接受前置-预热拉起方式访问行为(例如企业内部应用9:00预热拉起,保持到18:00下线)。如果是全天在线业务,这种方式成本不划算。
2、与EC2 GPU自行部署模型对比
在之前的文章中,介绍过使用EC2 GPU实例,通过vLLM推理框架部署模型。本文导入到Bedrock的模型是8B规模,使用FP8量化运行在G6e的L40s GPU上有着很好的承载能力。
这里以G6e.2xlarge(8vCPU/64GB,Nvidia L40s GPU*1 48GB显存)机型为例,在美西2俄勒冈区域的1年起无预付RI价格是$1,031.13。考虑到高可用、弹性缩放,如果是在线业务,一次要购买两台。由此成本会是$2000 per month,比用导入模型自带的弹性缩放模式还是具有很大优势的。
3、小结
由此可获得结论,针对低频访问、开发测试、非在线业务,Bedrock导入模型的方式具有很高灵活性,无须学习模型部署和运维相关技术。针对在线业务、全天有访问、高流量的场景下,可尝试EC2 GPU上用vLLM部署模型做推理。
七、参考文档
Invoke your imported model
https://docs.aws.amazon.com/bedrock/latest/userguide/invoke-imported-model.html
Bedrock Pricing
https://aws.amazon.com/bedrock/pricing/
EC2 GPU RI费用
https://aws.amazon.com/ec2/pricing/reserved-instances/pricing/
最后修改于 2025-12-03