Skip to main content
Presets are the recommended way to configure Polyglot. They live in YAML files, keep secrets in environment variables, and let you switch providers without touching application code. However, there are situations where presets are not sufficient — when configuration values are dynamic, generated at runtime, or sourced from your own application’s settings. In these cases, you can build LLMConfig or EmbeddingsConfig objects directly.

The Configuration Files

Polyglot ships with YAML preset files organized in two directories:
  • config/llm/presets/ — one file per inference provider (e.g. openai.yaml, anthropic.yaml)
  • config/embed/presets/ — one file per embeddings provider
A typical preset file looks like this:
# config/llm/presets/openai.yaml
driver: openai
apiUrl: 'https://api.openai.com/v1'
apiKey: '${OPENAI_API_KEY}'
endpoint: /chat/completions
metadata:
  organization: ''
  project: ''
model: gpt-4.1-nano
maxTokens: 1024
contextLength: 1000000
maxOutputLength: 16384
# @doctest id="0ca7"
Environment variable references like ${OPENAI_API_KEY} are resolved automatically at load time. Polyglot searches for preset files in the following directories, in order:
  1. config/llm/presets/ (your project root)
  2. packages/polyglot/resources/config/llm/presets/ (monorepo layout)
  3. vendor/cognesy/instructor-php/packages/polyglot/resources/config/llm/presets/
  4. vendor/cognesy/instructor-polyglot/resources/config/llm/presets/
The first directory that exists wins. You can override the search path by passing a $basePath argument to Inference::using().

Configuration Parameters

Each LLM configuration includes these parameters:
ParameterTypeDescription
driverstringThe protocol driver to use (e.g. openai, anthropic, openai-compatible)
apiUrlstringBase URL for the provider’s API
apiKeystringAPI key for authentication
endpointstringThe API endpoint path (e.g. /chat/completions)
queryParamsarrayOptional query string parameters appended to the URL
metadataarrayProvider-specific settings (organization, API version, etc.)
modelstringDefault model name
maxTokensintDefault maximum tokens for responses
contextLengthintMaximum context window supported by the model
maxOutputLengthintMaximum output length supported by the model
optionsarrayDefault request options passed to every call
pricingarrayOptional token pricing information for cost tracking
Embeddings configurations use a similar structure with dimensions and maxInputs instead of the token-related fields.

Runtime Configuration with LLMConfig

When you need to build a configuration programmatically, use the LLMConfig class:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Config\LLMConfig;
use Cognesy\Polyglot\Inference\Inference;

$config = new LLMConfig(
    driver: 'openai',
    apiUrl: 'https://api.openai.com/v1',
    apiKey: (string) getenv('OPENAI_API_KEY'),
    endpoint: '/chat/completions',
    model: 'gpt-4.1-nano',
    maxTokens: 2048,
    contextLength: 1000000,
    maxOutputLength: 16384,
);

$text = Inference::fromConfig($config)
    ->withMessages(Messages::fromString('Say hello.'))
    ->get();
// @doctest id="bde8"
Note: Messages is imported from Cognesy\Messages\Messages. You can create messages from a string with Messages::fromString() or from an array of role/content pairs with Messages::fromArray(). This is useful when your application stores provider credentials in a database, rotates API keys at runtime, or needs to construct configurations for providers not included in the bundled presets.

Creating Configurations from Arrays

You can also create an LLMConfig from an associative array, which is convenient when loading configuration from a database or external source:
<?php

use Cognesy\Polyglot\Inference\Config\LLMConfig;

$config = LLMConfig::fromArray([
    'driver' => 'openai',
    'apiUrl' => 'https://api.openai.com/v1',
    'apiKey' => $apiKeyFromDatabase,
    'endpoint' => '/chat/completions',
    'model' => 'gpt-4.1-nano',
    'maxTokens' => 1024,
]);
// @doctest id="f270"

Overriding Configuration Values

If you need to modify an existing configuration, use withOverrides() to create a new instance with specific values changed:
<?php

use Cognesy\Polyglot\Inference\Config\LLMConfig;

$baseConfig = LLMConfig::fromPreset('openai');

// Create a variant with a different model and higher token limit
$highCapConfig = $baseConfig->withOverrides([
    'model' => 'gpt-4.1',
    'maxTokens' => 4096,
]);
// @doctest id="bfd0"

Embeddings Configuration

The embeddings equivalent follows the same pattern:
<?php

use Cognesy\Polyglot\Embeddings\Config\EmbeddingsConfig;
use Cognesy\Polyglot\Embeddings\Embeddings;

