使用 BentoML 部署 Outlines 结构化生成服务:从本地推理到 BentoCloud 生产部署
2026/9/14 8:54:31 网站建设 项目流程

使用 BentoML 部署 Outlines 结构化生成服务:从本地推理到 BentoCloud 生产部署

【免费下载链接】outlinesStructured Outputs项目地址: https://gitcode.com/GitHub_Trending/ou/outlines

本指南基于仓库 examples/bentoml/ 目录下的完整示例,讲解如何将 Outlines 的结构化输出能力封装为 BentoML Service,先在本地 GPU 上运行调试,再一键部署到 BentoCloud 托管推理平台。读完本文,你将掌握:把 Hugging Face 模型导入 BentoML Model Store、用@bentoml.service@bentoml.api定义生成服务、通过 HTTP 调用 JSON Schema 约束生成接口,以及使用bentoml serve/bentoml deploy完成本地与云端发布。

整体思路:用 BentoML 托管 Outlines 的约束生成

BentoML 是一个面向 Python AI 应用的开源模型服务库,提供服务化、模型打包与生产部署所需的工具链。将它与 Outlines 结合,核心路径分为三步:

  1. 导入模型:从 Hugging Face 下载 LLM,写入 BentoML 的 Model Store,实现模型与代码的解耦管理;
  2. 定义服务:用 BentoML 装饰器把 Outlines 的生成逻辑封装成带 HTTP 端点的 Service;
  3. 运行与部署:本地用bentoml serve调试,云端用bentoml deploy一键发布到 BentoCloud。

示例中的模型以 Mistral-7B-v0.1 为例,你也可以替换为任何其他兼容 transformers 的 LLM。完整可运行代码见 examples/bentoml/ 下的import_model.pyservice.pybentofile.yamlrequirements.txt

导入模型到 BentoML Model Store

安装依赖

在虚拟环境中安装依赖,仓库中 examples/bentoml/requirements.txt 固定了示例所需的版本:

pip install -r requirements.txt

该文件的关键依赖如下:

bentoml>=1.2.11 outlines==0.0.37 transformers==4.38.2 datasets==2.18.0 accelerate==0.27.2

编写并运行导入脚本

将下面的代码保存为import_model.py(与仓库 examples/bentoml/import_model.py 一致),然后执行python import_model.py

import bentoml MODEL_ID = "mistralai/Mistral-7B-v0.1" BENTO_MODEL_TAG = MODEL_ID.lower().replace("/", "--") def import_model(model_id, bento_model_tag): import torch from transformers import AutoModelForCausalLM, AutoTokenizer tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) model = AutoModelForCausalLM.from_pretrained( MODEL_ID, torch_dtype=torch.float16, low_cpu_mem_usage=True, ) with bentoml.models.create(bento_model_tag) as bento_model_ref: tokenizer.save_pretrained(bento_model_ref.path) model.save_pretrained(bento_model_ref.path) if __name__ == "__main__": import_model(MODEL_ID, BENTO_MODEL_TAG)

要点说明:

  • Tag 生成规则BENTO_MODEL_TAG = MODEL_ID.lower().replace("/", "--")把 Hugging Face 的组织/模型名转换成 BentoML 允许的标签格式(斜杠替换为双连字符),例如mistralai/Mistral-7B-v0.1mistralai--mistral-7b-v0.1。后续service.py会通过bentoml.models.get(BENTO_MODEL_TAG)按此标签取回模型。
  • 权重精度与内存:加载时指定torch_dtype=torch.float16(半精度)与low_cpu_mem_usage=True,可显著降低显存占用并避免 CPU 内存峰值。
  • Model Store 落盘bentoml.models.create(bento_model_tag)会在 Model Store 中创建一条模型记录,把 tokenizer 与权重一并保存到其目录下,使模型可脱离原始下载链接被服务直接引用。

注意:首次下载 Mistral-7B-v0.1 前,需要先在 Hugging Face 上接受该模型的使用条款,否则下载会失败。

校验导入结果

运行以下命令确认模型已进入 Model Store:

$ bentoml models list Tag Module Size Creation Time mistralai--mistral-7b-v0.1:m7lmf5ac2cmubnnz 13.49 GiB 2024-04-25 06:52:39

