AWS Machine Learning

在 Amazon SageMaker AI 上使用 llama.cpp 部署决策模型

AWS介绍在SageMaker AI上用llama.cpp DLC部署决策模型,并通过SemIf扩展对声明选项直接返回概率。在231个JevBench任务上Qwen3.5-4B准确率77.5%至77.9%,但测量含网络延迟,并非服务保证。

An application invokes an Amazon SageMaker AI real-time endpoint that can use the AWS Deep Learning Container for llama.cpp for generated text or a SemIf child image for option probabilities. Either serving mode can run on CPU or GPU.
配图来源 · AWS Machine Learning

路由请求、选择智能体动作或分配策略结果的应用程序,通常需要在一组固定选项上给出评分,而不是生成自由格式的文本。部署这些决策模型时 llama.cpp 于 Amazon SageMaker AI 为您提供了在 CPU 或 GPU 基础设施上部署量化模型的托管路径。

本文继续介绍用于生成式 AI 推理的专用 AWS Deep Learning Containers (DLC) 系列。之前的文章涵盖了 WhisperX, vLLM-Omni – 第1部分,以及 vLLM-Omni – 第2部分.

在这篇文章中,你首先使用 用于 llama.cpp 的 AWS DLC 通过 SageMaker AI 提供 OpenAI 兼容的聊天补全服务 InvokeEndpoint。然后,您使用以下内容扩展同一运行时: SemIf,前身为 OpenJev,它在不解码答案 token 的情况下返回针对已声明选项的概率分布。随附的 代码示例 包括 CPU 和 GPU 部署选项。

解决方案概述

图1展示了来自同一个打包模型的两种部署路径。文本生成路径使用适用于llama.cpp的AWS DLC,并通过OpenAI兼容API返回生成的响应。结构化决策路径构建一个子镜像,将默认服务器替换为SemIf适配器,并返回已声明选项的概率。

An application invokes an Amazon SageMaker AI real-time endpoint that can use the AWS Deep Learning Container for llama.cpp for generated text or a SemIf child image for option probabilities. Either serving mode can run on CPU or GPU.

图1:根据工作负载的 API 和延迟要求,在 CPU 或 GPU 上运行用于 llama.cpp 的 AWS DLC 或 SemIf 子镜像

对于标准路径,将模型打包为 model.tar.gz 中 Amazon Simple Storage Service (Amazon S3) 并直接引用已发布的 DLC 镜像。容器会找到第一个 .gguf 归档于 /opt/ml/model, 地图 POST /invocations 至 llama-server 在 /v1/chat/completions, 并将 SM_LLAMA_CPP_* 环境变量传递给 llama.cpp 参数。

该 llama-server HTTP API 未公开 SemIf 所使用的最终位置 logits 和状态操作。因此结构化决策路径使用 AWS CodeBuild 构建子镜像并将其存储在 Amazon Elastic Container Registry (Amazon ECR)中。子镜像保留 DLC 已编译的 CPU 或 CUDA 库,同时将其入口点替换为与 SageMaker 兼容的适配器。

理解输入和输出模式

用于 llama.cpp 的 AWS DLC 接受 OpenAI Chat Completions 模式。发送一个 messages 数组,其中包含 role 和 content,以及诸如 max_tokens 和 stream:

{
  "messages": [
    {
      "role": "user",
      "content": "A customer cannot receive a password reset email. Reply with the best support queue."
    }
  ],
  "max_tokens": 64,
  "stream": false
}

等生成控制参数。响应使用兼容 OpenAI 的 choices 数组。从 choices[0].message.content.

中读取生成的文本。SemIf 使用受约束的决策模式而非聊天消息。请求包含调用方定义的 ID、非结构化状态、一个问题以及允许选项的有序列表:

{
  "decision": {
    "id": "support-route",
    "state": "The customer cannot receive a password reset email.",
    "question": "Which queue should handle this request?",
    "options": [
      {"id": "account_access", "description": "Account access support."},
      {"id": "billing", "description": "Billing support."}
    ]
  }
}

响应按相同顺序返回 option_ids, probabilities和原始 option_logits ,以及提示词、计时和固定的模型元数据。借助稳定的选项 ID,您的应用程序可以应用阈值、回退和策略检查,而无需解析生成的文本。

SemIf 属于更广泛的一类决策模型,这类模型从非结构化状态中对应用程序定义的结果进行评分。其他实现包括 Jev、TypeSafe 的决策模型及其 /v1/systemone API; Kev,一个为 TypeSafe API 兼容性设计的模型服务器;以及 Strands Decider 2B,一个专为智能体工作流构建、具有校准输出的模型。

选择合适的决策工作流

