Skip to content

Prompts

Instructor provides several prompt hooks that let you shape the messages sent to the LLM. These are intentionally simple -- Instructor is not a prompt management framework, but it gives you the building blocks you need for most structured output tasks.

StructuredPromptRequestMaterializer is the default. It uses prompt classes and bundled Twig markdown templates. Custom prompt classes are the supported extension seam.

The deprecated RequestMaterializer remains available through explicit StructuredOutputRuntime::withRequestMaterializer() injection for 2.5 compatibility.

Prompt Hooks

System Message

Set a system-level instruction that frames the entire extraction task.

use Cognesy\Instructor\StructuredOutput;

$result = (new StructuredOutput)
    ->withSystem('You are a data extraction assistant. Be precise and thorough.')
    ->with(messages: $text, responseModel: Person::class)
    ->get();

User Prompt

Add an additional prompt that supplements the input messages. This is useful for providing extraction instructions without mixing them into the data.

$result = (new StructuredOutput)
    ->withPrompt('Extract all person information. If age is not stated, estimate based on context.')
    ->with(messages: $text, responseModel: Person::class)
    ->get();

Examples

Provide input/output examples to guide the LLM's extraction behavior. Few-shot examples are one of the most effective ways to improve extraction accuracy.

use Cognesy\Instructor\Extras\Example\Example;

$result = (new StructuredOutput)
    ->withExamples([
        new Example(
            input: 'Dr. Smith is a 45-year-old cardiologist from Boston.',
            output: ['name' => 'Dr. Smith', 'age' => 45, 'occupation' => 'cardiologist'],
        ),
    ])
    ->with(messages: $text, responseModel: Person::class)
    ->get();

Combined Usage

All prompt hooks can be used together in a single request, either through the fluent API or the with() shorthand.

$result = (new StructuredOutput)
    ->withSystem('You are a precise data extraction assistant.')
    ->withPrompt('Extract person details from the text below.')
    ->withExamples($examples)
    ->withMessages($text)
    ->withResponseClass(Person::class)
    ->get();

// Or equivalently:
$result = (new StructuredOutput)->with(
    system: 'You are a precise data extraction assistant.',
    prompt: 'Extract person details from the text below.',
    examples: $examples,
    messages: $text,
    responseModel: Person::class,
)->get();

Using Stringable Objects as Prompts

Both withSystem() and withPrompt() accept string|\Stringable, so you can pass any object that implements Stringable -- such as an xprompt Prompt class -- directly, without calling ->render() or (string) yourself. The value is cast to string immediately at the boundary.

use Cognesy\Instructor\StructuredOutput;
use App\Prompts\ExtractionSystem;

$result = (new StructuredOutput)
    ->withSystem(ExtractionSystem::with(domain: 'finance'))
    ->withPrompt('Extract person details from the text below.')
    ->with(messages: $text, responseModel: Person::class)
    ->get();

Cached Context

For applications that use the same large context across multiple requests (such as a long document or a set of reference materials), withCachedContext() marks content for provider-level prompt caching. This can significantly reduce costs and latency when supported by the provider.

$result = (new StructuredOutput)
    ->withCachedContext(
        system: 'You are a legal document analyst.',
        messages: $longDocument,
        prompt: 'Extract all party names and obligations.',
        examples: $examples,
    )
    ->with(messages: 'Focus on section 3.', responseModel: ContractDetails::class)
    ->get();

Cached context messages are placed before the regular messages in the chat structure. The exact caching behavior depends on the LLM provider -- Anthropic and OpenAI both support prompt caching with different mechanisms.

On the default path, cached prompt content is not flattened into ordinary live messages. It is projected into InferenceRequest::cachedContext() so provider-native caching can take effect, while the per-request prompt remains live.

Switching Materializers

use Cognesy\Instructor\Core\RequestMaterializer;
use Cognesy\Instructor\StructuredOutput;
use Cognesy\Instructor\StructuredOutputRuntime;

$runtime = StructuredOutputRuntime::fromDefaults();

$legacyRuntime = $runtime->withRequestMaterializer(new RequestMaterializer());

$so = (new StructuredOutput)
    ->withRuntime($runtime)
    ->with(messages: $text, responseModel: Person::class);

Use the legacy runtime only as a migration bridge. RequestMaterializer and its inline prompt/chat-structure configuration are scheduled for removal in 2.6.

Template Engine Integration

If your application needs a more sophisticated prompt management system with variable interpolation, conditional logic, or template libraries, use the companion Template class from the cognesy/template package.

use Cognesy\Template\Template;

$rendered = Template::twig()
    ->from('Extract {{ entity_type }} from the following text: {{ text }}')
    ->with(['entity_type' => 'person', 'text' => $input])
    ->toText();

$result = (new StructuredOutput)
    ->with(messages: $rendered, responseModel: Person::class)
    ->get();

The generic Template package supports Twig, Blade, and Arrowpipe. That does not make the bundled Instructor prompts engine-selectable: the bundled prompt set uses Twig. Render alternate templates before passing them to StructuredOutput, or supply custom prompt classes. See the Template package documentation for full details.