元鉴
返回中文阅读流

NVIDIA Developer Blog

通过语法约束解码改进小语言模型中的 Bash 生成

Bash 是向 AI 代理暴露的最灵活强大的接口之一。在合适的系统中,能够输出 grep、curl、tar 或 shell 管道的模型是...

中文内容

已翻译official company source英文原文2026-05-26

Bash 是暴露给 AI 智能体的最灵活、最强大的接口之一。在合适的系统中,一个输出 grep、curl、tar 或 shell 管道的模型,正在生成一种可执行操作,能够读取文件、修改工作区、打开网络连接,并将多个工具串联起来。对于 NVIDIA AI Red Team 来说,这使得命令生成成为一个有用的研究目标。如果较小的语言模型能够被引导生成有效且符合策略的命令结构,它们就会成为智能体工作流中更可靠的组件,并可部署到更广泛的环境中。

约束解码是一种修改自回归语言模型生成过程中采样流程的技术。在每个生成步骤中,模型会像往常一样产生 logits,但在选择 token 之前,会应用一种语法来改变分布(通常是通过有效阻止某些 token)。

例如,PICARD 使用了这种技术来改进 SQL 生成。AI Red Team 将同样的概念应用于 Bash,以提升小模型成功完成命令行任务的能力。

本文介绍了一个用于生成 Bash 命令语法并在解码过程中应用这些语法的实验性流水线。我们让 13 个小型语言模型执行 299 项任务,并将平均通过率从 62.5% 提高到 75.2%。最强的结果出现在 Qwen3-0.6B 上,其通过率从 16.7% 提高到 59.2%。

为什么是 Bash

智能体系统越来越多地使用语言模型生成代码和命令,并由工具、shell、notebook、构建系统和 CI 作业执行。安全挑战不仅在于模型是否“理解”某项任务,而在于它是否能够生成语法有效、限定在预期环境范围内,并且受约束而避免不安全形式的操作。

Bash 是这一问题的一个紧凑示例:

  • 语法错误是不可宽恕的,并且风险会随着任务复杂性而增加。
  • 有效命令在操作上仍可能具有危险性,例如没有超时设置的网络命令,或路径范围过宽的破坏性命令。
  • Shell 组合会成倍扩大状态空间。管道、重定向、命令替换、heredoc、循环和条件语句都会改变模型必须输出的内容以及语法规则的应用方式。
  • 小模型通常知道要调用的根二进制文件,但在精确语法、参数顺序、引号、控制运算符或终止方面会出错。
  • 如果模型能够具备适当的表达能力,Bash 的表现力和强大功能可能使其成为唯一所需的工具

核心研究问题是:受约束解码能否足够提升小模型 Bash 命令的可靠性,使其可用于智能体工作流?

生成语法

为每个命令手写语法规则很脆弱。Bash 命令有许多标志、别名、可选值、位置参数和语法变体。相反,grammargen 会将结构化的命令证据转换为 Lark 语法。

中间表示会捕获受约束解码所需的组成部分,例如:

  • 命令名称和别名。
  • 布尔型短标志和长标志。
  • 带值标志,例如 -A 3 或 --max-count=10。
  • 位置参数,例如路径、模式、单词和整数。
  • 有界重复,以保持解码状态有限。

例如,生成的 grep 语法包括命令级起始规则、有界选项重复、组合短标志、长标志替代项、类型化值以及共享终结符:

start: "grep" (WS grep_opt){0,8} WS WORD (WS PATH){0,5}
grep_opt: "-" /[EFGHILPRTUVZabchilnoqrsvwxz]+/
        | "-e" WS WORD
        | "-f" WS PATH
        | "-m" WS /[0-9]+/
        | "--ignore-case"
        | "--recursive"
        | "--regexp" ("=" | WS) WORD
        | "--file" ("=" | WS) PATH
        | "--max-count" ("=" | WS) /[0-9]+/
WORD: /[^\s|><&;()]{1,200}/

