ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

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

使用 BentoML 部署 Outlines 结构化生成服务:从本地推理到 BentoCloud 生产部署 使用 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 结合核心路径分为三步导入模型从 Hugging Face 下载 LLM写入 BentoML 的 Model Store实现模型与代码的解耦管理定义服务用 BentoML 装饰器把 Outlines 的生成逻辑封装成带 HTTP 端点的 Service运行与部署本地用bentoml serve调试云端用bentoml deploy一键发布到 BentoCloud。示例中的模型以 Mistral-7B-v0.1 为例你也可以替换为任何其他兼容 transformers 的 LLM。完整可运行代码见 examples/bentoml/ 下的import_model.py、service.py、bentofile.yaml与requirements.txt。导入模型到 BentoML Model Store安装依赖在虚拟环境中安装依赖仓库中 examples/bentoml/requirements.txt 固定了示例所需的版本pip install -r requirements.txt该文件的关键依赖如下bentoml1.2.11 outlines0.0.37 transformers4.38.2 datasets2.18.0 accelerate0.27.2编写并运行导入脚本将下面的代码保存为import_model.py与仓库 examples/bentoml/import_model.py 一致然后执行python import_model.pyimport 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_dtypetorch.float16, low_cpu_mem_usageTrue, ) 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.1→mistralai--mistral-7b-v0.1。后续service.py会通过bentoml.models.get(BENTO_MODEL_TAG)按此标签取回模型。权重精度与内存加载时指定torch_dtypetorch.float16半精度与low_cpu_mem_usageTrue可显著降低显存占用并避免 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.serviceservice.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_dtypetorch.float16, low_cpu_mem_usageTrue, device_mapcuda ) # 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分别返回Transformers或TransformersMultiModal实例这里传入 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必须是整数、armor与weapon通过$ref引用definitions中的枚举模型只能在给定枚举值中选择。这样模型输出天然满足 Schema无需事后解析纠错。端点行为与约束原理HTTP 语义generate接受 JSON 请求体字段为prompt和可选的json_schema缺省时使用上面的DEFAULT_SCHEMA。函数签名中的类型提示str、t.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: falseservice指定服务入口格式为模块:类名即service.py中的Outlines类include把目录下所有*.py文件打入 Bento 包import_model.py中的BENTO_MODEL_TAG常量因此可用python.requirements_txt声明运行时依赖清单lock_packages: false表示构建时不锁定传递依赖版本。本地运行与调试启动服务在包含service.py与bentofile.yaml的目录下运行bentoml serve .服务启动后监听 http://localhost:3000BentoML 会自动提供 Swagger UI 便于交互式调试也可以用下面两种方式调用。方式一CURLcurl -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( promptGive me a character description ) print(response)预期输出两种方式均返回符合 Schema 的 JSON例如{ name: Aura, age: 15, armor: plate, weapon: sword, strength: 20 }注意armor的值必然是leather、chainmail、plate三者之一weapon必然是六种武器之一——这正是 logits 层面约束生效的直接体现。部署到 BentoCloud服务在本地验证通过后即可发布到 BentoCloud 获得托管、弹性伸缩与统一管理能力尚未注册的话先在 BentoCloud 注册账号确保已登录 BentoCloud配置好访问令牌在项目目录下执行一键部署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.pyBentoML 负责模型管理、HTTP 服务与云端部署两者各司其职。若需调整生成约束只需修改json_schema入参或替换DEFAULT_SCHEMA若需更换模型更新MODEL_ID并重新执行导入脚本即可。完整示例代码可在 examples/bentoml/ 目录中直接查看或复用。【免费下载链接】outlinesStructured Outputs项目地址: https://gitcode.com/GitHub_Trending/ou/outlines创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进