当您的应用程序在请求时定义允许的选项,并需要模型来解释非结构化上下文时,请使用此模式。示例包括将案例路由到队列、从已知集合中提取一个值、分配事件优先级、检查策略结果或选择智能体操作。请将授权和确定性的业务规则保留在模型之外,并在将模型概率视为运营置信度之前对其进行验证。

当您需要通过 OpenAI 兼容的聊天补全时,请使用标准的 SageMaker AI 文本生成路径 InvokeEndpoint获得 OpenAI 兼容的聊天补全时,请使用标准的 SageMaker AI 文本生成路径。SageMaker AI 镜像将 POST /invocations 映射到 llama-server /v1/chat/completions 端点。仅当您的应用程序需要此接口不提供的行为(例如 SemIf 的直接 logits 和状态访问)时,才构建子镜像。

移除答案 token 的生成并不会移除模型推理。在 SemIf 读取最终 logits 之前,模型仍会处理完整的状态、问题和选项描述。请保持提示词聚焦,并在生产使用之前使用您应用程序中带标签的决策来评估所选模型。

针对您的延迟和质量目标进行调优

以下基准测试适用于 SemIf 扩展,而非文本生成端点。模型大小、量化、提示词长度、运行时和 CPU 线程数都会影响每次决策。为了量化这些权衡,我们将相同的 231 个公开的 JevBench 任务串行地发送到一个 CPU 端点和一个 GPU 端点。

配置 AWS DLC for llama.cpp 有效响应 准确率 客户端 p50 客户端 p95
Qwen3.5-4B Q4_K_M, ml.c6i.8xlarge,32 线程 llama-cpp:server-sagemaker-cpu-v1 231/231 179/231 (77.5%) 1.715 秒 19.291 秒
Qwen3.5-4B Q4_K_M, ml.g6e.xlarge,完全 GPU 卸载 llama-cpp:server-sagemaker-cuda-v1 231/231 180/231 (77.9%) 0.352 秒 0.599 秒

与 CPU 配置相比,GPU 端点在 p50 时快 4.9 倍,在 p95 时快 32.2 倍。该示例使用 SageMaker AI 实例池功能按优先级顺序列出兼容的 GPU 实例类型,因此当首选实例不可用时,SageMaker 可以选择替代实例。该池的排序为 g6e, g6, g5,然后是 g4dn。SageMaker 选择了 ml.g6e.xlarge,启动日志确认 llama.cpp 将全部 34 个模型层卸载到了 NVIDIA L40S。CPU 和 GPU 镜像使用了不同的 llama.cpp 构建,并在六个困难任务上产生了不同的预测。请将这一个答案的准确率差异视为运行时差异,而不是 GPU 卸载能提升模型质量的证据。

更小的模型降低了中位延迟,但 2B 和 0.8B 候选模型的准确率分别为 66.7% 和 58.4%。因此,该示例保留了 4B Q4_K_M 模型作为其质量优先的默认选择。这些测量包含网络延迟,并非服务保证。

请根据您自己的决策对完整的模型和基础设施配置进行基准测试。对于不敏感于延迟、可以容忍数秒响应时间的后台、离线或低吞吐量工作负载,请使用 CPU。对于交互式决策、长提示词或有严格尾延迟目标的工作负载,请使用 GPU。保持状态和选项描述简洁,将共享相同状态的决策组合到一个请求中,并为并发扩展端点实例。共享状态评分会重用共同的提示词前缀,而适配器会返回可重试的 HTTP 503 响应,而不是让其有状态的 llama.cpp 上下文周围形成无界队列。

先决条件

你需要:

  • 一个 AWS 账户以及位于您部署所在 AWS 区域的一个 S3 存储桶。
  • Python 3.10 或更高版本、Git,以及 AWS 命令行界面(AWS CLI)。
  • 一个专用于可选 SemIf 扩展的特定用途 CodeBuild 服务角色。
  • 一篇 AWS Identity and Access Management (IAM) SageMaker AI 可以承担的角色。
  • SageMaker AI、Amazon ECR、Amazon S3、CodeBuild、IAM pass-role 操作以及 Amazon CloudWatch Logs.
  • 兼容的 x86 CPU 或 NVIDIA GPU SageMaker 实时端点的配额。

文本生成示例使用 CPU DLC 和固定的 CPU 实例。SemIf 扩展将 CPU 保留为非延迟敏感工作负载的默认选项,并提供带有序实例池的可选 CUDA 镜像。评测 SageMaker AI 定价 在创建端点之前。

部署一个决策模型并使用 SemIf 对其进行扩展