该语法并不旨在证明每个被接受的命令都是安全的。它定义了一个解码边界,将模型限制为生成符合语法的 token。随后,可以将策略编码为额外的语法限制,或作为单独的控制措施应用。grammargen 将从 --help 文档或 JSON 工具 schema 生成语法。

在解码过程中应用语法

然后,这些语法可以通过 llguidance 应用于 llama.cpp 推理。我们的评估重点是将原生模型性能与一种“受约束重试”模式进行比较;该模式使用语法约束解码,然后在执行前用 tree-sitter-bash 检查输出。

如果 tree-sitter 抛出错误,我们会将该错误作为上下文传回原生模式,以便至少获得原生级别的性能。通过这种方式,我们可以提升模型性能,同时在测试环境中仍然只执行一条命令。

例如,当提示为“Base64 encode the contents of /workspace/plain.txt using openssl”时,我们期望模型在 openssl 后接 base64,但 SmolLM2-360M-Instruct 的最高 logit token 是 2,这会导致一条语法无效的命令。如下所示,在应用 openssl 语法后,我们得到的下一个 token 变为 base(并以自回归方式生成到 openssl base64,最终成功完成任务)。

start: "openssl" WS ssl_command

ssl_command: ssl_enc
           | ssl_dgst
           | ssl_rand
           | ssl_genrsa
           | ssl_req
           | ssl_x509
           | ssl_s_client
           | ssl_version

ssl_enc: ("enc" | "base64" | "aes-256-cbc" | "des3") (WS enc_opt){0,8}
ssl_dgst: ("dgst" | "sha256" | "sha512" | "md5") (WS dgst_opt){0,8}
ssl_rand: "rand" (WS rand_opt){0,8}
ssl_genrsa: "genrsa" (WS genrsa_opt){0,8}
ssl_req: "req" (WS req_opt){0,8}
ssl_x509: "x509" (WS x509_opt){0,8}
ssl_s_client: "s_client" (WS s_client_opt){0,8}
ssl_version: "version" (WS "-a"){0,2}

enc_opt: "-e" | "-d" | "-a" | "-base64"
       | "-aes-256-cbc" | "-aes-128-cbc" | "-des3" | "-des-ede3-cbc"
       | "-in" WS PATH | "-out" WS PATH
       | "-k" WS WORD | "-pass" WS WORD
       | "-salt" | "-nosalt" | "-pbkdf2"

dgst_opt: "-" /[a-z0-9]+/
        | "-out" WS PATH
        | PATH

rand_opt: "-hex" | "-base64" | "-out" WS PATH
        | /[0-9]+/

genrsa_opt: "-out" WS PATH | /[0-9]+/

req_opt: "-new" | "-x509" | "-nodes" | "-newkey" WS WORD
       | "-key" WS PATH | "-out" WS PATH
       | "-subj" WS SQ_STRING | "-days" WS /[0-9]+/

x509_opt: "-in" WS PATH | "-out" WS PATH | "-text" | "-noout"
        | "-dates" | "-subject" | "-issuer" | "-serial"
        | "-fingerprint" | "-inform" WS /[A-Z]+/ | "-outform" WS /[A-Z]+/

s_client_opt: "-connect" WS HOST_PORT
            | "-servername" WS WORD
            | "-showcerts"
            | "-CAfile" WS PATH
            | "-verify_return_error"
            | "-brief"

HOST_PORT: /[a-zA-Z0-9.\-]+:[0-9]+/
WORD: /[^\s|><&;]{1,200}/

同样,如下所示,语法约束解码可以减少小模型常见的过早终止失效模式。在这种情况下,组合语法阻止了管道操作符后紧跟换行符,模型转而使用 x 作为 xargs 中的第一个 token。另外,请注意,在有语法约束时 cat 位于前 5 个 logits 中,这是一个好迹象,因为通过管道传给 cat 是一种常见操作。

