#语言模型 #BNF #标记 #格式 #递归 #语法 #下降

bnf_sampler

一个使用递归下降算法确保大型语言模型产生的标记遵循巴科斯-诺尔范式(BNF)方案的软件包

15个版本

0.3.8 2024年6月26日
0.3.7 2024年5月14日
0.3.6 2024年3月27日
0.3.5 2023年10月24日
0.1.2 2023年8月31日

#338数据库接口

Download history 29/week @ 2024-04-17 27/week @ 2024-04-24 44/week @ 2024-05-01 50/week @ 2024-05-08 197/week @ 2024-05-15 59/week @ 2024-05-22 14/week @ 2024-05-29 25/week @ 2024-06-05 10/week @ 2024-06-12 153/week @ 2024-06-26 6/week @ 2024-07-03

每月1,253次下载

MIT/Apache

73KB
1.5K SLoC

bnf_sampler

crates.iodocs.rs

此软件包已弃用。请使用kbnf代替。

这是一个使用递归下降算法确保大型语言模型产生的标记遵循基于巴科斯-诺尔范式(BNF)的方案的采样语言模型。

标记必须以UTF-8编码。

特性

  1. 非常快速。
  2. 与任何类型的语言模型词汇兼容。
  3. 易于使用。

如何尝试?

  1. 安装Rust.
  2. 运行cargo run --release来运行console_playground程序。您的控制台输入被视为标记。运行cargo run --release -- --help来检查所有可能的命令行配置。修改`assets/grammar.bnf`来更改方案。(见语法方案部分和可能的标记列表部分)

或者您可以从发布页面下载预编译的二进制文件并运行。

在您的项目中使用

要在您的Rust项目中使用,只需在您的Cargo.toml中将bnf_sampler = "0.3.1"作为依赖项添加即可。

示例

将这些示例之一复制粘贴到assets/grammar.bnf中,自行尝试。

DNA序列

<start>::=<sequence>
<sequence>::=<base>|<base><sequence>
<base>::="A"|"C"|"G"|"T"

整数

<start>::=<integer>
<integer>::=<positive_digit><digits>|'0'
<digits>::=<digit>|<digit><digits>
<digit>::='0'|<positive_digit>
<positive_digit>::="1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"

字符串

<start>::=<string>
<string>::='"'<content>'"'
<content>::=<except!([escaped_literals])>|<except!([escaped_literals])><content>|'\\"'<content>|'\\"'
<escaped_literals>::='\t'|'\n'|'\r'|'"'

语法方案

在本项目中,使用了一个略微修改的BNF版本。主要区别是

  • 不支持左递归。(计划在未来支持。)

  • 连续的终结符合并为一个终结符。例如,'b''o''y'变为'boy'

  • <any!> 被添加为一个特殊的非终结符,它可以匹配给定词汇表中的任何标记。

  • <except!(excepted_literals)> 被添加为一个特殊的非终结符,它可以

    • 匹配给定词汇表中不包含任何 excepted_literals 的任何标记。

    • 如果标记包含任何 excepted_literals,并且至少有一个可能的子串前缀等于给定词汇表中的任何标记,则匹配子串 token[:the beginning of the first appearing excepted literal]

    • <except!(excepted_literals)> 有两种形式

      • <except!('excepted_literal')><except!("excepted_literal")>,它指定一个且仅有一个 excepted_literal
        • 例如,<except!('excepted_literal')>ar 指定为 excepted_literal。它将匹配 card 中的 c(假设 c 是一个有效的标记),并将 ard 传递给下一个语法项。
      • <except!([nonterminal])> 指定任何非终结符接受的标记属于 excepted_literals。
        • 警告:非终结符本身以及从非终结符扩展的所有非终结符不应为 <except!([nonterminal])>,否则程序可能会崩溃。
        • 例如,给定 <abc> ::= 'a'|'b'|'c'<sequence>::= <abc>|<abc><sequence> <except!([sequence])> 指定所有仅包含 abc 的标记作为 excepted_literals。
  • 在终端和 excepted_literals 中,识别并转换如下转义序列为相应的UTF-8字节:\t\r\n\u1234。然而,如 \x<hex><hex>\x00 这样的序列会被转换成原始字节。

列出可能的标记

列出的可能是当前状态下采样器可以接受的标记。以下规则定义了标记是否以给定BNF列在 Sampler::all_possible_tokens 的返回值中。

  • 采样器未终止或进入无效状态。换句话说,当前输入标记可以被采样器接受,且不存在一条路径使得所有终端和非终端都在这条路径上被消耗。

    • 例如,使用 <start>::=<A><B><C>, <A>::='boy', <B>::='next', <C>::='door',当以精确的顺序输入 boynextdoor 时,将创建一个在输入后终止的采样器,否则将进入无效状态。
    • 例如,<sequence>::=<any!>|<any!><sequence> 将创建一个在任意输入标记后终止的采样器,因为路径中的 <sequence> 变为 <any!>。换句话说,<any!> 是路径中的唯一非终端,且被消耗。
  • 对于给定的终端,只列出可能的最长标记。

    • 例如,终端 'apple' 仅在存在该标记的情况下列出标记 apple。标记如 aapapp 不会被列出。
  • 终端可以部分匹配和消耗。

    • 例如,终端 apple66666 只会列出标记 apple(见规则 1),因为 apple66666 不是一个有效的标记。输入 apple 之后,终端变为 66666,因为前缀 apple 已匹配。
  • 一个标记可以在字节级别上被多个终端匹配。

    • 例如,给定 <byte> ::= '\xf0'|'\xa0'|'xb0'<sequence>::= <byte>|<byte><sequence><sequence> 将列出所有只包含字节值 240160176 的 UTF-8 编码的标记。

路线图

  1. 添加更多示例和现成的 BNF 架构。
  2. 添加更多测试。
  3. 测试更高级的解析算法(如 Earley)并查看是否可以提高速度。
  4. Python 绑定。
  5. Huggingface transformers 集成。

依赖项

~5–8MB
~145K SLoC