2943 字
约 9 分钟
16
S27-X08 · Bedrock 与 Vertex:云厂商模型服务的接入差异

同一句"调模型",在官方 API 上是三行 HTTP,在云平台上是一套鉴权链、一个区域概念、一份配额单。Bedrock(AWS)和 Vertex AI(GCP)都不是模型本身,而是模型的托管入口:把多家模型放进同一个账单、同一个 IAM、同一个 VPC。

这篇不比较模型能力,只比较"接进来要付出什么",以及什么时候该加一层抽象、什么时候不该。


1. 云厂商模型服务在解决什么

诉求 云平台的做法 直连官方 API 的做法
合规与数据边界 走 VPC 私有端点、区域固定、审计日志 依赖厂商区域策略,审计在对方侧
网络 与业务同区域,低延迟、可走内网 公网出口,受限于出口带宽与稳定性
计费 与云账单合并,统一预算与成本分摊 单独账户、单独发票
多模型池 一个 SDK 入口切多家模型 每家一套 SDK 与鉴权
权限 复用 IAM / 服务账号,按角色授权 各自发 key,散落在各环境变量
配额 按区域按模型统一申请 按账号申请,口径不同

对照结论:云平台卖的是"治理",不是"模型"。 如果团队已经在用这套云(IAM、VPC、账单都在里面),接入的边际成本很低;如果只是想在个人项目里调一次模型,多出来的鉴权链纯属负担。

2. 鉴权:两套完全不同的思路

维度 AWS Bedrock GCP Vertex AI
身份 IAM 用户 / 角色 服务账号 / 用户账号
凭证形态 Access Key + Secret,或临时凭证(STS) 服务账号 JSON key,或 ADC
请求签名 SigV4(由 SDK 完成) OAuth2 Bearer token(由 SDK 完成)
权限粒度 IAM policy,可精确到模型 ARN IAM role,按资源与 API
有效期 临时凭证有有效期,需刷新 token 短期有效,ADC 自动刷新
本地开发 aws configure / SSO 登录 gcloud auth application-default login
# AWS:SDK 自动做 SigV4,凭证来自环境链(环境变量 → profile → 实例角色)
import boto3, json

client = boto3.client("bedrock-runtime", region_name="us-east-1")
resp = client.invoke_model(
    modelId="MODEL_ID",                       # 具体模型标识,按当前版本核对可用列表
    body=json.dumps({"prompt": "你好", "max_gen_len": 256}),
    accept="application/json",
)
print(json.loads(resp["body"].read()))
# GCP:走应用默认凭证,避免把 key 文件塞进仓库
gcloud auth application-default login
export GOOGLE_CLOUD_PROJECT="PROJECT_ID"
export GOOGLE_CLOUD_REGION="us-central1"

临时凭证最典型的坑:在容器里挂了一个带有效期的 STS 凭证,进程跑得比凭证久,几小时后开始报鉴权失败,而重启后又正常。判断方法是看错误码是不是"过期/无效凭证"类,而不是权限不足类。

3. 区域与模型可用性

同一家模型,在不同区域的可选性并不一致,而且模型标识本身带区域语义。这带来两个工程约束:

约束 表现 处理
模型不在该区域 调用直接报"模型不存在/不可用" 启动时做一次可用性探测,别等线上
跨区域延迟 请求绕路,P95 明显变差 业务与模型同区域部署
数据驻留要求 某些行业要求数据不出境 固定区域,禁用跨区回退
新模型上线节奏 各区域不同步 把模型标识做成配置项,不硬编码

工程上的做法是把"区域 + 模型标识"当成一对配置,而不是两个独立配置:

# application.yml(示意,值按当前版本核对)
llm:
  provider: bedrock
  region: ${LLM_REGION:us-east-1}
  model-id: ${LLM_MODEL_ID:MODEL_ID}
  fallback:
    enabled: false        # 跨区回退会违反数据驻留要求时关掉

4. 调用形态:同步、流式、批处理

形态 适用 注意点
同步(invoke) 短请求、结果要立刻用 超时要设,别用 SDK 默认值
流式(stream) 对话、首字延迟敏感 断流要能续,前端要能处理半截响应
批处理(batch job) 离线大规模推理 输入输出走对象存储,格式有约定
异步长任务 视频/大文档 轮询或回调,别同步等

流式的实现差异会被 SDK 抹平一半,但事件结构不一样:Bedrock 返回的是带类型标签的事件流,Vertex 侧是增量文本块。做统一封装时,要在这一层做归一化,否则上层得为每家写一份解析。

5. 统一抽象层:什么时候值得加

方案 抽象层级 适合
Spring AI ChatClient + 模型实现 Java/Spring 技术栈,想换模型只改配置
LangChain4j ChatLanguageModel + AiServices 需要工具调用、RAG 组件的 Java 项目
自建薄封装 一个接口 + 两个实现 只用到一两个模型,不想引入大依赖
直接用厂商 SDK 无 只用一家,且要用厂商特有能力
// LangChain4j 的形态:业务代码只依赖接口
ChatLanguageModel model = BedrockChatModel.builder()
        .region(REGION)
        .modelId(MODEL_ID)
        .build();