看到类似输出即表示导入成功,记录下 Tag(含版本后缀)供服务加载使用。

定义 BentoML Service:封装 Outlines 生成接口

服务声明:@bentoml.service

service.py首先用@bentoml.service装饰一个普通类(这里叫Outlines),并通过装饰器参数声明流量与资源配置:

import typing as t import bentoml from import_model import BENTO_MODEL_TAG @bentoml.service( traffic={ "timeout": 300, }, resources={ "gpu": 1, "gpu_type": "nvidia-l4", }, ) class Outlines: bento_model_ref = bentoml.models.get(BENTO_MODEL_TAG) def __init__(self) -> None: import outlines import torch from transformers import AutoModelForCausalLM, AutoTokenizer # Load tokenizer and model from the BentoML model reference path hf_tokenizer = AutoTokenizer.from_pretrained(self.bento_model_ref.path) hf_model = AutoModelForCausalLM.from_pretrained( self.bento_model_ref.path, torch_dtype=torch.float16, low_cpu_mem_usage=True, device_map="cuda" ) # Then use the loaded model with Outlines self.model = outlines.from_transformers(hf_model, hf_tokenizer) ...

这里有几个关键设计:

  • 配置项语义traffic.timeout为请求超时时间(秒),设为 300 以容纳长文本生成;resources.gpu指定显卡数量,resources.gpu_type指定云端 GPU 型号(示例为 24GB 显存的nvidia-l4)。这些资源声明在 BentoCloud 部署时生效,用于调度对应的 GPU 实例。
  • 模型引用bento_model_ref = bentoml.models.get(BENTO_MODEL_TAG)在类体内直接解析 Model Store 中的模型标签,拿到模型目录路径bento_model_ref.path,随后在__init__中从该路径加载 tokenizer 与权重。
  • 接入 Outlinesoutlines.from_transformers(hf_model, hf_tokenizer)把 transformers 模型与分词器包装成 Outlines 的可控生成模型。从源码看,from_transformers 会根据传入的是PreTrainedTokenizer还是ProcessorMixin,分别返回TransformersTransformersMultiModal实例,这里传入 tokenizer 因此得到文本生成模型。

生成端点:@bentoml.api

接下来用@bentoml.api装饰generate方法,把它暴露为 HTTP 端点:

... @bentoml.api async def generate( self, prompt: str = "Give me a character description.", json_schema: t.Optional[str] = DEFAULT_SCHEMA, ) -> t.Dict[str, t.Any]: import json import outlines from outlines.types import JsonSchema generator = outlines.Generator(self.model, JsonSchema(json_schema)) character = generator(prompt) return json.loads(character)

对应仓库 examples/bentoml/service.py 中默认使用的 JSON Schema 如下(一个 RPG 角色对象,包含字符串、整数与枚举类型字段):

DEFAULT_SCHEMA = """{ "title": "Character", "type": "object", "properties": { "name": { "title": "Name", "maxLength": 10, "type": "string" }, "age": { "title": "Age", "type": "integer" }, "armor": {"$ref": "#/definitions/Armor"}, "weapon": {"$ref": "#/definitions/Weapon"}, "strength": { "title": "Strength", "type": "integer" } }, "required": ["name", "age", "armor", "weapon", "strength"], "definitions": { "Armor": { "title": "Armor", "description": "An enumeration.", "enum": ["leather", "chainmail", "plate"], "type": "string" }, "Weapon": { "title": "Weapon", "description": "An enumeration.", "enum": ["sword", "axe", "mace", "spear", "bow", "crossbow"], "type": "string" } } }"""

该 Schema 展示了结构化约束的典型形态:name限制最长 10 字符、age/strength必须是整数、armorweapon通过$ref引用definitions中的枚举,模型只能在给定枚举值中选择。这样模型输出天然满足 Schema,无需事后解析纠错。

