-
Notifications
You must be signed in to change notification settings - Fork 31
Expand file tree
/
Copy path09-grammar.php
More file actions
88 lines (64 loc) · 2.99 KB
/
Copy path09-grammar.php
File metadata and controls
88 lines (64 loc) · 2.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env php
<?php
declare(strict_types=1);
require __DIR__ . '/../vendor/autoload.php';
use FerryAI\Core\ValueObjects\SamplingParams;
use FerryAI\LlamaBackend\Grammar\GbnfGrammar;
use FerryAI\LlamaBackend\Sampling\GreedySampler;
use FerryAI\LlamaBackend\Sampling\SamplerFactory;
use FerryAI\LlamaBackend\Sampling\TopKSampler;
use FerryAI\LlamaBackend\Sampling\TopPSampler;
echo "=== 09 — Grammar & Samplers ===\n\n";
echo "--- GBNF Grammar ---\n\n";
$yesNo = GbnfGrammar::fromString('root ::= "yes" | "no"');
printf("fromString: %s\n\n", $yesNo->toString());
$jsonSchema = [
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'age' => ['type' => 'integer'],
'city' => ['type' => 'string', 'enum' => ['Paris', 'Tokyo', 'NYC']],
],
'required' => ['name', 'age'],
];
$jsonGrammar = GbnfGrammar::fromJsonSchema($jsonSchema);
printf("fromJsonSchema:\n%s\n\n", $jsonGrammar->toString());
echo "--- Samplers ---\n\n";
$logits = array_fill(0, 100, 0.0);
$logits[0] = 10.0;
$logits[1] = 5.0;
$logits[2] = 3.0;
$params = new SamplingParams(temperature: 0.7, topK: 5, topP: 0.9);
$greedy = new GreedySampler();
printf("GreedySampler: token=%d\n", $greedy->sample($logits, $params));
$topK = new TopKSampler();
printf("TopKSampler: token=%d\n", $topK->sample($logits, $params));
$topP = new TopPSampler();
printf("TopPSampler: token=%d\n", $topP->sample($logits, $params));
$factory = new SamplerFactory();
printf("Factory(greedy): token=%d\n", $factory->create('greedy')->sample($logits, $params));
printf("Factory(top-k): token=%d\n", $factory->create('top-k')->sample($logits, $params));
printf("Factory(top-p): token=%d\n\n", $factory->create('top-p')->sample($logits, $params));
echo "--- Grammar vs no-grammar (needs llama.cpp) ---\n\n";
$llamaDir = getenv('FERRY_AI_LLAMA_DIR') ?: dirname(__DIR__) . '/models';
$llamaPath = getenv('FERRY_AI_LLAMA_MODEL') ?: $llamaDir . DIRECTORY_SEPARATOR . 'qwen-0.5b.Q4_K_M.gguf';
if (!file_exists($llamaPath)) {
echo "SKIP: GGUF model not found — set FERRY_AI_LLAMA_MODEL.\n";
echo "=== OK ===\n";
exit(0);
}
putenv('FERRY_AI_LLAMA_WRAPPER=' . $llamaDir . DIRECTORY_SEPARATOR . (PHP_OS_FAMILY === 'Windows' ? 'ferry_llama.dll' : 'ferry_llama.so'));
putenv('PATH=' . $llamaDir . PATH_SEPARATOR . (getenv('PATH') ?: ''));
\FerryAI\AI::config([
'backend' => 'llama',
'device' => getenv('FERRY_AI_LLAMA_DEVICE') ?: 'cpu',
'backends' => ['llama' => ['model_path' => $llamaPath]],
]);
$prompt = [['role' => 'user', 'content' => 'Is the sky blue? Answer only yes or no.']];
// Without grammar — the model answers freely (might reason, explain, etc.)
$free = \FerryAI\AI::chat($prompt, ['max_tokens' => 8]);
printf("no-grammar: %s\n", trim($free->text));
// With grammar — the model is constrained to exactly "yes" or "no"
$constrained = \FerryAI\AI::chat($prompt, ['grammar' => 'root ::= "yes" | "no"', 'max_tokens' => 6]);
printf("grammar: %s\n\n", trim($constrained->text));
echo "=== OK ===\n";