后端与接口
创建生产级 SageMaker 端点时默认启用自动扩缩…
在创建 SageMaker 实时/异步端点或编写调用 create_endpoint 的部署代码时,用一套默认配置把演示端点变成可长期运行的生产端点。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
创建生产级 SageMaker 端点时默特定
解决思路
- 每个端点都作为一个整体创建以下资源:SageMaker Model(镜像 + 环境变量 + 执行角色 + S3 产物)、Endpoint config(实例类型、初始数量、可选数据捕获)、Endpoint、Autoscaling target + policy(按每实例调用数做目标跟踪)、CloudWatch alarms(延迟、错误、平台开销)。
- 使用 inference component 部署(deploy_ic.py)时结构有两处不同:执行角色放在 endpoint config 上并带 ManagedInstanceScaling,模型放在 inference component 上;其自动扩缩目标是组件而非 variant。
- 数据捕获默认关闭,仅在需要时用 --enable-data-capture 开启,因为会持续产生 S3 费用。
- 所有资源打上统一标签,包含 CreatedBy=agentic-deploy-skills 以便后续清理。
- 部署 vLLM 文本生成 LLM 前,先把固定版本的模型快照打包成 SageMaker model.tar.gz 并上传到自有 S3 桶,SageMaker 会解压到 /opt/ml/model,运行时不再拉取或执行仓库代码。
- 运行 deploy.py 时传入 --model-name、--image-uri、--inference-ami-version、--role-arn、--model-s3-uri、--instance-type、--region 以及模型相关的 --env(如 SM_VLLM_MODEL=/opt/ml/model、SM_VLLM_HOST=0.0.0.0、SM_VLLM_TRUST_REMOTE_CODE=false、SM_VLLM_MAX_MODEL_LEN=4096)。
- 部署嵌入模型(TEI,通常跑在 CPU)时不要传 --inference-ami-version(该参数仅 vLLM 需要),环境变量也更简单,用 HF_MODEL_ID 即可,无需 host 或 trust-remote-code。
- 各参数来源:--image-uri 与 --inference-ami-version 来自镜像选择步骤(读 AWS DLC 目录页),--role-arn 来自 IAM 预检(check_role.py),--region 来自 AWS 上下文发现,--instance-type 来自用户输入或规划器建议。
- 脚本按顺序创建资源并处理错误,等待 InService(最多 30 分钟),暴露失败原因,注册自动扩缩与告警,并打印包含 teardown 命令的摘要;stdout 输出 JSON 供下游脚本使用。
- 若安装副本缺少 scripts/ 目录(某些 harness 只复制 SKILL.md),从源仓库获取脚本,不要根据描述重新实现。
- 模型加载默认做法:预先把固定权重放到 S3 并通过 --model-s3-uri 传入,容器从 /opt/ml/model 加载,不依赖运行时 Hub;从 Hub 加载是显式例外,需预期端点启动后 5–15+ 分钟下载、为受限模型提供 token,并保持 SM_VLLM_TRUST_REMOTE_CODE=false,除非特定架构需要经过审查的自定义代码。
- InService 不等于成功:MMS 类容器(HF Inference Toolkit)的 Java 前端即使 Python worker 崩溃循环也会响应 ping,因此必须做两项检查。
- 检查一:做一次真实调用。实时端点用 invoke_endpoint.py 发最小 payload,要求 HTTP 200 且响应体合理;异步端点先上传一个输入到 S3,调用 invoke-endpoint-async,再轮询输出 URI 几分钟,出现结果对象即成功,失败 URI 有对象或什么都没有即失败。
- 检查二:扫描端点日志中的 worker 崩溃标记,命令为 aws logs filter-log-events --log-group-name /aws/sagemaker/Endpoints/<endpoint-name> --filter-pattern '?"Worker died" ?"Load model failed" ?"ImportError"' --region <region> --max-items 5;inference component 部署的日志在 /aws/sagemaker/InferenceComponents/<component-name>,deploy_ic.py 会在等待时自动扫描该组。
- 诊断权限被拒时的通用规则:当只读诊断调用被拒(如受限角色没有 logs:FilterLogEvents、servicequotas:ListServiceQuotas),用一行说明并继续做能做的检查;绝不因仅用于诊断的权限阻塞部署,也绝不把被拒调用当作没有问题的证据。
- 只有两项检查都通过后才报告部署完成;若日志扫描命中,展示 CloudWatch 中的真实 traceback,而不是 InService 状态。
- 实时端点 InService 后用自带的 invoke_endpoint.py 测试(跨平台且 BOM 安全),支持 --payload '<json>' 内联或 --payload-file <path>,会校验 JSON、以纯 UTF-8 写请求体、调用端点并把响应体打印到 stdout。
- Windows 上不要用 Set-Content -Encoding UTF8 写 payload,某些 PowerShell 版本会加 UTF-8 BOM,SageMaker JSON 解析器会以 400 ModelError 拒绝(Unexpected UTF-8 BOM);这不是模型、端点健康或镜像问题,只是请求体文件编码问题。
- 若必须直接调用 CLI,用 [System.IO.File]::WriteAllText((Resolve-Path "payload.json"), $json, [System.Text.UTF8Encoding]::new($false)) 写无 BOM 的 UTF-8,再执行 aws sagemaker-runtime invoke-endpoint --endpoint-name <endpoint-name> --content-type application/json --body fileb://payload.json --region $REGION response.json。
- 若任何调用报 Unexpected UTF-8 BOM,先把 payload 重写为无 BOM UTF-8(或改用 invoke_endpoint.py)重试一次,再判断端点或模型是否损坏。
- 调用生成式重排器(Qwen3-Reranker 等,由镜像选择路由到 HuggingFace vLLM DLC)时,使用 completions API 加原始 prompt,不要用 messages/chat API,因为 chat 模板不能可靠遵守 chat_template_kwargs(如 {"enable_thinking": false}),模板错误会静默返回几乎相同的分数而不报错。
- 重排器 payload 使用 Qwen3-Reranker 期望格式,包含 prompt、max_tokens: 1、temperature: 0、logprobs: 20,且结尾的 <|im_start|>assistant\n thinking\n\n</think>\n\n 后缀是必需的,用于预填空 thinking 块使首个生成 token 就是 yes/no 判断。
- 从返回的 logprobs 计算分数 P("yes") / (P("yes") + P("no")),并用一对相关文档(期望 >0.9)和一对不相关文档(期望 <0.05)做健全性检查;若各对分数几乎相同,说明 prompt 模板错误而非模型损坏。
- 该规则可推广:任何 thinking 模式且 prompt 必须逐字节精确的模型,优先用原始 completions API 而非 chat。
- 从 AWS Deep Learning Containers 目录页读取镜像 URI,选择与模型家族匹配的行(LLM 用 HuggingFace vLLM,嵌入用 TEI 等),把 <region> 替换为部署区域后传给 deploy.py --image-uri。
- 对 vLLM 镜像(huggingface-vllm 及 AWS vllm 回退)还要检查 tag 的 CUDA 版本:cu130 及以上必须传 --inference-ami-version al2-ami-sagemaker-inference-gpu-3-1;cu129 及以下则省略该参数。
- 实时端点只有托管 inference component 时才能缩到零实例;deploy.py 注册的 variant 级目标不能低于 1 个实例,因此用 deploy_ic.py 构建基于组件的形态。
- 在流量稀疏或按计划运行、且客户端能容忍首次请求数分钟延迟时使用缩零;不要用于有 SLA 的交互式流量,因为唤醒需要数分钟且唤醒期间每个请求都会失败。
- 缩零需要四件套且缺一不可:ManagedInstanceScaling 设 MinInstanceCount: 0、以 SageMakerInferenceComponentConcurrentRequestsPerCopyHighResolution(5 并发/副本)为目标跟踪指标、由 NoCapacityInvocationFailures 告警触发的 step policy;目标跟踪无法从零出发(不能除以零副本),缺少 step policy 或其告警会导致缩到零后永远不再响应。
- 组件部署中 InferenceAmiVersion 仍放在 variant 上,并与 ManagedInstanceScaling 共存(已在 cu130 + ml.g5.xlarge 验证)。
- 生产环境预置权重并传 --model-s3-uri:除避免运行时 Hub 访问外,还能缩短每次唤醒,因为模型产物在每次唤醒时都会重新加载,其获取位于空闲后首个请求的关键路径上。
- 组件大小:ComputeResourceRequirements 是调度预留而非上限,请求 1024 MB 的组件可让 vLLM 使用数 GB 主机内存;可调度池远小于实例内存,ml.g5.xlarge(16 GiB)接受 1024 MB 而拒绝 4096 MB,过度申请会立即报 There is not enough hardware resources on the instances for this endpoint to create a copy of the inference component,应视为请求过大而非需要加实例,从默认 1024 MB 起步,仅在多个组件共享一个实例时提高。
- --accelerator-devices 必须与 SM_VLLM_TENSOR_PARALLEL_SIZE 匹配以支持多 GPU 模型。
- 调用缩零组件时传 --inference-component-name,并用 --wait-for-capacity 900 容忍唤醒;400 has no capacity 是唤醒信号而非故障,它会发布触发 step policy 的指标,带 --wait-for-capacity 时 helper 每 30 秒重试直到有副本服务请求,不带则冷端点总是看起来像坏了。
- 拆除顺序至关重要:先删告警(<endpoint>-* 和 <component>-*),再删扩缩策略与 scalable target(按组件资源 id),然后删 inference components,最后删 endpoint、endpoint config、model。
- 必须注意两点:delete-endpoint 不会删除组件,组件会存活并继续报告 InService,还会阻塞同名新组件,所以必须先删组件;组件在瞬态(容器启动时的 CREATE_IN_PROGRESS、扩缩改变副本数时的 UPDATE_RC_IN_PROGRESS)会被拒绝删除,脚本每 15 秒重试共 15 分钟,扩缩事件后立即拆除耗时数分钟是正常的。
- TargetTracking-inference-component/<ic>-AlarmHigh|Low 告警属于 Application Auto Scaling,删除策略会一并移除,脚本无需处理。
- 对长时间推理(>60s)、大 payload 或突发/稀疏且受益于缩零的工作负载,用 deploy_async.py 而非 deploy.py;异步支持 variant 本身 MinCapacity=0,且当单次推理超过 InvokeEndpoint 的 60s 响应限制时异步仍是正确选择。
- 异步部署必须额外传 --output-s3-uri 指定结果落地的位置(结果不同步返回)。
- 异步可选参数:--failure-s3-uri 指定失败调用的单独路径,--success-sns-topic 与 --error-sns-topic 在结果就绪或失败时通知,--min-capacity 0(默认)在批次间缩到零,--backlog-per-instance-target N 设每实例目标队列深度(默认 5),--max-concurrent-invocations-per-instance N(默认 4)。
- 异步缩零在 variant 上注册两个扩缩策略:基于 ApproximateBacklogSizePerInstance 的目标跟踪负责 min 与 max 之间的持续扩缩,由 HasBacklogWithoutCapacity 告警触发的 step scaling 负责 0→1 唤醒;两者都必需,只有目标跟踪无法从零转换,端点会在首批后缩到零且永不再唤醒。
- 异步创建三个 CloudWatch 告警:ApproximateBacklogSize > 50(队列增长快于容量消化)、InvocationsFailed > 5(反复处理失败)、HasBacklogWithoutCapacity(驱动唤醒策略,其动作是 step policy 而非 SNS 通知);传 --sns-alarm-topic <arn> 时前两个在该主题通知,唤醒告警始终指向 step policy。
- 调用异步端点:先把输入上传到 S3(aws s3 cp input.json s3://amzn-s3-demo-input/job1/input.json),再调用 aws sagemaker-runtime invoke-endpoint-async --endpoint-name <endpoint-name> --input-location s3://amzn-s3-demo-input/job1/input.json --content-type application/json --region <region>,然后轮询输出 URI(aws s3 cp s3://amzn-s3-demo-async-output/async-output/<inference-id>.out result.json)。
- 上传的 input.json 同样有 UTF-8 BOM 问题:在 Windows 上构建时写成无 BOM UTF-8,否则容器的 JSON 解析器会拒绝。
- 按模型类型调整自动扩缩目标:默认 --target-invocations-per-instance 20 面向每次请求 1–5 秒的 LLM;嵌入(TEI)请求快得多(CPU 通常 <100ms,GPU <20ms),应把目标提高到 100–500,否则默认 20 会过度扩缩浪费钱;经验公式为目标值 ≈ 60 / 典型请求延迟(秒),LLM 3s → 20,嵌入 100ms → 600,生成式重排器每次只生成一个 token,40–100 较合理。
- 数据捕获与 IAM 陷阱:启用数据捕获时执行角色需要对捕获前缀有 S3 写权限,默认 URI(s3://sagemaker-<region>-<account>/<endpoint>/data-capture/)通常与模型产物桶不同;若 IAM 预检把内联策略窄化到只有模型桶,捕获写入会静默失败(端点继续服务但无数据)。用户报告数据捕获不出现时,检查角色的 S3 访问,放宽内联策略或传 --data-capture-s3-uri 指向角色可写的桶。
- 拆除命令:python3 scripts/teardown.py <endpoint-name> <region>(macOS/Linux)或 python scripts\teardown.py <endpoint-name> <region>(Windows),按安全顺序删除告警 → 自动扩缩 → endpoint(停止计费)→ endpoint config → model,且幂等。
- 拆除不会删除:IAM 执行角色(可能共享)、数据捕获 S3 对象(用户可能想保留)、SNS 主题、原始模型产物。
- 部署摘要后务必告知用户 teardown 命令,用户容易忘记而端点会持续产生费用。
- 失败排查:CannotStartContainerError 且从未产生 CloudWatch 日志,是 InferenceAmiVersion 问题——镜像 tag 含 cu130 及以上且未传 --inference-ami-version al2-ami-sagemaker-inference-gpu-3-1 时即为此因,不要追查镜像、IAM 角色、环境变量或实例类型。
- 失败排查:Failed to pass ping health check 表示容器已启动并产生日志但 /ping 无响应,检查 /aws/sagemaker/Endpoints/<endpoint-name>,通常是镜像与模型架构不匹配、缺 HF token 或 OOM。
- 失败排查:Container failed to start(有日志)表示 entrypoint 运行后退出,常见原因是缺必需环境变量(SM_VLLM_MODEL、SM_VLLM_HOST、SM_VLLM_TRUST_REMOTE_CODE)、ModelDataUrl 格式错误或模型产物不可读。
- 失败排查:ResourceLimitExceeded 表示该区域该实例类型无配额,申请提升或换类型(规划器应事先检查配额)。
- 失败排查:CloudWatch 日志出现 ImportError: libtorch_cuda.so: undefined symbol: ncclCommResume 是 huggingface-pytorch-inference GPU 镜像的已知打包缺陷,在容器内部,任何环境变量、AMI、实例类型或同族 tag 都修不好,改用 DJL Inference。
- 失败排查:InService 但调用超时或异步输出不出现,是 MMS 前端存活而 Python worker 已死,运行前述日志扫描,CloudWatch 中的 traceback 才是真实错误。
- 失败排查:启动时从 HF Hub 下载权重报 403 Forbidden,是容器内置 huggingface_hub 早于 HF XET CDN 认证,加 --env HF_HUB_ENABLE_HF_TRANSFER=0 或预置权重到 S3;注意这可能掩盖更深层失败(下载成功后 worker 仍可能崩溃),修复后要重新检查日志。
- 诊断规则:当多种配置(不同镜像、角色、实例类型)下失败表现相同且从未产生日志时,原因几乎总在容器之下——主机 AMI、网络、账户级问题——而非部署配置;停止迭代配置,检查 AMI 版本与账户状态。
- 失败排查:组件卡在 Creating 且无 FailureReason,是容器崩溃循环被 supervisord 重启导致状态不变,组件会保持 Creating 直到 ContainerStartupHealthCheckTimeoutInSeconds 到期(最长一小时);读 /aws/sagemaker/InferenceComponents/<component-name> 找 exited: app、not expected 或 api_server.py: error:,deploy_ic.py 每次轮询都会扫描并在约一分钟内中止。
- 失败排查:There is not enough hardware resources on the instances for this endpoint 表示组件 ComputeResourceRequirements 超过可调度池(远小于实例内存),降低 --min-memory-mb(ml.g5.xlarge 上 1024 可行,4096 被拒),不要加实例,因为该消息在实例健康时也会出现。
- 失败排查:Cannot delete inference component ... while it is in state CREATE_IN_PROGRESS / UPDATE_RC_IN_PROGRESS 是正常现象而非错误,重试即可,teardown.py 会重试 15 分钟;UPDATE_RC_IN_PROGRESS 表示扩缩动作正在改变副本数。
- 失败排查:组件比端点存活更久——delete-endpoint 会留下仍报告 InService 的组件并阻塞名称复用,先删组件,这正是 teardown.py 的做法。
- 不要盲目重试:脚本会打印 describe-endpoint 中的具体 FailureReason,先修根因再重试。
适用边界 · 注意事项
- 不要用于有 SLA 的交互式流量且需要缩零的场景:唤醒需要数分钟,唤醒期间每个请求都会失败。
- 不要在没有 IAM 执行角色、镜像 URI 与 AMI 版本等前置条件就绪时使用(这些由规划器、IAM 预检和镜像选择步骤提供)。
- 不要为 TEI 嵌入部署传 --inference-ami-version,该参数仅 vLLM 需要。