端点行为与约束原理

  • HTTP 语义generate接受 JSON 请求体,字段为prompt和可选的json_schema(缺省时使用上面的DEFAULT_SCHEMA)。函数签名中的类型提示(strt.Optional[str]t.Dict[str, t.Any])会被 BentoML 用于校验和转换入参、出参。返回前通过json.loads(character)把模型生成的 JSON 字符串解析为 Python 字典。
  • 可扩展性:你可以在Outlines类中继续用@bentoml.api装饰更多方法,定义任意数量的 HTTP 端点。
  • 约束生成的底层链路:从源码看,Generator 是工厂函数:对支持可控生成的模型,会构造SteerableGenerator,在其__init__中把JsonSchema输出类型翻译成 logits 处理器——见 src/outlines/generator.py 的SteerableGenerator.__init__,它调用get_json_schema_logits_processor构建约束处理器(具体实现分发到 xgrammar、llguidance 或 outlines_core 等后端,见 src/outlines/backends/init.py);每次调用生成时处理器会先reset()(generator.py),再传给模型执行受限采样。换言之,所谓"JSON Schema 约束"是在采样阶段通过 logits 掩码实现的,而非提示词工程。
  • 关于两种写法:本文档正文中的outlines.Generator(self.model, JsonSchema(json_schema))与仓库 examples/bentoml/service.py 里的outlines.Generator(self.model, outlines.json_schema(json_schema))等价——outlines.json_schema只是JsonSchema的工厂函数(见 src/outlines/types/dsl.py),两者都接受 Schema 字符串。注意from outlines.types import JsonSchema与顶层outlines.json_schema在 Outlines 顶层命名空间中均可导入(见 src/outlines/init.py)。

BentoML 构建配置

仓库中的 bentofile.yaml 定义了 Bento 的构建方式:

service: "service:Outlines" labels: owner: bentoml-team stage: demo include: - "*.py" python: requirements_txt: "./requirements.txt" lock_packages: false
  • service:指定服务入口,格式为模块:类名,即service.py中的Outlines类;
  • include:把目录下所有*.py文件打入 Bento 包(import_model.py中的BENTO_MODEL_TAG常量因此可用);
  • python.requirements_txt:声明运行时依赖清单;lock_packages: false表示构建时不锁定传递依赖版本。

本地运行与调试

启动服务

在包含service.pybentofile.yaml的目录下运行:

bentoml serve .

服务启动后监听 http://localhost:3000,BentoML 会自动提供 Swagger UI 便于交互式调试,也可以用下面两种方式调用。

方式一:CURL

curl -X 'POST' \ 'http://localhost:3000/generate' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "prompt": "Give me a character description." }'

方式二:Python 客户端

import bentoml with bentoml.SyncHTTPClient("http://localhost:3000") as client: response = client.generate( prompt="Give me a character description" ) print(response)

预期输出

两种方式均返回符合 Schema 的 JSON,例如:

{ "name": "Aura", "age": 15, "armor": "plate", "weapon": "sword", "strength": 20 }

注意armor的值必然是leatherchainmailplate三者之一,weapon必然是六种武器之一——这正是 logits 层面约束生效的直接体现。

部署到 BentoCloud

服务在本地验证通过后,即可发布到 BentoCloud 获得托管、弹性伸缩与统一管理能力:

  1. 尚未注册的话,先在 BentoCloud 注册账号;
  2. 确保已登录 BentoCloud(配置好访问令牌);
  3. 在项目目录下执行一键部署:
bentoml deploy .

部署完成后,应用会暴露一个公网 URL,直接通过该 URL 调用/generate端点即可,调用方式与本地完全一致。

提示:如果你希望部署到自有基础设施而非 BentoCloud,可以改用 BentoML 生成 OCI 兼容的容器镜像,在任何支持 OCI 镜像的平台上运行同样的服务。

小结

通过本文的四个步骤——导入模型到 Model Store、用装饰器定义 Service 与端点、bentoml serve本地调试、bentoml deploy云端发布——即可把 Outlines 的 JSON Schema 约束生成能力快速产品化。整套流程中,Outlines 负责在采样阶段把 Schema 编译为 logits 约束处理器(相关源码入口见 src/outlines/generator.py、src/outlines/backends/init.py),BentoML 负责模型管理、HTTP 服务与云端部署,两者各司其职。若需调整生成约束,只需修改json_schema入参或替换DEFAULT_SCHEMA;若需更换模型,更新MODEL_ID并重新执行导入脚本即可。完整示例代码可在 examples/bentoml/ 目录中直接查看或复用。

【免费下载链接】outlinesStructured Outputs项目地址: https://gitcode.com/GitHub_Trending/ou/outlines

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询