使用以下步骤部署标准文本生成端点,然后在 CPU 或 GPU 上构建可选的 SemIf 扩展以实现结构化决策。

  1. 克隆代码示例并安装其依赖项。
    git clone https://github.com/aws-samples/sagemaker-genai-hosting-examples.git
    cd sagemaker-genai-hosting-examples/03-features/semif-decision-model
    python3 -m venv .venv
    . .venv/bin/activate
    python3 -m pip install -r deploy/requirements.txt
  2. 为您的账户设置部署值。
    export AWS_REGION="<your-region>"
    export ARTIFACT_BUCKET=amzn-s3-demo-semif-artifacts
    export CODEBUILD_ROLE_ARN=arn:aws:iam::111122223333:role/semif-codebuild-role
    export SAGEMAKER_ROLE_ARN=arn:aws:iam::111122223333:role/semif-sagemaker-role
    export STANDARD_ENDPOINT_NAME=llamacpp-gguf
    export SEMIF_ENDPOINT_NAME=semif-decision-workflows
  3. 使用 CodeBuild 打包固定版本的 GGUF 模型和分词器。
    python deploy/prepare_model_build.py \
      --region "$AWS_REGION" \
      --bucket "$ARTIFACT_BUCKET" \
      --codebuild-role-arn "$CODEBUILD_ROLE_ARN" \
      --model-s3-uri "s3://$ARTIFACT_BUCKET/semif-llamacpp/model.tar.gz"

    等待返回的构建 ID 达到 SUCCEEDED。构建会将源代码修订版本和校验和记录在 model-manifest.json 中,如果 GGUF 校验和与已验证的值不同则会停止。

  4. 使用用于 llama.cpp 的 AWS DLC 部署 GGUF 模型。

    解析一个以摘要固定的 server-sagemaker-cpu-v1 镜像,来源为 用于 llama.cpp 的 AWS DLC 文档,然后创建 SageMaker AI 模型、端点配置和端点:

    export STANDARD_IMAGE_URI="<published-llama-cpp-cpu-image>@sha256:<digest>"
    
    python deploy/deploy_standard_endpoint.py \
      --region "$AWS_REGION" \
      --image-uri "$STANDARD_IMAGE_URI" \
      --model-data-url "s3://$ARTIFACT_BUCKET/semif-llamacpp/model.tar.gz" \
      --role-arn "$SAGEMAKER_ROLE_ARN" \
      --instance-type ml.c6i.2xlarge \
      --name "$STANDARD_ENDPOINT_NAME"

    选择 server-sagemaker-cpu-v1 或 server-sagemaker-cuda-v1 镜像,而不是对应的 EC2 镜像。这些 SageMaker AI 镜像实现了 /ping 和 /invocations 容器契约,并将调用负载映射到聊天补全。

    本演练通过 Amazon S3 中的 SageMaker AI 模型工件提供 GGUF 模型。作为替代方案,当端点具有网络出站流量时,您可以配置 SM_LLAMA_CPP_HF_REPO 和 SM_LLAMA_CPP_HF_FILE 以便从 Hugging Face 下载 GGUF 文件。

    此路径不需要 Dockerfile 或 ECR 存储库。等待端点进入 InService状态,然后发送兼容 OpenAI 的聊天请求:

    python deploy/invoke_standard_endpoint.py \
      --region "$AWS_REGION" \
      --endpoint-name "$STANDARD_ENDPOINT_NAME"
  5. 构建可选的 SemIf 子镜像并解析其不可变摘要。

    对于 CPU:

    python deploy/prepare_build.py \
      --region "$AWS_REGION" \
      --bucket "$ARTIFACT_BUCKET" \
      --codebuild-role-arn "$CODEBUILD_ROLE_ARN"

    对于 GPU,改为构建 CUDA 子镜像:

    python deploy/prepare_build.py \
      --region "$AWS_REGION" \
      --bucket "$ARTIFACT_BUCKET" \
      --codebuild-role-arn "$CODEBUILD_ROLE_ARN" \
      --dockerfile Dockerfile.gpu \
      --image-tag "gpu-$(date +%Y%m%d%H%M%S)"

    构建成功后,构造不可变的镜像 URI:

    ECR_REPOSITORY_URI=$(aws ecr describe-repositories \
      --region "$AWS_REGION" \
      --repository-names semif-llamacpp-dlc \
      --query 'repositories[0].repositoryUri' \
      --output text)
    IMAGE_DIGEST=$(aws ecr describe-images \
      --region "$AWS_REGION" \
      --repository-name semif-llamacpp-dlc \
      --query 'sort_by(imageDetails,&imagePushedAt)[-1].imageDigest' \
      --output text)
    export IMAGE_URI="${ECR_REPOSITORY_URI}@${IMAGE_DIGEST}"

    部署脚本会拒绝可变的镜像标签。

  6. 部署 SemIf 端点。

    CPU 配置使用固定的实例类型:

    python deploy/deploy_endpoint.py \
      --region "$AWS_REGION" \
      --image-uri "$IMAGE_URI" \
      --model-data-url "s3://$ARTIFACT_BUCKET/semif-llamacpp/model.tar.gz" \
      --role-arn "$SAGEMAKER_ROLE_ARN" \
      --instance-type ml.c6i.8xlarge \
      --threads 32 \
      --name "$SEMIF_ENDPOINT_NAME"

    等待返回的端点名称进入 InService状态。此路径设置 n_gpu_layers=0。适配器围绕一个有状态的 llama.cpp 上下文进行评分序列化,因此请在测量您的工作负载后通过端点实例进行横向扩展,而不是假设在单个容器内进行并行评分。

    对于 GPU 镜像,请提供有序的实例池并请求完整的模型卸载:

    python deploy/deploy_endpoint.py \
      --region "$AWS_REGION" \
      --image-uri "$IMAGE_URI" \
      --model-data-url "s3://$ARTIFACT_BUCKET/semif-llamacpp/model.tar.gz" \
      --role-arn "$SAGEMAKER_ROLE_ARN" \
      --instance-pool ml.g6e.xlarge \
      --instance-pool ml.g6.2xlarge \
      --instance-pool ml.g5.2xlarge \
      --instance-pool ml.g4dn.2xlarge \
      --gpu-layers=-1 \
      --provision-timeout 1200 \
      --name "$SEMIF_ENDPOINT_NAME"

    实例池是有序的放置回退机制,而不是推理负载均衡。SageMaker 会为该变体选择一个可用的类型。在 SageMaker AI 遍历池的过程中,端点创建可能需要更长时间。请检查启动日志中是否出现所选 GPU 以及确认所有模型层均已卸载的消息。

  7. 使用示例决策调用 SemIf 端点。

    该请求为每个允许的选项声明了稳定 ID:

    {
      "decision": {
        "id": "support-route",
        "state": "Customer asks to reset a forgotten password and says the reset email never arrived.",
        "question": "Which queue should handle this request?",
        "options": [
          {"id": "account_access", "description": "Account access and authentication support."},
          {"id": "billing", "description": "Billing and payment support."},
          {"id": "sales", "description": "Sales and product evaluation."}
        ]
      }
    }
    python deploy/invoke_endpoint.py \
      --region "$AWS_REGION" \
      --endpoint-name "$SEMIF_ENDPOINT_NAME"

    响应保留了选项顺序,并包含条件概率、原始 logits、token 和提示元数据,以及固定的模型身份:

    {
      "result": {
        "id": "support-route",
        "option_ids": ["account_access", "billing", "sales"],
        "probabilities": [0.99996, 0.00003, 0.00001],
        "option_logits": [28.47, 17.92, 17.04],
        "prompt_sha256": "016267542103ab91422c425d2234ec7e1b9aef77f9d3e481b96db2de7cca470a",
        "readout": "quantized last-position logits restricted to declared answer slots; no generated tokens"
      }
    }

    在应用层面设置阈值和回退机制。不要将模型决策用作授权的替代品。

