Instructor’s request parameter responseModel allows you to specify shape of the response you expect from LLM .

Instructor translates the responseModel parameter into actual schema based on the type and value of the parameter.

Handling string $responseModel value

If string value is provided, it is used as a name of the class of the response model.

Instructor checks if the class exists and analyzes the class & properties type information & doc comments to generate a schema needed to specify LLM response constraints.

The best way to provide the name of the response model class is to use NameOfTheClass::class, making it easy for IDE to check the type, handle refactorings, etc.

Handling object $responseModel value

If object value is provided, it is considered an instance of the response model. Instructor checks the class of the instance, then analyzes it and its property type data to specify LLM response constraints.

Handling array $responseModel value

If array value is provided, it is considered a raw JSON Schema, therefore allowing Instructor to use it directly in LLM requests (after wrapping in appropriate context - e.g. function call).

Instructor requires information on the class of each nested object in your JSON Schema, so it can correctly deserialize the data into appropriate type.

This information is available to Instructor when you are passing $responseModel as a class name or an instance, but it is missing from raw JSON Schema. Lack of the information on target class makes it impossible for Instructor to deserialize the data into appropriate, expected type.

Current design uses JSON Schema $comment field on property to overcome this information gap. Instructor expects developer to use $comment field to provide fully qualified name of the target class to be used to deserialize property data of object or enum type.

Custom response handling strategy

Instructor allows you to customize processing of $responseModel value also by looking at the interfaces the class or instance implements:

  • CanProvideJsonSchema - implement to be able to provide raw JSON Schema (as an array) of the response model, overriding the default approach of Instructor, which is analyzing $responseModel value class information,
  • CanProvideSchema - implement to be able to provide Schema object of the response model, overriding class analysis stage; can be useful in building object wrappers (see: Sequence class),
  • CanDeserializeSelf - implement to customize the way the response from LLM is deserialized from JSON into PHP object,
  • CanValidateSelf - implement to customize the way the deserialized object is validated - it fully replaces the default validation process for given response model,
  • CanTransformSelf - implement to transform the validated object into any target value that will be then passed back to the caller (e.g. unwrap simple type from a class to scalar value)

Methods implemented by those interfaces are executed as following:

  • CanProvideJsonSchema - executed during the schema generation phase,
  • CanDeserializeSelf - executed during the deserialization phase,
  • CanValidateSelf - executed during the validation phase,
  • CanTransformSelf - executed during the transformation phase.

When implementing custom response handling strategy, avoid doing all transformations in a single block of code. Split the logic between relevant methods implemented by your class for clarity and easier code maintenance.

Example implementations

For a practical example of using those contracts to customize Instructor processing flow see:

  • src/Extras/Scalar/
  • src/Extras/Sequence/

Examples contain an implementation of custom response model handling strategies, e.g. providing scalar value support via a wrapper class implementing:

  • custom schema provider,
  • deserialization,
  • validation
  • and transformation

into requested value type.