菜单

语法约束生成

相关源文件

本页面介绍了llama.cpp中的语法约束生成功能,该功能允许您将模型的输出限制为遵循特定格式,如JSON、XML或自定义结构化文本。有关通用采样参数和策略,请参阅Token Sampling

概述

语法约束生成使用户能够定义正式的语法,将模型的输出限制在特定的完整性子集中。这对于以下场景特别有用:

  1. 结构化数据生成 - 带有模式验证的JSON、XML、YAML
  2. 工具调用 - 确保函数调用参数与预期模式匹配
  3. 聊天模板集成 - 在对话流程中强制执行格式约束
  4. API响应 - 保证一致的输出格式以便下游处理
  5. 代码生成 - 确保特定语言的语法正确的代码

语法系统通过在生成过程的每一步过滤模型的令牌概率分布来工作,删除会导致无效语法结构的令牌。现代llama.cpp将语法约束与聊天模板和工具调用集成,以实现无缝的结构化输出生成。

语法约束管道

来源

语法格式

Llama.cpp 支持多种定义语法约束的格式

JSON Schema(主要方法)

JSON Schema 是定义结构化输出约束的主要方法,尤其是在服务器环境和工具调用场景中。json_schema_to_grammar() 函数会自动将 JSON Schema 转换为 GBNF 语法。

此 Schema 会被自动转换为强制执行结构的 GBNF 语法。服务器通过聊天补全中的 json_schema 参数和 response_format 字段支持此功能。

来源

GBNF 格式

GBNF (Grammar BNF) 是一种类似 BNF 的上下文无关语法格式,但针对令牌级约束进行了优化。它定义了指定有效令牌序列的产生规则。

GBNF 基本语法

  • 非终结符:rulename ::= definition
  • 终结符:"literal"
  • 正则表达式:[a-z]+/regex/
  • 选择项:a | b
  • 序列:a b
  • 重复:*(零次或多次),+(一次或多次),?(可选)
  • 分组:(a | b) c

JSON 的 GBNF 语法示例

root  ::= object
value ::= object | array | string | number | "true" | "false" | "null"

