使用 llama-cpp-python 实现受限推理 (Constrained Inference),通过 GBNF 语法强制本地 LLM 输出结构化 JSON。
演示如何使用语法约束让本地大语言模型:
- 🔒 强制输出 JSON - 无需在 Prompt 中反复强调格式
- ⚡ 提高可靠性 - 避免模型"胡言乱语"或输出非法格式
- 🎨 自定义结构 - 通过 GBNF 语法定义任意输出格式
.
├── main.py # 基础推理示例 (带 logprobs)
├── grammar.py # GBNF 语法约束推理
├── .env.local # 环境变量配置 (需手动创建)
└── pyproject.toml # 项目依赖
# 安装 uv (如果还没有)
curl -LsSf https://astral.sh/uv/install.sh | sh
# 创建虚拟环境
uv venv
# 激活环境
source .venv/bin/activate # macOS/Linux
# .venv\Scripts\activate # Windows
# 安装依赖
uv pip install llama-cpp-python python-dotenv创建 .env.local 文件:
MODEL_PATH=/path/to/your/model.gguf示例(使用 LM Studio 下载的模型):
MODEL_PATH=/Users/你的用户名/.cache/lm-studio/models/lmstudio-community/Qwen3-4B-Instruct-2507-GGUF/Qwen3-4B-Instruct-2507-Q4_K_M.gguf
# 基础推理 (无约束)
python main.py
# 受限推理 (强制 JSON 输出)
python grammar.pyGBNF (GGML BNF) 是一种类似正则表达式的语法定义语言,用于约束模型输出:
# 定义 JSON 对象格式
specific_grammar_str = r"""
root ::= object
object ::= "{" space field-name "," space field-age "}" space
field-name ::= "\"name\"" ":" space string
field-age ::= "\"age\"" ":" space number
string ::= "\"" [^"]* "\""
number ::= [0-9]+
space ::= [ \t\n]*
"""
# 编译并挂载到推理
grammar = LlamaGrammar.from_string(specific_grammar_str)
output = llm(prompt, grammar=grammar)| 对比项 | 普通推理 | 受限推理 |
|---|---|---|
| 输出格式 | 不可控,可能乱码 | 严格符合 GBNF 定义 |
| Prompt 要求 | 需反复强调"输出 JSON" | 不需要,语法已锁定 |
| 可靠性 | 依赖模型训练质量 | 100% 保证格式正确 |
| 性能 | 略快 | 稍慢(需额外语法检查) |
- llama-cpp-python - Python 绑定库
- Metal (Apple Silicon) - GPU 加速 (
n_gpu_layers=-1) - Qwen3-4B-Instruct - 示例模型
- GBNF 语法 - 输出约束
模型输出: 以下是三个程序员喜欢的颜色的 RGB 值:
1. 蓝色:(0, 128, 255)
2. 绿色:(0, 255, 0)
3. 红色:(255, 0, 0)
{
"name": "Elon Musk",
"age": 52
}- 支持更复杂的嵌套 JSON 结构
- 自动从 Pydantic 模型生成 GBNF 语法
- 添加流式输出示例
- 性能基准测试
欢迎提交 Issue 和 Pull Request!
MIT License