gguf: SmolLM2-360M-Instruct.Q4_K_M.gguf
task: xargs_01
prompt: "Read filenames from /workspace/files.txt and delete them using xargs and rm"
canonical: cat /workspace/files.txt | xargs rm
assistant prefix: "cat /workspace/files.txt | "
grammar commands: ["cat", "xargs", "pipe"]
legal next tokens after mask: 37

native top logits
rank    token piece                                   logit
1         198 "\n"                                  17.3023
2        1792 " x"                                  16.1400
3         907 " #"                                  12.4901
4          33 "1"                                   12.4090
5         693 "xt"                                  12.3238

grammar-masked top logits
rank    token piece                                   logit
1        1792 " x"                                  16.1400
2         197 "\t"                                   9.6412
3         104 "x"                                    8.5847
4        2644 " cat"                                 7.3603
5         265 " c"                                   5.2345

衡量提升

每个模型都在相同的 299 项任务上进行评估:

  • 第 1 层:57 项 I/O 基础任务
  • 第 2 层:65 项过滤和转换任务
  • 第 3 层:139 个侦察和操作任务
  • 第 4 层:38 个 shell 构造任务

结果以通过率形式报告。表 1 比较了原生解码与采用 tree-sitter 重试的约束解码。

ModelNative passed
(out of 299)RateConstrained passed
(out of 299)RateUpliftQwen3-0.6B5016.7%17759.2%+42.5 ptsSmolLM2-360M-Instruct8829.4%17157.2%+27.8 ptsQwen2.5-0.5B-Instruct13344.5%20568.6%+24.1 ptsQwen3.5-0.8B15852.8%20066.9%+14.0 ptsgemma-3n-E2B-it19063.5%22775.9%+12.4 ptsSmolLM3-3B20769.2%23678.9%+9.7 ptsgemma-4-E2B-it21371.2%24180.6%+9.4 ptsNemotron-3-Nano-4B24280.9%26488.3%+7.4 ptsPhi-4-mini-instruct22575.3%24381.3%+6.0 ptsQwen3-1.7B21471.6%22976.6%+5.0 ptsQwen3-4B23478.3%24782.6%+4.3 ptsQwen3.5-4B25284.3%25886.3%+2.0 ptsQwen2.5-3B-Instruct22374.6%22675.6%+1.0 pts
表 1. 模型性能以及约束解码带来的提升

在全部 13 个模型中,受约束重试将平均通过率从 62.5% 提高到 75.2%。每个模型的整体表现都有所提升,但如图 1 所示,提升幅度最大的是规模最小、基线最弱的模型。表 2 中的分层平均值显示了语法在哪些方面帮助最大:

TierNative averageConstrained retry averageAverage upliftTier 1: I/O primitives79.8%89.7%+10.0 ptsTier 2: Filter/transform55.1%72.5%+17.4 ptsTier 3: Recon/action56.9%72.2%+15.3 ptsTier 4: Shell constructs69.4%69.0%-0.4 pts
表 2. 按任务层级复杂度划分的模型表现以及受约束解码带来的提升

第 4 层级涉及诸如命令串联、后台运行和循环等任务,需要组合多种命令语法。最终,受约束生成要么过于严格,要么过于宽松,难以发挥帮助作用。

A bar chart showing the pass rate performance of 13 models tested against four tiers of tasks and the relative uplift provided by constrained decoding.A bar chart showing the pass rate performance of 13 models tested against four tiers of tasks and the relative uplift provided by constrained decoding.
图 1. 按模型和任务层级划分的任务成功率,其中绿色表示受约束解码带来的提升,红色表示回退

图 2 展示了任务和模型提升与回退的对比。在 3,887 组配对的模型-任务结果中,受约束重试保留了 2,248 个原生通过,修复了 676 个原生失败,导致 181 个原生通过回退,并留下 782 个失败未解决。

换言之,语法路径在整个运行中带来了 495 个通过任务的净增益,但也确实出现了一些回退,原因包括:当存在多种完成任务的方式时,语法与模型偏置发生冲突,或者语法不完整削弱了模型的原生能力。