object ::= "{" ws (string ws ":" ws value (ws "," ws string ws ":" ws value)*)? ws "}"
array  ::= "[" ws (value (ws "," ws value)*)? ws "]"
string ::= "\"" ([^"\\] | "\\" .)* "\""

number ::= ["-"]? ([0-9] | [1-9] [0-9]*) ("." [0-9]+)? ([eE] [+-]? [0-9]+)?
ws ::= [ \t\n\r]*

来源

聊天模板集成

聊天模板可以直接指定语法约束和触发器。这使得格式感知的对话流程成为可能,其中语法是根据对话上下文激活的。

来源

实现架构

语法约束生成与llama.cpp中的多个系统集成

核心语法系统

JSON Schema 到 Grammar 管道

关键组成部分是

  1. JSON Schema 转换json_schema_to_grammar() 将 JSON Schema 转换为 GBNF
  2. 语法触发器common_grammar_trigger 定义激活模式
  3. 延迟加载:语法约束仅在被触发时激活
  4. 令牌保留:在应用语法时,特定令牌(如工具调用标记)会被保留

来源

语法触发器和延迟加载

现代llama.cpp实现了复杂的语法触发系统,仅在需要时激活约束

语法触发器类型

触发类型描述用例示例
COMMON_GRAMMAR_TRIGGER_TYPE_WORD在特定单词令牌上激活工具调用标记,如<tool_call>
COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN正则表达式匹配函数名称模式
COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN_FULL完全文本正则表达式匹配复杂格式检测
COMMON_GRAMMAR_TRIGGER_TYPE_TOKEN特定令牌 ID保留的特殊令牌

延迟语法激活过程

保留的令牌

系统维护一组preserved_tokens,这些令牌永远不会被语法约束过滤掉,确保重要的标记(如工具调用边界)可用。

来源

使用示例

命令行界面

基本语法文件使用

JSON Schema 约束

带触发器的延迟语法

HTTP 服务器 API

服务器提供了多个用于结构化生成的端点

带有 JSON Schema 的聊天补全

直接 JSON Schema 参数

带有补全端点的语法

工具调用集成

语法约束在工具调用场景中自动应用

系统会自动生成语法约束,以确保工具调用参数与指定的 Schema 匹配。

来源

工具调用和聊天模板集成

语法约束已深度集成到工具调用和聊天模板中,实现无缝的结构化输出。

工具的自动语法生成

当在聊天补全中指定工具时,系统会自动生成语法约束。

聊天模板语法支持

聊天模板可以指定语法触发器和约束。

语法触发器配置

语法触发器通过聊天模板系统进行配置。

参数描述示例
grammar_triggers触发器模式列表[{"type": "word", "value": "<tool_call>"}]
preserved_tokens永远不会被语法过滤的令牌["<tool_call>", "</tool_call>"]
grammar_lazy启用延迟语法激活true

工具调用语法流程

在工具场景中测试语法

测试套件验证了跨不同聊天模板的语法行为。

来源

编写自定义 GBNF 语法

对于高级用例,您可以编写自定义 GBNF 语法。

GBNF 最佳实践

  1. 从简单开始:从定义主结构的root规则开始。
  2. 增量组合:从更简单的组件构建复杂的语法。
  3. 使用空白规则:定义ws规则以实现灵活的间距。
  4. 彻底测试:使用各种输入验证语法。

JSON 语法示例

函数调用语法示例

来源

性能考量

语法约束生成会产生额外的计算开销,该开销因实现方法而异。

优化策略

策略性能影响用例
延迟语法加载触发前最小化工具调用、条件格式化
保留的令牌低开销在应用语法时维护特殊令牌
语法触发器激活前开销极低具有偶尔结构化输出的大型上下文
简单语法较低的解析开销基本 JSON、简单格式

性能特征

延迟加载的好处

grammar_lazy 功能通过延迟语法激活显著提高了性能。

这在仅偶尔需要结构化输出的聊天场景中尤其有效。

内存使用

语法解析会创建其他数据结构

  • 语法规则:存储在内存中的已解析产生规则。
  • 解析器状态:用于约束检查的基于堆栈的解析器状态。
  • 令牌保留:一组永远不会被语法过滤的令牌。

对于长上下文长度,延迟加载通过在需要时避免语法结构分配来减少内存压力。

来源

与核心功能的集成

语法约束生成与llama.cpp的其他功能无缝集成

投机解码

语法约束应用于投机解码,以确保草稿令牌保持有效。

多模态模型

语法约束可与多模态模型(LLaVA)配合使用,以确保即使在处理图像时也能获得结构化的响应。

连续批处理

服务器的连续批处理系统为每个槽维护独立的语法状态。

聊天模板生态系统

语法与完整的聊天模板生态系统集成。

模板功能语法集成
工具使用模板函数调用的自动语法生成
推理格式用于结构化思维模式的语法
多轮对话上下文感知语法激活
自定义格式模板定义的语法触发器

跨平台兼容性

语法约束在所有llama.cpp后端之间一致工作

  • CPU后端:提供完整的语法支持和优化的解析。
  • GPU后端(CUDA、Metal等):语法在令牌生成后在CPU上应用。
  • 量化模型:语法支持所有量化格式。

来源

调试语法问题

如果您遇到语法问题:

  1. 使用 llama-gbnf-validator 工具验证语法文件。
  2. 启用详细模式以查看详细的解析信息。
  3. 从简单的语法结构开始,逐步添加复杂性。
  4. 在使用语法进行生成之前,先用简短的示例文本测试语法。

对于更复杂的语法创建,请考虑使用专门的工具或库来从其他格式生成 GBNF。

来源