$embeddings = Embeddings::fromConfig(new EmbeddingsConfig(
    driver: 'openai',
    apiUrl: 'https://api.openai.com/v1',
    apiKey: (string) getenv('OPENAI_API_KEY'),
    endpoint: '/embeddings',
    model: 'text-embedding-3-small',
    dimensions: 1536,
    maxInputs: 2048,
));
// @doctest id="120b"
The embeddings configuration parameters are:
ParameterTypeDescription
driverstringThe driver to use (e.g. openai, cohere, gemini, jina)
apiUrlstringBase URL for the provider’s API
apiKeystringAPI key for authentication
endpointstringThe API endpoint path (e.g. /embeddings)
modelstringThe embedding model name
dimensionsintThe dimensionality of the embedding vectors
maxInputsintMaximum number of inputs per batch request
metadataarrayProvider-specific settings

DSN Input

Both LLMConfig and EmbeddingsConfig support a lightweight DSN (Data Source Name) format for quick inline configuration:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Config\LLMConfig;
use Cognesy\Polyglot\Inference\Inference;

$config = LLMConfig::fromDsn('openai://api.openai.com/v1?model=gpt-4.1-nano&apiKey=sk-...');

$response = Inference::fromConfig($config)
    ->withMessages(Messages::fromString('Hello!'))
    ->get();
// @doctest id="9254"
The DSN format encodes the driver as the scheme, the host and path as the API URL, and query parameters for the remaining configuration values.

Managing API Keys

API keys should never be committed to your codebase. Polyglot preset files use environment variable references (${OPENAI_API_KEY}) that are resolved at load time. Store your keys in a .env file:
OPENAI_API_KEY=sk-your-key-here
ANTHROPIC_API_KEY=sk-ant-your-key-here
GEMINI_API_KEY=your-key-here
MISTRAL_API_KEY=your-key-here
# @doctest id="0d7f"
Load them with a package like vlucas/phpdotenv, or rely on your framework’s built-in environment handling (Laravel loads .env automatically).
Security Tip: The apiKey parameter on LLMConfig is marked with PHP’s #[SensitiveParameter] attribute, which prevents it from appearing in stack traces. Polyglot also redacts sensitive values from event payloads and debug output.

Provider-Specific Options

Different providers support unique request parameters. You can pass these through the options parameter on each request:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;

// OpenAI-specific options
$response = Inference::using('openai')
    ->with(
        messages: Messages::fromString('Generate a creative story.'),
        options: [
            'temperature' => 0.8,
            'top_p' => 0.95,
            'frequency_penalty' => 0.5,
            'presence_penalty' => 0.5,
            'stop' => ["\n\n", "THE END"],
        ],
    )
    ->get();
// @doctest id="ddc3"
For Anthropic, the available options differ:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;

// Anthropic-specific options
$response = Inference::using('anthropic')
    ->with(
        messages: Messages::fromString('Generate a creative story.'),
        options: [
            'temperature' => 0.7,
            'top_p' => 0.9,
            'top_k' => 40,
        ],
    )
    ->get();
// @doctest id="2a0c"
Polyglot passes these options through to the provider’s API without modification, so consult each provider’s documentation for the full list of supported parameters. You can also set default options in the preset YAML file so they apply to every request made with that preset:
# config/llm/presets/creative-openai.yaml
driver: openai
apiUrl: 'https://api.openai.com/v1'
apiKey: '${OPENAI_API_KEY}'
endpoint: /chat/completions
model: gpt-4.1
maxTokens: 2048
options:
  temperature: 0.9
  top_p: 0.95
# @doctest id="e154"

Environment-Based Configuration

You can create custom presets for different deployment environments. For example, use a local Ollama instance in development and a cloud provider in production:
# config/llm/presets/dev-local.yaml
driver: openai-compatible
apiUrl: 'http://localhost:11434/v1'
apiKey: ''
endpoint: /chat/completions
model: llama3
maxTokens: 1024
# @doctest id="9686"
Then select the preset based on your application’s environment:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;

$preset = getenv('APP_ENV') === 'production' ? 'openai' : 'dev-local';

$response = Inference::using($preset)
    ->withMessages(Messages::fromString('Hello!'))
    ->get();
// @doctest id="7929"
This pattern keeps your application code completely environment-agnostic. The only thing that changes between environments is which preset name is selected.

Creating Custom Preset Files

To add a new provider or a custom configuration, create a new YAML file in your project’s config/llm/presets/ directory:
# config/llm/presets/my-proxy.yaml
driver: openai-compatible
apiUrl: 'https://my-proxy.example.com/v1'
apiKey: '${MY_PROXY_API_KEY}'
endpoint: /chat/completions
model: gpt-4.1-nano
maxTokens: 2048
contextLength: 128000
maxOutputLength: 16384
# @doctest id="6da3"
Then reference it by name:
<?php

use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;

$response = Inference::using('my-proxy')
    ->withMessages(Messages::fromString('Hello from my proxy!'))
    ->get();
// @doctest id="864f"
Polyglot will find your custom preset file before falling back to the bundled presets, so you can override any built-in preset by creating a file with the same name in your project’s configuration directory.