文法制約付きデコーディングによる小型言語モデルの Bash 生成能力向上
NVIDIA は、小型言語モデル(SLM)における Bash コード生成の精度と信頼性を向上させるため、文法制約付きデコーディング(Grammar-Constrained Decoding)技術の有効性を実証した。
キーポイント
小型モデルでの Bash 生成課題
従来の手法では、小型言語モデルが Bash スクリプトを生成する際に構文エラーや無効なパイプラインを生じやすく、AI エージェントの実用化に支障をきたしていた。
文法制約付きデコーディングの導入
Bash の形式言語(BNF 等)をモデルの生成プロセスに組み込むことで、出力されるコードが常に構文的に正しいことを保証する手法を採用した。
精度と信頼性の劇的向上
実験により、文法制約を適用することで、小型モデルからの Bash コード生成成功率が大幅に向上し、実行可能なスクリプトの割合が高まったことが確認された。
リソース効率と実用性の両立
大規模な計算資源を要さない小型モデルでも、この手法を用いることで複雑なタスク処理が可能なレベルに達し、エッジデバイスやコスト敏感な環境での AI エージェント展開を可能にする。
影響分析・編集コメントを表示
影響分析
この技術は、AI エージェントの実用化における最大の障壁の一つであった「コード生成の信頼性」を、リソース効率の高い小型モデルで解決する道筋を示しています。特に、大規模計算資源が利用できない現場やエッジ環境において、自律的なシステム管理タスクを実行可能な AI を構築するための重要な基盤技術となります。
編集コメント
小型モデルの弱点を技術的な制約で補完するアプローチは、実社会への AI エージェント導入において極めて重要なステップです。特に Bash のようなシステムコマンド生成においては、エラー許容が許されないため、この手法の価値は非常に高いと言えます。
Bash は、AI エージェントに対して公開されている最も柔軟かつ強力なインターフェースの一つです。適切なシステムにおいて、grep、curl、tar、あるいはシェルスクリプトのパイプラインを出力するモデルは、ファイルの読み込み、ワークスペースの変更、ネットワーク接続の確立、ツールの連鎖実行といった実行可能なアクションを生み出しています。NVIDIA の AI Red Team にとって、これはコマンド生成が有用な研究対象であることを意味します。より小さな言語モデルを有効でポリシーに準拠したコマンド構造へと誘導できれば、それらはより広範な環境へ展開可能なエージェントワークフローにおける信頼性の高い構成要素となります。
制約付きデコーディングは、自己回帰型言語モデルの生成プロセスにおけるサンプリング工程を変更する技術です。各生成ステップにおいて、モデルは通常通りロジットを生成しますが、トークンが選択される前に文法が適用され、分布が変更されます(多くの場合、特定のトークンを効果的にブロックすることで実現されます)。
例えば、PICARD はこの技術を用いて SQL 生成の改善を行いました。AI Red Team は同様の概念を Bash に適用し、小型モデルがコマンドラインタスクを成功裏に達成する能力を向上させました。
本記事では、Bash コマンド文法の生成パイプラインと、デコーディング中におけるその適用方法について説明します。私たちは 13 の小型言語モデルに対して 299 のタスクを実行し、平均パス率を 62.5% から 75.2% に向上させました。最も顕著な結果は Qwen3-0.6B で得られ、パス率は 16.7% から 59.2% に増加しました。
なぜ Bash
エージェントシステムは、ツール、シェル、ノートブック、ビルドシステム、CI ジョブによって実行されるコードやコマンドを生成するために、言語モデルをますます利用するようになっています。セキュリティ上の課題は、モデルがタスクを「理解」しているかどうかだけではありません。重要なのは、意図した環境にスコープを限定し、安全でない形式から制約された、構文上有効なアクションを生成できるかどうかです。
Bash はその問題のコンパクトな例です:
- 構文エラーは許容されず、タスクの複雑さが増すにつれてリスクも拡大します。
- 有効なコマンドでも、タイムアウトのないネットワークコマンドや、パスが過度に広い破壊的なコマンドなど、運用上危険な場合があります。
- シェルの組み合わせにより状態空間が乗算的に増加します。パイプ、リダイレクト、コマンド置換、heredoc(ヘアドキュメント)、ループ、条件分岐はすべて、モデルが生成すべき内容や文法がどのように適用されるかを変化させます。
- 小型モデルは呼び出すべきルートバイナリを知っていても、正確な構文、引数の順序、引用符の使い方、制御演算子、または終端処理において失敗することがよくあります。
- Bash の表現力と威力により、モデルが適切に表現できるのであれば、これが唯一必要なツールとなる可能性があります。
核心的な研究課題は次の通りです:制約付きデコーディング(constrained decoding)を用いることで、小型モデルによる 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}/
この文法は、受け入れられたすべてのコマンドが安全であることを証明するために意図されたものではありません。これは、モデルを文法に準拠したトークンのみに制限するデコーディングの境界線を定義するものです。ポリシーは、追加の文法制約としてエンコードするか、または別の制御として適用することができます。grammargen は、--help ドキュメントまたは JSON ツールスキーマから文法を生成します。
デコーディング中の文法の適用
これらの文法は、llguidance を通じて llama.cpp の推論に適用することができます。私たちの評価では、ネイティブモデルのパフォーマンスと、文法制約付きデコーディングを使用した「制約付きリトライ」モードを比較し、実行前に tree-sitter-bash で出力を確認することに焦点を当てました。
tree-sitter がエラーをスローした場合、そのエラーをコンテキストとしてネイティブモードに戻すことで、少なくともネイティブレベルのパフォーマンスを確保できるようにしました。このようにして、テスト環境で実行されるコマンドは 1 つだけにしたまま、モデルのパフォーマンスを向上させることができます。
例えば、「openssl を使用して /workspace/plain.txt の内容を Base64 エンコードしてください」とプロンプトされた場合、モデルは openssl と base64 を従うことが期待されますが、SmolLM2-360M-Instruct における最高ロジットトークンは 2 であり、これは構文上無効なコマンドの結果となります。以下に示すように openssl の文法を適用すると、代わりに次のトークンとして 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}/
同様に、以下に示すように、文法制約付きデコーディングは、小規模モデルにおける早期終了という一般的な失敗モードを軽減できます。この場合、構成された文法によりパイプ演算子の後に改行が続くことが防止され、代わりにモデルは xargs の最初のトークンとして x を使用しました。また、文法を用いることで cat が上位 5 つのロジットに含まれている点にもご注目ください。これは、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 のタスクに対して評価されました:
- Tier 1: 57 の I/O プリミティブタスク
- Tier 2: 65 のフィルタおよび変換タスク
- Tier 3: 139 の再構築およびアクションタスク
- Tier 4: 38 のシェル構文タスク
結果はパス率として報告されます。表 1 は、ネイティブなデコーディングと、tree-sitter retry(再試行)を伴う制約付きデコーディングを比較しています。
モデルネイティブパス数**
**(299 件中)率制約付きパス数**
**(299 件中)率改善幅
Qwen3-0.6B5016.7%17759.2%+42.5 ポイント
SmolLM2-360M-Instruct8829.4%17157.2%+27.8 ポイント
Qwen2.5-0.5B-Instruct13344.5%20568.6%+24.1 ポイント
Qwen3.5-0.8B15852.8%20066.9%+14.0 ポイント
gemma-3n-E2B-it19063.5%22775.9%+12.4 ポイント
SmolLM3-3B20769.2%23678.9%+9.7 ポイント
gemma-4-E2B-it21371.2%24180.6%+9.4 ポイント
Nemotron-3-Nano-4B24280.9%26488.3%+7.4 ポイント
Phi-4-mini-instruct22575.3%24381.3%+6.0 ポイント
Qwen3-1.7B21471.6%22976.6%+5.0 ポイント
Qwen3-4B23478.3%24782.6%+4.3 ポイント
Qwen3.5-4B25284.3%25886.3%+2.0 ポイント
Qwen2.5-3B-Instruct22374.6%22675.6%+1.0 ポイント
*表 1. モデルのパフォーマンスと制約付きデコーディングによる改善幅*
全 13 モデルにおいて、制約付き再試行により平均パス率は 62.5% から 75.2% に向上しました。すべてのモデルで全体的な改善が見られましたが、その効果は最も小さく、基盤性能が低いモデルほど顕著でした(図 1 参照)。表 2 のティア別平均値は、文法制約が最も効果を発揮した箇所を示しています:
ティア別 ネイティブ平均 制約付きリトライ平均 平均向上幅
ティア 1: I/O プリミティブ79.8%89.7%+10.0 ポイント
ティア 2: フィルタ/変換55.1%72.5%+17.4 ポイント
ティア 3: 再構築/アクション56.9%72.2%+15.3 ポイント
ティア 4: シェル構文69.4%69.0%-0.4 ポイント
*表 2. タスクの複雑さによるモデル性能と制約付きデコーディングからの向上幅*
ティア 4 に含まれるタスクには、コマンド文法の組み合わせを必要とするチェーン処理、バックグラウンド実行、ループなどが含まれます。最終的に、制約付き生成は有用であるためには過度に制限的すぎたか、あるいは過度に寛容すぎました。
image*図 1. モデルおよびタスクティア別のタスク成功率。制約付きデコーディングによる向上は緑色、回帰は赤色で示されています*
図 2 は、タスクとモデルの向上幅と回帰を示しています。3,887 のペア化されたモデル・タスク結果全体において、制約付きリトライは 2,248 のネイティブ成功を維持し、676 のネイティブ失敗を修正しましたが、181 のネイティブ成功が回帰し、782 の失敗は未解決のまま残りました。
言い換えれば、文法パス全体を通じて 495 のタスクが追加で成功するネット増となりましたが、タスク達成方法が複数存在する場合に文法とモデルのバイアスが競合したり、文法の不完全性がモデルのネイティブ能力を損なったりしたために、いくつかの回帰が発生しました。
image*図 2. 制約付きデコーディングによって提供されたタスク別の成功遷移*
文法は、1〜3 階層における多くのコマンド構文および表面形式の失敗を回復します。4 階層は、マルチラインスクリプト、heredocs(ヘアドキュメント)、ループ、条件分岐、コマンド置換、プロセス置換など、より豊富な Bash 構文を含むため困難であり、これにはより豊かな文法が必要か、あるいはネイティブ生成を状況に応じて選択的にフォールバックできる戦略が必要です。
改善された点
モデルがすでに正しい意図を持っているが、構文で迷走する可能性が高い場合に、文法は最も効果を発揮します。コマンド名とフラグの選択、入力値のタイプ、ターン終了時の処理における精度を向上させます。
Tree-sitter のキャッチ&リトライ機能は第 2 レイヤーを追加します。制約付きデコーディングが文法のギャップや切り捨てのために誤った Bash を生成した場合でも、評価者は実行前に構文エラーを検出し、解析エラーを含めて修正されたネイティブ出力を要求できます。これはシステムの制約に応じて、エラー訂正の単一のレイヤーとなる可能性があります。
セキュリティへの影響
制約付きデコーディングは、実行前のモデルの出力確率分布を変更します。これは有用ですが、アジェンティック AI の制御スタックにおける一つのレイヤーとしてのみ機能するものです。興味深いセキュリティ特性は以下の通りです:
- 信頼性をセキュリティ特性として。アクション表面を制限することで、アクション空間の不確実性を低減できます。
- 構文としてエンコードされたポリシー。文法により、特定の形式や引数を禁止または必須とすることができます。例えば、不安全なフラグの除外やタイムアウトの要求などが該当します。
研究はまた、一つの限界も浮き彫りにしています。生成された文法はコマンドが受け入れるものを記述しますが、特定のモデルが正しく使用するものを記述するものではありません。curl のような広範なコマンドの場合、ヘルプテキストから生成された文法では数百もの法的フラグを許可してしまう可能性があります。これは構文的には正確ですが、信頼性を意味ある形で向上させたり、戦術を強制したりするには、あまりに寛容すぎます。
これは、学習済みまたはポリシーで洗練された文法へと向かう示唆です。すべての法的コマンド空間を受け入れるのではなく、学習された文法は、特定のモデルが信頼できるサブセットと、HTTPS のみを使用する URL や必須のタイムアウト、破壊的なフラグの禁止など、堅牢な安全ルールを符号化できます。
推奨事項
文法制約付き生成を実験しているチームに向けて:
- まず狭いベンチマークから始めます。文法を変更する前に、同じプロンプトでネイティブ出力と制約付き出力の両方を測定してください。
- 構造的および行動的な観点から文法を検証します。文法は解析可能であり、既知の良いコマンドを受け入れ、既知の悪い例を拒絶すべきです。
- 向上だけでなく回帰も追跡します。パフォーマンスの純増を示しましたが、結果は、文法が意図した構造を表現できない場合に制約付きデコーディングがモデルと対立し得ることを示しています。
- 構文的成功とタスクの成功を分離して考えます。構文的に有効なコマンドでも、意味的に誤っていたり、運用上安全でない場合があります。
始め方
文法制約デコーディングは、特に実行に基づく評価や構文検証と組み合わせることで、Bash 生成エージェントに対する有望な制御手段となります。私たちの実験では、制約付きリトライにより 13 モデル全体の平均パス率が 62.5% から 75.2% に向上し、中でも Qwen3-0.6B の単一モデルにおける最大の改善は、その两倍の規模を持つモデルに匹敵する最終的なタスク成功率を達成しました。また、結果は文法制約がより複雑なシェル構文や組み合わせにおいては依然として課題を抱えていることも示しています。
これらのアイデアを独自のエージェントシステムに応用するには、文法制約デコーディングを広範な NVIDIA AI スタックにおける一つの制御手段として位置づけてください。タスクに対して良好に動作する小規模モデル(例えば NVIDIA Nemotron 3 Nano)を特定し、制約付きデコーディングによってその性能を引き上げてください。
システムを堅牢化するためには、NVIDIA NeMo Guardrails を用いて、プログラム可能なプロンプト、レスポンス、およびエージェントセキュリティチェックを評価してください。実用的なパターンは多層防御です:アクションの文法を制約し、Brev などの孤立したホストで実行をサンドボックス化し、ネイティブから制約付きへの移行を測定し、残存する実行リスクを隠蔽することなく信頼性を向上させる制御のみを採用してください。
より多くの AI セキュリティ研究とガイダンスについては、NVIDIA AI Red Team をフォローしてください。
原文を表示
Bash is one of the most flexible and powerful interfaces exposed to AI agents. In the right system, a model that emits grep, curl, tar, or a shell pipeline is producing an executable action that can read files, mutate a workspace, open network connections, and chain tools together. For the NVIDIA AI Red Team, this makes command generation a useful research target. If smaller language models can be guided into valid, policy-aware command structures, they become more reliable components for agentic workflows that can be deployed into a wider range of environments.
Constrained decoding is a technique that modifies the sampling process in autoregressive language model generation. At each generation step, the model produces logits as normal, but before a token is selected, a grammar is applied to change the distribution (often by effectively blocking certain tokens).
PICARD used this technique to improve SQL generation, for example. The AI Red Team applied the same concept to Bash to improve the ability of small models to successfully achieve command-line tasks.
This post describes an experimental pipeline for generating Bash command grammars and applying them during decoding. We ran 13 small language models against 299 tasks and improved the average pass rate from 62.5% to 75.2%. The strongest result was on Qwen3-0.6B, where the pass rate increased from 16.7% to 59.2%.
Why Bash
Agentic systems increasingly use language models to generate code and commands that are executed by tools, shells, notebooks, build systems, and CI jobs. The security challenge isn’t only whether the model “understands” a task. It is whether it can generate a syntactically valid action, scoped to the intended environment, and constrained away from unsafe forms.
Bash is a compact example of that problem:
- Syntax errors are unforgiving, and risk scales with task complexity.
- A valid command can still be operationally dangerous, such as a network command without a timeout or a destructive command with an overbroad path.
- Shell composition multiplies the state space. Pipes, redirects, command substitution, heredocs, loops, and conditionals all change what the model must emit and how a grammar would be applied.
- Small models often know the root binary to call but fail on exact syntax, argument order, quoting, control operators, or termination.
- Bash’s expressiveness and power might make it the only tool needed if the model can be suitably expressive
The core research question was: Can constrained decoding improve small-model Bash command reliability enough to make them useful for agentic workflows?
Generating grammars
Handwriting a grammar for every command is brittle. Bash commands have many flags, aliases, optional values, positional arguments, and syntax variations. Instead, grammargen turns structured command evidence into Lark grammars.
The intermediate representation captures the pieces needed for constrained decoding, like:
- Command names and aliases.
- Boolean short flags and long flags.
- Valued flags, such as -A 3 or --max-count=10.
- Positional arguments such as paths, patterns, words, and integers.
- Bounded repetition to keep the decoding state finite.
For example, a generated grep grammar includes a command-level start rule, a bounded option repetition, combined short flags, long flag alternatives, typed values, and shared terminals:
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}/
This grammar isn’t intended to prove that every accepted command is safe. It defines a decoding boundary that restricts the model to tokens compliant with the grammar. Policy can then be encoded as additional grammar restrictions or applied as a separate control. grammargen will generate grammars from --help documentation or JSON tool schemas.
Applying grammars during decoding
These grammars can then be applied to llama.cpp inference through llguidance. Our evaluation focused on comparing native model performance with a “constrained retry” mode that used grammar-constrained decoding, then checked the output with tree-sitter-bash before executing.
If tree-sitter threw an error, we passed the error back as context into native mode so that we could at least have native-level performance. In this way, we could uplift model performance while still only executing one command in the test environment.
For example, prompted with “Base64 encode the contents of /workspace/plain.txt using openssl” we expect the model to follow openssl with base64, but the highest logit token for SmolLM2-360M-Instruct is 2, which would result in a syntactically invalid command. With an openssl grammar applied as shown below, we instead get base as the next token (and autoregressively to openssl base64 and eventually successful task completion).
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}/
Similarly, as shown below, grammar constrained decoding can reduce the common small model failure mode of early termination. In this case, the composed grammar prevented a pipe operator from being followed by a newline, and instead the model used x as the first token in xargs. Also, notice how with the grammar cat is in the top 5 logits, a good sign since piping to cat is a common operation.
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
Measuring uplift
Each model was evaluated on the same 299 tasks:
- Tier 1: 57 I/O primitive tasks
- Tier 2: 65 filter and transform tasks
- Tier 3: 139 recon and action tasks
- Tier 4: 38 shell construct tasks
The results are reported as pass rates. Table 1 compares native decoding to constrained decoding with tree-sitter retry.
Across all 13 models, constrained retry improved the mean pass rate from 62.5% to 75.2%. Every model improved overall, but the gains were largest for the smallest and weakest baselines, as shown in Figure 1. The tier-level averages in Table 2 show where the grammar helped most:
Tier 4 involved tasks like chaining, backgrounding, and loops that required combinations of command grammars. Ultimately, the constrained generation was either too restrictive or too permissive to be helpful.

