1. Go to this page and download the library: Download mikibuilder/llm-vcr library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
mikibuilder / llm-vcr example snippets
$result = $this->analyzer->analyze('I cannot access my account');
$this->assertSame('access', $result->category); // 🎲 passes sometimes
$platform = new RecordingPlatform(
inner: new GroqPlatform($apiKey), // your real provider
cassetteDir: __DIR__ . '/cassettes',
mode: Mode::fromEnv(), // record locally, replay in CI
);
use MikiBuilder\LlmVcr\Bridge\Symfony\PlatformFactory;
final class TicketAnalyzer
{
public function __construct(
private PlatformFactory $vcr,
private MyLlmClient $client,
) {}
public function analyze(string $text): TicketDto
{
$platform = $this->vcr->wrap($this->client, cassette: 'tickets');
$result = $platform->invoke('llama-3.1-8b-instant', [
['role' => 'system', 'content' => 'Classify tickets. Respond with JSON.'],
['role' => 'user', 'content' => $text],
]);
return TicketDto::fromArray($result->asStructured() ?? []);
}
}
use MikiBuilder\LlmVcr\Testing\InteractsWithLlm;
final class TicketTest extends TestCase
{
use InteractsWithLlm;
public function testClassifiesAnAccessProblem(): void
{
$platform = $this->recordLlm(GroqPlatform::fromEnv());
$result = $platform->invoke('llama-3.1-8b-instant', [
['role' => 'system', 'content' => 'Classify tickets. Respond with JSON.'],
['role' => 'user', 'content' => 'I cannot access my account.'],
]);
$this->assertNoLiveLlmCalls();
$this->assertLlmJsonShape([
'category' => 'string',
'urgency' => 'int',
], $result);
}
}
use function MikiBuilder\LlmVcr\Testing\recordLlm;
it('classifies an access problem', function () {
$platform = recordLlm(GroqPlatform::fromEnv(), cassette: 'tickets');
$result = $platform->invoke('llama-3.1-8b-instant', [...]);
expect($platform)->toHaveMadeNoLiveCalls()->toHaveReplayed(1);
expect($result)->toBeLlmJson()
->toMatchLlmShape(['category' => 'string', 'urgency' => 'int'])
->toHaveLlmValueIn(['access', 'billing'], 'category');
});
// 1. Exact — the prompt never varies
new ExactMatcher();
// 2. Placeholders — YOU declare what varies. Zero false positives.
new PlaceholderMatcher([
'order_id' => '/ORD-\d+/',
'amount' => '/\d+\.\d{2} ?€/',
]);
// "Review order ORD-4417 for 89.90 €"
// "Review order ORD-9902 for 12.50 €" → same cassette
// 3. Semantic — tolerates rewording (default)
new SemanticMatcher(threshold: 0.82);
new Redactor(); // credentials + PII
Redactor::credentialsOnly(); // credentials only
new Redactor(customRules: ['/\bCASE-\d{4}\b/' => '<REDACTED:CASE>']);
new GroqPlatform($key, baseUrl: 'https://openrouter.ai/api/v1');
new GroqPlatform('ollama', baseUrl: 'http://localhost:11434/v1');
bash
git clone https://github.com/MikiBuilder/llm-vcr.git
cd llm-vcr
composer install
php examples/demo.php
bash
cp .env.example .env # paste your GROQ_API_KEY
php examples/groq_record.php # first run: hits the API
php examples/groq_record.php # second run: from the cassette, no network
bash
php bin/llm-vcr drift # console report
php bin/llm-vcr drift --markdown # table to paste into a PR
php bin/llm-vcr stats # summary of recorded cassettes
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.