String answer = model.generate("用三句话解释什么是重排");

// 换到 Vertex 只需替换实现类,业务代码不动
// ChatLanguageModel model = VertexGeminiChatModel.builder()...build();

抽象层的代价也要认清:它只能抹平"共同子集"。厂商特有的能力(比如某种结构化输出约束、某个专用工具协议)穿过抽象层时会被削平,这时候要么在抽象层开逃生口,要么就承认这层不值得。

6. 配额与限流

维度 常见现象 处理
按区域 同模型在 A 区够用、B 区一调就 429 配额按区域申请,配置里标明
按模型 换了模型标识,配额是另一套 上线前核对目标模型的配额
RPM / TPM 双限 请求数没超,token 先超 限流器要同时算请求与 token
突发流量 自动扩缩容把配额打满 客户端限流 + 队列,别指望云侧兜底
共享账号 多个服务抢同一配额 按服务分账号或分区域

限流不要在业务代码里散着写,统一放到模型客户端外层:一个令牌桶按 token 估重、一个按请求数,两个都过才放行。

7. 计费口径

计费方式 形态 适合 陷阱
按 token 输入/输出分别计价 调用量波动大 长上下文与重试放大成本
按实例/时长 独占推理端点,按小时 稳定高并发 低峰期空转也在计费
按批处理任务 离线作业按量 大规模离线 结果延迟,不适合在线
按预置吞吐 预留容量 有明确峰值 预留不足仍会限流

成本归因的关键是在每个请求上打业务标签(租户、功能、版本),否则月底只能看到一个总数。云平台的标签体系能用就用,用不上就在应用侧记账。

8. 换厂商要改什么

改动点 具体内容 容易漏的地方
模型标识 名称体系完全不同 配置里散落多份,改漏一处就回退到默认
参数映射 max_tokens / top_p / 停止符命名不同 语义相近但边界不同(默认值、上限)
消息结构 system 是独立字段还是消息角色 迁移后系统提示失效
工具调用 schema 格式与回填方式不同 参数嵌套层数不一致
流式事件 事件类型与结束标记不同 结束判断依赖了某家的特定字段
嵌入维度 向量维度与归一化方式不同 向量库直接不兼容
错误码 限流/超限/内容策略的码不同 重试策略把不可重试的错也重试了
# 参数映射要显式做一层,别在调用点各写各的
def to_provider_params(p: dict, provider: str) -> dict:
    if provider == "bedrock":
        return {"max_gen_len": p["max_tokens"], "temperature": p["temperature"],
                "top_p": p["top_p"]}
    if provider == "vertex":
        return {"max_output_tokens": p["max_tokens"],
                "temperature": p["temperature"], "top_p": p["top_p"]}
    raise ValueError(provider)

嵌入维度这一条是最容易被低估的:换嵌入模型等于换向量空间,旧向量全部失效,必须整库重建并重新索引。切模型前先确认这件事的代价。


9. 排错:七种接入后的典型报错

现象 原因 处理
报"模型不存在" 模型在该区域不可用,或标识写错 按当前版本核对区域与标识
报鉴权失败且重启后恢复 临时凭证过期,进程长于凭证 用 SDK 的凭证链自动刷新,别硬编码
429 但请求数远低于预期 token 维度先超限 限流器加 token 估算
流式响应中途断了 超时/网关缓冲/心跳缺失 检查中间层是否缓冲,补心跳与重试
从官方 API 迁过来参数报错 参数名与语义不同 走显式参数映射层
检索结果突然全变差 嵌入模型换了,向量空间不兼容 整库重建,别混用新旧向量
账单暴涨但 QPS 没变 重试放大或上下文变长 按请求打标签,看是哪类请求变贵

10. 边界:什么情况别上云平台

场景 更合适 理由
个人验证一个想法 官方 API 鉴权链的成本大于收益
只用一家模型、不用其云资源 官方 SDK 抽象层与云治理都白付
数据不能出内网 私有化部署的开源模型 托管服务无法满足边界要求
极低延迟要求(毫秒级) 本地小模型 网络往返本身就是成本
需要模型厂商的最新特性 官方 API 云平台上新通常滞后

一句话定位:Bedrock 和 Vertex 是"把模型纳入云治理"的入口,不是"更好的模型"。选它是因为你已经在治理体系里,不是因为它的模型更强。


11. 自测

  1. 云厂商模型服务真正卖的是什么,和直连官方 API 的取舍在哪?
  2. AWS 与 GCP 的鉴权在"凭证有效期"上的差异会引发什么线上问题?
  3. 为什么"区域"和"模型标识"应该当成一对配置?
  4. 统一抽象层能抹平什么,抹不平什么?
  5. 换嵌入模型时,向量库为什么必须整库重建?
  6. 什么情况下不该引入云平台模型服务?
S27-X08 · Bedrock 与 Vertex:云厂商模型服务的接入差异
https://www.clxhxhhr.top/posts/5786/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。