Figure 2 shows task and model uplift vs regressions. Across 3,887 paired model-task results, constrained retry preserved 2,248 native passes, fixed 676 native failures, regressed 181 native passes, and left 782 failures unresolved.
In other words, the grammar path produced a net gain of 495 passing tasks across the full run, but did suffer some regressions based on the grammar conflicting with model bias when there were multiple ways to accomplish the task, or grammar incompleteness undermining the model’s native capability.

The grammar recovers many command syntax and surface-form failures in tiers 1-3. Tier 4 is harder with richer Bash constructs, such as multiline scripts, heredocs, loops, conditionals, command substitution, and process substitution, which need either richer grammars or a strategy that can selectively fall back to native generation.
What improved
The grammar helps most when the model already has the right intent but is likely to drift on syntax. It improves the selection of command names and flags, typed values, and end-of-turn handling.
Tree-sitter catch and retry adds a second layer. Even when constrained decoding produces malformed Bash because of a grammar gap or truncation, the evaluator can detect syntax errors before execution and ask for a corrected native output with the parse error included. This could be just one layer of error correction, depending on the system’s constraints.
Security implications
Constrained decoding changes the probability distribution of the model’s output before execution. That makes it useful, but only as one layer in an agentic AI control stack. The interesting security properties are:
- Reliability as a security property. Restricting the action surface can decrease uncertainty in the action space.
- Policy encoded as syntax. Grammars can forbid or require forms and arguments, such as excluding insecure flags or requiring timeouts.
The research also highlights a limitation. Generated grammars describe what a command accepts, but not what a specific model uses correctly. For broad commands such as curl, a grammar generated from help text may allow hundreds of legal flags. That is syntactically accurate, but too permissive to meaningfully improve reliability or enforce tradecraft.
This points toward learned or policy-refined grammars. Instead of accepting the entire legal command space, a learned grammar can encode the subset where a given model is reliable, plus hard safety rules such as HTTPS-only URLs, mandatory timeouts, or disallowed destructive flags.
Recommendations
For teams experimenting with grammar-constrained generation:
- Start with a narrow benchmark. Measure native and constrained outputs on the same prompts before changing the grammar.
- Validate grammars structurally and behaviorally. A grammar should parse, accept known-good commands, and reject known-bad examples.
- Track regressions, not only uplift. While we showed a net increase in performance, our results show that constrained decoding can fight the model when the grammar can’t express the intended structure.
- Separate syntax success from task success. A syntactically valid command can still be semantically wrong or operationally unsafe.
Get started
Grammar-constrained decoding is a promising control for Bash-generating agents, especially when paired with execution-grounded evaluation and syntax validation. In our experiment, constrained retry improved the mean pass rate across 13 models from 62.5% to 75.2%, with the largest single-model gain on Qwen3-0.6B achieving a final task success close to models twice its size. The results also show that grammar constraints still struggle with richer shell constructs and composition.
To apply these ideas in your own agentic systems, treat grammar-constrained decoding as one control in a broader NVIDIA AI stack. Identify a small model, like NVIDIA Nemotron 3 Nano that performs well on your task and uplift it with constrained decoding.
To harden the system, evaluate programmable prompt, response, and agentic-security checks with NVIDIA NeMo Guardrails. The practical pattern is defense in depth: constrain the action grammar, sandbox execution with isolated hosts like Brev, measure native-to-constrained transitions, and promote only controls that improve reliability without hiding residual execution risk.
For more AI security research and guidance, follow the NVIDIA AI Red Team.
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み