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
// }
// ...
$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
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.