PHP code example of cognesy / instructor-php

1. Go to this page and download the library: Download cognesy/instructor-php 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/ */

    

cognesy / instructor-php example snippets


use Cognesy\Instructor\Instructor;

// Step 0: Create .env file in your project root:
// OPENAI_API_KEY=your_api_key

// Step 1: Define target data structure(s)
class Person {
    public string $name;
    public int $age;
}

// Step 2: Provide content to process
$text = "His name is Jason and he is 28 years old.";

// Step 3: Use Instructor to run LLM inference
$person = (new Instructor)->respond(
    messages: $text,
    responseModel: Person::class,
);

// Step 4: Work with structured response data
assert($person instanceof Person); // true
assert($person->name === 'Jason'); // true
assert($person->age === 28); // true

echo $person->name; // Jason
echo $person->age; // 28

var_dump($person);
// Person {
//     name: "Jason",
//     age: 28
// }    

    // This is fragment of /config/llm.php file
    'defaultConnection' => 'openai',
    //...
    'connections' => [
        'anthropic' => [ ... ],
        'azure' => [ ... ],
        'cohere1' => [ ... ],
        'cohere2' => [ ... ],
        'fireworks' => [ ... ],
        'gemini' => [ ... ],
        'grok' => [ ... ],
        'groq' => [ ... ],
        'mistral' => [ ... ],
        'ollama' => [
            'providerType' => LLMProviderType::Ollama->value,
            'apiUrl' => 'http://localhost:11434/v1',
            'apiKey' => Env::get('OLLAMA_API_KEY', ''),
            'endpoint' => '/chat/completions',
            'defaultModel' => 'qwen2.5:0.5b',
            'defaultMaxTokens' => 1024,
            'httpClient' => 'guzzle-ollama', // use custom HTTP client configuration
        ],
        'openai' => [ ... ],
        'openrouter' => [ ... ],
        'together' => [ ... ],
    // ...


// ...
$user = (new Instructor)
    ->withConnection('ollama')
    ->respond(
        messages: "His name is Jason and he is 28 years old.",
        responseModel: Person::class,
    );
// ...


use Cognesy\Instructor\Instructor;

class Email {
    public function __construct(
        public string $address = '',
        public string $subject = '',
        public string $body = '',
    ) {}
}

$email = new Email(
    address: 'joe@gmail',
    subject: 'Status update',
    body: 'Your account has been updated.'
);

$translation = (new Instructor)->respond(
    input: $email,
    responseModel: Email::class,
    prompt: 'Translate the text fields of email to Spanish. Keep other fields unchanged.',
);

assert($translation instanceof Email); // true
dump($translation);
// Email {
//     address: "joe@gmail",
//     subject: "Actualización de estado",
//     body: "Su cuenta ha sido actualizada."
// }

use Symfony\Component\Validator\Constraints as Assert;

class Person {
    public string $name;
    #[Assert\PositiveOrZero]
    public int $age;
}

$text = "His name is Jason, he is -28 years old.";
$person = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => $text]],
    responseModel: Person::class,
);

// if the resulting object does not validate, Instructor throws an exception

use Symfony\Component\Validator\Constraints as Assert;

class Person {
    #[Assert\Length(min: 3)]
    public string $name;
    #[Assert\PositiveOrZero]
    public int $age;
}

$text = "His name is JX, aka Jason, he is -28 years old.";
$person = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => $text]],
    responseModel: Person::class,
    maxRetries: 3,
);

// if all LLM's attempts to self-correct the results fail, Instructor throws an exception

use Cognesy\Instructor\Instructor;

$instructor = (new Instructor)->request(
    messages: "His name is Jason, he is 28 years old.",
    responseModel: Person::class,
);
$person = $instructor->get();


use Cognesy\Instructor\Instructor;

$stream = (new Instructor)->request(
    messages: "His name is Jason, he is 28 years old.",
    responseModel: Person::class,
    options: ['stream' => true]
)->stream();

foreach ($stream as $partialPerson) {
    // process partial person data
    echo $partialPerson->name;
    echo $partialPerson->age;
}

// after streaming is done you can get the final, fully processed person object...
$person = $stream->getLastUpdate()
// ...to, for example, save it to the database
$db->save($person);

use Cognesy\Instructor\Instructor;

function updateUI($person) {
    // Here you get partially completed Person object update UI with the partial result
}

$person = (new Instructor)->request(
    messages: "His name is Jason, he is 28 years old.",
    responseModel: Person::class,
    options: ['stream' => true]
)->onPartialUpdate(
    fn($partial) => updateUI($partial)
)->get();

// Here you get completed and validated Person object
$this->db->save($person); // ...for example: save to DB

// Usually, you work with sequences of messages:

$value = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => "His name is Jason, he is 28 years old."]],
    responseModel: Person::class,
);

// ...but if you want to keep it simple, you can just pass a string:

$value = (new Instructor)->respond(
    messages: "His name is Jason, he is 28 years old.",
    responseModel: Person::class,
);

use Cognesy\Instructor\Extras\Scalar\Scalar;
use Cognesy\Instructor\Instructor;

$value = (new Instructor)->respond(
    messages: "His name is Jason, he is 28 years old.",
    responseModel: Scalar::integer('age'),
);

var_dump($value);
// int(28)

use Cognesy\Instructor\Extras\Scalar\Scalar;
use Cognesy\Instructor\Instructor;

enum ActivityType : string {
    case Work = 'work';
    case Entertainment = 'entertainment';
    case Sport = 'sport';
    case Other = 'other';
}

