资讯动态

LocalAI 受限生成实战:用 BNF 语法(grammar)精确约束 LLM 输出格式

发布时间:2026/9/8 22:53:00 来源:尧图企业网站定制
LocalAI 受限生成实战用 BNF 语法grammar精确约束 LLM 输出格式【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAILocalAI 的chat端点支持grammar参数允许以 Backus-Naur FormBNF描述文法来锁死大语言模型的输出格式——无论是 JSON、YAML还是只允许 yes/no 二选一。读完本文你将掌握如何在请求中传入自定义 BNF 文法、理解文法在 LocalAI 源码中从 HTTP 请求到 llama.cpp 后端的完整传递链路并了解response_format、函数调用等功能如何与受限生成协同工作。一、功能概述grammar 参数与 BNF 文法chat端点支持grammar请求字段其值是一段 BNF 文法。该特性使 LLM 只能生成严格符合用户自定义 schema 的输出例如JSON、YAML或任何其他可以用 BNF 定义的格式。在请求结构中该字段的定义位于 OpenAI 兼容 Schema// A grammar to constrain the LLM output Grammar string json:grammar,omitempty yaml:grammar JSONFunctionGrammarObject *functions.JSONFunctionStructure json:grammar_json_functions,omitempty yaml:grammar_json_functions可以看到grammar是一个可选的字符串字段omitempty因此不会出现在转发给上游严格 Provider 的请求体中——这与 LocalAI 对 LocalAI 私有字段零值不泄漏的设计一致。兼容性说明该特性目前仅由使用 llama.cpp 后端的模型支持受限于底层解码器对文法约束的实现。完整兼容模型列表可参见 模型兼容性参考页。该能力源自 llama.cpp 项目对 grammar/logits 过滤的支持。二、文法语法速览BNF 规则支持的语法元素对于更复杂的文法可以定义多行 BNF 规则。语法解析支持以下元素语法元素符号说明选择Alternation\|在多个候选中任选其一重复*、*表示零次或多次表示一次或多次可选?元素可出现零次或一次字符类[a-z]匹配某一类字符字符串字面量text精确匹配指定文本规则定义rule :: ...命名规则root为入口规则文法以root规则为起点请求体中可以通过\n换行符拼接多条规则。三、实战示例完整可复制示例 1二值响应约束yes / no以下示例将模型输出严格限制为 yes 或 no适用于需要严格控制回答格式的场景curl http://localhost:8080/v1/chat/completions -H Content-Type: application/json -d { model: gpt-4, messages: [{role: user, content: Do you like apples?}], grammar: root :: (\yes\ | \no\) }grammar参数被设置为 yes/no 的简单选择无论上下文如何模型响应都只能是这两个选项之一。示例 2强制 JSON 输出也可以用文法强制 JSON 输出格式curl http://localhost:8080/v1/chat/completions -H Content-Type: application/json -d { model: gpt-4, messages: [{role: user, content: Generate a person object with name and age}], grammar: root :: \{\ \\\\name\\\:\ string \,\\\age\\\:\ number \}\\nstring :: \\\\\ [a-z] \\\\\\nnumber :: [0-9] }注意请求体中\\\的转义层级外层是 JSON 字符串的转义内层是 BNF 字符串字面量中的引号最终传给文法解析器的是\name\:这样的字面量规则。示例 3强制 YAML 输出同理可以用文法强制 YAML 格式此处为 fruits 列表curl http://localhost:8080/v1/chat/completions -H Content-Type: application/json -d { model: gpt-4, messages: [{role: user, content: Generate a YAML list of fruits}], grammar: root :: \fruits:\ newline (\ - \ string newline)\nstring :: [a-z]\nnewline :: \\\n\ }三个示例的共同点root规则定义了输出的骨架子规则string、number、newline负责可复用的片段。文法只约束输出 token 序列不改变提示词模板的生成过程。四、源码纵深grammar 从请求到后端的完整链路4.1 入口中间件读取请求字段用户传入的grammar字段首先由请求中间件写入运行配置见 请求中间件if input.Grammar ! { config.Grammar input.Grammar }4.2 chat 端点文法的多个来源与优先级chat 端点 中文法并非只能来自用户手写实际存在多条生成路径按请求内容触发response_format自动转文法当请求携带response_format时端点会将其转换为文法type: json_object→ 直接套用内置的functions.JSONBNF完整合法 JSON 文法type: json_schema→ 将 schema 包装为JSONFunctionStructure调用fs.Grammar(...)即时生成 BNF。函数调用Functions/Tools自动生成文法当请求需要走函数调用且未禁用文法NoGrammar为 false或处于strict模式时端点会把函数列表转换为 JSON 结构并调用jsStruct.Grammar(...)生成约束文法非 strict 模式下还会追加一个answer可通过NoActionFunctionName配置改名无动作函数允许模型直接回答而不调用工具。grammar_json_functions字段请求可直接携带 LocalAI 私有的JSONFunctionGrammarObject一个 JSON Schema 结构端点同样调用其Grammar()方法生成 BNF。上述逻辑执行完毕后config.Grammar被赋值并在调试日志中输出xlog.Debug(Grammar, ...)便于排查文法是否生效。4.3 后端投递透传给 llama.cpp运行配置中的Grammar最终被打包进发给后端的PredictOptions见 后端选项组装pbOpts : pb.PredictOptions{ ... Grammar: c.Grammar, ... }由于 llama.cpp 后端以独立 gRPC worker 进程运行文法字符串经 backend.proto 定义的PredictOptions协议传递到 C 侧由 llama.cpp 的采样器在逐 token 解码时进行 logits 过滤从而保证每个输出的 token 都满足文法约束。这也解释了该特性的兼容边界只有实现了 grammar 解码路径的 llama.cpp 系后端可用其他后端会忽略该字段。4.4 JSON Schema → BNF 的内部实现自动路径中文法生成能力位于 pkg/functions/grammars 目录。其基础构件是 BNF 原始规则表PRIMITIVE_RULES map[string]string{ boolean: (true | false) space, number: (-? ([0-9] | [1-9] [0-9]*)) (. [0-9])? ([eE] [-]? [0-9])? space, integer: (-? ([0-9] | [1-9] [0-9]*)) space, string: \ ([^\\] | \\ ([\\/bfnrt] | u ...))* \ space, null: null space, }这解释了为什么示例 2 中的string、number规则与手写版本行为不同内置转换会生成处理转义、负数、指数形式的严格规则源码注释中还特别说明freestring规则若不允许\和\\会产生歧义、实测效果显著变差——这类细节正是手写文法时容易踩坑的地方。五、受限生成在 LocalAI 其他功能中的体现grammar并非孤立特性它还是多个 OpenAI 兼容能力的底层机制OpenAI Functions / 函数调用OpenAI Functions 文档 描述的 structured outputs 正是通过上文的函数列表 → JSON 结构 → BNF 文法路径实现的模型输出被约束为合法的函数调用 JSON。Moderation 端点/v1/moderations的实现会先生成对应 moderation 响应 schema 的文法再约束输出见 moderations 端点 处cfg.Grammar grammar的赋值保证返回内容严格符合 moderation schema。Completion 端点/v1/completions同样读取grammar字段并在response_format为 JSON 时套用JSONBNF见 completion 端点。从源码结构看文法约束在模板层面还有配合逻辑模板求值器 中config.Grammar ! 会参与函数调用模板的分支判断即是否携带文法会影响最终 prompt 模板的形态。六、使用限制与注意事项后端限制仅 llama.cpp 后端模型支持grammar约束使用前请确认模型的 backend 字段文法正确性自负手写 BNF 若有歧义或无法被解析服务端会记录Failed generating grammar错误日志并可能退化为无约束输出建议先用简单文法验证再复杂化与response_format、functions的交互三者都可能最终落到config.Grammar上若同时传入grammar与函数定义按 chat 端点的分支逻辑函数生成的文法可能覆盖此前由response_format设置的值使用时应避免混用转义层级curl 请求体中\n、\需要按JSON 字符串 → BNF 字面量两层转义书写是实际调试中最常见的报错来源。相关功能OpenAI Functions — 函数调用与结构化输出文本生成 — 通用文本生成能力Moderation — OpenAI 兼容的安全分类其响应被约束到 moderation schema模型兼容性参考 — 各后端能力对照表【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价