Overview

As your applications grow in complexity, your prompts may become large and complex, with multiple variables and metadata. Managing these prompts can become a challenge, especially when you need to reuse them across different parts of your application. Large prompts are also hard to maintain if they are part of your codebase.

Prompt addon provides a powerful and flexible way to manage your prompts. It supports multiple template engines (Twig, Blade), prompt metadata, variable injection, and validation.

What are Prompts

Prompts in Instructor are based on structured text templates that can be rendered to text or series of chat messages. As many of your prompts will be dynamically generated based on input data, you can use syntax of one of the supported template engines (Twig, Blade) to define your prompts.

This document will be using Twig syntax for prompt templates for simplicity and consistency, but you can use Blade syntax in your prompts if you prefer it.

Basic Prompt Template

Example prompt template in Twig:

Hello, world.

Prompt Template with Variables

You can define variables in your prompt templates and inject values when rendering the prompt.

Hello, {{ name }}!

Chat Messages

You can define chat messages in your prompts, which can be used to generate a sequence of messages for LLM chat APIs.

<chat>
    <message role="system">You are a helpful assistant.</message>
    <message role="user">What is the capital of {{ country }}?</message>
</chat>

Prompt Template Metadata

We recommend to preface each prompt with front matter - a block of metadata that describes the prompt and its variables. This metadata can be used for validation, documentation, and schema generation.

{#---
description: Capital finder template
variables:
    country:
        description: Country name
        type: string
        default: France
schema:
    name: capital
    properties:
        name:
            description: Capital city name
            type: string
    required: [name]
---#}
<chat>
    <message role="system">You are a helpful assistant.</message>
    <message role="user">What is the capital of {{ country }}?</message>
</chat>

Template Libraries

Instructor allows you to define multiple template libraries in your app. Library is just a collection of prompt templates which is stored under a specific directory. Library can have a nested structure, which allows you to organize your prompts in a way that makes sense for your application.

Library properties are specified in config/prompt.php configuration file.

where you can define:

  • templateEngine - template engine used for prompts in this library,
  • resourcePath - path to prompt templates,
  • cachePath - path to compiled templates,
  • extension - file extension for prompt templates,
  • frontMatterTags - start and end tags for front matter,
  • frontMatterFormat - format of front matter (yaml, json, toml),
  • metadata - engine-specific configuration.

Instructor comes with 3 default prompt libraries:

  • system - prompt templates used by Instructor itself,
  • demo-twig - demo prompt templates using Twig template engine,
  • demo-blade - demo prompt templates using Blade template engine.

Instructor’s does not specify how you should organize or manage your prompt templates, but it provides a flexible way to do it in a way that suits your application.

Using Prompt Templates

Rendering a Simple Prompt

To get started, you can create and render a simple prompt defined in the bundled library using the Prompt::using or Prompt::make methods. Here’s how you can use them:

<?php
use Cognesy\Instructor\Extras\Prompt\Template;

// Basic example using "using->get->with" syntax
$prompt = Template::using('demo-twig')->get('hello')->with(['name' => 'World']);

echo $prompt->toText(); // Outputs: "Hello, World!"
?>

Or, using the shorthand make() syntax:

<?php
$prompt = Template::make('demo-twig:hello')->with(['name' => 'World']);

echo $prompt->toText(); // Outputs: "Hello, World!"
?>

Rendering a Chat Template

The Prompt class can also render prompts directly as chat-style messages:

<?php
$messages = Template::messages('demo-twig:hello', ['name' => 'World']);

print_r($messages->toArray());
// Outputs:
// [
//     ['role' => 'user', 'content' => 'Hello, World!']
// ]
?>

Custom Configuration and Template Content

If you need to customize the configuration or set the template content directly, you can do so with additional methods:

<?php
use Cognesy\Instructor\Extras\Prompt\Data\TemplateEngineConfig;
use Cognesy\Instructor\Extras\Prompt\Enums\TemplateEngineType;

// Setting custom configuration
$config = new TemplateEngineConfig(
    templateEngine: TemplateEngineType::Twig,
    resourcePath: '',
    cachePath: '/tmp/cache',
    extension: '.twig',
);

$prompt = new Template();
$prompt->withConfig($config)
       ->withTemplateContent('Hello, {{ name }}!')
       ->withValues(['name' => 'World']);

echo $prompt->toText(); // Outputs: "Hello, World!"
?>

In Memory Templates

If you need to create an inline prompt (without saving it to a file), you can use following syntax:

<?php
$prompt = Template::twig() // or Template::blade() for Blade syntax
    ->withTemplateContent('Hello, {{ name }}!')
    ->withValues(['name' => 'World'])
    ->toText();
?>

There’s shorter syntax for creating in-memory prompts:

<?php
$prompt = Template::twig() // or Template::blade() for Blade syntax
    ->from('Hello, {{ name }}!')
    ->with(['name' => 'World'])
    ->toText();
?>

Handling Template Variables

To check which variables are available in a prompt template:

<?php
$prompt = Template::using('demo-twig')
    ->withTemplateContent('Hello, {{ name }}!')
    ->withValues(['name' => 'World']);

$variables = $prompt->variables();

print_r($variables); // Outputs: ['name']
?>

Loading Templates by Name and Using DSNs

For more flexible template loading, you can load templates by name or use a ‘DSN-like’ (Data Source Name) syntax:

<?php
// Load a template by name using specified library 'demo-blade'
$prompt = Template::using('demo-blade')->withTemplate('hello');
echo $prompt->template();

// Load a template from specified library using DSN syntax
$prompt = Template::fromDsn('demo-blade:hello')->with(['name' => 'World']);
echo $prompt->toText(); // Outputs: "Hello, World!"
?>

Converting to Messages with Markup

The Prompt class also supports converting templates containing chat-specific markup into structured messages:

Here is an example XML that can be used to generate a sequence of chat messages:

<chat>
    <message role="system">You are a helpful assistant.</message>
    <message role="user">Hello, {{ name }}</message>
</chat>

And here is how you use Prompt class to convert XML template into a sequence of messages:

<?php
use Cognesy\Instructor\Utils\Messages\Messages;

$prompt = Template::using('demo-blade')
    ->withTemplateContent('<chat><message role="system">You are a helpful assistant.</message><message role="user">Hello, {{ $name }}</message></chat>')
    ->withValues(['name' => 'assistant']);

$messages = $prompt->toMessages();

echo $messages->toArray();
// Outputs:
// [
//     ['role' => 'system', 'content' => 'You are a helpful assistant.'],
//     ['role' => 'user', 'content' => 'Hello, assistant']
// ]
?>