0
# Grammar and Structured Generation
1
2
Constrained text generation using formal grammars (GBNF), JSON Schema validation, and built-in templates for structured outputs like JSON, code, and domain-specific formats.
3
4
## Capabilities
5
6
### Grammar-Based Generation
7
8
Control model output using formal grammar rules in GBNF (GGML BNF) format.
9
10
```python { .api }
11
class LlamaGrammar:
12
def __init__(self, grammar_str: str, verbose: bool = True):
13
"""
14
Initialize grammar from GBNF string.
15
16
Args:
17
grammar_str: Grammar rules in GBNF format
18
verbose: Enable verbose logging
19
"""
20
21
@classmethod
22
def from_string(
23
cls,
24
grammar_str: str,
25
verbose: bool = True
26
) -> "LlamaGrammar":
27
"""
28
Create grammar from GBNF string.
29
30
Args:
31
grammar_str: Grammar rules in GBNF format
32
verbose: Enable verbose logging
33
34
Returns:
35
LlamaGrammar instance
36
"""
37
38
@classmethod
39
def from_file(
40
cls,
41
file_path: str,
42
verbose: bool = True
43
) -> "LlamaGrammar":
44
"""
45
Create grammar from GBNF file.
46
47
Args:
48
file_path: Path to GBNF grammar file
49
verbose: Enable verbose logging
50
51
Returns:
52
LlamaGrammar instance
53
"""
54
55
@classmethod
56
def from_json_schema(
57
cls,
58
json_schema: str,
59
verbose: bool = True
60
) -> "LlamaGrammar":
61
"""
62
Create grammar from JSON Schema string.
63
64
Args:
65
json_schema: JSON Schema as string (use json.dumps() to convert dict)
66
verbose: Enable verbose logging
67
68
Returns:
69
LlamaGrammar instance with schema constraints
70
"""
71
```
72
73
### JSON Schema Conversion
74
75
Convert JSON Schema specifications to GBNF grammar format for structured JSON generation.
76
77
```python { .api }
78
def json_schema_to_gbnf(
79
schema: dict,
80
prop_order: Optional[List[str]] = None,
81
allow_fetch: bool = True,
82
dotall: bool = False,
83
raw_pattern: bool = False
84
) -> str:
85
"""
86
Convert JSON Schema to GBNF grammar format.
87
88
Args:
89
schema: JSON Schema dictionary
90
prop_order: Property ordering for object serialization
91
allow_fetch: Allow fetching external schema references
92
dotall: Enable dotall mode for regex patterns
93
raw_pattern: Use raw pattern matching
94
95
Returns:
96
GBNF grammar string
97
"""
98
99
class SchemaConverter:
100
def __init__(
101
self,
102
prop_order: Optional[List[str]] = None,
103
allow_fetch: bool = True,
104
dotall: bool = False,
105
raw_pattern: bool = False
106
):
107
"""
108
Initialize schema converter.
109
110
Args:
111
prop_order: Default property ordering
112
allow_fetch: Allow external references
113
dotall: Dotall mode for patterns
114
raw_pattern: Raw pattern mode
115
"""
116
117
def convert(self, schema: dict) -> str:
118
"""
119
Convert schema to GBNF format.
120
121
Args:
122
schema: JSON Schema dictionary
123
124
Returns:
125
GBNF grammar string
126
"""
127
```
128
129
### Built-in Grammar Rules
130
131
Pre-defined grammar building blocks for common patterns.
132
133
```python { .api }
134
class BuiltinRule:
135
def __init__(self, rule_name: str, content: str):
136
"""
137
Built-in grammar rule definition.
138
139
Args:
140
rule_name: Name of the rule
141
content: Rule content in GBNF format
142
"""
143
self.rule_name = rule_name
144
self.content = content
145
```
146
147
## Pre-defined Grammar Templates
148
149
```python { .api }
150
# Arithmetic expressions
151
ARITHMETIC_GBNF: str
152
153
# C-like programming language syntax
154
C_GBNF: str
155
156
# Chess notation (algebraic notation)
157
CHESS_GBNF: str
158
159
# Japanese text patterns
160
JAPANESE_GBNF: str
161
162
# JSON array format
163
JSON_ARR_GBNF: str
164
165
# JSON object format
166
JSON_GBNF: str
167
168
# List structures
169
LIST_GBNF: str
170
171
# Default grammar root rule
172
LLAMA_GRAMMAR_DEFAULT_ROOT: str
173
```
174
175
## Usage Examples
176
177
### Basic Grammar Usage
178
179
```python
180
from llama_cpp import Llama, LlamaGrammar
181
182
# Initialize model
183
llm = Llama(model_path="./models/llama-2-7b.gguf")
184
185
# Create simple grammar for yes/no responses
186
yes_no_grammar = """
187
root ::= response
188
response ::= "yes" | "no" | "Yes" | "No" | "YES" | "NO"
189
"""
190
191
grammar = LlamaGrammar.from_string(yes_no_grammar)
192
193
# Generate constrained response
194
response = llm.create_completion(
195
prompt="Do you like pizza? Answer with yes or no:",
196
max_tokens=10,
197
grammar=grammar,
198
)
199
200
print(response['choices'][0]['text']) # Will be "yes", "no", etc.
201
```
202
203
### JSON Schema Generation
204
205
```python
206
from llama_cpp import Llama, LlamaGrammar
207
208
llm = Llama(model_path="./models/llama-2-7b.gguf")
209
210
# Define JSON schema for person data
211
person_schema = {
212
"type": "object",
213
"properties": {
214
"name": {"type": "string"},
215
"age": {"type": "integer", "minimum": 0, "maximum": 150},
216
"email": {"type": "string", "format": "email"},
217
"hobbies": {
218
"type": "array",
219
"items": {"type": "string"},
220
"maxItems": 5
221
}
222
},
223
"required": ["name", "age"],
224
"additionalProperties": False
225
}
226
227
# Create grammar from schema (convert dict to string first)
228
import json
229
grammar = LlamaGrammar.from_json_schema(json.dumps(json.dumps(person_schema)))
230
231
# Generate valid JSON
232
response = llm.create_completion(
233
prompt="Generate a person's information in JSON format:",
234
max_tokens=200,
235
grammar=grammar,
236
temperature=0.7,
237
)
238
239
import json
240
generated_json = json.loads(response['choices'][0]['text'])
241
print(json.dumps(generated_json, indent=2))
242
```
243
244
### Pre-defined Grammar Templates
245
246
```python
247
from llama_cpp import Llama, LlamaGrammar
248
from llama_cpp.llama_grammar import JSON_GBNF, ARITHMETIC_GBNF
249
250
llm = Llama(model_path="./models/model.gguf")
251
252
# Use built-in JSON grammar
253
json_grammar = LlamaGrammar.from_string(JSON_GBNF)
254
255
response = llm.create_completion(
256
prompt="Create a JSON object describing a book:",
257
max_tokens=150,
258
grammar=json_grammar,
259
)
260
261
print("JSON output:", response['choices'][0]['text'])
262
263
# Use arithmetic grammar
264
math_grammar = LlamaGrammar.from_string(ARITHMETIC_GBNF)
265
266
math_response = llm.create_completion(
267
prompt="Write a mathematical expression:",
268
max_tokens=50,
269
grammar=math_grammar,
270
)
271
272
print("Math expression:", math_response['choices'][0]['text'])
273
```
274
275
### Complex Grammar Rules
276
277
```python
278
# Create grammar for structured code generation
279
code_grammar = """
280
root ::= program
281
program ::= statement+
282
statement ::= assignment | function_call | comment
283
assignment ::= variable " = " expression "\\n"
284
function_call ::= function_name "(" arguments? ")" "\\n"
285
comment ::= "# " [^\\n]* "\\n"
286
variable ::= [a-zA-Z_][a-zA-Z0-9_]*
287
function_name ::= [a-zA-Z_][a-zA-Z0-9_]*
288
expression ::= number | string | variable
289
arguments ::= expression ("," " " expression)*
290
number ::= [0-9]+
291
string ::= "\\"" [^"]* "\\""
292
"""
293
294
grammar = LlamaGrammar.from_string(code_grammar)
295
296
response = llm.create_completion(
297
prompt="Write a Python program that processes data:",
298
max_tokens=200,
299
grammar=grammar,
300
)
301
302
print("Generated code:")
303
print(response['choices'][0]['text'])
304
```
305
306
### Multi-step Structured Generation
307
308
```python
309
# Generate structured conversation data
310
conversation_schema = {
311
"type": "object",
312
"properties": {
313
"conversation_id": {"type": "string"},
314
"participants": {
315
"type": "array",
316
"items": {"type": "string"},
317
"minItems": 2,
318
"maxItems": 4
319
},
320
"messages": {
321
"type": "array",
322
"items": {
323
"type": "object",
324
"properties": {
325
"speaker": {"type": "string"},
326
"message": {"type": "string"},
327
"timestamp": {"type": "string", "format": "time"}
328
},
329
"required": ["speaker", "message"]
330
},
331
"minItems": 1
332
},
333
"topic": {"type": "string"},
334
"sentiment": {"enum": ["positive", "negative", "neutral"]}
335
},
336
"required": ["conversation_id", "participants", "messages", "topic"]
337
}
338
339
conversation_grammar = LlamaGrammar.from_json_schema(json.dumps(conversation_schema))
340
341
# Generate structured conversation
342
response = llm.create_completion(
343
prompt="Create a conversation between friends about technology:",
344
max_tokens=300,
345
grammar=conversation_grammar,
346
temperature=0.8,
347
)
348
349
conversation_data = json.loads(response['choices'][0]['text'])
350
print("Generated conversation:")
351
print(json.dumps(conversation_data, indent=2))
352
```
353
354
### Grammar File Usage
355
356
```python
357
# Save grammar to file
358
weather_grammar = """
359
root ::= weather_report
360
weather_report ::= location " weather: " condition " " temperature " " humidity
361
location ::= [A-Z][a-z]+ ("," " " [A-Z][a-z]+)?
362
condition ::= "sunny" | "cloudy" | "rainy" | "snowy" | "overcast"
363
temperature ::= [0-9]+ "°" ("C" | "F")
364
humidity ::= [0-9]+ "%"
365
"""
366
367
# Write to file
368
with open("weather_grammar.gbnf", "w") as f:
369
f.write(weather_grammar)
370
371
# Load from file
372
grammar = LlamaGrammar.from_file("weather_grammar.gbnf")
373
374
response = llm.create_completion(
375
prompt="Give me a weather report for New York:",
376
max_tokens=50,
377
grammar=grammar,
378
)
379
380
print("Weather report:", response['choices'][0]['text'])
381
```
382
383
### Advanced Schema Patterns
384
385
```python
386
# Complex nested schema with arrays and objects
387
api_response_schema = {
388
"type": "object",
389
"properties": {
390
"status": {"enum": ["success", "error"]},
391
"data": {
392
"oneOf": [
393
{
394
"type": "object",
395
"properties": {
396
"users": {
397
"type": "array",
398
"items": {
399
"type": "object",
400
"properties": {
401
"id": {"type": "integer"},
402
"username": {"type": "string"},
403
"active": {"type": "boolean"}
404
},
405
"required": ["id", "username"]
406
}
407
},
408
"total_count": {"type": "integer"}
409
}
410
},
411
{
412
"type": "null"
413
}
414
]
415
},
416
"error": {
417
"type": "object",
418
"properties": {
419
"code": {"type": "integer"},
420
"message": {"type": "string"}
421
}
422
}
423
},
424
"required": ["status"]
425
}
426
427
api_grammar = LlamaGrammar.from_json_schema(json.dumps(api_response_schema))
428
429
# Generate API response
430
response = llm.create_completion(
431
prompt="Generate a successful API response with user data:",
432
max_tokens=250,
433
grammar=api_grammar,
434
)
435
436
api_data = json.loads(response['choices'][0]['text'])
437
print("API Response:")
438
print(json.dumps(api_data, indent=2))
439
```
440
441
### Grammar Debugging
442
443
```python
444
# Enable verbose mode for grammar debugging
445
debug_grammar = """
446
root ::= greeting
447
greeting ::= salutation " " name punctuation
448
salutation ::= "Hello" | "Hi" | "Hey"
449
name ::= [A-Z][a-z]+
450
punctuation ::= "!" | "."
451
"""
452
453
grammar = LlamaGrammar.from_string(debug_grammar, verbose=True)
454
455
# This will show grammar parsing information
456
response = llm.create_completion(
457
prompt="Say hello to someone:",
458
max_tokens=20,
459
grammar=grammar,
460
)
461
462
print("Greeting:", response['choices'][0]['text'])
463
```
464
465
### Schema Validation Integration
466
467
```python
468
import jsonschema
469
470
# Create schema and corresponding grammar
471
product_schema = {
472
"type": "object",
473
"properties": {
474
"product_name": {"type": "string"},
475
"price": {"type": "number", "minimum": 0},
476
"in_stock": {"type": "boolean"},
477
"categories": {
478
"type": "array",
479
"items": {"type": "string"},
480
"uniqueItems": True
481
}
482
},
483
"required": ["product_name", "price", "in_stock"]
484
}
485
486
grammar = LlamaGrammar.from_json_schema(json.dumps(product_schema))
487
488
# Generate product data
489
response = llm.create_completion(
490
prompt="Create product information for an electronic device:",
491
max_tokens=150,
492
grammar=grammar,
493
)
494
495
# Validate against original schema
496
try:
497
product_data = json.loads(response['choices'][0]['text'])
498
jsonschema.validate(product_data, product_schema))
499
print("Generated valid product data:")
500
print(json.dumps(product_data, indent=2))
501
except jsonschema.ValidationError as e:
502
print(f"Validation error: {e}")
503
except json.JSONDecodeError as e:
504
print(f"JSON parsing error: {e}")
505
```