A horizontal stacked bar chart for the 13 models showing comparing per-task performance between native and constrained modes, with each task categorized as passing both, uplifted from failing to passing, regressed from passing to failing, oA horizontal stacked bar chart for the 13 models showing comparing per-task performance between native and constrained modes, with each task categorized as passing both, uplifted from failing to passing, regressed from passing to failing, o
图 2. 受约束解码提供的逐任务成功状态转移

该语法在第 1-3 层中恢复了许多命令语法和表层形式失败。第 4 层由于包含更丰富的 Bash 构造而更难,例如多行脚本、heredocs、循环、条件语句、命令替换和进程替换,这需要更丰富的语法,或一种能够选择性回退到原生生成的策略。

改进之处

当模型已经具备正确意图但可能在语法上偏离时,语法约束最有帮助。它改进了命令名称和标志、类型化值以及回合结束处理的选择。

Tree-sitter 捕获并重试增加了第二层保障。即使受约束解码由于语法缺口或截断而生成格式错误的 Bash,评估器也可以在执行前检测语法错误,并请求包含解析错误信息的修正后的原生输出。这可能只是错误纠正的一层,具体取决于系统的约束条件。

安全影响

约束解码会在执行之前改变模型输出的概率分布。这使其很有用,但它只是智能体 AI 控制栈中的一层。其有意义的安全属性包括:

  • 可靠性作为一种安全属性。限制动作表面可以降低动作空间中的不确定性。
  • 将策略编码为语法。语法可以禁止或要求特定形式和参数,例如排除不安全的标志或要求设置超时。

该研究还强调了一个局限性。生成的语法描述的是某个命令接受什么,而不是某个特定模型能正确使用什么。对于 curl 等范围较广的命令,根据帮助文本生成的语法可能允许数百个合法标志。这在语法上是准确的,但过于宽松,无法有意义地提高可靠性或强制执行操作规范。

这指向了经过学习或策略精炼的语法。与其接受整个合法命令空间,经过学习的语法可以编码给定模型可靠的子集,并加入硬性安全规则,例如仅限 HTTPS 的 URL、强制超时,或禁止破坏性标志。

对于正在尝试语法约束生成的团队:

  1. 从一个范围较窄的基准开始。在更改语法之前,在相同提示上衡量原生输出和受约束输出。
  2. 从结构和行为两方面验证语法。语法应能解析、接受已知正确的命令,并拒绝已知错误的示例。
  3. 跟踪性能回退,而不仅是提升。虽然我们展示了整体性能的净增长,但结果表明,当语法无法表达预期结构时,约束解码可能会与模型产生冲突。
  4. 将语法成功与任务成功区分开来。语法上有效的命令仍然可能在语义上错误,或在操作上不安全。

开始使用

语法约束解码对于生成 Bash 的智能体而言是一种有前景的控制手段,尤其是在与基于执行的评估和语法验证相结合时。在我们的实验中,约束重试将 13 个模型的平均通过率从 62.5% 提高到 75.2%,其中 Qwen3-0.6B 取得了最大的单模型提升,最终任务成功率接近其两倍规模的模型。结果还表明,语法约束在处理更丰富的 shell 构造和组合时仍然存在困难。

要在你自己的智能体系统中应用这些理念,请将语法约束解码视为更广泛的 NVIDIA AI 技术栈中的一项控制措施。选择一个小模型,例如在你的任务上表现良好的 NVIDIA Nemotron 3 Nano,并通过约束解码对其进行提升。

为了加固系统,请使用 NVIDIA NeMo Guardrails 评估可编程的提示、响应和智能体安全检查。实际模式是纵深防御:约束动作语法,使用 Brev 等隔离主机对执行进行沙箱化,衡量原生到受约束状态的转换,并且只推广那些在不掩盖残余执行风险的情况下提高可靠性的控制措施。

如需更多 AI 安全研究和指导,请关注 NVIDIA AI Red Team。

Like

标签

原文标题

Improving Bash Generation in Small Language Models with Grammar-Constrained Decoding