清理

删除 SageMaker AI 端点、端点配置和模型:

python deploy/cleanup_endpoint.py \
  --region "$AWS_REGION" \
  --name "$STANDARD_ENDPOINT_NAME"

python deploy/cleanup_endpoint.py \
  --region "$AWS_REGION" \
  --name "$SEMIF_ENDPOINT_NAME"

该脚本只删除那些被明确指定名称的 SageMaker AI 资源。当不再需要时,请删除 CodeBuild 项目、ECR 仓库、Amazon S3 中的模型和源对象、日志以及专用的 IAM 角色。

结论

用于 llama.cpp 的 AWS DLC 为您在 SageMaker AI 上跨 CPU 和 GPU 实例服务决策模型提供了一个托管的基础。它可以从 SageMaker AI 模型工件或配置的 Hugging Face 仓库加载 GGUF 模型,然后通过 InvokeEndpoint 提供 OpenAI 兼容的聊天补全服务,无需自定义容器。当您的应用需要直接的 logits 和模型状态操作时,可以使用 SemIf 适配器扩展该 DLC。对于不延迟敏感的工作负载,请选择 CPU;当提示预填充和尾延迟影响应用体验时,请选择 GPU。

查看 代码示例, AWS DLC for llama.cpp 文档以及 SageMaker AI 自定义推理容器契约 ,以便针对您的工作负载调整部署。

 


关于作者

原始出处

AWS Machine Learning

内容说明

原始发布及相关权利归来源方。

机器翻译 · 请以原文为准