Customize Prompts
Instructor builds a structured prompt from several components: system text, user messages, a mode-specific instruction prompt, examples, and retry context. You can customize most of these to tune extraction behavior without changing the underlying extraction flow.
The default StructuredPromptRequestMaterializer uses prompt classes backed by bundled
Twig templates. Customize it by supplying your own prompt classes.
System And Prompt Text¶
The two most common customization points are the system message and the prompt text:
use Cognesy\Instructor\StructuredOutput;
$result = (new StructuredOutput)
->withSystem('You are a precise data extraction assistant. Return only factual data.')
->withPrompt('Extract the contact details from the text below.')
->with(messages: $text, responseModel: Contact::class)
->get();
// @doctest id="c9d2"
- System text sets the model's persona and overall behavior. Use it for stable instructions that apply across many requests.
- Prompt text provides task-specific instructions for this particular extraction. On the default structured prompt path it is rendered inside the single system prompt body alongside the mode-specific extraction instructions.
You can also pass both through the with() method:
$result = (new StructuredOutput)
->with(
messages: $text,
responseModel: Contact::class,
system: 'Return concise, accurate data.',
prompt: 'Extract the contact details.',
)
->get();
// @doctest id="2d31"
Examples¶
Few-shot examples are another prompt component. On the default structured prompt path they are rendered as markdown inside the system prompt to demonstrate the expected extraction style:
use Cognesy\Instructor\Extras\Example\Example;
$result = (new StructuredOutput)
->withExamples([
Example::fromText('Jane Doe, 31', ['name' => 'Jane Doe', 'age' => 31]),
])
->with(messages: $text, responseModel: Person::class)
->get();
// @doctest id="ee09"
See the Demonstrations page for details on the Example class.
Cached Context¶
Some providers (notably Anthropic) support prompt caching, where stable parts of the
conversation are cached between requests to reduce latency and cost. Use
withCachedContext() to mark content as cacheable:
$result = (new StructuredOutput)
->withCachedContext(
messages: $referenceDocument,
system: 'You are a document analyst.',
prompt: 'Extract entities from the document.',
examples: $examples,
)
->with(messages: 'Now extract from this specific paragraph...', responseModel: Entity::class)
->get();
// @doctest id="5a27"
The cached context is placed before the per-request content in the prompt. On the new
structured prompt path, cached system text, cached task text, and cached examples are
rendered into a cached system prompt and projected through provider-native cached context.
Content passed through withCachedContext() is marked with cache control headers where the
provider supports them.
Mode-Specific Prompts¶
Instructor uses a default prompt class for each output mode that tells the model how to
format its response. The bundled classes use .md.twig templates and are configured in
StructuredOutputConfig.
| Mode | Default prompt behavior |
|---|---|
Tools |
"Extract correct and accurate data from the input using provided tools." |
Json |
Includes the JSON Schema and asks for a strict JSON response |
JsonSchema |
Asks for a strict JSON response following the provided schema |
MdJson |
Includes the JSON Schema and asks for JSON inside a Markdown code block |
Overriding Mode Prompts¶
Use prompt classes as the supported customization seam:
$config = new StructuredOutputConfig(
modePromptClasses: [
OutputMode::Tools->value => App\Prompts\ToolsSystemPrompt::class,
OutputMode::Json->value => App\Prompts\JsonSystemPrompt::class,
OutputMode::JsonSchema->value => App\Prompts\JsonSchemaSystemPrompt::class,
OutputMode::MdJson->value => App\Prompts\MdJsonSystemPrompt::class,
],
retryPromptClass: App\Prompts\RetryFeedbackPrompt::class,
deserializationErrorPromptClass: App\Prompts\DeserializationRepairPrompt::class,
);
// @doctest id="b4c5"
If you store these in YAML, use FQN strings:
modePromptClasses:
tool_call: 'App\\Prompts\\ToolsSystemPrompt'
json: 'App\\Prompts\\JsonSystemPrompt'
json_schema: 'App\\Prompts\\JsonSchemaSystemPrompt'
md_json: 'App\\Prompts\\MdJsonSystemPrompt'
retryPromptClass: 'App\\Prompts\\RetryFeedbackPrompt'
deserializationErrorPromptClass: 'App\\Prompts\\DeserializationRepairPrompt'
# @doctest id="6405"
Tool Name And Description¶
In OutputMode::Tools, the tool definition sent to the model includes a name and
description. These provide semantic context that can improve extraction quality:
use Cognesy\Instructor\Config\StructuredOutputConfig;
$config = new StructuredOutputConfig(
toolName: 'extract_person',
toolDescription: 'Extract personal information from the provided text.',
);
// @doctest id="5dcb"
The defaults are extracted_data and Function call based on user instructions.
respectively. Overriding them with task-specific values can help the model understand
what the tool represents.
OutputMode::JsonandOutputMode::MdJsonignore tool name and description since they do not use tool calling.
Retry Prompt¶
When validation fails and retries are enabled, Instructor renders the configured retry prompt class:
$config = new StructuredOutputConfig(
retryPromptClass: App\Prompts\RetryFeedbackPrompt::class,
);
// @doctest id="6aa0"
The same pattern applies to deserialization repair via deserializationErrorPromptClass.
Legacy Compatibility¶
The inline modePrompts, retryPrompt, and chatStructure settings were removed in 2.7
along with the legacy materializer that read them. StructuredOutputConfig::fromArray()
ignores them rather than failing, so old config files keep loading. Use prompt classes, or
provide a custom CanMaterializeRequest implementation when prompt-class customization is
insufficient.