$value = (new Instructor)->respond(
    messages: "His name is Jason, he currently plays Doom Eternal.",
    responseModel: Scalar::enum(ActivityType::class, 'activityType'),
);

var_dump($value);
// enum(ActivityType:Entertainment)

class Person
{
    public string $name;
    public int $age;
}

$text = <<<TEXT
    Jason is 25 years old. Jane is 18 yo. John is 30 years old
    and Anna is 2 years younger than him.
TEXT;

$list = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => $text]],
    responseModel: Sequence::of(Person::class),
    options: ['stream' => true]
);

    class Person {
        public string $name;
        public ?int $age;
        public Address $address;
    }

class Person {
    /** @var string */
    public $name;
    /** @var int */
    public $age;
    /** @var Address $address person's address */
    public $address;
}

class Person {
    // ...
}

class Event {
    // ...
    /** @var Person[] list of extracted event participants */
    public array $participants;
    // ...
}

use Cognesy\Instructor\Instructor;

// define a data structures to extract data into
class Person {
    public string $name;
    public int $age;
    public string $profession;
    /** @var Skill[] */
    public array $skills;
}

class Skill {
    public string $name;
    public SkillType $type;
}

enum SkillType {
    case Technical = 'technical';
    case Other = 'other';
}

$text = "Alex is 25 years old software engineer, who knows PHP, Python and can play the guitar.";

$person = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => $text]],
    responseModel: Person::class,
); // client is passed explicitly, can specify e.g. different base URL

// data is extracted into an object of given class
assert($person instanceof Person); // true

// you can access object's extracted property values
echo $person->name; // Alex
echo $person->age; // 25
echo $person->profession; // software engineer
echo $person->skills[0]->name; // PHP
echo $person->skills[0]->type; // SkillType::Technical
// ...

var_dump($person);
// Person {
//     name: "Alex",
//     age: 25,
//     profession: "software engineer",
//     skills: [
//         Skill {
//              name: "PHP",
//              type: SkillType::Technical,
//         },
//         Skill {
//              name: "Python",
//              type: SkillType::Technical,
//         },
//         Skill {
//              name: "guitar",
//              type: SkillType::Other
//         },
//     ]
// }


use Cognesy\Instructor\Extras\Structure\Field;
use Cognesy\Instructor\Extras\Structure\Structure;

enum Role : string {
    case Manager = 'manager';
    case Line = 'line';
}

$structure = Structure::define('person', [
    Field::string('name'),
    Field::int('age'),
    Field::enum('role', Role::class),
]);

$person = (new Instructor)->respond(
    messages: 'Jason is 25 years old and is a manager.',
    responseModel: $structure,
);

// you can access structure data via field API...
assert($person->field('name') === 'Jason');
// ...or as structure object properties
assert($person->age === 25);

use Cognesy\Instructor\Features\LLM\Data\LLMConfig;
use Cognesy\Instructor\Features\LLM\Drivers\OpenAIDriver;
use Cognesy\Instructor\Instructor;

// OpenAI auth params
$yourApiKey = Env::get('OPENAI_API_KEY'); // use your own API key

// Create instance of OpenAI driver initialized with custom parameters
$driver = new OpenAIDriver(new LLMConfig(
    apiUrl: 'https://api.openai.com/v1', // you can change base URI
    apiKey: $yourApiKey,
    endpoint: '/chat/completions',
    metadata: ['organization' => ''],
    model: 'gpt-4o-mini',
    maxTokens: 128,
));

/// Get Instructor with the default client component overridden with your own
$instructor = (new Instructor)->withDriver($driver);

$user = $instructor->respond(
    messages: "Jason (@jxnlco) is 25 years old and is the admin of this project. He likes playing football and reading books.",
    responseModel: User::class,
    model: 'gpt-3.5-turbo',
    options: ['stream' => true ]
);

/**
 * Represents a skill of a person and context in which it was mentioned. 
 */
class Skill {
    public string $name;
    /** @var SkillType $type type of the skill, derived from the description and context */
    public SkillType $type;
    /** Directly quoted, full sentence mentioning person's skill */
    public string $context;
}

use Cognesy\Instructor\Features\Validation\Traits\ValidationMixin;

class User {
    use ValidationMixin;

    public int $age;
    public int $name;

    public function validate() : array {
        if ($this->age < 18) {
            return ["User has to be adult to sign the contract."];
        }
        return [];
    }
}

use Cognesy\Instructor\Instructor;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

class UserDetails
{
    public string $name;
    public int $age;
    
    #[Assert\Callback]
    public function validateName(ExecutionContextInterface $context, mixed $payload) {
        if ($this->name !== strtoupper($this->name)) {
            $context->buildViolation("Name must be in uppercase.")
                ->atPath('name')
                ->setInvalidValue($this->name)
                ->addViolation();
        }
    }
}

$user = (new Instructor)->respond(
    messages: [['role' => 'user', 'content' => 'jason is 25 years old']],
    responseModel: UserDetails::class,
    maxRetries: 2
);

assert($user->name === "JASON");

$instructor = (new Instructor)
    // see requests to LLM
    ->onEvent(RequestSentToLLM::class, fn($e) => dump($e))
    // see responses from LLM
    ->onEvent(ResponseReceivedFromLLM::class, fn($event) => dump($event))
    // see all events in console-friendly format
    ->wiretap(fn($event) => dump($event->toConsole()));

$instructor->respond(
    messages: "What is the population of Paris?",
    responseModel: Scalar::integer(),
);
// check your console for the details on the Instructor execution
bash
composer